Reputation: 693
I'm having issues with individual elements with an imported SVG and was hoping somehow could advise.
I have an SVG created in Illustrator, with several layers, which end up being group elements. When I retrieve the SVG from my server, I get something similar to.
<svg>
<g>
<g>
</svg>
I do not want to place the image as one, so I break it up by the groups, and surround each by their own svg tag and then place on the page.
<svg>
<g>
</svg>
<svg>
<g>
</svg>
This is great, works like I want.
My issue lies, where the paths of each of these items is drawn in the original file. They are all drawn off (0,0) from the Illustrator file, so when I try to place them, they all have a ton of white space area on the left, where the other elements once existed.
I've tried using transform="translate(-50,-50)" or whatever, which does shift the elements, but since they do not have x,y properties, I do not know where to shift them.
Does anyone know of a way to offset a path drawn? Or if there is a way to read the SVG and break it up into each individual element and work with?
When using firebug or chrome, they show me the individual element with correct sizes, but they are placed with lots of white space because of position of the paths drawn in Illustrator.
I've tried contentDocument
, documentElement
and both of these come up as null. Maybe I'm using them wrong?
I'm a heavy Actionscript developer, and now working with Javascript and jQuery so I'm use to x,y coord system and placing elements, but this is not seeming the way it should work :/
Upvotes: 3
Views: 3360
Reputation: 303225
If you really want to get the XY parts of a path I have written a function to convert paths to use all-absolute commands. With this you could then run through the path commands (using the pathSegList
DOM interface, not the raw string attribute) and pull out all the X/Y values and do with them what you will.
However, far easier is to simply calculate the bounding box of the path and set the viewBox
on your <svg>
element to fit around that directly:
// In case you want to leave the old SVG document unchanged
var newGroup = oldGroup.cloneNode(true);
var newSVG = document.createElementNS('http://www.w3.org/2000/svg','svg');
newSVG.appendChild(newGroup);
var bbox = newGroup.getBBox();
newSVG.setAttribute(
'viewBox',
[bbox.x,bbox.y,bbox.width,bbox.height].join(' ')
);
The above answer does not properly account for the case where a transform
has already been applied to the group you want to move. (The bounding box is returned in the untransformed space of the element.) I've created a demo that accounts for this, calculating the correct bounding box for transformed elements.
// Find all the root groups in the original SVG file
var rootGroups = document.querySelectorAll('svg > g');
for (var i=rootGroups.length;i--;){
var newSVG = elementToSVG(rootGroups[i]);
document.body.appendChild(newSVG);
}
// Create a new SVG wrapping around a copy of the element
// with the viewBox set to encompass the element exactly
function elementToSVG(el){
var old = el.ownerSVGElement,
svg = document.createElementNS(old.namespaceURI,'svg'),
css = old.querySelectorAll('style,defs');
// Preserve elements likely needed for correct appearance
[].forEach.call(css,copyToNewSVG);
copyToNewSVG(el);
var bb = globalBoundingBox(el);
svg.setAttribute('viewBox',[bb.x,bb.y,bb.width,bb.height].join(' '));
return svg;
function copyToNewSVG(e){
svg.appendChild(e.cloneNode(true));
}
}
// Calculate the bounding box of an element in global SVG space
// accounting for transforms applied to the element
function globalBoundingBox(el){
var bb = el.getBBox(),
svg = el.ownerSVGElement,
m = el.getTransformToElement(svg);
var pts = [
svg.createSVGPoint(), svg.createSVGPoint(),
svg.createSVGPoint(), svg.createSVGPoint()
];
pts[0].x=bb.x; pts[0].y=bb.y;
pts[1].x=bb.x+bb.width; pts[1].y=bb.y;
pts[2].x=bb.x+bb.width; pts[2].y=bb.y+bb.height;
pts[3].x=bb.x; pts[3].y=bb.y+bb.height;
var xMin=Infinity,xMax=-Infinity,yMin=Infinity,yMax=-Infinity;
pts.forEach(function(pt){
pt = pt.matrixTransform(m);
xMin = Math.min(xMin,pt.x);
xMax = Math.max(xMax,pt.x);
yMin = Math.min(yMin,pt.y);
yMax = Math.max(yMax,pt.y);
});
bb = {}; //IE9 disallows mutation of the original bbox
bb.x = xMin; bb.width = xMax-xMin;
bb.y = yMin; bb.height = yMax-yMin;
return bb;
}
Upvotes: 5