如何将 D3 图保存为 django 网站中的图像?
Posted
技术标签:
【中文标题】如何将 D3 图保存为 django 网站中的图像?【英文标题】:How to save D3 graphs as images in django website? 【发布时间】:2016-05-10 08:03:14 【问题描述】:我是 Django 和 D3 的新手。我创建了一个可以创建多个动态 d3 图的 Django 网站。我想添加一个功能,用户可以将图表保存为图像,以便他们可以将其用于报告目的。
我使用以下链接作为tutorials 还可以找到我的代码以供参考
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: A starting point for interactivity</title>
<script type="text/javascript" src="../d3/d3.v3.js"></script>
<style type="text/css">
.graph1
float : left ;
height : 400px;
width : 600px;
font: 20px sans-serif;
text-align: left;
margin-left : 20px;
border : 1px solid black;
.graph2
float : right ;
margin-right : 20px ;
width : 600px;
height : 400px;
border : 1px solid black;
overflow: scroll;
border : 1px solid black;
.button1
float :left ;
.button2
float :right ;
</style>
</head>
<body>
<div id="area1" class="graph1"></div>
<div id="area2" class="graph2"></div>
<button id="save" class="button1">Save as Image</button>
<canvas id="canvas1" style="display:none"> </canvas>
<button id="save1" class="button2">Save as Image</button>
<canvas id="canvas2" style="display:none"></canvas>
<script type="text/javascript">
//Width and height
var w = 600;
var h = 400;
var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, w], 0.05);
var yScale = d3.scale.linear()
.domain([0, d3.max(dataset)])
.range([0, h]);
//Create SVG element
var svg1 = d3.select("#area1")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create bars
svg1.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i)
return xScale(i);
)
.attr("y", function(d)
return h - yScale(d);
)
.attr("width", xScale.rangeBand())
.attr("height", function(d)
return yScale(d);
)
.attr("fill", function(d)
return "rgb(0, 0, " + (d * 10) + ")";
);
//Create labels
svg1.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d)
return d;
)
.attr("text-anchor", "middle")
.attr("x", function(d, i)
return xScale(i) + xScale.rangeBand() / 2;
)
.attr("y", function(d)
return h - yScale(d) + 14;
)
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
d3.select("#save").on("click", function()
var html = d3.select("svg")
.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg")
.node().parentNode.innerHTML;
//console.log(html);
var imgsrc = 'data:image/svg+xml;base64,'+ btoa(html);
var img = '<img src="'+imgsrc+'">';
//d3.select("#svgdataurl").html(img);
var canvas = document.getElementById("canvas1"),
context = canvas.getContext("2d");
var image = new Image;
image.src = imgsrc;
image.onload = function()
context.drawImage(image, 0, 0);
var canvasdata = canvas.toDataURL("image/png");
var pngimg = '<img src="'+canvasdata+'">';
//d3.select("#pngdataurl").html(pngimg);
var a = document.createElement("a");
a.download = "sample1.png";
a.href = canvasdata;
document.body.appendChild(a);
a.click();
;
);
//pie chart
//Width and height
var w = 380;
var h = 380;
var dataset = [ 5, 10, 20, 45, 6, 25 ];
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie();
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category10();
//Create SVG element
var svg = d3.select("#area2")
.append("svg")
.attr("width", w)
.attr("height", h);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
//Draw arc paths
arcs.append("path")
.attr("fill", function(d, i)
return color(i);
)
.attr("d", arc);
//Labels
arcs.append("text")
.attr("transform", function(d)
return "translate(" + arc.centroid(d) + ")";
)
.attr("text-anchor", "middle")
.text(function(d)
return d.value;
);
d3.select("#save1").on("click", function()
var html = d3.select("svg")
.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg")
.node().parentNode.innerHTML;
//console.log(html);
var imgsrc = 'data:image/svg+xml;base64,'+ btoa(html);
var img = '<img src="'+imgsrc+'">';
//d3.select("#svgdataurl").html(img);
var canvas = document.getElementById("canvas2"),
context = canvas.getContext("2d");
var image = new Image;
image.src = imgsrc;
image.onload = function()
context.drawImage(image, 0, 0);
var canvasdata = canvas.toDataURL("image/png");
var pngimg = '<img src="'+canvasdata+'">';
//d3.select("#pngdataurl").html(pngimg);
var a = document.createElement("a");
a.download = "sample2.png";
a.href = canvasdata;
document.body.appendChild(a);
a.click();
;
);
</script>
</body>
从两个另存为按钮我只能保存第一张图片。我想我无法正确选择 d3/svg 元素。
谢谢
【问题讨论】:
【参考方案1】:在您的d3.select("#save1").on("click"
中,您的 svg 选择器是错误的。这个:
var html = d3.select("svg")
...
将始终选择页面上的 first svg
元素。你需要这样的东西:
var html = d3.select("#area2>svg")
...
这将选择svg
,它是您的div
的子代,ID 为 area2。
完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>D3: A starting point for interactivity</title>
<script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<style type="text/css">
.graph1
float : left ;
height : 400px;
width : 600px;
font: 20px sans-serif;
text-align: left;
margin-left : 20px;
border : 1px solid black;
.graph2
float : right ;
margin-right : 20px ;
width : 600px;
height : 400px;
border : 1px solid black;
overflow: scroll;
border : 1px solid black;
.button1
float :left ;
.button2
float :right ;
</style>
</head>
<body>
<div id="area1" class="graph1"></div>
<div id="area2" class="graph2"></div>
<button id="save" class="button1">Save as Image</button>
<canvas id="canvas1" style="display:none"></canvas>
<button id="save1" class="button2">Save as Image</button>
<canvas id="canvas2" style="display:none"></canvas>
<script type="text/javascript">
//Width and height
var w = 600;
var h = 400;
var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset.length))
.rangeRoundBands([0, w], 0.05);
var yScale = d3.scale.linear()
.domain([0, d3.max(dataset)])
.range([0, h]);
//Create SVG element
var svg1 = d3.select("#area1")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create bars
svg1.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function(d, i)
return xScale(i);
)
.attr("y", function(d)
return h - yScale(d);
)
.attr("width", xScale.rangeBand())
.attr("height", function(d)
return yScale(d);
)
.attr("fill", function(d)
return "rgb(0, 0, " + (d * 10) + ")";
);
//Create labels
svg1.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d)
return d;
)
.attr("text-anchor", "middle")
.attr("x", function(d, i)
return xScale(i) + xScale.rangeBand() / 2;
)
.attr("y", function(d)
return h - yScale(d) + 14;
)
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white");
d3.select("#save").on("click", function()
var html = d3.select("svg")
.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg")
.node().parentNode.innerHTML;
//console.log(html);
var imgsrc = 'data:image/svg+xml;base64,'+ btoa(html);
var img = '<img src="'+imgsrc+'">';
//d3.select("#svgdataurl").html(img);
var canvas = document.getElementById("canvas1"),
context = canvas.getContext("2d");
context.strokeStyle = "black";
context.rect(0,0,w,h);
context.fill();
var image = new Image;
image.src = imgsrc;
image.onload = function()
context.drawImage(image, 0, 0);
var canvasdata = canvas.toDataURL("image/png");
var pngimg = '<img src="'+canvasdata+'">';
//d3.select("#pngdataurl").html(pngimg);
var a = document.createElement("a");
a.download = "sample1.png";
a.href = canvasdata;
document.body.appendChild(a);
a.click();
;
);
//pie chart
//Width and height
var w = 380;
var h = 380;
var dataset = [ 5, 10, 20, 45, 6, 25 ];
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie();
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category10();
//Create SVG element
var svg = d3.select("#area2")
.append("svg")
.attr("width", w)
.attr("height", h);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
//Draw arc paths
arcs.append("path")
.attr("fill", function(d, i)
return color(i);
)
.attr("d", arc);
//Labels
arcs.append("text")
.attr("transform", function(d)
return "translate(" + arc.centroid(d) + ")";
)
.attr("text-anchor", "middle")
.text(function(d)
return d.value;
);
d3.select("#save1").on("click", function()
var html = d3.select("#area2>svg")
.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg")
.node().parentNode.innerHTML;
//console.log(html);
var imgsrc = 'data:image/svg+xml;base64,'+ btoa(html);
var img = '<img src="'+imgsrc+'">';
//d3.select("#svgdataurl").html(img);
var canvas = document.getElementById("canvas2"),
context = canvas.getContext("2d");
context.strokeStyle = "black";
context.rect(0,0,w,h);
context.fill();
var image = new Image;
image.src = imgsrc;
image.onload = function()
context.drawImage(image, 0, 0);
var canvasdata = canvas.toDataURL("image/png");
var pngimg = '<img src="'+canvasdata+'">';
//d3.select("#pngdataurl").html(pngimg);
var a = document.createElement("a");
a.download = "sample2.png";
a.href = canvasdata;
document.body.appendChild(a);
a.click();
;
);
</script>
</body>
</html>
编辑意见
要设置背景,您需要将其“绘制”到画布上:
var canvas = document.getElementById("canvas2"),
context.strokeStyle = "black";
context.rect(0,0,w,h);
context.fill();
运行上面的sn-p,我已经加进去了。
【讨论】:
感谢您的回答。实际上,我的页面上有两个以上的图表。我假设我可以为第三个 d3 图定义 var html = d3.select("#area3>svg") 等等。 是否可以将画布的背景设置为白色或黑色。?现在 d3 图中的空白空间被小块占据。谢谢 非常感谢。现在它真的很好看,很棒以上是关于如何将 D3 图保存为 django 网站中的图像?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用在 jython 上运行的 django 创建图像缩略图?