Is it possible to merge SVG files?

5,872 views
Skip to first unread message

Conor

unread,
Jul 18, 2013, 5:59:13 AM7/18/13
to d3...@googlegroups.com
Hello All,

I have several html pages that contain multiple d3 charts.

I need to allow the user to download an image of all the charts displayed on the page. I'm having some trouble with this and am wondering if someone can point me towards a solution.

I can successfully convert and download any single d3 chart as a PDF. I'm doing this by selecting the svg element I want, serializing it to xml and passing it to my server where I use batik to do the PDF conversion. However I'm not sure how I can handle multipole charts.

Is there a way to concatanate multiple SVG files into a single SVG before I do the conversion?

Ian Johnson

unread,
Jul 18, 2013, 12:36:44 PM7/18/13
to d3...@googlegroups.com

Yes, you can concatenate the serialized strings together before sending them.
Its all just html, so it would work the same as if you copy pasted the svgs into an html file and loaded it in your browser

--
You received this message because you are subscribed to the Google Groups "d3-js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Conor

unread,
Jul 19, 2013, 4:47:45 AM7/19/13
to d3...@googlegroups.com
Hi Ian,

I have attempted this and it works. The problem is that the svgs are layered on top of one another. I suppose I could parse the xml and alter the "<g transform="translate(n,n)">" attribute on each chart so they wouldn't overlap? Maybe theres a better solution?

Nate Vack

unread,
Jul 19, 2013, 11:15:22 AM7/19/13
to d3...@googlegroups.com
You could put the <svg> elements in their own containers with explicit
sizes so they don't overlap.

-n

Conor Walsh

unread,
Apr 17, 2014, 4:30:22 AM4/17/14
to d3...@googlegroups.com, wels...@gmail.com
Hi Kiran,

I moved away from batik and am now using phantomjs.

I didn't merge the svg files. When a user wishes to download the charts in my application I select all of the svg's on the page and send them to my server. I then use phantomjs to render the svg's in a pdf file and send it back to the user.

I find phantomjs to be very good for this functionality. It seemed to be the way most people were rendering d3 server side at the time I implemented it. I'm not sure if something better has come along as its been about 6 months since I looked at the issue. I probably need to revisit server side rendering myself as I'm not sure if this is the best approach. I hope this helps.

On Thursday, April 17, 2014 7:40:36 AM UTC+1, Kiran P Radder wrote:
Hi Conor,

Did you find the solution for this, if yes please share the solution, i am facing the same problem from long time.
Thank you

Spandan Chatterjee

unread,
Apr 17, 2014, 4:42:37 AM4/17/14
to d3...@googlegroups.com, d3...@googlegroups.com, wels...@gmail.com
Hi,

Even I'm using phantomJs for this need.

Thanks

Sent from my iPhone
--
You received this message because you are subscribed to the Google Groups "d3-js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Artan Simeqi

unread,
Apr 17, 2014, 1:48:47 PM4/17/14
to d3...@googlegroups.com
I have written some code to do this client side.
I started with svgenie (https://github.com/Causata/svgenie) which is a
wrapper around canvg.

svgenie by default only supports one svg, but I changed the function
_toCanvas to accept a
2 dimensional array of svgs. It will draw the svgs in a matrix like arrangement.
The problem with this approach (doing it client side) is that canvg
does't support all svg.
For me it was not a problem since my graphs were pretty simple.
If the client side approach doesn't work for you, you might be able to
use the ideas in my script
to do something similar server side.

Here is my change to _toCanvas:


var _toCanvas = function (svgArray, options, callback) {

var numCols = svgArray[0].length;
var numRows = svgArray.length;

var maxWidth = -1;
var maxHeight = -1;

for (var row = 0; row < svgArray.length; row++) {
for (var col = 0; col < svgArray[0].length; col++) {
if (svgArray[row][col]) {
if (svgArray[row][col].scrollWidth > maxWidth) {
maxWidth = svgArray[row][col].scrollWidth;
}

if (svgArray[row][col].scrollHeight > maxHeight) {
maxHeight = svgArray[row][col].scrollHeight;
}
}
}
}

var imageSeparation = 20; //pixel
var canvasWidth = numCols * maxWidth + (numCols - 1) * imageSeparation;
var canvasHeight = numRows * maxHeight + (numRows - 1) *
imageSeparation;

var bgColor = window.getComputedStyle(document.body,
null).getPropertyValue('background-color');
// Hopefully don't need to attach anything to the DOM
var canvas = document.createElement("canvas");
canvas.height = canvasHeight;
canvas.width = canvasWidth;

//Create a rectangle with body background color
var ctx = canvas.getContext('2d');
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, canvasWidth, canvasHeight);

//draw all svgs to canvas
for (var row = 0; row < svgArray.length; row++) {
for (var col = 0; col < svgArray[0].length; col++) {
var svg = svgArray[row][col];
if (svg) {
var leftX = col * (maxWidth + imageSeparation);
var leftY = row * (maxHeight + imageSeparation);


if (typeof svg == "string") {
if (svg.substr(0, 1) == "#") { svg = svg.substr(1); }
svg = document.getElementById(svg);
}


var serSvg = _serializeXmlNode(svg);

canvg(canvas, serSvg, {
ignoreMouse: true,
ignoreClear: true,
ignoreDimensions: true,
ignoreAnimation: true,
offsetX: leftX,
offsetY: leftY
});
}
}
}
//Output the canvas
canvg(canvas, "<svg></svg>", {
ignoreMouse: true,
ignoreClear: true,
ignoreAnimation: true,
ignoreDimensions: true,
offsetX: 0,
offsetY: 0,
renderCallback: function () { callback(canvas); }
});
};
Reply all
Reply to author
Forward
Message has been deleted
0 new messages