Fill polygon with pattern doesn't work with leaflet - svg

I try to render a SVG polygon filled with pattern. SVG.path filled with pattern doesn't work. As you can see in this jsfiddle, filled background shows up transparent in Firefox and black in Chrome.
The example is based on leaflet GeoJSON Example and uses the diagonalHatch pattern described by carto.net.
<defs>
<pattern id="diagonalHatch" patternUnits="userSpaceOnUse" x="0" y="0" width="105" height="105">
<g style="fill:none; stroke:black; stroke-width:1">
<path d="M0 90 l15,15"/><path d="M0 75 l30,30"/>
<path d="M0 60 l45,45"/><path d="M0 45 l60,60"/>
<path d="M0 30 l75,75"/><path d="M0 15 l90,90"/>
<path d="M0 0 l105,105"/><path d="M15 0 l90,90"/>
<path d="M30 0 l75,75"/><path d="M45 0 l60,60"/>
<path d="M60 0 l45,45"/><path d="M75 0 l30,30"/>
<path d="M90 0 l15,15"/>
</g>
</pattern>
</defs>
As this jsfiddle shows, copying the SVG polygons below the map, makes it work on Chrome but not on Firefox. Apply a fill pattern adding this style to SVG.path:
style="fill: url(#diagonalHatch)"
I'm really not sure if this is a bug in leaflet or some conflict with SVG implementation on Firefox and Chrome.

I've wrote a leaflet plugin for this, you may try it,
https://github.com/lnaweisu/leaflet-polygon-fillPattern

Maybe you can try setting the path via the shape's attribute as mentioned in this thread: Leaflet polygon with fuzzy outline
// Set filter attribute on the polygon
polygon._path.setAttribute('filter', 'url(#blur)');

Related

SVG getting distorted in IE

I am trying to embed an svg into a web page. It works fine in Chrome and Firefox but gets completely distorted in IE. Please use the below svg block of code as reference:
<svg width="33" height="33" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path d="M21 17.625h-3.375c-.619 0-1.125.506-1.125 1.125v3.375c0 .619.506 1.125 1.125 1.125H21c.619 0 1.125-.506 1.125-1.125V18.75c0-.619-.506-1.125-1.125-1.125zm0-11.25V7.5h-9V6.375c0-.619-.506-1.125-1.125-1.125S9.75 5.756 9.75 6.375V7.5H8.625a2.24 2.24 0 00-2.239 2.25L6.375 25.5a2.25 2.25 0 002.25 2.25h15.75a2.257 2.257 0 002.25-2.25V9.75a2.257 2.257 0 00-2.25-2.25H23.25V6.375c0-.619-.506-1.125-1.125-1.125S21 5.756 21 6.375zM23.25 25.5H9.75a1.128 1.128 0 01-1.125-1.125v-11.25h15.75v11.25c0 .619-.506 1.125-1.125 1.125z" id="a"/>
</defs>
<g fill="none" fill-rule="evenodd">
<path fill="#FFF" d="M-134-821h1400V297H-134z"/>
<path fill="#FFF" d="M-134-821h1400V204H-134z"/>
<path fill="#FFF" d="M-134-821h1400V204H-134z"/>
<circle fill="#269F96" cx="16.5" cy="16.5" r="16.5"/>
<use fill="#FFF" fill-rule="nonzero" xlink:href="#a"/>
</g>
</svg>
So some browsers have a hard time with the <use>, <mask> and <def> tags.
To fix this you can sometimes "flatten" your image in the graphics editor. Remove any folders containing layers, etc etc.
You can also fix this manually. It is not hard and doing it once helps you learn SVG syntax:
Start by looking at the id referenced in the href attribute <use ... xlink:href="#a">. As you can see it is a
Now we look for the tag with id="a" In this case it is the path inside the <def> tag. This is kind of expected as the def means "define for later use".
Remove the <def> tags but keep that <path id="a" ...> and all its guts.
Move the all the attributes (except the xlink:href="#a") in the <use> tag (fill and fill-rule ) to the path#id="a" element.
Remove the <use> tag.
place all <path> tags inside the one <g> tag
In this case the other fill tags are pointless (artifacts maybe from the editor). They are just white squares so you can ditch those.
I put the circle first since this renders in order top renders on bottom. So visually the bottom layer should be a circle top layer is some drawing in white.
End result should be something like this:
No def or use tags.
All shapes inside a root g tag
Removed pointless shapes.
.
<svg width="33" height="33" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g fill="none" fill-rule="evenodd">
<circle fill="#269F96" cx="16.5" cy="16.5" r="16.5"/>
<path fill="#FFF" fill-rule="nonzero" d="M21 17.625h-3.375c-.619 0-1.125.506-1.125 1.125v3.375c0 .619.506 1.125 1.125 1.125H21c.619 0 1.125-.506 1.125-1.125V18.75c0-.619-.506-1.125-1.125-1.125zm0-11.25V7.5h-9V6.375c0-.619-.506-1.125-1.125-1.125S9.75 5.756 9.75 6.375V7.5H8.625a2.24 2.24 0 00-2.239 2.25L6.375 25.5a2.25 2.25 0 002.25 2.25h15.75a2.257 2.257 0 002.25-2.25V9.75a2.257 2.257 0 00-2.25-2.25H23.25V6.375c0-.619-.506-1.125-1.125-1.125S21 5.756 21 6.375zM23.25 25.5H9.75a1.128 1.128 0 01-1.125-1.125v-11.25h15.75v11.25c0 .619-.506 1.125-1.125 1.125z"/>
</g>
</svg>
I don't have enough reputation points to answer #cloned question in the comments. One annoying thing I have found out about IE11 is that not all versions of IE11 will break the same. The versions among Win7, Win8, Win8.1, and Win10 actually intemperate code differently.

