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

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>

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>

CSS JS animate image along path and make dashes afterwards

I would like to animate an image on a path and show the route of the object (e.g a plane flying over a map). It should look like on this image:
But the dashes should apply after the object has reached the position, so the dashes were shown after the object.
I have tried multiple times, but I can do only once. Dash animation or plane on path . Does someone knows a solution.
animate a mask over the dashed path
move the plane along the same path
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1" height="200" width="400">
<defs>
<path id="basePath" d="M 50,150 A 280 500 0 0 1 350,150" />
<mask id="mask">
<use xlink:href="#basePath" stroke-width="3" stroke="white"
stroke-dasharray="1000,0" fill="none">
<animate attributeName="stroke-dasharray" from="0,348.5" to="348.5,0"
begin="0s" dur="5s" fill="freeze" />
</use>
</mask>
</defs>
<circle r="4" cx="50" cy="150" fill="grey" />
<circle r="4" cx="350" cy="150" fill="grey" />
<use xlink:href="#basePath" stroke-width="2" stroke-dasharray="10"
stroke="grey" fill="none" mask="url(#mask)"/>
<path d="M 27,3 H 21 L 13,15 H 9 L 12,3 H 5 L 3,7 H -1 L 1,0 -1,-7 H 3 L 5,-3 H 12 L 9,-15 H 13 L 21,-3 H 27 C 33,-3 33,3 27,3 Z"
fill="white" stroke="black" stroke-width="1.5">
<animateMotion rotate="auto" begin="0s" dur="5s" fill="freeze">
<mpath xlink:href="#basePath"/>
</animateMotion>
</path>
</svg>
The main thing to do is to calculate the length of the path, so you can set the stroke-dasharray values for the mask animation such that they keep pace with the animated plane. You can get that length in Javascript with
document.querySelector('#basePath').getTotalLength()

SVG path overflow and centered dynamically

