How to align a group (instead of text) along a path in svg? - javascript

Lets assume I have programmatically created a circle and some text,
that I want to align along the circle.
I am able to do so using the textPath element.
In addition I have a rectangular image (or any svg group <g>),
that I also would like to align to the circle
(the red rectangle in the image below is just an example; actually I would like to be able to align arbitrary svg groups <g> as image labels on the nodes of a chord diagram.).
However, textPath only seems to work for text elements.
=> Is there something similar that works for group elements?
Or do I need to manually calculate the transformation for my group
(following from some tangent of the circle)?
(A workaround could be to create some hidden text with a single letter and
the same size as my group ... align it and grab its transformation. However, that feels ugly.)

In addition I have a rectangular image (or any svg group ), that I
also would like to align to the circle (see red rectangle in the
example image below).
However, textPath only seems to work for text elements.
You can use the rectangle unicode character ▮
In this case you will be able to include it in one textPath command along with other words
<svg width="400" height="400" viewBox="0 0 400 400">
<path id="pathChain" d="M87 199C87 114 141 64 200 64 258 64 310 122 313 199 315 273 258 335 200 335 141 335 87 279 87 199Z" style="fill:#089421;"/>
<text font-size="36" font-family="Times New Roman" fill="grey" >
<textPath id="result" startOffset="7%" xlink:href="#pathChain">
<tspan dx="0" dy="-5" fill="black" font-size="48px"> Hello World </tspan> <tspan dx="-20" dy="-10" fill="red" font-size="72px"> ▮</tspan>
</textPath>
</text>
</svg>
You can use any unicode character that suits you
<svg width="400" height="400" viewBox="0 0 400 400">
<path id="pathChain" d="M87 199C87 114 141 64 200 64 258 64 310 122 313 199 315 273 258 335 200 335 141 335 87 279 87 199Z" style="fill:#089421;"/>
<text font-size="36" font-family="Times New Roman" fill="grey" >
<textPath id="result" startOffset="7%" xlink:href="#pathChain">
<tspan dx="0" dy="-5" fill="black" font-size="48px"> Hello World </tspan> <tspan dx="-5" fill="red" font-size="72px"> ⮔</tspan>
</textPath>
</text>
</svg>
If necessary, you can make the animation of the letters
<svg width="400" height="400" viewBox="0 0 400 400">
<path id="pathChain" d="M87 199C87 114 141 64 200 64 258 64 310 122 313 199 315 273 258 335 200 335 141 335 87 279 87 199Z" style="fill:#089421;"/>
<text font-size="36" font-family="Times New Roman" fill="grey" >
<textPath id="result" xlink:href="#pathChain">
<tspan dx="0" dy="-5" fill="black" font-size="48px"> Hello World </tspan> <tspan dx="-5" fill="red" font-size="72px"> ⮔</tspan>
<animate dur="10s" repeatCount="5" attributeName="startOffset" values="5%;50%;50%;5%;5%"/>
</textPath>
</text>
</svg>

