I am trying to save an svg element as png as instructed here. It says to use saveSvgAsPng(document.getElementById("diagram"), "diagram.png"); where "diagram" is the id of the svg element. Now I am having trouble finding out the id.
function guid() {
function _p8(s) {
var p = (Math.random().toString(16)+"000000000").substr(2,8);
return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
}
return _p8() + _p8(true) + _p8(true) + _p8();
}
var svg = d3.select("#hiddenblock").append("svg")
.attr("svgid",guid())
.attr("width", width + margin.left + margin.right)
.attr("height", height+300+ margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
Above I tried to give var svg a id name svgid then implemented it at the position of diagram but in the browser console in says Uncaught Error: an HTMLElement or SVGElement is required; got null. I tried to use hiddenblock but it didn't work.
A sample of my browser's output is here. It seems here the element got an id but saveSvgAsPng() function doesn't seem to recognize it.
Related
I'm trying to implement box plots as part of a data visualization interface that uses d3 and AngularJS. I'm working with this box plot package: https://bl.ocks.org/mbostock/4061502.
However, I can't figure out which part of the sample code controls the positioning of the box plots. In the example, the five box plots are arranged sequentially. When I try to generate my plots, they all appear on top of each other.
Here is the code that I'm using to generate the box plots:
boxplots = svg.selectAll("svg")
.data(boxPlotData)
.enter().append("svg")
.attr("class", "box")
.attr("width", boxWidth + margin.left + margin.right)
.attr("height", boxHeight + margin.bottom + margin.top)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(chart);
Here's the code for how my svg canvas is created. This is done in an angular directive:
template:"<svg width='825' height='600'></svg>",
link: function($scope, elem){
var d3 = $window.d3;
var rawSvg=elem.find('svg'); // this is the svg created in the template
var width = rawSvg[0].attributes[0].value;
var height = rawSvg[0].attributes[1].value;
var svg = d3.select(rawSvg[0]);
Edit: not perfect yet but getting there:
What you need is an ordinal scale to position the svg-elements for the boxes within the parent svg. Assuming width represents the width of your parent svg element and data is an array of your data elements, you can use this to create the scale:
const x = d3.scaleBand()
.range( [0, width] )
.domain( data.map( (el,i) => i ) );
Within the svg creation you can now use
boxplots = svg.selectAll("svg")
.data(boxPlotData)
.enter().append("svg")
.attr( "x", (d,i) => x(i) ) // this is added
.attr("class", "box")
.attr("width", boxWidth + margin.left + margin.right)
.attr("height", boxHeight + margin.bottom + margin.top)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(chart);
PS: This assumes you use v4 of d3js. The syntax in v3 for the scale is different.
PPS: I currently can not test the code, but it should work like described.
Here is a part of code I got from some example:
svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")").on("click", click)
;
And here is what I am trying to do based on some other example:
var rect = svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("height", height)
.attr("width", width)
.style("fill", '#000');
rect.on("click", click);
Click works, but I cannot known where th clickable zone is located, it is not covering my chart, but is somewhere in a corner of it. So I tried to give it a colour (black in this case), but still it stay invisible.
I have also tried
var rect = svg.append("rect")
.attr("x", margin.left)
.attr("y", margin.top)
.attr("height", height + margin.top + margin.bottom)
.attr("width", width + margin.left + margin.right)
.style("fill", '#000');
rect.on("click", click);
No better result.
Questions:
How can I give my rectangle a colour so that I can know where it is
on the page?
How can I have my rectangle match the whole SVG?
EDIT: I have just realised that "onclick" works because it is also attached to the "g" , but I am still interested in the answers.
You have given it a colour, #000 i.e. black.
The trouble is here
svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")").on("click", click)
;
The svg variable is not the <svg> element, because of chaining it's the <g> element, which has a transform on it so the rect is transformed.
I'm modifying the following code for a stacked bar chart by Mike Bostock from http://bl.ocks.org/yuuniverse4444/8325617 in order to learn d3.
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right+legend_width)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
I find that this code only renders just inside the closing body tag. I've tried moving the placement of the script in the page and changing d3.select("body") to d3.select("#chart_name").
Unless I use the term body the chart won't appear at all. Any ideas? Thanks.
Place your Javascript file at the bottom of your DOM structure.
Otherwise, D3 won't be able to make the selection.
Something like:
</body>
<script src="myscripts.js"></script>
I am trying to make this script responsive and need it to use % rather than pixels but it seems to blowup. Is there some kind of syntax I am missing when I use a %? Does it need escaped or something?
Its currently set to 960 but I would like it to be 100%. I tried to breakout the relevant code but didn't find anything in the script that had "px"set.
var margin = { top: 50, right: 0, bottom: 100, left: 30 },
width = 960 - margin.left - margin.right,
height = 430 - margin.top - margin.bottom,
gridSize = Math.floor(width / 24),
legendElementWidth = gridSize*2,
buckets = 9
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
You need to include the units as a string:
.attr("width", width + margin.left + margin.right + "%")
By default, the unit used is pixels (px). So if you want any unit other than pixels, you must include it as a string.
U need to use following
d3.select("#chart").append("svg").attr("width", ''+width + margin.left + margin.right+'%')
OR u can also use
.css("width", width + margin.left + margin.right + "%")
if width attribute is getting appended separately .Means outside style="" tag.
Same for others also
Here is my code:
var svg = d3.select("body").append("svg");
console.log(svg.attr);
svg.attr("width", width + margin.left + margin.right);
svg.attr("height", height + margin.top + margin.bottom);
svg.append("g");
svg.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
The console.log(svg) outputs:
function (t,e){if(arguments.length<2){if("string"==typeof t){var n=this.node();return t=ja.ns.qualify(t),t.local?n.getAttributeNS(t.space,t.local):n.getAttribute(t)}for(e in t)this.each(xe(e,t[e]));return this}return this.each(xe(t,e))}
However when I try to call svg.attr method right after that, I get this in the console:
Uncaught TypeError: Cannot call method 'attr' of null
Can anybody explain this? Clearly svg is not null as I log it in console before trying to use it...