I am new to Django and D3 . I have created a Django website that can create more than one dynamic d3 graph . I want to add a functionality where user can save the graphs as images so that they can use it for their reporting purposes .
I am using the following link as tutorials Also find my codes for reference
<!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" width="960" height="500" style="display:none"> </canvas>
<button id="save1" class="button2">Save as Image</button>
<canvas id="canvas2" width="960" height="500" 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>
From both save as buttons I am able to save first image only . I think I am not able to select d3/svg element properly .
Thanks
In your d3.select("#save1").on("click"
, your svg selector is wrong. This:
var html = d3.select("svg")
...
will always select the first svg
element on the page. You need something like:
var html = d3.select("#area2>svg")
...
Which will select the svg
that's a child of your div
with id of area2.
Full code:
<!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" width="960" height="500" style="display:none"></canvas> <button id="save1" class="button2">Save as Image</button> <canvas id="canvas2" width="960" height="500" 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>
EDITS FOR COMMENTS
To set a background you need to "draw" it onto the canvas:
var canvas = document.getElementById("canvas2"),
context.strokeStyle = "black";
context.rect(0,0,w,h);
context.fill();
Run the snippet above, I've added this to it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.