As #Paul LeBeau commented:
No there is no automatic way to do that. You have to position it
yourself
Consider adding svg images to text using absolute positioning
Since any text in SVG is a vector object, it has absolute coordinates x, y, as the first character of the word and the last.
Using this you can position an icon or any other vector image to the beginning or end of the text.
I put the icon in the <symbol> tag and position it at the end of the word using the <use> tag
<use xlink:href="#speaker" x="245" y="35" />
<svg width="400" height="400" viewBox="0 0 400 400">
<symbol>
<g id="speaker" style="transform-origin:center;transform-box: fill-box;transform:rotate(15deg);" >
<path fill="#089421" d="M28,7.1v2c7.3,1,13,7.3,13,14.9s-5.7,13.9-13,14.9v2c8.4-1,15-8.2,15-16.9S36.4,8.1,28,7.1z"/>
<path fill="#546E7A" d="M14,32H7c-1.1,0-2-0.9-2-2V18c0-1.1,0.9-2,2-2h7V32z"/>
<polygon fill="#78909C" points="26,42 14,32 14,16 26,6"/>
<path fill="#089421" d="M28,17.3v2.1c1.8,0.8,3,2.5,3,4.6s-1.2,3.8-3,4.6v2.1c2.9-0.9,5-3.5,5-6.7S30.9,18.2,28,17.3z"/>
<path fill="#089421" d="M28,12.2v2c4.6,0.9,8,5,8,9.8s-3.4,8.9-8,9.8v2c5.7-1,10-5.9,10-11.8S33.7,13.1,28,12.2z"/>
</g>
</symbol>
<path id="pathChain" d="M87 199C87 114 141 64 200 64 258 64 310 122 313 199 315 273 258 335 200 335 141 335 87 279 87 199Z" style="fill:#089421;"/>
<text font-size="36" font-family="Times New Roman" fill="grey" >
<textPath id="result" xlink:href="#pathChain">
<tspan dx="0" dy="-5" fill="black" font-size="48px"> Hello Wordl </tspan>
</textPath>
</text>
<use xlink:href="#speaker" x="245" y="35" />
</svg>
An example with a growing line on which text and an icon are located
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400" viewBox="0 0 400 400" version="1">
<symbol id="grow">
<g>
<circle fill="#FF9800" cx="28" cy="9" r="5"/>
</g>
<path fill="#00796B" d="M29,27.3l-9.2-4.1c-1-0.5-1.5,1-2,2c-0.5,1-4.1,7.2-3.8,8.3c0.3,0.9,1.1,1.4,1.9,1.4c0.2,0,0.4,0,0.6-0.1 L28.8,31c0.8-0.2,1.4-1,1.4-1.8C30.2,28.4,29.7,27.6,29,27.3z"/>
<path fill="#009688" d="M26.8,15.2l-2.2-1c-1.3-0.6-2.9,0-3.5,1.3L9.2,41.1c-0.5,1,0,2.2,1,2.7c0.3,0.1,0.6,0.2,0.9,0.2 c0.8,0,1.5-0.4,1.8-1.1c0,0,9.6-13.3,10.4-14.9s4.9-9.3,4.9-9.3C28.7,17.4,28.2,15.8,26.8,15.2z"/>
<path fill="#FF9800" d="M40.5,15.7c-0.7-0.8-2-1-2.8-0.3l-5,4.2l-6.4-3.5c-1.1-0.6-2.6-0.4-3.3,0.9c-0.8,1.3-0.4,2.9,0.8,3.4 l8.3,3.4c0.3,0.1,0.6,0.2,0.9,0.2c0.5,0,0.9-0.2,1.3-0.5l6-5C41.1,17.8,41.2,16.6,40.5,15.7z"/>
<path fill="#FF9800" d="M11.7,23.1l3.4-5.1l4.6,0.6l1.5-3.1c0.4-0.9,1.2-1.4,2.1-1.5c-0.1,0-0.2,0-0.2,0h-9c-0.7,0-1.3,0.3-1.7,0.9 l-4,6c-0.6,0.9-0.4,2.2,0.6,2.8C9.2,23.9,9.6,24,10,24C10.6,24,11.3,23.7,11.7,23.1z"/>
</symbol>
<path id="txtPath" d="m22 366c0 0 59-24 74-50C132 253 129 213 128 161 125 33 200 2 200 2" style="fill:none;stroke:#00796B;stroke-width:3"/>
<use xlink:href="#grow" x="123" y="10" />
<text dx="0" dy="-10px" font-size="20" font-family="Times New Roman" fill="#414141" >
<textPath id="result" startOffset="5%" xlink:href="#txtPath"> Stock growth in the first half of the year </textPath>
</text>
</svg>
One more example
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400" viewBox="0 0 400 400" version="1">
<symbol id="Cactus" style="transform-origin:center;transform-box: fill-box;transform:rotate(15deg);">
<path fill="#7CB342" d="M35.3,9.6c-1.6-0.2-1.3,0.9-1.9,2.7l-1,4.3c-0.3,1-0.7,1.4-2,1.3L25,17.3c-1.6-0.2-3.1,1-3.2,2.6 c-0.2,1.6,1,3.1,2.6,3.2l6.3,0.7c3,0.3,5.5-0.9,6-5.4c0,0,0.6-4.7,0.3-6.6C36.7,10.2,36.6,9.7,35.3,9.6z"/>
<path fill="#7CB342" d="M12.2,13.6c1.6-0.1,1.3,0.9,1.9,2.8l1.3,6.3c0.3,1,0.7,1.4,2,1.3l5.4-0.4c1.6-0.1,3,1.1,3.2,2.7 c0.1,1.6-1.1,3-2.7,3.2l-6.3,0.5c-3,0.2-5.5-1-5.9-5.5c0,0-0.8-6.7-0.5-8.5C10.7,14.2,10.8,13.7,12.2,13.6z"/>
<path fill="#8BC34A" d="M24,5c-2.4,0-4,0.6-4.5,3.2c0,0-2.1,16.9,0,32.1c0.3,3.2,2,1.2,4.4,1.2s3.8,2.7,4.4-0.8 c2.5-15.1,0-32.6,0-32.6C27.7,5.2,26.4,5,24,5z"/>
<path fill="#FFB74D" d="M38.8,43H9.2c0,0,4.9-2.3,14.8-2.3S38.8,43,38.8,43z"/>
</symbol>
<path id="txtPath" d="m200 2c0 0 36 31 57 42 15 8 34 6 47 16 15 11 26 27 33 43 8 18 2 41 11 58 9 17 41 40 41 40" fill="none" stroke="green" stroke-width="2"/>
<use xlink:href="#Cactus" x="355" y="150" />
<text font-size="20" font-family="Times New Roman" fill="grey" >
<textPath id="result" startOffset="7%" xlink:href="#txtPath">
<tspan dx="0" dy="-5" fill="black" >Decrease in stocks per year </tspan>
</textPath>
</text>
</svg>

