"Shrink to page" SVG on printing? - javascript

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

Related

Fix responsive SVG breaking out of Bootstrap grid?

Example Codepen: http://codepen.io/mattrice/full/peXeqd/
What I want is for the SVG to stay completely contained within the parent's given width (6 columns for this example, but could be any other arbitrary width grid element).
This example functions as expected at widths <768px because the Bootstrap columns are full-page width; however, when the Bootstrap columns flow back to horizontally stacked at widths above 768 the SVG takes up the entire width of the page.
I think the problem stems from the arguments to updateDimensions() in render():
function render() {
updateDimensions(window.innerWidth);
...<snip>...
}
I have also tried getBoundingClientRect() like so
function render() {
updateDimensions(d3.select(options.selector).node().getBoundingClientRect().width);
...<snip>...
}
but that led to some odd results (probably outside of the scope of this question).
How can I fix this?
If you want the SVG to scale to fit its parent element, it needs to have a viewBox attribute.
Instead of setting the width and height of your SVG, use those values for the viewBox instead.
Change
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom);
to
.attr("viewBox", [0, 0, (width + margin.right + margin.left),
(height + margin.top + margin.bottom)].join(' '))
Updated Codepen
You may want to tweak the width and height components of the viewBox if you want, to remove the gap on the right, so it fits more neatly.

Implementing multiple D3 layout on same page

I tried to add multiple D3 graphs on same page i.e. Pie Chart, Bar Graph and a tree layout using different data in either CSV or JSON format. But I am not able to implement all of these 3 graphs on the same page. When I link more than 1 layout on a same page, I get a blank page.
I tried to append each chart in a different div using following HTML and JS
HTML
<div id="piediv"></div>
<div id="bardiv"></div>
<div id="treediv"></div>
JS
var svg = d3.select("#piediv").append("svg")
var svg = d3.select("#bardiv").append("svg")
var svg = d3.select("#treediv").append("svg")
All of the JS lines above are in their respective individual JS files viz. pie.js, bar.js and tree.js
First of all i suggest you to declare svg variables with a different names.
I made a fiddle for you with a similar problem; more in details, I have created two donut charts in the same page in this way:
I have created two different <div> with two different ids
<div id="chart"></div>
<div id="chart2"></div>
and I also created two different svgs (with different name)
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var svg2 = d3.select("#chart2").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
Check the fiddle for more details
Let me know.

Responsive Donut Chart d3

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')

How to set the exact size of an inline SVG element?

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)

d3 Nested SVG plots differently in firefox than in Chrome

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.

Categories