I have the SVG path curve that should be centered every time on the center icons, even I add the text below icon on above them, how to hold this line to the center of the icon. Should I draw it as one path or as several paths? I've hot now such picture codepen .I use foundation zurb 6.Is it possible to hold the line to svg cordinate with Javascript and make it responsive? Or Snap.svg
I try to achieve this one :
<div class="wrapper">
<div class="container">
<div style="text-align:center">
<h1> The text should not shift the line</h1></div>
<div class="row columns">
<div class="svg-container">
<!-- The line -->
<svg class="red svg svg-1 svg-2" preserveAspectRatio="none">
<!--лишню лінію викинути-->
<path d="M 50 0 l 0 27 q 0 50 50 50 l 1000 0 q 50 0 50 50 l 0 150" stroke="#d4d4d4" stroke-width="1" fill="none" />
<path d="M 50 0 l 0 27 q 0 50 50 50 l 2000 0 " stroke="#d4d4d4" stroke-width="1" fill="none" />
</svg>
<svg class="icon-svg" version="1.1" id="Layer_1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="75.001px" height="75px" viewBox="0 0 75.001 75"
enable-background="new 0 0 75.001 75" xml:space="preserve">
<switch>
<g i:extraneous="self">
<g>
<!-- circle for closing LINES 1 -->
<circle cx="37.5" cy="37.5" r="36" stroke="black" stroke-width="0" fill="gray" />
<!--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-->
<path fill="#FFD100" d="M64.017,10.984C56.934,3.9,47.517,0,37.5,0S18.067,3.901,10.984,10.984S0,27.484,0,37.5
c0,10.017,3.901,19.433,10.984,26.517C18.067,71.1,27.483,75,37.5,75s19.434-3.9,26.517-10.982
c7.083-7.084,10.984-16.5,10.984-26.517C75.001,27.484,71.1,18.067,64.017,10.984z M72.001,37.5c0,2.656-0.308,5.264-0.889,7.791
l-6.286-7.793l6.278-7.823C71.69,32.212,72.001,34.832,72.001,37.5z M13.105,13.105C19.622,6.588,28.285,3,37.5,3
s17.879,3.588,24.396,10.105c3.739,3.739,6.509,8.188,8.195,13.04l-7.043,8.775c-5.706-8.429-15.305-13.585-25.547-13.585
S17.66,26.491,11.954,34.92L4.91,26.144C6.597,21.292,9.366,16.844,13.105,13.105z M61.151,37.5
c-5.063,8.144-14.045,13.166-23.65,13.166S18.914,45.645,13.851,37.5c5.063-8.144,14.045-13.166,23.65-13.166
S56.088,29.357,61.151,37.5z M3,37.5c0-2.669,0.311-5.289,0.896-7.827l6.279,7.824l-6.287,7.795C3.308,42.766,3,40.157,3,37.5z
M61.896,61.896C55.379,68.412,46.715,72,37.5,72s-17.878-3.588-24.395-10.104c-3.749-3.75-6.522-8.211-8.208-13.078l7.053-8.742
c5.706,8.432,15.307,13.59,25.551,13.59s19.845-5.158,25.551-13.59l7.052,8.742C68.419,53.685,65.645,58.146,61.896,61.896z"/>
<path fill="#FFD100" d="M37.501,26.833c-5.882,0-10.667,4.785-10.667,10.667c0,5.881,4.785,10.666,10.667,10.666
c5.881,0,10.666-4.784,10.666-10.666C48.167,31.619,43.382,26.833,37.501,26.833z M37.501,45.166
c-4.228,0-7.667-3.438-7.667-7.666c0-4.228,3.439-7.667,7.667-7.667s7.666,3.439,7.666,7.667
C45.167,41.728,41.729,45.166,37.501,45.166z"/>
<path fill="#FFD100" d="M37.501,34.583c-1.608,0-2.917,1.309-2.917,2.917c0,1.608,1.309,2.916,2.917,2.916
c1.607,0,2.916-1.308,2.916-2.916C40.417,35.892,39.108,34.583,37.501,34.583z"/>
</g>
</g>
</switch>
</svg>
<svg class="icon-svg" version="1.1" id="Layer_1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="74.963px" height="75px" viewBox="0 0 74.963 75"
enable-background="new 0 0 74.963 75" xml:space="preserve">
<switch>
<foreignObject requiredExtensions="&ns_ai;" x="0" y="0" width="1" height="1">
<i:pgfRef xlink:href="#adobe_illustrator_pgf">
</i:pgfRef>
</foreignObject>
<g i:extraneous="self">
<g>
<!-- circle for closing LINES 2 -->
<circle cx="37.5" cy="37.5" r="36" stroke="black" stroke-width="0" fill="gray" />
<!--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-->
<path fill="#FFD100" d="M63.998,10.984C56.914,3.9,47.497,0,37.48,0S18.048,3.901,10.965,10.984
c-14.62,14.621-14.62,38.412,0,53.033C18.048,71.1,27.464,75,37.48,75s19.434-3.9,26.518-10.983
C78.618,49.396,78.618,25.605,63.998,10.984z M61.877,61.896C55.36,68.412,46.696,72,37.48,72
c-9.215,0-17.878-3.589-24.395-10.104c-13.45-13.451-13.45-35.339,0-48.791C19.603,6.588,28.266,3,37.48,3
c9.216,0,17.88,3.588,24.396,10.105C75.327,26.557,75.327,48.445,61.877,61.896z"/>
<path fill="#FFD100" d="M34.736,37.307H17.043c-0.828,0-1.5,0.671-1.5,1.5V56.5c0,0.829,0.672,1.5,1.5,1.5h17.693
c0.828,0,1.5-0.671,1.5-1.5V38.806C36.236,37.978,35.564,37.307,34.736,37.307z M33.236,55H18.543V40.306h14.693V55z"/>
<path fill="#FFD100" d="M57.92,37.307H40.227c-0.828,0-1.5,0.671-1.5,1.5V56.5c0,0.829,0.672,1.5,1.5,1.5H57.92
c0.828,0,1.5-0.671,1.5-1.5V38.806C59.42,37.978,58.748,37.307,57.92,37.307z M56.42,55H41.727V40.306H56.42V55z"/>
<path fill="#FFD100" d="M47.828,33.667V15.974c0-0.829-0.672-1.5-1.5-1.5H28.635c-0.828,0-1.5,0.671-1.5,1.5v17.693 c0,0.829,0.672,1.5,1.5,1.5h17.693C47.156,35.167,47.828,34.496,47.828,33.667z M44.828,32.167H30.135V17.474h14.693V32.167z"/>
</g>
</g>
</switch>
</svg>
<svg class="icon-svg" version="1.1" id="Layer_1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="74.963px" height="75px" viewBox="0 0 74.963 75"
enable-background="new 0 0 74.963 75" xml:space="preserve">
<switch>
<foreignObject requiredExtensions="&ns_ai;" x="0" y="0" width="1" height="1">
<i:pgfRef xlink:href="#adobe_illustrator_pgf">
</i:pgfRef>
</foreignObject>
<g i:extraneous="self">
<g>
<!-- circle for closing LINES 3 -->
<circle cx="37.5" cy="37.5" r="36" stroke="black" stroke-width="0" fill="gray" />
<!--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-->
<path fill="#FFD100" d="M63.998,10.984C56.914,3.9,47.497,0,37.48,0S18.048,3.901,10.965,10.984
c-14.62,14.621-14.62,38.412,0,53.033C18.048,71.1,27.464,75,37.48,75s19.434-3.9,26.518-10.983
C78.618,49.396,78.618,25.605,63.998,10.984z M61.877,61.896C55.36,68.412,46.696,72,37.48,72
c-9.215,0-17.878-3.589-24.395-10.104c-13.45-13.451-13.45-35.339,0-48.791C19.603,6.588,28.266,3,37.48,3
c9.216,0,17.88,3.588,24.396,10.105C75.327,26.557,75.327,48.445,61.877,61.896z"/>
<path fill="#FFD100" d="M34.736,37.307H17.043c-0.828,0-1.5,0.671-1.5,1.5V56.5c0,0.829,0.672,1.5,1.5,1.5h17.693
c0.828,0,1.5-0.671,1.5-1.5V38.806C36.236,37.978,35.564,37.307,34.736,37.307z M33.236,55H18.543V40.306h14.693V55z"/>
<path fill="#FFD100" d="M57.92,37.307H40.227c-0.828,0-1.5,0.671-1.5,1.5V56.5c0,0.829,0.672,1.5,1.5,1.5H57.92
c0.828,0,1.5-0.671,1.5-1.5V38.806C59.42,37.978,58.748,37.307,57.92,37.307z M56.42,55H41.727V40.306H56.42V55z"/>
<path fill="#FFD100" d="M47.828,33.667V15.974c0-0.829-0.672-1.5-1.5-1.5H28.635c-0.828,0-1.5,0.671-1.5,1.5v17.693 c0,0.829,0.672,1.5,1.5,1.5h17.693C47.156,35.167,47.828,34.496,47.828,33.667z M44.828,32.167H30.135V17.474h14.693V32.167z"/>
</g>
</g>
</switch>
</svg>
</div>
</div>
</div>
</div>