As a starting point here is the workaround I mentioned.
It uses some invisible placeholder text and extracts the transformation information with
placeHolder.getBoundingClientRect();
and
placeHolder.getRotationOfChar(0);
The result is only an approximation that depends on the font size and on the character of the placeholder.
var svg = document.getElementById('svg');
var text = document.createElement('text');
text.setAttribute('fill','black');
svg.appendChild(text);
var placeHolder = document.getElementById('placeholder');
var placeHolderBounds = placeHolder.getBoundingClientRect();
var angle = placeHolder.getRotationOfChar(0);
var group = document.getElementById('my-group');
var groupBounds = group.getBoundingClientRect();
var dx = 0; //groupBounds.width/2;
var dy = -groupBounds.height;
var x = placeHolderBounds.x;
var y = placeHolderBounds.y;
var transform = 'translate(' + x +','+ y +') '+
'rotate('+ angle +') '+
'translate('+ dx +','+ dy +')';
group.setAttribute('transform', transform);
<svg id='svg' width="400" height="400" viewBox="0 0 400 400">
<path id="my-path" d="M87 199C87 114 141 64 200 64 258 64 310 122 313 199 315 273 258 335 200 335 141 335 87 279 87 199Z" style="fill:#089421;"/>
<g id="my-group">
<rect width="30" height="20" style="fill:red"/>
</g>
<text font-size="12px" >
<textPath startOffset="10%" xlink:href="#my-path">
<tspan>Hello World</tspan><tspan id='placeholder' visibility="hidden" >-</tspan>
</textPath>
</text>
</svg>

Related

Removing gap between two SVG paths without removing anti-aliasing

