Find svg viewbox that trim whitespace around - svg

Assuming I have an svg that draws some paths, what tools should I use to find a viewbox that perfectly fits those paths so that all redundant space around is trimmed?

You can simply set your svg's viewBox to its Bounding Box.
function setViewbox(svg) {
var bB = svg.getBBox();
svg.setAttribute('viewBox', bB.x + ',' + bB.y + ',' + bB.width + ',' + bB.height);
}
document.querySelector('button').addEventListener('click', function() {
setViewbox(document.querySelector('svg'));
});
svg { border: 1px solid }
<svg version="1.1" id="svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 500 300" enable-background="new 0 0 500 300" xml:space="preserve" width="250" height="150">
<path fill="none" stroke="#B2E230" d="M413.7,276.5c0,0,67-37,116,0c-24.1-33,16.4-53,0-34s-100-2-75-38" transform="translate(-75,-75)" />
</svg>
<button>setViewbox</button>
Note: It will also take into account the non-visible anchors of your pathes.

Related

Cannot change the size of a use SVG element

this is the raw code I've received. Just a cross defined as a polygon :
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 115.9 80" style="enable-background:new 0 0 115.9 80;" xml:space="preserve">
<polygon points="78.8,36.5 70.5,36.5 70.5,28.2 66.5,28.2 66.5,36.5 58.2,36.5 58.2,40.5 66.5,40.5 66.5,48.8 70.5,48.8 70.5,40.5
78.8,40.5 "/>
</svg>
and this is what I've done :
<svg class="icons" version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px">
<symbol id="cross">
<polygon points="78.8,36.5 70.5,36.5 70.5,28.2 66.5,28.2 66.5,36.5 58.2,36.5 58.2,40.5 66.5,40.5 66.5,48.8 70.5,48.8 70.5,40.5 78.8,40.5" style="fill:#6511e4;"/>
</symbol>
</svg>
<div class="cross">
<svg viewBox="0 0 115.9 80" width="15" height="15">
<use href="#cross" id="cross-1"/>
</svg>
</div>
following the solution for the same problem someone else had (Cannot Change SVG <use> icon size when linked to <symbol>)
but this is not working :/ I just want for exemple to resize the cross with a 15px width and 15px height.
Could someone provide me the solution as well as some explanations ? thanks : )
If you encapsulate a SVG drawing in a symbol, the viewBox attribute moves from the <svg> to the <symbol> element.
The viewBox values of your source are not really helpful. A tight bounding box around the grafic can be achieved with viewBox="58.2 28.2 20.6 20.6". You can find it with the original file loaded in a browser. Then do
document.querySelector('polygon').getBBox()
The returned object provides you with x/y/width/height values you can feed into the viewBox.
I'd like to point out there is an implicit sizing going on here: The symbol is shown according to the x/y/width/height values of the <use> element where it is referenced. None of them are present; they default to 0 (position) and 100% (size). In other words: the <use> element just fills its surrounding <svg> element, where width and height are set.
<svg class="icons" width="0px" height="0px">
<symbol viewBox="58.2 28.2 20.6 20.6" id="cross">
<polygon points="78.8,36.5 70.5,36.5 70.5,28.2 66.5,28.2 66.5,36.5 58.2,36.5 58.2,40.5 66.5,40.5 66.5,48.8 70.5,48.8 70.5,40.5 78.8,40.5" style="fill:#6511e4;"/>
</symbol>
</svg>
<div class="cross">
<svg width="15" height="15">
<use href="#cross" id="cross-1"/>
</svg>
</div>

Responsive full width svg logo