Dashed SVG line with non-dashed marker in Safari

I want a dashed line with a non-dashed arrow head, but in Safari the dashiness is apparently also applied on the markers.
Demo:
<svg width="100%" height="100%">
<defs>
<marker style="overflow:visible" id="myMarker" refX="0.0" refY="0.0" orient="auto">
<path transform="scale(-0.4) translate(-3,0)" style="fill-rule:evenodd;fill:#ffffff;stroke:#000000;stroke-width:1pt;stroke-opacity:1" d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "></path>
</marker>
</defs>
<line class="line" stroke-dasharray="5,5" x1="20" y1="20" x2="80" y2="80" marker-start="url(#myMarker)" stroke-width="10" stroke="black"></line>
</svg>
How it looks like in Firefox (and Chrome), that's how I want it to be:
How it looks like in Safari (12.0 and the current Technology Preview):
Setting stroke-dasharray to 0 or an empty string for the <path> of the marker does not seem to have any effect at all. Setting it to 1 0 (which smells like a hack) does nearly perfect, but the arrow head's tip is not pointy:
How to best override this behaviour of Safari and get a dashed line with non-dashed arrow head with a pointy tip? Is there something I am missing why Safari is behaving this way or is this simply a bug?
I've rewritten the path for the marker. Now it begins in the middle of the side instead of the vertex. Also I'm using stroke-dasharray="30,0"where 30 is the length of the path for the marker.
<svg width="100%" height="100%">
<defs>
<marker style="overflow:visible" id="myMarker" refX="0.0" refY="0.0" orient="auto">
<path transform="scale(-0.4) translate(-3,0)" style="fill-rule:evenodd;fill:#ffffff;stroke:#000000;stroke-width:1pt;stroke-opacity:1" d="M-2.88,0L-2.88,5L 5.77,0L -2.88,-5L-2.88,0z" stroke-dasharray="30,0"></path>
</marker>
</defs>
<line class="line" stroke-dasharray="5,5" x1="20" y1="20" x2="80" y2="80" marker-start="url(#myMarker)" stroke-width="10" stroke="black"></line>
</svg>

Add svg icon in the middle of an svg curved line

