Removing gap between two SVG paths without removing anti-aliasing - javascript
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>
Related
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>
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>
SVG custom circles shape
I don't have experience with SVG and I have a problem with creating my custom shape. I want to create below shape. Share of slices and belongings lines should be genarated dynamically. All slices are the same. For example: If we have 4 slices each slices would have 25% value, if there are 10 slices we would have 10 slices with 10%. <!DOCTYPE html> <html> <body> <svg width="800" height="800"> <circle cx="400" cy="400" r="300" stroke="black" stroke-width="2" fill="red" /> <circle cx="400" cy="400" r="80" stroke="black" stroke-width="2" fill="blue" /> <path d="M 400 400 H 480 320" stroke="black" stroke-width="2" fill="none" />Sorry, your browser does not support inline SVG. </svg> </body> </html> Please, help me out.
You will need multiple elements to this SVG. Two for the center circle Four for the outer circle First, you need 4 areas for the 4 sections in the outside circle. This can be done like so: <svg width="50%" viewbox="0 0 100 100"> <path d="M50,50 L0,50 A50,50 0 0,1 50,0" fill="red"></path> <path d="M50,50 L100,50 A50,50 0 0,1 0,50" fill="blue"></path> <path d="M50,50 L100,50 A50,50 0 0,1 50,100" fill="green"></path> <path d="M50,50 L50,0 A50,50 0 0,1 100,50" fill="yellow"></path> </svg> For the inside area, you will need two segments with text inside. text { fill: white; font-size: 16px; } <svg width="50%" viewbo0x="0 0 100 100"> <path d="M0,50 A50,50 0 0,1 100,50z" fill="purple"></path> <path d="M0,50 A-50,-50 0 1,0 100,50z" fill="green"></path> <text x="18" y="40">Some text</text> <text x="15" y="70">Bottom text</text> </svg> Join them together and hey presto, you should have your shape. text { font-size: 2.5em; fill: white; } <svg width="50%" viewbox="0 0 1000 1000"> <path d="M500,500 L0,500 A500,500 0 0,1 500,0" fill="red"></path> <path d="M500,500 L1000,500 A500,500 0 0,1 0,500" fill="blue"></path> <path d="M500,500 L1000,500 A500,500 0 0,1 500,1000" fill="green"></path> <path d="M500,500 L500,0 A500,500 0 0,1 1000,500" fill="yellow"></path> <path d="M350,500 A100,100 0 0,1 650,500z" fill="purple" x="45" y="45"></path> <path d="M350,500 A-100,-100 0 1,0 650,500z" fill="pink"></path> <text x="420" y="450">Some text</text> <text x="410" y="550">Bottom text</text> </svg> SVG Documentation (MDN)
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>