So I have this logo that fits the whole page. Is there anyway that, when the browser is resized I can move these paths? That way the height stays the same?
Example of what I want to achieve
Here's my svg code
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1440 52" style="enable-background:new 0 0 1440 52;" xml:space="preserve">
<path d="M1428.4,6.9c-2.5-2.5-6-3.7-10.5-3.7h-7.6h-9.5v19.1H16.3V3.1H7.8v46.8h8.5V30.7h1384.5v19.1h0h9.4V30.6h7.5
c2.3,0,4.3-0.3,6-1c1.8-0.7,3.3-1.7,4.5-2.9c1.2-1.2,2.2-2.7,2.8-4.5c0.7-1.7,1-3.6,1-5.8C1432.2,12.1,1430.9,9.4,1428.4,6.9z
M1421.4,20.1c-1,1-2.8,1.9-5.2,2h-6v-12h6c2.3,0,4,0.6,5.2,1.8s1.7,2.7,1.7,4.4C1423.1,18.5,1421.8,19.8,1421.4,20.1z" />
</svg>
you can do something like this by using preserveAspectRatio="none" for the svg element together with a fixed height and width:100%. This would give tou what you need but the the stroke would be scaled differently on the vertical and horizontal.
To fix it you need to add vector-effect="non-scaling-stroke" for the path.
svg{height:100px; width:100%}
<svg viewBox="0 0 100 20" preserveAspectRatio="none">
<path stroke="black" stroke-width="5" vector-effect="non-scaling-stroke" d="M 1,5V15M1,10H97"/>
</svg>
Yes it is possible, with a bit of trickery. Below is a modified verion of your SVG that behaves how you want.
This matches your SVG exactly, but has a limitation. The trick we are using relies on extending the middle bar a long way to the left. Then covering up the left end of the bar with your vertical piece. But in your original SVG the vertical piece is not right at the left end of your SVG. So I've had to hide some of the extension with a white rectangle. This assumes your background will also be white. If it isn't you'll need to change that white rectangle to be the same colour as your page background.
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="52">
<defs>
<path id="middle-and-right" transform="translate(-1440 0)"
d="M1428.4,6.9c-2.5-2.5-6-3.7-10.5-3.7h-7.6h-9.5v19.1
h -3000 v 8.4 h 3000
v19.1h0h9.4V30.6h7.5 c2.3,0,4.3-0.3,6-1c1.8-0.7,3.3-1.7,4.5-2.9c1.2-1.2,2.2-2.7,2.8-4.5c0.7-1.7,1-3.6,1-5.8C1432.2,12.1,1430.9,9.4,1428.4,6.9z
M1421.4,20.1c-1,1-2.8,1.9-5.2,2h-6v-12h6c2.3,0,4,0.6,5.2,1.8s1.7,2.7,1.7,4.4C1423.1,18.5,1421.8,19.8,1421.4,20.1z" />
</defs>
<use xlink:href="#middle-and-right" x="100%"/>
<rect x="-1" y="3.1" width="10" height="46.8" fill="white"/>
<rect x="7.8" y="3.1" width="8.5" height="46.8"/>
</svg>
If you want to get a better idea how the trick works, have a look at this version. I've modified the SVG to make the trick more apparent.
svg {
background-color: red;
overflow: visible;
}
rect {
opacity: 0.5;
}
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="52">
<defs>
<path id="middle-and-right" transform="translate(-1440 0)"
d="M1428.4,6.9c-2.5-2.5-6-3.7-10.5-3.7h-7.6h-9.5v19.1
h -3000 v 8.4 h 3000
v19.1h0h9.4V30.6h7.5 c2.3,0,4.3-0.3,6-1c1.8-0.7,3.3-1.7,4.5-2.9c1.2-1.2,2.2-2.7,2.8-4.5c0.7-1.7,1-3.6,1-5.8C1432.2,12.1,1430.9,9.4,1428.4,6.9z
M1421.4,20.1c-1,1-2.8,1.9-5.2,2h-6v-12h6c2.3,0,4,0.6,5.2,1.8s1.7,2.7,1.7,4.4C1423.1,18.5,1421.8,19.8,1421.4,20.1z" />
</defs>
<use xlink:href="#middle-and-right" x="100%"/>
<rect x="-1" y="3.1" width="10" height="46.8" fill="white"/>
<rect x="7.8" y="3.1" width="8.5" height="46.8"/>
</svg>
However if you don't mind the vertical piece on the left end being moved so it's hard up against the left side of the SVG, then we can remove that restriction regarding the background. The new version below will work for any page background colour.
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="52">
<defs>
<path id="middle-and-right" transform="translate(-1440 0)"
d="M1428.4,6.9c-2.5-2.5-6-3.7-10.5-3.7h-7.6h-9.5v19.1
h -3000 v 8.4 h 3000
v19.1h0h9.4V30.6h7.5 c2.3,0,4.3-0.3,6-1c1.8-0.7,3.3-1.7,4.5-2.9c1.2-1.2,2.2-2.7,2.8-4.5c0.7-1.7,1-3.6,1-5.8C1432.2,12.1,1430.9,9.4,1428.4,6.9z
M1421.4,20.1c-1,1-2.8,1.9-5.2,2h-6v-12h6c2.3,0,4,0.6,5.2,1.8s1.7,2.7,1.7,4.4C1423.1,18.5,1421.8,19.8,1421.4,20.1z" />
</defs>
<use xlink:href="#middle-and-right" x="100%"/>
<rect x="0" y="3.1" width="8.5" height="46.8"/>
</svg>

