Blend SVG paths together to feel like 1 line - svg

I have the following SVG:
<svg viewBox="0 0 100 100" width="100" height="100" xmlns="http://www.w3.org/2000/svg" version="1.1">
<path d="M56,56 C112,56 28,28 56,56" fill="none" stroke="#0000FF" stroke-width="2px"></path>
<path d="M56,56 C112,56 8,1.5 16,3" fill="none" stroke="#FF7F00" stroke-width="2px"></path>
<path d="M16,3 C32,3 8,24 16,48" fill="none" stroke="#FF7F00" stroke-width="2px"></path>
<path d="M16,48 C32,48 6,2.5 12,5" fill="none" stroke="#FF0000" stroke-width="2px"></path>
</svg>
If you look closely, the lines abruptly end. You can see how they square off, like so:
Is there a way to make paths blend together?
EDIT: Ideally, I would want to find a way to automate this. The way I form the d value in the path is with the following:
const points = [
[56,56],
[16,3],
[16,48],
[12,5],
]
const generateLines = (points) => {
const lines = [];
for(let i = 0; i < points.length; i++) {
if(i == 0)
lines.push({x1: points[i][0], y1: points[i][1], x2: points[i][0], y2: points[i][1]});
else
lines.push({
x1: lines[i-1].x2,
y1: lines[i-1].y2,
x2: points[i][0],
y2: points[i][1]
});
}
return lines;
}
console.log(generateLines(points));
//<path d=M{x1},{y1} C{x1*2},{y1} {x2/2},{y2/2} {x2},{y2}

You can use pathLength (total length of path), stroke-dasharray (dash defined by length of dash and following space) and stroke-dashoffset (negative number along the path) on the same path to specify there a color should start and end.
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path d="m 42 57 C 112 56 29 49 62 48 C 109 47 2 3 16 3 C 32 3 3 48 16 48 C 32 48 4 8 12 5"
fill="none" stroke="#0000FF" stroke-width="2px" pathLength="100" stroke-dasharray="25 100" stroke-dashoffset="0"></path>
<path d="m 42 57 C 112 56 29 49 62 48 C 109 47 2 3 16 3 C 32 3 3 48 16 48 C 32 48 4 8 12 5"
fill="none" stroke="#FF7F00" stroke-width="2px" pathLength="100" stroke-dasharray="25 100" stroke-dashoffset="-25"></path>
<path d="m 42 57 C 112 56 29 49 62 48 C 109 47 2 3 16 3 C 32 3 3 48 16 48 C 32 48 4 8 12 5"
fill="none" stroke="#FF7F00" stroke-width="2px" pathLength="100" stroke-dasharray="25 100" stroke-dashoffset="-50"></path>
<path d="m 42 57 C 112 56 29 49 62 48 C 109 47 2 3 16 3 C 32 3 3 48 16 48 C 32 48 4 8 12 5"
fill="none" stroke="#FF0000" stroke-width="2px" pathLength="100" stroke-dasharray="25 100" stroke-dashoffset="-75"></path>
</svg>

For those who want to edit the path attributes once
<script>
customElements.define('svg-colored-line', class extends HTMLElement {
connectedCallback() {
this.innerHTML = `<svg viewBox="0 0 100 100">` + [
["red", 0],
["green", 1],
["gold", 2],
["blue", 3]
].map(([stroke, offset]) => `<path d="M42 57C112 56 29 49 62 48C109 47 2 3 16 3C32 3 3 48 16 48C32 48 4 8 12 5"
fill="none"stroke-width="5"pathLength="4"stroke-dasharray="1 4"
stroke="${stroke}"stroke-dashoffset="-${offset}"/>`).join("") + `</svg>`;
}
});
</script>
<svg-colored-line></svg-colored-line>

Related

Parse mutilple children attributes of element using cheerio in NodeJs

I have svg file that looks like this
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="300.000000pt" height="226.000000pt" viewBox="0 0 300.000000 226.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,226.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M891 2162 c-95 -33 -418 -606 -616 -1092 -75 -185 -106 -330 -70 -67 -2 3 7 36 19 75 13
27 67 2 -3 -7 -36 -19 -75z"/>
<path d="M1316 2019 c-33 -39 -8035 -57 -37 -58 -82 -59 -25 0 -55 -2 -66 -4 -11 -2 -58 -8 -104
-15 -158 -22 -330 -77 -315 -101 10 -17 85 -5 311 51 -12 -15 -27z"/>
<path d="M925 1349 c-4 -6 -5 -12 -2 -15 2 -3 7 2 10 11 7 17 1 20 -8 4z"/>
</g>
</svg>
I want to get d attribute of each path element and combine it in one svg path string (that consists of all three paths )
I've tried this buy only get first one every time
fs.readFile(path_to_svg,'utf8',(err,data)=>{
if(err) console.log(err);
$ = cheerio.load(data,{ xmlMode : true });
$('svg').children().each(function(i,path){
console.log($('path').attr('d'))
});
});
You can get those with:
$('svg path').get().map(path => $(path).attr('d'))

