I've seen versions of this question but they haven't helped me to solve this issue. I am using d3 with a nested svg, here is the code:
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var nestedSVG = svg.append('svg')
.attr("width", innerWidth)
.attr("height", innerHeight)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
The nestedSVG makes an inner height/width so that some plots get cutoff appropriately. This works perfectly in firefox, but not in Chrome. When I scroll over nestedSVG in firebug it shows the appropriate dimensions, but when I scroll over nestedSVG in javascript console in chrome the dimensions are altered. This results in the plots being different. Any clue as to why this is happening?
The ability to set a transform on an <svg> element is new in SVG 2 and is not yet widely supported. Firefox does support it, IE does not currently, not sure about other UAs.
Related
Is there any way to shrink my SVG graphic to fit the printing page, while leaving the web version of the graphic as it is? Or am I wasting my time?
I can only use FF at the moment but of course a cross-browser approach is even better...
Is there a CSS version of viewBox that I can put in a media
query?
Is there an onPrint event in js where I could apply
viewBox?
Any other approach - javascript, css, jquery, d3 all
welcome.
Googling suggests "no" to 1 & 2 but many of the posts are old.
Latest approach:
var svg = d3.select("div#matrix").append("svg")
.attr("width", 1000)
.attr("height", 1000)
//.attr("viewBox","0 0 500 500") - I don't want to apply this to the webpage SVG - this is just for testing
//.attr("preserveAspectRatio","xMinYMin meet")
.attr("id","matrixSVG")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
Once the text labels are added to the graphic I resize the container elements for the webpage:
var svgWidth = margin.left+margin.right+(cellSize*horizNodes.length);
var svgHeight = margin.top+margin.bottom+(cellSize*vertNodes.length);
d3.select("svg#matrixSVG").attr("width",svgWidth).attr("height",svgHeight);
d3.select("div#matrix").style("width",svgWidth+"px").style("height",svgHeight+"px");
CSS:
#media print {
svg#matrixSVG {
width: 175mm; //this is the max size to fit US letter and A4
height: 245mm;
}
}
Thanks for any help
I have been fiddling with this donut chart for a bit, but it won't render just right using the aspect ratio / viewbox method.
I got this working with a window resize function, but it has a bug -- since the container it can be can be collapsed, it can resize incorrectly. I figure I can work around this, but any tips on getting this to work with the commented out code?
What tends to happen is that based on the original window size the chart has dimensions based on that... which can skew the look if the window is at the wrong size when it starts.
https://jsfiddle.net/7rgf09x1/9/
// WORK IN PROGRESS: Responsive using only d3.
// var svg = d3.select('#revenue-chart').append('svg')
// .attr('id', 'revenue-chart-render')
// .attr("width", '100%')
// .attr("height", '100%')
// .attr('viewBox','0 0 '+Math.min(width,height)+' '+Math.min(width,height))
// .attr('preserveAspectRatio','xMinYMin')
// .attr("transform", "translate(" + Math.min(width,height) / 2 + "," + Math.min(width,height) / 2 + ")");
The goal of viewBox is to separate the page coordinates from the graphics coordinates. So
.attr('viewBox','0 0 '+width +' '+height)
gives you graphics coordinates in [0,width]x[0,height]. This is independent of the size of the svg in the page. You can change the '0 0' in order to have the origin of the graphics coordinates in the center instead of the top-left corner (although your solution with a translated g was valid too). Finally, preserveAspectRatio makes sure that your image isn't stretched by adding padding to the sides as necessary.
So overall this should give you
var svg = d3.select('#revenue-chart').append('svg')
.attr('id', 'revenue-chart-render')
.attr("width", '100%')
.attr("height", '100%')
.attr('viewBox',(-width / 2 ) + ' ' + (-height/2) + ' '+width +' '+height)
.attr('preserveAspectRatio','xMinYMin')
It is quite straight forward to implement responsive SVG elements like below.
<div id="chartId"/>
var svg = d3.select("#chartId")
.append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 600 400");
svg.append("rect")
.attr("fill","blue")
.attr("x", 10)
.attr("y", 10)
.attr("width", 500)
.attr("height", 500);
JSFIDDLE
The following takes place when the window size is shrank.
Before shrinking
After shrinking
As can be seen the rect angle is horizontally and vertically responsive.
But, how can I implement an SVG element that is only horizontally responsive and the following takes place?
One option would be to redraw the SVG element every time the window size is changed, but I would like know if there is more sophisticated solution available.
The preserveAspectRatio attribute determines the scaling and alignment used to fit the viewBox in the svg. When preserveAspectRatio = "xMinYMin meet", content is scaled uniformly (i.e. horizontal and vertical scaled at same ratio). When preserveAspectRatio = "none", content is scaled non-uniformly. In your code, change...
.attr("preserveAspectRatio", "xMinYMin meet")
to...
.attr("preserveAspectRatio", "none")
Some time ago, I was quite into the responsive D3, I am a bit sluggish now, but here is an answer anyway. And it is not so sophisticated. Just put '%' for the width dimension of your svg, and a fixed one for the height.
Do mind that when using '%', the actual dimensions are in function of those of the parent element. You need to take this into account.
Here is the code i took from your fiddle and adjusted it:
var svg = d3.select("#chartId")
.append("svg")
.attr("width", "100%")
.attr("height", "200");
svg.append("rect")
.attr("fill","blue")
.attr("x", 10)
.attr("y", 10)
.attr("width", '100%')
.attr("height", '100%');
It works, i tried it, but I am just not sure if it really is what you want...
I am creating a visualization with d3.js:
http://bl.ocks.org/EE2dev/raw/cd904f10097b9921f1cc/
In that code I create an SVG element and set the size with this line:
var chart = d3.select("body")
.append("div").attr("class", "chart")
.append("svg")
.attr("width", outerWidth) // outerWidth = 960
.attr("height", outerHeight) // outerHeight = 500
.append("g")
.attr("class", "margin")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
Testing the code in Chrome, everything works fine, the SVG has the desired size of (960, 500). When I open this site in Firefox, however, the SVG element is created with a different size, appearantly depending on the actual browser window size, e.g. (634, 856) in the case below.
How do I fix this behaviour to set the SVG to the desired fixed size for Firefox?
I tried several things, including wrapping a div around and/or following ideas I found elsewhere
SVG only shown partially in Firefox
http://tympanus.net/codrops/2014/08/19/making-svgs-responsive-with-css/
But I didn't find a way to fix this problem for me that worked:(
Any help would be greatly appreciated!
outerWidth and outerHeight are browsers Window properties. It is curious problem that these properties could be overwritten in Chrome but not in Firefox (FF API). So when you set
outerWidth = 960;
then outerWidth is changed to 960 in Chrome. In the case of Firefox it is current window width and it can not be changed by the client script.
So rename outerWidth and outerHeight and it should be working.
svgWidth = 960;
svgHeight = 500;
...
.append("svg")
.attr("width", svgWidth)
.attr("height", svgHeight)
I am new to D3.js, started learning today only
I looked the the donut example and found this code
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
I searched for documentation, but did not understood what .append("g") is appending
Is it even D3 specific?
Looking for guidance here
It appends a 'g' element to the SVG. g element is used to group SVG shapes together, so no it's not d3 specific.
I came here from a d3 learning curve as well. As already pointed out this is not specific to d3, it is specific to svg attributes. Here is a really good tutorial explaining the advantages of svg:g (grouping).
It is not that different from the use case of "grouping" in graphical drawings such
as ones you would do in a powerpoint presentation.
http://tutorials.jenkov.com/svg/g-element.html
As pointed in above link: to translate you need to use translate(x,y):
The <g>-element doesn't have x and y attributes. To move the contents
of a <g>-element you can only do so using the transform attribute,
using the "translate" function, like this: transform="translate(x,y)".