What determines if a svg can be rendered by openlayers

I've got 3 different SVGs that all display a marker. However only one of them works with the Openlayers icon. In this example only svg1 correctly displays the marker on the map. All three SVGs are correctly displayed when using an IMG element. What determines if a svg can be displayed by openlayers or what do i have to change to make it work?
var svg1 = '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="30px" height="30px" viewBox="0 0 30 30" enable-background="new 0 0 30 30" xml:space="preserve">' +
'<path fill="#156BB1" d="M22.906,10.438c0,4.367-6.281,14.312-7.906,17.031c-1.719-2.75-7.906-12.665-7.906-17.031S10.634,2.531,15,2.531S22.906,6.071,22.906,10.438z"/>' +
'<circle fill="#FFFFFF" cx="15" cy="10.677" r="3.291"/></svg>';
var svg2 = '<svg width="30" height="30" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" enable-background="new 0 0 30 30" version="1.1"><g><title>Layer 1</title><path id="svg_1" d="m22.906,10.438c0,4.367 -6.281,14.312 -7.906,17.031c-1.719,-2.75 -7.906,-12.665 -7.906,-17.031s3.54,-7.907 7.906,-7.907s7.906,3.54 7.906,7.907z" fill="#156BB1"/></g></svg>';
var svg3 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="#156BB1" d="M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0zM192 272c44.183 0 80-35.817 80-80s-35.817-80-80-80-80 35.817-80 80 35.817 80 80 80z"></path></svg>';
var mysvg = new Image();
mysvg.src = 'data:image/svg+xml,' + encodeURIComponent(svg1);
var style = new Style({
image: new Icon({
img: mysvg,
imgSize: [30, 30]
})
});
Apparently the order and the parameters used are of importance for Openlayers. I've got svg3 working by using the following as svg wrapper.
<svg version="1.1" id="Layer_1" width="30px" height="30px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512">
</svg>
Removing any of those parameters or changing the order resulted in the svg not showing on the map. Another issue was that the path values were not comma separated. That poses no issue with displaying it in an image but openlayers seems to require it at least for usage within an Icon.

Is there a way for two SVG <tspan> inside of <text> line up at the left edge without specifying an absolute x for the child?