Dynamically adapt a text to a path element in an SVG

My SVG has shapes with different dimensions as below, and I would like my text to have a size adapted to the length of its associated shape (fill without overflow).
I tried font-size-adjust but no result and textLength lengthAdjust deforms my text, should i use textPath & href logic ?
Thank you for your help
<svg viewBox="0 0 220 220">
<g>
<path fill="orange" d="M30 110 L 20 110 L 20 20 L 30 10 L 40 20 L 40 110 Z"/>
<text font-size="1em" transform="rotate(-90, 30, 110)" x="30" y="110" dominant-baseline="middle">Object number 1</text>
</g>
<g>
<path fill="red" d="M 50 110 L 40 110 L 40 50 L 50 40 L 60 50 L 60 110 Z"/>
<text transform="rotate(-90, 50, 110)" x="50" y="110" dominant-baseline="middle">Object number 2</text>
</g>
<g>
<path fill="yellow" d="M 80 110 L 60 110 L 60 50 L 80 40 L 100 50 L 100 110 Z"/>
<text transform="rotate(-90, 80, 110)" x="80" y="110" dominant-baseline="middle">Object number 3</text>
</g>
</svg>
This is the rendering I would like to obtain:
The space between letters is why i don't want to use textLength :
My render here would be:
First method: tou can set the textLength of the text to be equal to the height of the path. Since your path has a tip I've opted for the 90% of the height. However if your path is much smaller than the text the text will apear crammed. To understand what I mean change the font-size to 3em
let pthHeight = pth.getBBox().height;
txt.setAttribute("textLength",pthHeight*.9 )
svg{width:50vh}
<svg viewBox="0 0 50 120">
<path fill="orange" id="pth" d="M30 110 L 20 110 L 20 20 L 30 10 L 40 20 L 40 110 Z"/>
<text id="txt" font-size="1em" transform="rotate(-90, 30, 110)" x="30" y="110" dominant-baseline="middle" lengthAdjust="spacingAndGlyphs">Object number 1</text>
</svg>
yet another solution would be changing the font size in a while loop till the text length is smaller than the height of the path. This assumes that the initial length of the text is longet than the height.
let pthHeight = pth.getBBox().height;
function setFontSize(txt){
let fs = txt.getAttribute("font-size");
let textLength = txt.getComputedTextLength();
let fontSize = txt.getAttribute("font-size");
while(textLength > pthHeight){
fontSize -= 1;
txt.setAttribute("font-size",fontSize);
textLength = txt.getComputedTextLength();
}
}
setFontSize(txt)
svg{width:50vh}
<svg viewBox="0 0 50 120">
<path fill="orange" id="pth" d="M30 110 L 20 110 L 20 20 L 30 10 L 40 20 L 40 110 Z"/>
<text id="txt" font-size="16" transform="rotate(-90, 30, 110)" x="30" y="110" dominant-baseline="middle" >Object number 1</text>
</svg>

Combine several SVG <path>