Rotating a polygon in SVG

In the code below, I tried to move the polygon which is the arrow's head and place it at the position 100,100. But polygon is placed at wrong direction. The position of line and will change depending upon the input. I need the output to be something like this:
<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 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve">
<polygon class="st0" points="2,7 0,0 11,7 0,14" transform="translate(100,100) rotate(45 0 0)"/ stroke="red" fill="red"/>
<line x1="0" y1="0" x2="100" y2="100" stroke="green"/>
</svg>
The smallest fix is probably to add a translation that lets you treat the concave part of the arrow as the origin for both the rotation and other translation.
<polygon … transform="translate(100 100) rotate(45 0 0) translate(-2 -7)" />
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<polygon points="2,7 0,0 11,7 0,14" transform="translate(100 100) rotate(45 0 0) translate(-2 -7)" stroke="red" fill="red" />
<line x1="0" y1="0" x2="100" y2="100" stroke="green" />
</svg>
You are using
rotate(deg, cx, cy)
to rotate element. With this configuration, it means that rotate the element deg degree with respect to point (cx,cy) (of element)
So you should set cx, cy value as a center of your element.
<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 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve">
<polygon class="st0" points="2,7 0,0 11,7 0,14" transform="translate(100,100) rotate(45 10 0)"/ stroke="red" fill="red"/>
<line x1="0" y1="0" x2="100" y2="100" stroke="green"/>
</svg>

HTML5 SVG anti-aliasing causes grey line between paths. How to avoid it?

There is an imaginary square which I want to draw as two halves, i.e. two triangles. Whilst they should perfectly fit together and make a square, a tiny line caused by anti-aliasing appears.
These triangles should be of different color, but I left both them black in the given example to make the line more visible.
<svg width="100" height="100"
viewPort="0 0 100 100" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="first">
<path d="M 0 0 L 100 100 L 0 100 Z" fill="red"/>
</clipPath>
<clipPath id="second">
<path d="M 0 0 L 100 0 L 100 100 Z" fill="red"/>
</clipPath>
</defs>
<rect width="100" fill="black" height="100"
clip-path="url(#first)"/>
<rect width="100" fill="black" height="100"
clip-path="url(#second)"/>
</svg>
JSFiddle
I am open to solutions - canvas, WebGL etc. I just want to know possible solutions which would improve rendering.
I'm not sure why you are seeing the line using clip paths, but if I just change it around to using regular polygons and use shape-rendering: crispEdges the line doesn't appear:
<svg width="100" height="100" viewPort="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg">
<polygon points="0,0 100,0 100,100" style="fill:black;shape-rendering:crispEdges;" />
<polygon points="0,0 100,100 0,100" style="fill:black;shape-rendering:crispEdges;" />
</svg>

Categories

Resources