I have two SVG paths that have a gap between them.
From reading through other questions (in particular this one) I understand this is because of the native anti-aliasing properties of SVGs.
So I added shapeRendering="crispEdges"
This does remove the gap. However it results in jagged edges because of the removal of anti-aliasing.
<svg height="300" width="300" shapeRendering="crispEdges">
<path
d="M150 10 a120 120 0 0 1 103.9230 60"
fill="none"
stroke="green"
stroke-width="20"
/>
<path
d="M253.9230 70 a120 120 0 0 1 0 120"
fill="none"
stroke="green"
stroke-width="20"
/>
</svg>
I've also tried the suggestion in this question to add crispEdges to the parent svg of the path and add shapeRendering="optimizeQuality" to the path but that didn't work.
How can I remove the gap AND keep the smooth edges of my svg path?
You could also mitigate this gap rendering effect by applying a subtle svg feMorphology dilate filter – resulting in slightly expanded strokes closing thin gaps between paths:
SVG feMorphology filter
svg {
overflow: visible;
}
.chart path {
filter: url(#outline);
}
path:hover {
stroke: red;
}
<svg height="300" width="300" shape-rendering="geometricPrecision">
<g class="original">
<path d="M150 10 a120 120 0 0 1 103.9230 60" fill="none" stroke="green" stroke-width="20" />
<path d="M253.9230 70 a120 120 0 0 1 0 120" fill="none" stroke="green" stroke-width="20" />
</g>
<text x="50%" y="50%">Original</text>
</svg>
<svg height="300" width="300">
<filter filterUnits="userSpaceOnUse" id="outline" >
<feMorphology in="SourceGraphic" result="DILATED" operator="dilate" radius="0.5" />
</filter>
<g class="chart">
<path d="M150 10 a120 120 0 0 1 103.9230 60" fill="none" stroke="green" stroke-width="20" />
<path d="M253.9230 70 a120 120 0 0 1 0 120" fill="none" stroke="green" stroke-width="20" />
</g>
<text x="50%" y="50%">Dilate filter</text>
</svg>
But this approach will also introduce slightly rounded edges (you can see this effect on hover).
More importantly, svg filters are quite expensive with regards to rendering performance – rather negligible if you only display a few elements per page view.
Add concatenated background path
As suggested by #Robert Longson: you could also prepend a background path based on concatenated d path data.
This task could be achieved with a javaScript helper method cloning the first path and displaying the concatenated paths.
addBgPaths(".addBGPath");
function addBgPaths(selector) {
let addPathSvgs = document.querySelectorAll(selector);
addPathSvgs.forEach(function(svg) {
let paths = document.querySelectorAll(".addBGPath path");
let firstPath = paths[0];
let firstPathCloned = firstPath.cloneNode();
//cloned elements shouldn't have ids to avoid non unique ids
firstPathCloned.removeAttribute("id");
let dArr = [firstPath.getAttribute("d")];
for (let i = 1; i < paths.length; i++) {
let path = paths[i];
let d = path.getAttribute("d");
dArr.push(d);
}
firstPathCloned.setAttribute("d", dArr.join(" "));
svg.insertBefore(firstPathCloned, svg.children[0]);
});
}
<svg height="300" width="300" shape-rendering="geometricPrecision">
<path d="M150 10 a120 120 0 0 1 103.9230 60" fill="none" stroke="green" stroke-width="20" />
<path d="M253.9230 70 a120 120 0 0 1 0 120" fill="none" stroke="green" stroke-width="20" />
<text x="0" y="50%">Original</text>
</svg>
<svg class="addBGPath" height="300" width="300" shape-rendering="geometricPrecision">
<path id="first2" d="M150 10 a120 120 0 0 1 103.9230 60" fill="none" stroke="green" stroke-width="20" />
<path d="M253.9230 70 a120 120 0 0 1 0 120" fill="none" stroke="green" stroke-width="20" />
<text x="0" y="50%">Add bg path</text>
</svg>
<svg class="addBGPath" height="300" width="300" shape-rendering="geometricPrecision">
<path id="first" d="M150 10 a120 120 0 0 1 103.9230 60" fill="none" stroke="green" stroke-width="20" />
<path d="M253.9230 70 a120 120 0 0 1 0 120" fill="none" stroke="red" stroke-width="20" />
<text x="0" y="50%">Add bg path (red)</text>
</svg>
<svg height="300" width="300" shape-rendering="geometricPrecision">
<path d="M150 10 a120 120 0 0 1 103.9230 60" fill="none" stroke="green" stroke-width="20" />
<path d="M253.9230 70 a120 120 0 0 1 0 120" fill="none" stroke="red" stroke-width="20" />
<text x="0" y="50%">Original (red)</text>
</svg>
If all your path segments have the same color, this is probably the most elegant solution.
But this approach will also introduce colored "halos" when segments use different stroke colors (example #3 compared to #4).
If you able to edit the svg in editor, you can overlap like this. The darker green is the intersection between two paths.
As a quick fix, you can make the ends overlap with stroke-linecap="square"
But ideally, you need to create a single path instead of two separate paths.
<svg height="300" width="300" shapeRendering="crispEdges">
<path
d="M150 10 a120 120 0 0 1 103.9230 60"
fill="none"
stroke="green"
stroke-width="20"
stroke-linecap="square"
/>
<path
d="M253.9230 70 a120 120 0 0 1 0 120"
fill="none"
stroke="green"
stroke-width="20"
stroke-linecap="square"
/>
</svg>

Give numbers for svg path elements

I have the following svg file with a defined marker and different paths.
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="629" version="1.1" xmlns:xlink= "http://www.w3.org/1999/xlink">
<defs>
<marker id="start" viewBox="0 0 42 42" refX="10" refY="20" markerWidth="20" markerHeight="20">
<rect width="20" height="20" fill="#000"></rect>
<text x="10" y="10" font-family="Verdana" font-size="10" fill="#fff" text-anchor="middle" alignment-baseline="central" class="number"></text>
</marker>
</defs>
<path d="M110 543 L98 366" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start)" />
<path d="M172 544 L139 454 L140 420 L144 357 L146 283" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start)"/>
<path d="M151 447 L171 403 L174 326 L164 284 L158 279" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start)"/>
<path d="M234 571 L224 520 L244 465 L256 404 L248 361 L234 307 L236 256" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start)"/>
<path d="M383 578 L376 465 L361 430 L325 378 L325 311 L348 234" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start)"/>
<path d="M376 435 L380 356 L365 331 L358 284 L354 240" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-start="url(#start)"/>
</svg>
For each path element I want a marker displayed with enumerate numbers. So 1,2,3 ......
I want to solve it via javascript but I get the message "Cannot set property 'innerHTML' of undefined".
var number = document.querySelectorAll('.number');
var polygons = document.getElementsByTagName("path");
for (var i = 0; i < polygons.length; i++) {
number[i].innerHTML = i;
console.log(i);
}
Anyone who can help me?
Your problem here is, that you're using definitions to render the number. That has two implications:
Whereever you use this definition, it will print the same content, not different ones (like copying the element)
The definition itself only exists once
The first point means, you can only change all of the numbers to the same value, not to different ones (what, btw., seems to be what you want to do, so you can not do it how you did it now).
The second one is the cause of your error: You try to iterate over multiple numbers, however, your list of nodes (returned from document.querySelectorAll('.number')) only contains one element, as the DOM of your page only has one occurence of this class. So, your loop actually runs out of the array bounds, throwing the error you mentioned.
Actually, I don't know any way of solving your problem without needing to duplicate the markers for each element you want to have a different number for. You could do it in Javascript, something like that:
var number = document.querySelectorAll('.number');
var polygons = document.getElementsByTagName("path");
for (var i = 0; i < polygons.length; i++) {
var node = number[0].parentNode.cloneNode(true);
document.getElementsByTagName('defs')[0].appendChild(node);
node.querySelector('.number').innerHTML = i;
node.id = 'start' + i;
polygons[i].setAttribute("marker-start", 'url(#' + node.id + ')');
}
However, even if that code works, I would probably not use it in production without carefully thinking about the solution. There may be a better one or at least take a look where potentially this code could break.
You can't change the marker. However you can do something like this:
for every path you add a text element:
<text class="number" x="110" y="543" ></text>
the x and y values for the text are taken from the d attribute:in this case d="M110 543 L98 366"
Alternatively you can choose to add those text elements dynamically in a separate group.
var number = document.querySelectorAll('.number');
var polygons = document.getElementsByTagName("path");
for (var i = 0; i < polygons.length; i++) {
number[i].innerHTML = i;
}
svg{border:solid; width:90vh;}
text{font-family:Verdana;font-size:8px;fill:#fff;text-anchor:middle; dominant-baseline:middle}
<svg viewBox="70 230 350 370" >
<defs>
<marker id="start" viewBox="0 0 42 42" refX="10" refY="10" markerWidth="20" markerHeight="20">
<rect width="20" height="20"></rect>
</marker>
</defs>
<path d="M110 543 L98 366" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start)" />
<text class="number" x="110" y="543" ></text>
<path d="M172 544 L139 454 L140 420 L144 357 L146 283" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start)" />
<text class="number" x="172" y="544" ></text>
<path d="M151 447 L171 403 L174 326 L164 284 L158 279" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start)"/>
<text class="number" x="151" y="447" ></text>
<path d="M234 571 L224 520 L244 465 L256 404 L248 361 L234 307 L236 256" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start)"/>
<text class="number" x="234" y="571" ></text>
<path d="M383 578 L376 465 L361 430 L325 378 L325 311 L348 234" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start)" marker-start="url(#start)"/>
<text class="number" x="383" y="578" ></text>
<path d="M376 435 L380 356 L365 331 L358 284 L354 240" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-start="url(#start)"/>
<text class="number" x="376" y="435" ></text>
</svg>
solution is to add a marker tag for each polygon
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="629" version="1.1" xmlns:xlink= "http://www.w3.org/1999/xlink">
<defs>
<marker id="start" viewBox="0 0 42 42" refX="10" refY="20" markerWidth="20" markerHeight="20">
<rect width="20" height="20" fill="#000"></rect>
<text x="10" y="10" font-family="Verdana" font-size="10" fill="#fff" text-anchor="middle" alignment-baseline="central" class="number">1</text>
</marker>
<marker id="start2" viewBox="0 0 42 42" refX="10" refY="20" markerWidth="20" markerHeight="20">
<rect width="20" height="20" fill="#000"></rect>
<text x="10" y="10" font-family="Verdana" font-size="10" fill="#fff" text-anchor="middle" alignment-baseline="central" class="number">2</text>
</marker>
<marker id="start3" viewBox="0 0 42 42" refX="10" refY="20" markerWidth="20" markerHeight="20">
<rect width="20" height="20" fill="#000"></rect>
<text x="10" y="10" font-family="Verdana" font-size="10" fill="#fff" text-anchor="middle" alignment-baseline="central" class="number">3</text>
</marker>
</defs>
<path d="M110 543 L98 366" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start)" />
<path d="M172 544 L139 454 L140 420 L144 357 L146 283" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start2)"/>
<path d="M151 447 L171 403 L174 326 L164 284 L158 279" stroke="#E42522" stroke-width="2" stroke-dasharray="20,5" fill="none" marker-end="url(#dot)" marker-start="url(#start3)"/>
</svg>
Via javascript , you'll have to add in the defs tag a marker node for each polygon dynamically ( inside the for loop ).