I need to know how to combine multiple from a SVG file.
Right now I have three icons and somehow I can not find any logic behind that.
I read that I need to remove the last part and combine it with the following.
Example:
From
<path d="m150.355469 322.332031c-30.046875 0-54.402344 24.355469-54.402344 54.402344 0 30.042969 24.355469 54.398437 54.402344 54.398437 30.042969 0 54.398437-24.355468 54.398437-54.398437-.03125-30.03125-24.367187-54.371094-54.398437-54.402344zm0 88.800781c-19 0-34.402344-15.402343-34.402344-34.398437 0-19 15.402344-34.402344 34.402344-34.402344 18.996093 0 34.398437 15.402344 34.398437 34.402344 0 18.996094-15.402344 34.398437-34.398437 34.398437zm0 0"/><path d="m446.855469 94.035156h-353.101563l-7.199218-40.300781c-4.4375-24.808594-23.882813-44.214844-48.699219-48.601563l-26.101563-4.597656c-5.441406-.96875-10.632812 2.660156-11.601562 8.097656-.964844 5.441407 2.660156 10.632813 8.101562 11.601563l26.199219 4.597656c16.53125 2.929688 29.472656 15.871094 32.402344 32.402344l35.398437 199.699219c4.179688 23.894531 24.941406 41.324218 49.199219 41.300781h210c22.0625.066406 41.546875-14.375 47.902344-35.5l47-155.800781c.871093-3.039063.320312-6.3125-1.5-8.898438-1.902344-2.503906-4.859375-3.980468-8-4zm-56.601563 162.796875c-3.773437 12.6875-15.464844 21.367188-28.699218 21.300781h-210c-14.566407.039063-27.035157-10.441406-29.5-24.800781l-24.699219-139.398437h336.097656zm0 0"/>
TO
<path d="m150.355469 322.332031c-30.046875 0-54.402344 24.355469-54.402344 54.402344 0 30.042969 24.355469 54.398437 54.402344 54.398437 30.042969 0 54.398437-24.355468 54.398437-54.398437-.03125-30.03125-24.367187-54.371094-54.398437-54.402344zm0 88.800781c-19 0-34.402344-15.402343-34.402344-34.398437 0-19 15.402344-34.402344 34.402344-34.402344 18.996093 0 34.398437 15.402344 34.398437 34.402344 0 18.996094-15.402344 34.398437-34.398437 34.398437 m446.855469 94.035156h-353.101563l-7.199218-40.300781c-4.4375-24.808594-23.882813-44.214844-48.699219-48.601563l-26.101563-4.597656c-5.441406-.96875-10.632812 2.660156-11.601562 8.097656-.964844 5.441407 2.660156 10.632813 8.101562 11.601563l26.199219 4.597656c16.53125 2.929688 29.472656 15.871094 32.402344 32.402344l35.398437 199.699219c4.179688 23.894531 24.941406 41.324218 49.199219 41.300781h210c22.0625.066406 41.546875-14.375 47.902344-35.5l47-155.800781c.871093-3.039063.320312-6.3125-1.5-8.898438-1.902344-2.503906-4.859375-3.980468-8-4zm-56.601563 162.796875c-3.773437 12.6875-15.464844 21.367188-28.699218 21.300781h-210c-14.566407.039063-27.035157-10.441406-29.5-24.800781l-24.699219-139.398437h336.097656zm0 0"/>
But the output is empty.
And if I only take one path of both I will see only this path.
Is there any easy explanation how to do that?
If you then take your path:
M54.4 2a54.4 54.4 0 106.2 108.4c9.1 2.2 18.9 3.5 28.3 5.2a40 40 0 0132.4 32.4l35.4 99.7a49.9 49.9 0 0049.2 41.3h210c22 0 41.5-14.4 47.9-35.5l47-155.8c.8-3 .3-6.3-1.5-8.9-2-2.5-4.9-4-8-4H148.2l-7.2-40.3c-7-24.4-13.6-38.3-49.2-48.7A54.2 54.2 0 0054.4 2zm0 20a34.4 34.4 0 110 68.8 34.4 34.4 0 010-68.8zm97.4 182.7h336l-43.1 142.9a29.8 29.8 0 01-28.7 1.3H206c-14.6 0-27-10.4-29.5-24.8z
and multiply it by 10 using: https://yqnn.github.io/svg-path-editor/
You get rid of all decimal notation and make the file even smaller:
M 544 20 a 544 544 90 1 0 62 1084 c 91 22 189 35 283 52 a 400 400 90 0 1 324 324 l 354 1997 a 499 499 90 0 0 492 413 h 2100 c 220 0 415 -144 479 -355 l 470 -1558 c 8 -30 3 -63 -15 -89 c -20 -25 -49 -40 -80 -40 H 1482 l -72 -403 c -70 -244 -136 -383 -492 -487 A 542 542 90 0 0 544 20 z m 0 200 a 344 344 90 1 1 0 688 a 344 344 90 0 1 0 -688 z m 974 1827 h 3360 l -431 1429 a 298 298 90 0 1 -287 213 H 2060 c -146 0 -270 -104 -295 -248 z
The viewBox ofcourse needs to be multiplied as well. As the (default) stroke-width="1"
<svg width="400" viewBox="0 0 5150 3900">
<path d="M544 20a544 544 90 1 0 62 1084c91 22 189 35 283 52a400 400 90 0 1 324 324l354 1997
a499 499 90 0 0 492 413h2100c220 0 415-144 479-355l470-1558c8-30 3-63-15-89
c-20-25-49-40-80-40h-3531l-72-403c-70-244-136-383-492-487a542 542 90 0 0-374-938z
m0 200a344 344 90 1 1 0 688a344 344 90 0 1 0-688z
m974 1827h3360l-431 1429a298 298 90 0 1-287 213h-2100c-146 0-270-104-295-248z"
stroke="red" stroke-width="10" fill="gray"/>
</svg>
You can save 30 bytes more in the path if you now divide everything by 6
M90 3a90 90 90 1 0 10 180c15 4 31 6 47 9a66 66 90 0 1 54 54l59 332a83 83 90 0 0 82 69h349c37 0 69-24 80-59l78-259c1-5 0-10-2-15c-3-4-8-7-13-7h-588l-12-67c-12-41-23-64-82-81a90 90 90 0 0-62-156zm0 33a57 57 90 1 1 0 114a57 57 90 0 1 0-114zm162 303h558l-72 237a49 49 90 0 1-48 35h-348c-24 0-45-17-49-41z
You can visualize your paths if you put them in a suitable <svg> element. It needs to have a "sensible" viewBox attribute in it. For your example the following works: <svg viewBox="0 0 620 840">. I also added two rectangles (<rect>) to show the extent of your overlaying symbols.
Note: To actually combine two paths into one is a slightly more complex task. This can be done with a suitable graphical SVG-editor, like Inkscape (or many others ...).
<svg viewBox="0 0 620 840">
<rect x="0" y="0" width="480" height="440" style="stroke:black;fill:none"/>
<path d="m150.355469 322.332031c-30.046875 0-54.402344 24.355469-54.402344 54.402344 0 30.042969 24.355469 54.398437 54.402344 54.398437 30.042969 0 54.398437-24.355468 54.398437-54.398437-.03125-30.03125-24.367187-54.371094-54.398437-54.402344zm0 88.800781c-19 0-34.402344-15.402343-34.402344-34.398437 0-19 15.402344-34.402344 34.402344-34.402344 18.996093 0 34.398437 15.402344 34.398437 34.402344 0 18.996094-15.402344 34.398437-34.398437 34.398437zm0 0"/><path d="m446.855469 94.035156h-353.101563l-7.199218-40.300781c-4.4375-24.808594-23.882813-44.214844-48.699219-48.601563l-26.101563-4.597656c-5.441406-.96875-10.632812 2.660156-11.601562 8.097656-.964844 5.441407 2.660156 10.632813 8.101562 11.601563l26.199219 4.597656c16.53125 2.929688 29.472656 15.871094 32.402344 32.402344l35.398437 199.699219c4.179688 23.894531 24.941406 41.324218 49.199219 41.300781h210c22.0625.066406 41.546875-14.375 47.902344-35.5l47-155.800781c.871093-3.039063.320312-6.3125-1.5-8.898438-1.902344-2.503906-4.859375-3.980468-8-4zm-56.601563 162.796875c-3.773437 12.6875-15.464844 21.367188-28.699218 21.300781h-210c-14.566407.039063-27.035157-10.441406-29.5-24.800781l-24.699219-139.398437h336.097656zm0 0"/>
<rect x="80" y="300" width="540" height="440" style="stroke:black;fill:none"/>
<g style="fill:none;stroke:red">
<path d="m150.355469 322.332031c-30.046875 0-54.402344 24.355469-54.402344 54.402344 0 30.042969 24.355469 54.398437 54.402344 54.398437 30.042969 0 54.398437-24.355468 54.398437-54.398437-.03125-30.03125-24.367187-54.371094-54.398437-54.402344zm0 88.800781c-19 0-34.402344-15.402343-34.402344-34.398437 0-19 15.402344-34.402344 34.402344-34.402344 18.996093 0 34.398437 15.402344 34.398437 34.402344 0 18.996094-15.402344 34.398437-34.398437 34.398437 m446.855469 94.035156h-353.101563l-7.199218-40.300781c-4.4375-24.808594-23.882813-44.214844-48.699219-48.601563l-26.101563-4.597656c-5.441406-.96875-10.632812 2.660156-11.601562 8.097656-.964844 5.441407 2.660156 10.632813 8.101562 11.601563l26.199219 4.597656c16.53125 2.929688 29.472656 15.871094 32.402344 32.402344l35.398437 199.699219c4.179688 23.894531 24.941406 41.324218 49.199219 41.300781h210c22.0625.066406 41.546875-14.375 47.902344-35.5l47-155.800781c.871093-3.039063.320312-6.3125-1.5-8.898438-1.902344-2.503906-4.859375-3.980468-8-4zm-56.601563 162.796875c-3.773437 12.6875-15.464844 21.367188-28.699218 21.300781h-210c-14.566407.039063-27.035157-10.441406-29.5-24.800781l-24.699219-139.398437h336.097656zm0 0"/>
</g>
</svg>
I combined the two paths of your second part using Inkscape, put it through the online SVG optimizer SVGOMG! (thanks for the hint, Danny '365CSI' Engelman) and ended up with this:
<svg xmlns="http://www.w3.org/2000/svg"
width="400" viewBox="-1 0 515 390">
<path d="M54.4 2a54.4 54.4 0 106.2 108.4
c9.1 2.2 18.9 3.5 28.3 5.2
a40 40 0 0132.4 32.4l35.4 199.7a49.9 49.9 0 0049.2 41.3
h210c22 0 41.5-14.4 47.9-35.5l47-155.8
c.8-3 .3-6.3-1.5-8.9-2-2.5-4.9-4-8-4H148.2l-7.2-40.3
c-7-24.4-13.6-38.3-49.2-48.7A54.2 54.2 0 0054.4 2zm0 20
a34.4 34.4 0 110 68.8 34.4 34.4 0 010-68.8z
m97.4 182.7h336l-43.1 142.9a29.8 29.8 0 01-28.7 21.3H206
c-14.6 0-27-10.4-29.5-24.8z"
stroke="red" fill="gray"/>
</svg>