The following code will show the "World" as a continuous flow of the x position.
We can specify x="200" for that second <tspan> so that it lines up with the "Hello" at the left edge. But is there a way to do it without needing to specify an absolute x of 200?
It is like if we have a <div>, and then we have two <div>s inside, the left edge will line up, without needing to specify an absolute x for the parent and an absolute x for the child:
<svg xmlns="http://www.w3.org/2000/svg" xml:lang="en" xmlns:xlink="http://www.w3.org/1999/xlink" width="400px" height="200px" viewBox="0 0 400 200">
<text x="200" y="30">
<tspan>Hello</tspan>
<tspan dy="1.2em">World</tspan>
</text>
</svg>
I thought about using
<style>
text { position: relative }
tspan { position: absolute; left: 0 }
</style>
and it doesn't work inside of Chrome.
You can use a transform to position the text, then the additional tspan x value is 0.
<svg xmlns="http://www.w3.org/2000/svg" xml:lang="en" xmlns:xlink="http://www.w3.org/1999/xlink" width="400px" height="200px" viewBox="0 0 400 200">
<text transform="translate(200, 30)">
<tspan>Hello</tspan>
<tspan x="0" dy="1.2em">World</tspan>
</text>
</svg>

Proper SVG markup for external files to be loaded with Snap.svg

So here's the deal, I'm making some experiments with SVG and Snap.svg. I have an external SVG file, logo.svg, that was created with Adobe Illustrator, here's the markup:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="161.875px" height="144px" viewBox="0 0 161.875 144" enable-background="new 0 0 161.875 144" xml:space="preserve">
<polygon fill="#006098" points="144,144 27,144 57,0 144,0 144,54 161.875,72 144,90 "/>
<polygon fill="#00416A" points="57,144 0,144 0,0 87,0 "/>
<polygon fill="#98D5E9" points="72,57 72,27 87,27 117,27 117,57 117,72 117,94.5 117,117 87,117 87,94.5 57,94.5 57,72 87,72
87,57 "/>
<polygon fill="#288DC1" points="57,57 75.125,57 81.375,27 57,27 27,27 27,57 27,72 27,94.5 27,117 57,117 57,94.5 67.313,94.5
72,72 57,72 "/>
</svg>
I want to use this example and explore Snap.svg animations, so I'm loading it this way:
(...)
var s = Snap(element);
Snap.load('/images/logo.svg', function(f) {
s.append(f);
});
(...)
But for this to work my element must be a <svg>, so I end up with a <svg> inside a <svg>:
<svg logo-svg>
<desc>Created with Snap</desc>
<defs></defs>
<svg version="1.1" id="Layer_1" x="0px" y="0px" width="161.875px" height="144px" viewBox="0 0 161.875 144" enable-background="new 0 0 161.875 144" preserveAspectRatio="xMinYMin meet">
<polygon fill="#006098" points="144,144 27,144 57,0 144,0 144,54 161.875,72 144,90 "></polygon>
<polygon fill="#00416A" points="57,144 0,144 0,0 87,0 "></polygon>
<polygon fill="#98D5E9" points="72,57 72,27 87,27 117,27 117,57 117,72 117,94.5 117,117 87,117 87,94.5 57,94.5 57,72 87,72
87,57 "></polygon>
<polygon fill="#288DC1" points="57,57 75.125,57 81.375,27 57,27 27,27 27,57 27,72 27,94.5 27,117 57,117 57,94.5 67.313,94.5
72,72 57,72 "></polygon>
</svg>
</svg>
Somehow I fill this is a bit messy, is this correct? Or there's a better way to load external SVG files?
I think the principle is fine, ie often you may load quite a few SVGs and they need to be inside another SVG.
Plus Snap.load is actually taking a document fragment which needs appending to something. So to me it makes sense, but if you can highlight certain problems you are facing because of this, it could be there is a workaround.
I'm just going to post an example to adjust the main paper to the new svg which could be used...
var s = Snap("#svgpaper");
var bird = Snap.load("bird.svg", function ( loadedFragment ) {
var b = s.append( loadedFragment );
var bbox = b.getBBox();
var vbox = bbox.x + " " + bbox.y + " " + bbox.width + " " + bbox.height;
s.attr({ viewBox: vbox });
} );
testing example here

Resources