How can I add a pin marker icon on an SVG polygon element?

I have na SVG Map that contains cities and their districts. You can look one of them below. I want to add a pin icon on the center of district. You can see the text (district's name) in the middle of the district. I want to put over the text.
<g id="Hakkari" transform="translate(4607.000000, 1335.000000)" data-transform-left="-521.5" data-transform-top="-87">
<g id="Merkez" transform="translate(10.000000, 2.000000)">
<polygon id="Shape" stroke="#FFFFFF" fill="#9FB4B7" fill-rule="nonzero" points="31 59 119 38 181 0 193 43 155 64 163 167 49 175 0 142"></polygon>
<g id="MER" transform="translate(85.000000, 98.000000)" font-size="6" font-family="Helvetica-Bold, Helvetica" fill="#000000" font-weight="bold">
<text>
<tspan x="0" y="6">MER</tspan>
</text>
</g>
</g>
<g id="Yüksekova" transform="translate(165.000000, 0.000000)">
<polygon id="Shape" stroke="#FFFFFF" fill="#9FB4B7" fill-rule="nonzero" points="38 44 122 0 163 7 185 27 185 107 118 133 79 177 38 176 25 190 7 168 0 66"></polygon>
<g id="YÜK" transform="translate(78.000000, 86.000000)" font-size="6" font-family="Helvetica-Bold, Helvetica" fill="#000000" font-weight="bold">
<text>
<tspan x="0" y="6">YÜK</tspan>
</text>
</g>
</g>
<g id="Şemdinli" transform="translate(244.000000, 107.000000)">
<polygon id="Shape" stroke="#FFFFFF" fill="#9FB4B7" fill-rule="nonzero" points="106 0 168 47 172 104 121 94 40 169 14 127 31 87 0 70 39 26"></polygon>
<g id="ŞEM" transform="translate(81.000000, 62.000000)" font-size="6" font-family="Helvetica-Bold, Helvetica" fill="#000000" font-weight="bold">
<text>
<tspan x="0" y="6">ŞEM</tspan>
</text>
</g>
</g>
<g id="Çukurca" transform="translate(0.000000, 143.000000)">
<polygon id="Shape" stroke="#FFFFFF" fill="#9FB4B7" fill-rule="nonzero" points="190 47 163 76 70 72 20 51 0 24 10 0 58 33 173 26"></polygon>
<g id="ÇUK" transform="translate(104.000000, 50.000000)" font-size="6" font-family="Helvetica-Bold, Helvetica" fill="#000000" font-weight="bold">
<text>
<tspan x="0" y="6">ÇUK</tspan>
</text>
</g>
</g>
</g>
I'm using the Google's icon "location on" as as symbol. I hope this is what you need.
<svg viewBox="4600 1300 500 300">
<defs>
<symbol id="pin" viewBox='0 0 24 24'><title>location on</title>
<path d='M12 2c-3.87 0-7 3.13-7 7 0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z'></path>
<path d='M0 0h24v24h-24z' fill='none'></path>
</symbol>
</defs>
<g id="Hakkari" transform="translate(4607.000000, 1335.000000)" data-transform-left="-521.5" data-transform-top="-87">
<g id="Merkez" transform="translate(10.000000, 2.000000)">
<polygon id="Shape" stroke="#FFFFFF" fill="#9FB4B7" fill-rule="nonzero" points="31 59 119 38 181 0 193 43 155 64 163 167 49 175 0 142"></polygon>
<g id="MER" transform="translate(85.000000, 98.000000)" font-size="6" font-family="Helvetica-Bold, Helvetica" fill="#000000" font-weight="bold">
<use xlink:href="#pin" x="-5" y="-24" width="24" height="24" />
<text>
<tspan x="0" y="6">MER</tspan>
</text>
</g>
</g>
<g id="Yüksekova" transform="translate(165.000000, 0.000000)">
<polygon id="Shape" stroke="#FFFFFF" fill="#9FB4B7" fill-rule="nonzero" points="38 44 122 0 163 7 185 27 185 107 118 133 79 177 38 176 25 190 7 168 0 66"></polygon>
<g id="YÜK" transform="translate(78.000000, 86.000000)" font-size="6" font-family="Helvetica-Bold, Helvetica" fill="#000000" font-weight="bold">
<use xlink:href="#pin" x="-5" y="-24" width="24" height="24" />
<text>
<tspan x="0" y="6">YÜK</tspan>
</text>
</g>
</g>
<g id="Şemdinli" transform="translate(244.000000, 107.000000)">
<polygon id="Shape" stroke="#FFFFFF" fill="#9FB4B7" fill-rule="nonzero" points="106 0 168 47 172 104 121 94 40 169 14 127 31 87 0 70 39 26"></polygon>
<g id="ŞEM" transform="translate(81.000000, 62.000000)" font-size="6" font-family="Helvetica-Bold, Helvetica" fill="#000000" font-weight="bold">
<use xlink:href="#pin" x="-5" y="-24" width="24" height="24" />
<text>
<tspan x="0" y="6">ŞEM</tspan>
</text>
</g>
</g>
<g id="Çukurca" transform="translate(0.000000, 143.000000)">
<polygon id="Shape" stroke="#FFFFFF" fill="#9FB4B7" fill-rule="nonzero" points="190 47 163 76 70 72 20 51 0 24 10 0 58 33 173 26"></polygon>
<g id="ÇUK" transform="translate(104.000000, 50.000000)" font-size="6" font-family="Helvetica-Bold, Helvetica" fill="#000000" font-weight="bold">
<use xlink:href="#pin" x="-5" y="-24" width="24" height="24" />
<text>
<tspan x="0" y="6">ÇUK</tspan>
</text>
</g>
</g>
</g>
</svg>
UPDATE
In this case I'm using a png instead of an SVG path. The png is in this case square (120px/120px) with a transparent background.
<svg viewBox="4600 1300 500 300">
<symbol id="pin" viewBox='0 0 24 24'><title>location on</title>
<!--<path d='M12 2c-3.87 0-7 3.13-7 7 0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z'></path>
<path d='M0 0h24v24h-24z' fill='none'></path>-->
<image width="24" height="24" xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/pin.png" />
</symbol>
<g id="Hakkari" transform="translate(4607.000000, 1335.000000)" data-transform-left="-521.5" data-transform-top="-87">
<g id="Merkez" transform="translate(10.000000, 2.000000)">
<polygon id="Shape" stroke="#FFFFFF" fill="#9FB4B7" fill-rule="nonzero" points="31 59 119 38 181 0 193 43 155 64 163 167 49 175 0 142"></polygon>
<g id="MER" transform="translate(85.000000, 98.000000)" font-size="6" font-family="Helvetica-Bold, Helvetica" fill="#000000" font-weight="bold">
<use xlink:href="#pin" x="-5" y="-24" width="24" height="24" />
<text>
<tspan x="0" y="6">MER</tspan>
</text>
</g>
</g>
<g id="Yüksekova" transform="translate(165.000000, 0.000000)">
<polygon id="Shape" stroke="#FFFFFF" fill="#9FB4B7" fill-rule="nonzero" points="38 44 122 0 163 7 185 27 185 107 118 133 79 177 38 176 25 190 7 168 0 66"></polygon>
<g id="YÜK" transform="translate(78.000000, 86.000000)" font-size="6" font-family="Helvetica-Bold, Helvetica" fill="#000000" font-weight="bold">
<use xlink:href="#pin" x="-5" y="-24" width="24" height="24" />
<text>
<tspan x="0" y="6">YÜK</tspan>
</text>
</g>
</g>
<g id="Şemdinli" transform="translate(244.000000, 107.000000)">
<polygon id="Shape" stroke="#FFFFFF" fill="#9FB4B7" fill-rule="nonzero" points="106 0 168 47 172 104 121 94 40 169 14 127 31 87 0 70 39 26"></polygon>
<g id="ŞEM" transform="translate(81.000000, 62.000000)" font-size="6" font-family="Helvetica-Bold, Helvetica" fill="#000000" font-weight="bold">
<use xlink:href="#pin" x="-5" y="-24" width="24" height="24" />
<text>
<tspan x="0" y="6">ŞEM</tspan>
</text>
</g>
</g>
<g id="Çukurca" transform="translate(0.000000, 143.000000)">
<polygon id="Shape" stroke="#FFFFFF" fill="#9FB4B7" fill-rule="nonzero" points="190 47 163 76 70 72 20 51 0 24 10 0 58 33 173 26"></polygon>
<g id="ÇUK" transform="translate(104.000000, 50.000000)" font-size="6" font-family="Helvetica-Bold, Helvetica" fill="#000000" font-weight="bold">
<use xlink:href="#pin" x="-5" y="-24" width="24" height="24" />
<text>
<tspan x="0" y="6">ÇUK</tspan>
</text>
</g>
</g>
</g>
</svg>
My idea is same as "enxaneta" below:
// use <path> or <use> element as you like
var pinIconNode = document.createElement("path");
// supporse the <g> element id is the city you want
var city = document.getElementById("cityName");
city.prepend(pinIconNode);

Using feMorphology svg filter trims corners in the output

I am using SVG filter feMorphology's dilate to implement shadow spread for a shape.
Am expecting below result.
<?xml version="1.0" encoding="UTF-8"?>
<svg width="188px" height="209px" viewBox="0 0 188 209" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Test</title>
<defs>
<polygon id="path-1" points="94 29 168 194 20 194"></polygon>
<filter x="-100%" y="-100%" width="1000%" height="1000%" filterUnits="userSpaceOnUse" id="filter">
<feMorphology radius="5" operator="dilate" in="SourceAlpha" result="morphOut"></feMorphology>
<feMerge>
<feMergeNode in="morphOut"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
</defs>
<g id="Triangle">
<path d="M 20 20 L 120 20 L 120 120 L 20 120 z " filter="url(#filter)" stroke-width="1" fill-rule="evenodd" fill="rgb(216,216,216)"/>
<path d="M 70 150 L 120 200 L 20 200 z" filter="url(#filter)" stroke-width="1" fill-rule="evenodd" fill="rgb(216,216,216)"/>
</g>
</svg>
But my code returns somewhat trimmed corners in some shapes. Help me
sort out this.
The filter is working as expected:
The dilation (or erosion) kernel is a rectangle with a width of 2*x-radius and a height of 2*y-radius. In dilation, the output pixel is the individual component-wise maximum of the corresponding R,G,B,A values in the input image's kernel rectangle. In erosion, the output pixel is the individual component-wise minimum of the corresponding R,G,B,A values in the input image's kernel rectangle.
Imagine a square of, in your case, 10px × 10px, moving along the path. For dilation, the outermost pixel the square sweeps over will define the new outer border of the grafic. (For erosion, it would be the outermost pixel inside the path the square does not sweep over.)

How to animate changing path lengths (line) with markers in svg

I have this svg path:
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width='500' height='500'>
<defs id="def">
<marker orient="auto" refY="0.0" refX="-3" id="Arrow2Mend" style="overflow:visible;">
<path id="path3900" style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" d="M -15 -5 L 0 0 L -15 5 z" transform="scale(0.5)"></path>
</marker>
</defs>
<path style="fill:none;stroke:#000000;stroke-width:2.58384609;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;marker-end:url(#Arrow2Mend)" d="m 189,100.09448 200,0" id="arrowline"></path></svg>
I want to be able to increase and decrease the length of the "#arrowline" path, with an animation, keeping the arrowhead also in the correct place while animating. I tried various methods but they were either too complicated for implementing or didn't work. Probably I am missing something. Any help appreciated. Thank you.
I don't know what you mean by "correct" - do you mean the following?
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width='500px' height='500px'>
<defs id="def">
<marker orient="auto" refY="0.0" refX="-3" id="Arrow2Mend" style="overflow:visible;">
<path id="path3900" style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;" d="M -15 -5 L 0 0 L -15 5 z" transform="scale(0.5)"></path>
</marker>
</defs>
<path style="fill:none;stroke:#000000;stroke-width:2.58384609;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;marker-end:url(#Arrow2Mend)" d="m 10 10 l200,0" id="arrowline">
<animate attributeName="d" from="m 10 10 l200,0" to="m 10 10 l400,0" dur="1s" repeatCount="indefinite"/>
</path>
</svg>

Categories

Resources