Text cutout of paths body

I'm currently trying to create the SVG of an old image, however I have trouble creating the correct rotated and positioned text cutout.
When I try to add a <text> element it ends up stretched, under the form or is not visible at all.
Here is what I came up with so far:
<svg
height="360px"
width="100%"
preserveAspectRatio="none"
viewBox="0 0 100 360"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path
id="banner"
d="M0,186 L 100,0 100,186 0,360 Z"
fill="#2180b3"
vector-effect="non-scaling-stroke" />
</defs>
<use xlink:href="#banner" />
</svg>
And here is what I'm trying to archive:
The cutout should be white
Thanks!
You can just use an image to svg converter like this one
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="1280.000000pt" height="376.000000pt" viewBox="0 0 1280.000000 376.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.13, written by Peter Selinger 2001-2015
</metadata>
<g transform="translate(0.000000,376.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M12700 3702 c-52 -7 -95 -14 -96 -15 -14 -22 -434 -961 -432 -966 2
-5 143 -157 313 -339 l310 -330 3 413 c1 227 1 602 0 832 l-3 418 -95 -13z"/>
<path d="M11785 3569 c-176 -26 -331 -49 -343 -51 -21 -3 0 -33 199 -283 184
-231 223 -276 230 -260 10 28 240 617 246 633 3 6 1 11 -3 11 -5 -1 -153 -23
-329 -50z"/>
<path d="M5440 2648 c-2989 -435 -5436 -792 -5438 -793 -1 -1 -1 -391 0 -866
l3 -864 5592 760 c3076 418 5596 765 5601 770 10 10 441 948 449 976 3 10
-122 155 -352 410 -319 353 -360 394 -388 396 -18 1 -2478 -354 -5467 -789z"/>
<path d="M11818 2058 c-75 -189 -135 -344 -134 -344 1 -2 669 88 732 98 18 2
-14 46 -208 283 -126 154 -234 286 -242 293 -10 10 -38 -52 -148 -330z"/>
</g>
</svg>

Twice-interrupted circular path in SVG

I want to create a circular path with multiple "Holes" in it, preferably without using masks and the like.
Currently, what I've got is this:
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 400 400">
<path d="M 100 100 A 90 90 0 1 0 200 100 M 110 90 A 90 90 0 0 1 190 90" stroke="#424242" stroke-width="5" fill="transparent" />
</svg>
As you can see, this relies on manually moving the start of the new arc, which results in the arc being off.
I'd rather not have to do a lot of math to get the position for the move just right, so is there a sort of "Arc move" I can use?
If not, how does the math for this work (I'm very rusty in geometry stuff)
The simplest way to achieve what you want is probably just to use a dash array.
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 400 400">
<path d="M 100 100 A 90 90 0 1 0 200 100 M 110 90 A 90 90 0 0 1 190 90" stroke="#424242" stroke-width="5" fill="transparent" />
<path d="M 60 175 A 90 90 0 0 1 240 175 A 90 90 0 0 1 60 175" stroke="red" stroke-width="5" fill="transparent" stroke-dasharray="88 14 78 14 372"/></svg>

Resources