Display of SVG on Leaflet map - svg

I have a moderately large SVG to be displayed as an overlay on a Leaflet map - it's basically a selection of roads from a road network. The leaflet map is instantiated with:
testMap = L.map('mapdiv', { renderer: L.svg({ padding: 100 }) })
.setView([33.085, -96.815], 11);
and the SVG layer is created with:
var imgUrl = url, imgBnds;
L.imageOverlay(imgUrl, imgBnds, {opacity:0.3}).addTo(testMap);
This all displays nicely when zoomed out, but when zooming in, the SVG gets tiled, and only the top-left tile is displayed even though this is not the area being shown in the map.
The SVG has the following:
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" x="0" y="0" width="1920" height="767"
clip-path="url(#MapClipRectangle)" style="overflow:hidden;text-rendering:optimizeLegibility" xmlns="http://www.w3.org/2000/svg">
</desc>
<defs>
<clipPath clipPathUnits="userSpaceOnUse" id="MapClipRectangle">
<rect x="0" y="0" width="1920" height="767" />
</clipPath>
<symbol id="1" style="fill:none">
<path d="M985.96 476.76 l-0.26 0.06" />
<!-- ... Many Symbols and Paths, plus some Polygons, Text, Line_artwork, Map_decoration and a Map_frame... -->
And it ends up looking like this (example actually shows the top-left tile, but if I zoom in to the right, you don't actually see anything from the overlay SVG):
How do you stop/control this behaviour?
Sample SVG for which this behaviour occurs

I have not investigated this question in any depth, but in the interest of having some answer at all that might help:
It seems unusual to me that you want to use an svg for geospatial data like a road network.
If someone runs into a similar problem in the future, I would recommend, rather than trying to fix the svg rendering, convert the data to geojson which is more of a standard option for this sort of data display need and then style as needed using the options in leaflet.
To OP, did you ever find a solution?
As a note, it is not clear to me which part of the images posted are svg's vs which parts are basemap or other layers.

Related

SVG symbol with stroke has wrong size in Illustrator

I'm generating an SVG file on a website and it's supposed to be imported in Ilustrator. I use <symbol /> element to store a shape definition and I reference it with the <use /> element on the "sheet". Users are able to set size of the shape and it's really crucial that it's exactly the same size when imported to Adobe Illustrator. It works unless I add a stroke.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg id="SvgjsSvg1000" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" width="210mm" height="297mm" viewBox="0 0 210 297" viewbox="0 0 210 297">
<defs id="SvgjsDefs1001">
<symbol id="shape_id70" preserveAspectRatio="xMinYMin meet" viewBox="0 0 27.841039657592773 12.2083101272583">
<path id="SvgjsPath1030" d="M26.4405 13.067C25.685728 11.72066 22.49458 8.90142 20.73442 7.678030000000001C22.99088 7.6388854 23.85819 7.6146637 28.738950000000003 7.456081C26.298620000000003 6.628644 23.737080000000002 5.904501 21.418080000000003 4.973881C23.937200000000004 4.5081560000000005 26.519460000000002 4.085806000000001 28.376120000000004 3.7947010000000008C28.376120000000004 3.7946453179000006 19.370760000000004 2.7013810000000005 8.358420000000002 4.414499000000001L9.412540000000002 1.364679000000001L6.497860000000001 3.520859000000001L4.442800000000001 0.858699000000001L4.324531000000001 4.464059000000001L0.897911000000001 5.542179000000001L4.249861000000001 6.913239000000001L4.236664300000001 10.198599000000002L6.192894300000001 7.622079000000001L9.099554300000001 8.802649L8.143547300000002 6.432539C12.463087300000002 6.813516 22.5756473 8.818239 26.440547300000002 13.067009Z" fill="none"></path>
</symbol>
</defs>
<use id="SvgjsUse1034" xlink:href="#shape_id70" x="0" y="0" width="50"></use>
</svg>
This is fine in both browser and Illustrator. But when I add attributes stroke-width="0.1" stroke="#000". In Illustrator, the size of the shape changesto 48.951. It's still 50 in browser though. I tried to add these attributes to the <symbol />, <path /> and <use /> elements with the same result.
I know that the SVG standard doesn't have any attribute that would control how to render the stroke. I know there is a discussion about the stroke-alignment attribute for future versions of SVG. But browsers don't support that yet, and neither Adobe Illustrator.
So my question is: Is there any way how to adjust the SVG so that Illustrator would render the shape with the size that is set by the width attribute in the <use /> element regardless of the stroke settings
The width value on your <use> should be having no effect on your <symbol> because your symbol has no viewBox attribute. Without a viewBox, only the x and y attributes of the <use> will be doing anything.
Also, be aware that we've seen a few questions on S.O. in the past, complaining about bugs in Illustrator's SVG import filter. If <symbol> is working, then that's great. However, in general, you may find that keeping your SVG structure simple, and avoiding the more advanced SVG features, might be a good idea.

What is the iesiest way to transform an SVG image using an arbitrary function (x,y) --> (x'(x,y),y'(x,y))?

What is the easiest way to transform the (x,y) coordinates of an SVG image in the following way:
x --> x'(x,y)
y --> y'(x,y)
Example:
x --> x^2+y^2
y --> sinx + cosy
The method can either modify the original SVG file or produce a new SVG file containing the modified SVG image.
Remember that SVG includes the following functions:
translate()
rotate()
scale()
skew()
matrix()
I initially thought you could use the matrix transformation function that is available to the SVG system. Because that matrix is static, I'm not positive you will get what you are after. A lot depends on what the transform matrix looks like.
Here's a sample jsfiddle.
<svg version="1.1" baseProfile="full" width="300" height="200" xmlns="http://www.w3.org/2000/svg">
<image x="20" y="20" width="300" height="250" xlink:href="https://upload.wikimedia.org/wikipedia/commons/0/0c/Cow_female_black_white.jpg" />
</svg>
<h2>A skew transformation along the y-axis</h2>
<svg version="1.1" baseProfile="full" width="300" height="400" xmlns="http://www.w3.org/2000/svg">
<image x="20" y="20" width="300" height="250" xlink:href="https://upload.wikimedia.org/wikipedia/commons/0/0c/Cow_female_black_white.jpg"
transform="matrix(1,.5,0,1,0,0)" />
</svg>
Have you looked at the D3.js library for your projection stuff? D3 uses SVG elements, and they've got some pretty good tools. I see folks writing additional tools for that as well. Have you seen the geo projections project for D3 at Github? I do see d3.geo.equirectangular option there. Perhaps that will get you to beer quickly?
I do know you can do much more involved stuff using Canvas. You'd have to convert your SVG image over to Canvas, but that is do-able. Check out this awesome tutorial for swirling an image dynamically, in canvas.

SVG image generated in browser different in Illustrator

I'm writing a web application which generates SVG images in the browser.
The SVG's I'm generating work fine in ever browser. However, when I download one of the SVG's and try to open it in Adobe Illsutrator, all the transformations are all over the place.
They are in fact so different that you have to zoom right out to see where the shapes are positioned.
This is the contents of the SVG, you can see it's pretty simple. Just a couple of nested SVG's and a few basic shapes:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="592" height="592" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg style="overflow:visible;" x="88.80000305175781" y="88.80000305175781" fill="#777777">
<svg style="overflow:visible;" height="100px" width="100px">
<rect width="100" height="100" style="stroke:#006600;" transform="scale(4.144 4.144)"></rect>
</svg>
</svg>
<svg style="overflow:visible;" width="592" height="592" x="176.60000000000016" y="177.60000000000014" fill="#000000">
<rect width="592" height="592" fill="rgba(0,0,0,0)" stroke="#bbbbbb" transform="scale(0.4 0.4)"></rect>
<svg style="overflow:visible;" x="-0.0000015258789005656581" y="-0.0000015258789005656581">
<svg style="overflow:visible;" height="48px" width="48px">
<ellipse id="SvgjsEllipse1010" rx="24" ry="24" cx="24" cy="24" style="stroke:#006600;fill:#00cc00;" transform="scale(4.933333333333334 4.933333333333334)"></ellipse>
</svg>
</svg>
</svg>
</svg>
I don't know the SVG spec inside out, but I'm doing anything particularly complex, so it all seems good to me. I can't see a reason why Illustrator would render it so differently to browsers.
Does anyone know why this is happening?
Edit
This is what it looks like in Illsutrator, as you can see the scaling and positioning is all off, the small square in the center is the 592 x 592 canvas area, so you can see who far I am zoomed out.
I suspect AI doesn't like/handle/expect nested <svg> elements. Try replacing them with groups. Those with x and y attributes may need to have a transform added to get it to look the same. Also if the overflow is important, you may need to tweak things further as that property is not valid for group elements.

SVG Rotation in 3D

I need to rotate the paths in my SVG document around an arbitrary point in 3D. It appears that there are multiple ways to do this by either using a 4x4 transformation matrix or the rotateX or rotateY transforms. I've tried both of these methods, and neither seem to work. Are these supported anywhere?
For my application, a bitmap is going to be the final output, so I'm not worried about browser support. I am open to any tool--I can run a specific browser through selenium, or use a standalone SVG rasterizer.
This is what I've tried so far (using Google Chrome 31):
I would expect this to be a black rectangle, rotated about the X axis, and appearing like a trapezoid.
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="640px" height="480px">
<rect x="100" y="100" width="440" height="280" fill="#000000"
transform="rotateX(30 580 100)"></rect>
</svg>
(omitting cy and cz from rotateX gives the same result).
I've also tried with a 4x4 matrix. I don't see any difference from above. I also doubt my math is correct in finding the right matrix elements.
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="640px" height="480px">
<rect x="100" y="100" width="440" height="280" fill="#000000"
transform="matrix(102400 0 0 0 0 88681.00134752653 -159.99999999999997 1387899.8652473476 0 159.99999999999997 88681.00134752653 -15986.602540378442)"></rect>
</svg>
I found that there really isn't a way in SVG to do a 3D rotation that is supported in any modern browser (to the best of my knowledge). However, CSS3 does have a similar "transform" property.
The following works for me:
<svg version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="640px" height="480px">
<rect x="100" y="100" width="440" height="280" fill="#000000" style="-webkit-transform: rotateX(30); -webkit-transform-origin-y: 580px; -webkit-transform-origin-z: 100"></rect>
</svg>
This, obviously, isn't a good cross-browser solution (as it uses prefixed properties), but that isn't something I need in my application.
3d rotations are tricky and i've only just started using them. transform: rotateX() and rotateY() will apply the transformations for you, but to get that perspective of a trapezoid, you'll need to use perspective in the css of the parent element.
Here's a codepen.
The relevant bits are
#parent {
perspective: 4rem;
}
#child {
transform: rotateX(45deg);
}
Think of perspective as the distance the object is from the back of your screen. The lower the value, the more intense the distortion of the perspective will be.
See https://www.w3schools.com/css/css3_3dtransforms.asp :
indeed the CSS code { transform: rotateX(##deg) } and similar for -Y and -Z should work now without prefix in most browsers. But it appears these cannot be combined. So you may want to use the more general method: { transform: rotate3d(x,y,z,angle) } , where you can give an arbitrary rotation axis.
Hope that helps...

Scaling SVG image element when image is another SVG file

I am making a tool where I need a possibility to add an image into existing SVG. This image can be both Bitmap file and another SVG file. So I do it using element, like this:
<image x="100" y="100" width="200" height="100" preserveAspectRatio="none" xlink:href="image.jpg">
I need this image to fit to width/height I specified (I don't care about the original size of an image), that's why I set preserveAspectRatio to "none". And it works fine with bitmaps. However when I try the same code with another SVG image, it is not scaled. The preserverAspectRatio description says that viewBox should be set on this image element, however it doesn't help - the image is not scaled.
Here is the code which, as far as I understand should work:
<image x="100" y="100" width="200" height="100" viewBox="0 0 200 100" preserveAspectRatio="none" xlink:href="clock.svg">
And here is source of the clock.svg:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Map">
<path d="M8.179,20.115c-0.478,0.277-0.642,0.889-0.365,1.366c0.275,0.479,0.889,0.642,1.365,0.366c0.479-0.275,0.643-0.888,0.367-1.367C9.27,20.004,8.658,19.84,8.179,20.115zM9.18,12.239c-0.479-0.276-1.09-0.112-1.366,0.366s-0.111,1.09,0.365,1.366c0.479,0.276,1.09,0.113,1.367-0.366C9.821,13.126,9.657,12.516,9.18,12.239zM8.625,17.043c-0.001-0.552-0.448-0.999-1.001-1c-0.553,0-1,0.448-1,1c0,0.553,0.449,1,1,1C8.176,18.043,8.624,17.596,8.625,17.043zM16.312,3.957V3.031h1c0.275,0,0.5-0.225,0.5-0.5v-0.5c0-0.275-0.225-0.5-0.5-0.5h-3.625c-0.275,0-0.5,0.225-0.5,0.5v0.5c0,0.275,0.225,0.5,0.5,0.5h1v0.926C7.819,4.381,2.376,10.068,2.374,17.042C2.376,24.291,8.251,30.166,15.5,30.169c7.249-0.003,13.124-5.878,13.125-13.127C28.624,10.067,23.181,4.38,16.312,3.957zM15.5,27.166C9.909,27.157,5.385,22.633,5.375,17.042C5.385,11.451,9.909,6.927,15.5,6.917c5.59,0.01,10.115,4.535,10.124,10.125C25.615,22.633,21.091,27.157,15.5,27.166zM12.062,22.998c-0.478-0.275-1.089-0.111-1.366,0.367c-0.275,0.479-0.111,1.09,0.366,1.365c0.478,0.277,1.091,0.111,1.365-0.365C12.704,23.887,12.54,23.275,12.062,22.998zM12.062,11.088c0.479-0.276,0.642-0.888,0.366-1.366c-0.276-0.478-0.888-0.642-1.366-0.366s-0.642,0.888-0.366,1.366C10.973,11.2,11.584,11.364,12.062,11.088zM22.822,13.971c0.478-0.275,0.643-0.888,0.366-1.366c-0.275-0.478-0.89-0.642-1.366-0.366c-0.479,0.278-0.642,0.89-0.366,1.367C21.732,14.083,22.344,14.247,22.822,13.971zM15.501,23.92c-0.552,0-1,0.447-1,1c0,0.552,0.448,1,1,1s1-0.448,1-1C16.501,24.367,16.053,23.92,15.501,23.92zM19.938,9.355c-0.477-0.276-1.091-0.111-1.365,0.366c-0.275,0.48-0.111,1.091,0.366,1.367s1.089,0.112,1.366-0.366C20.581,10.245,20.418,9.632,19.938,9.355zM23.378,16.042c-0.554,0.002-1.001,0.45-1.001,1c0.001,0.552,0.448,1,1.001,1c0.551,0,1-0.447,1-1C24.378,16.492,23.929,16.042,23.378,16.042zM22.823,20.115c-0.48-0.275-1.092-0.111-1.367,0.365c-0.275,0.479-0.112,1.091,0.367,1.367c0.477,0.275,1.089,0.112,1.365-0.366C23.464,21.004,23.3,20.391,22.823,20.115zM15.501,8.167c-0.552,0-1,0.448-1,1l-0.466,7.343l-3.004,1.96c-0.478,0.277-0.642,0.889-0.365,1.366c0.275,0.479,0.889,0.642,1.365,0.366l3.305-1.676c0.055,0.006,0.109,0.017,0.166,0.017c0.828,0,1.5-0.672,1.5-1.5l-0.5-7.876C16.501,8.614,16.053,8.167,15.501,8.167zM18.939,22.998c-0.479,0.276-0.643,0.888-0.366,1.367c0.275,0.477,0.888,0.642,1.366,0.365c0.478-0.276,0.642-0.889,0.366-1.365C20.028,22.886,19.417,22.723,18.939,22.998zM11.197,3.593c-0.836-1.04-2.103-1.718-3.541-1.718c-2.52,0-4.562,2.042-4.562,4.562c0,0.957,0.297,1.843,0.8,2.576C5.649,6.484,8.206,4.553,11.197,3.593zM27.106,9.014c0.503-0.733,0.8-1.619,0.8-2.576c0-2.52-2.043-4.562-4.562-4.562c-1.438,0-2.704,0.678-3.541,1.717C22.794,4.553,25.351,6.484,27.106,9.014z" fill="#000000" fill-opacity="1" stroke="#DDDDDD" stroke-width="0.5" stroke-opacity="1"/>
I want this clock to be scaled and occupy all the 200x100 rectangle, but it is not.
I would be very grateful if anybody could help.
From the 'image' element definition in the SVG 1.1 spec:
The value of the ‘viewBox’ attribute to use when evaluating the
‘preserveAspectRatio’ attribute is defined by the referenced content.
For content that clearly identifies a viewBox (e.g. an SVG file with
the ‘viewBox’ attribute on the outermost svg element) that value
should be used. For most raster content (PNG, JPEG) the bounds of the
image should be used (i.e. the ‘image’ element has an implicit
‘viewBox’ of '0 0 raster-image-width raster-image-height'). Where no
value is readily available (e.g. an SVG file with no ‘viewBox’
attribute on the outermost svg element) the ‘preserveAspectRatio’
attribute is ignored, and only the translation due to the ‘x’ & ‘y’
attributes of the viewport is used to display the content.
What the spec tells you is that the referenced svg (your clock.svg) should define it's coordinate system (aka 'viewBox').

Resources