I have a curved svg line like this
<path d="M70,260 C105,260 126,330 160,330"
style="stroke: #ff4444;stroke-width:2; fill:none;"/>
what I want is to add another svg (like https://www.flaticon.com/free-icon/play-button_149657) in the middle of my line pointing to the end point.
any ideas?
One way to achieve the result is a degenerate animation:
Define the marker shape (obj1 in the example below)
Position the marker at the beginning of the curve (track1 below; this is the path definition from your example).
Specify an animated motion of the marker shape along the curve with some particular settings:
Explicit positioning along the track using keyTimes, keyPoints attributes, limiting the range of positions to exactly one point: the midpoint of the curve
Infinite duration, infinite repeat
Auto-rotation of the shape according to the orientation of the track curve ( rotate attribute )
Effectively there is no animation at all but the shape is positioned at the center of the curve, properly oriented.
Example
<html>
<head>
<title>SVG object centered on path</title>
</head>
<body>
<svg width="200px" height="200px"
viewBox="0 0 500 500"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<defs>
<path
id="obj1"
d="M11.18,0 L-2.5,10 -2.5,-10 Z"
stroke="black" stroke-width="1" fill="green"
>
</path>
<path
id="track1"
d="M70,260 C105,260 126,330 160,330"
stroke="#ff4444" stroke-width="2" fill="none"
/>
</defs>
<use xlink:href="#track1"/>
<use xlink:href="#obj1">
<animateMotion
calcMode="linear"
dur="infinite"
repeatCount="infinite"
rotate="auto"
keyPoints="0.5;0.5"
keyTimes="0.0;1.0"
>
<mpath xlink:href="#track1"/>
</animateMotion>
</use>
</svg>
</body>
</html>
There are a number of ways to do this.
One way is to "cheat" a little and use a <textPath> and an arrow character.
SVG marker-mid on specific point on path
This is a little hacky, and may not work reliably on all browsers, but it may be good enough for your needs.
Another way is split the path in two (using De Casteljau's algorithm), and use a <marker>.
<svg viewBox="0 200 200 200" width="400">
<defs>
<marker id="Triangle"
viewBox="0 0 10 10" refX="0" refY="5"
markerUnits="strokeWidth"
markerWidth="4" markerHeight="3"
orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
</defs>
<path d="M 70,260
C 87.5,260 101.5,277.5 115.375,295
C 129.25,312.5 143,330 160,330"
style="stroke: #ff4444; stroke-width:2; fill:none; marker-mid:url(#Triangle)"/>
</svg>
There are other ways using Javascript. For example, you could use the SVGPathElement.getPointAtLength() method to find the coordinates of the centre of the path. Then position a triangle at that location.

Improve SVG so pin is centered inside circle, without multiple viewboxes

I have a pin that needs to be shown inside a circle in Svg.
My current code is the following:
<svg viewBox="0 0 20 20" preserveAspectRatio="xMinYMin meet">
<circle cx="50%" cy="1.5" r="1.5" style="fill: green;"></circle>
<svg x="47.5%" y="5%" viewBox="0 0 10000 10000" fill="#fff" preserveAspectRatio="none">
<g>
<path d="M250,124.3c-35,0-63.4,28.8-63.4,64.1c0,35.3,28.5,64,63.4,64s63.4-28.8,63.4-64.1C313.4,153,285,124.3,250,124.3z
M250,222c-18.3,0-33.2-15.1-33.2-33.7s14.9-33.7,33.2-33.7s33.2,15.1,33.2,33.7S268.3,222,250,222z">
</path>
<path d="M250,50.9c-74.9,0-135.8,61.6-135.8,137.4c0,31.3,22.5,84.4,66.9,157.7c32.9,54.4,66.2,100.3,66.6,100.7l2.4,3.3l2.4-3.3
c0.3-0.5,33.7-46.3,66.6-100.7c44.4-73.3,66.9-126.4,66.9-157.7C385.8,112.5,324.9,50.9,250,50.9z M250,397.6
c-16.5-24.3-45.5-68.4-69.9-114c-23.5-44-35.9-77-35.9-95.4c0-59,47.4-107,105.8-107s105.8,48,105.8,107
c0,18.4-12.4,51.4-35.9,95.4C295.4,329.3,266.5,373.4,250,397.6z">
</path>
</g>
</svg>
</svg>
which works somewhat but seems inelegant, and perhaps also buggy. What I would like is a better way to center the group 'inside' the circle without using JavaScript
It would be nice if I could get rid of the extra SVG element in the middle with its really big viewBox that I'm using to place the pin. So if you can show me how to do it with just a g and make a scaling function that would be good.
If you want to use coordinates that contain percentage values, you need an element that has x and y attributes. <use> is such an element, <g> is not.
Your live will be easier if you draw your pin centered on the origin of the coordinate system: translate(-250 -230).
After that, you can easily scale it to the size you need: scale(0.0025) (remember: multiple transform commands are processed right-to-left.)
Finally, you use the pin template with the same x and y coordinates as your circle.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 20 20" preserveAspectRatio="xMinYMin meet">
<defs>
<!--center the pin around the origin and scale it to final size-->
<g id="pin" transform="scale(0.0025) translate(-250 -230)">
<path d="M250,124.3c-35,0-63.4,28.8-63.4,64.1c0,35.3,28.5,64,63.4,64s63.4-28.8,63.4-64.1C313.4,153,285,124.3,250,124.3z
M250,222c-18.3,0-33.2-15.1-33.2-33.7s14.9-33.7,33.2-33.7s33.2,15.1,33.2,33.7S268.3,222,250,222z" />
<path d="M250,50.9c-74.9,0-135.8,61.6-135.8,137.4c0,31.3,22.5,84.4,66.9,157.7c32.9,54.4,66.2,100.3,66.6,100.7l2.4,3.3l2.4-3.3
c0.3-0.5,33.7-46.3,66.6-100.7c44.4-73.3,66.9-126.4,66.9-157.7C385.8,112.5,324.9,50.9,250,50.9z M250,397.6
c-16.5-24.3-45.5-68.4-69.9-114c-23.5-44-35.9-77-35.9-95.4c0-59,47.4-107,105.8-107s105.8,48,105.8,107
c0,18.4-12.4,51.4-35.9,95.4C295.4,329.3,266.5,373.4,250,397.6z" />
</g>
</defs>
<!--use the same coordinates for the center of the circle and the pin-->
<circle cx="50%" cy="1.5" r="1.5" fill="green" />
<use xlink:href="#pin" x="50%" y="1.5" fill="white" />
</svg>

SVG: Mask not working as expected

I have this rather basic SVG with a vertical line going through 4 circles. The mask that I have for the vertical line has the same definition as the line itself, the only difference being the stroke color (#fff in this case) because I want to be able to see through the mask. But, for unknown reasons, the mask still acts as if the color is black, thus hiding the element. If anyone knows why it's behaving like this, please let me know.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400">
<defs>
<mask id="education">
<path class="through" fill="none" stroke="#fff" stroke-width="2" stroke-miterlimit="10" d="M200 325.6v42.5M200 325.6V44.2"/>
</mask>
</defs>
<path class="arrow" fill="#C57773" d="M191.9 41.5l8.1-14 8.1 14"/>
<path style="mask: url(#education);" class="through" fill="none" stroke="#58595B" stroke-width="2" stroke-miterlimit="10" d="M200 325.6v42.5M200 325.6V44.2"/>
<path class="circle2" fill="#C95147" d="M200 234.7c-4.6 0-8.3 3.7-8.3 8.3s3.7 8.3 8.3 8.3c4.6 0 8.3-3.7 8.3-8.3s-3.7-8.3-8.3-8.3z"/>
<path class="circle1" fill="#C95147" d="M200 317.2c-4.6 0-8.3 3.7-8.3 8.3s3.7 8.3 8.3 8.3c4.6 0 8.3-3.7 8.3-8.3s-3.7-8.3-8.3-8.3z"/>
<path class="circle3" fill="#C95147" d="M200 152c-4.6 0-8.3 3.7-8.3 8.3 0 4.6 3.7 8.3 8.3 8.3 4.6 0 8.3-3.7 8.3-8.3 0-4.5-3.7-8.3-8.3-8.3z"/>
<path class="circle4" fill="#C95147" d="M200 67.1c-4.6 0-8.3 3.7-8.3 8.3s3.7 8.3 8.3 8.3c4.6 0 8.3-3.7 8.3-8.3s-3.7-8.3-8.3-8.3z"/>
</svg>
P.S. Just started tinkering around with SVG, but this (the element dissapearing) happens no matter what shape I define in the mask or what color I give that shape.
SVG is not like CSS, it doesn't use the stroke-width when calculating dimensions for masks and filters, so you can't mask a shape like a horizontal or vertical line (zero-height/zero-width bounding box) using default mask parameters. Just add "maskUnits="userSpaceOnUse" to your mask element to fix.
<mask id="education" maskUnits="userSpaceOnUse">

Resources