I am trying to put numbers inside custom shapes. I am using getBBox() to find center of the shape. It works only on certain shapes, because center point may not be inside a hollow shape.
Demo on Codepen:
https://codepen.io/arindamx01/pen/KKyLNrj?editors=1010
Here is my JavaScript code:
let colorGroup = ['#700843', '#E95C87', '#AED9C5', '#FDFCFD', '#F8AF3F'];
colorGroup.forEach( function(e, i) {
console.log(e, i);
$(`path[data-color-group = "${e}"]`).each(function(){
let pathBBox = $(this)[0].getBBox();
console.log(pathBBox, $(this)[0])
let getPathData = $(this).attr("data-index");
var svgNS = "http://www.w3.org/2000/svg";
var newText = document.createElementNS(svgNS,"text");
newText.setAttributeNS(null,"x", pathBBox.x + pathBBox.width/2);
newText.setAttributeNS(null,"y", pathBBox.y + pathBBox.height/2);
newText.setAttributeNS(null,"font-size","10");
var textNode = document.createTextNode(i+1);
newText.appendChild(textNode);
document.getElementById("myIdInfo").appendChild(newText);
});
});
I tried using getBBox() method but it is not working for all shapes.
In above image, the number 4 should be inside the hollow C shape.
Each shape is different center of the box may not be inside the actual shape. For those hollow shapes there are no exact centers. You just need to find any suitable point that falls inside the shape.
Considering center of the box as origin we can try to find points that intersect with x and y axis. And pick a point in between two intersections:
Demo on codesandbox. It'll take some time to load.
let sv = document.querySelector('svg');
let colorGroup = ['#700843', '#E95C87', '#AED9C5', '#FDFCFD', '#F8AF3F'];
colorGroup.forEach(function (e, i) {
$(`path[data-color-group = "${e}"]`).each(function (ii, aa) {
let path = $(this)[0]
if (i == 3) {
path.setAttribute('style', `fill: #cf0acf`);
} else if (i == 0) {
path.setAttribute('style', `fill: #a35a83`);
} else {
path.setAttribute('style', `fill: ${e}`);
}
//console.log(pathBBox, path);
let getPathData = $(this).attr("data-index");
point = getInsidePoint(path);
var svgNS = "http://www.w3.org/2000/svg";
var newText = document.createElementNS(svgNS, "text");
newText.setAttributeNS(null, "x", point.x);
newText.setAttributeNS(null, "y", point.y);
newText.setAttributeNS(null, "font-size", "10");
var textNode = document.createTextNode(i + 1);
newText.appendChild(textNode);
document.getElementById("myIdInfo").appendChild(newText);
});
});
// figure out point insice the shape
function getInsidePoint(path) {
let pathBBox = path.getBBox();
let point = sv.createSVGPoint();
point.x = Math.floor(pathBBox.x + pathBBox.width / 2);
point.y = Math.floor(pathBBox.y + pathBBox.height / 2);
// if mid point is inside then return
if (path.isPointInFill(point)) {
return point;
}
let result = sv.createSVGPoint();
let l = path.getTotalLength();
let h = []; // horizontal intersections
let v = []; // vertical intersections
// find intersecting points along x and y axis
for (let i = 0; i < l; i++) {
let p = path.getPointAtLength(i);
p.x = Math.floor(p.x)
p.y = Math.floor(p.y);
if (p.x == point.x) v.push(p);
if (p.y == point.y) h.push(p);
}
// whichever axis has less intersecitions
// get center point of the intersection
try {
if (h.length < v.length) {
result.y = point.y;
// find out which point in between two intersection points falls inside
for (let i = 0; i < h.length - 1; i++) {
result.x = Math.abs(h[i + 1].x - h[i].x) / 2;
if (result.x < 2) continue;
result.x += Math.min(h[i + 1].x, h[i].x);
if (path.isPointInFill(result)) {
break;
}
}
} else {
result.x = point.x;
for (let i = 0; i < v.length - 1; i++) {
result.y = Math.abs(v[i + 1].y - v[i].y) / 2;
if (result.y < 2) continue;
result.y += Math.min(v[i + 1].y, v[i].y);
if (path.isPointInFill(result)) {
break;
}
}
}
} catch (e) {
// ignore errors for dots and open shapes
}
return result;
}
Here is how it looks:
Note, play with the getInsidePoint function to adjust number positions. This isn't the most efficient implementation, refer this answer for more efficient implementation approach.
Possible improvements could be:
Find out better points manually for each shape and put them in data-* attributes in path elements:
<path data-label-x='10' data-label-y='40' ...>...</path>
and use these co-ordinates. No need to calculate on client side every time.
If the diagram is scalable then mark similar shapes. And do calculations for only one shape and use the same point for all similar shapes considering rotation.
Since your graphic (mandala) has a radial layout, you might also try to find angle based intersections.
We can assume that shapes which don't have fill intersecting centers will have some intersections around the center x/y.
Essentially, we're also using isPointInFill() to first exclude already fine coordinates within the shape's fill area and then find appropriate (x/y shifted) alternatives for all exceptions.
This approach provides some "best match" logic – i.e. prefer intersecting coordinates with more surrounding space. Illustrated above by green dots: more intersections (array.length based) will be preferred to calculate the label's x/y coordinates.
We can drastically reduce the number of "checkpoints" by analyzing only some predictable and also prioritized (angle based) points around the shapes's center (retrieved by getBBox()).
This is still quite expensive regarding performance due to the graphic's complexity.
Example check points around center:
let svg = document.querySelector('svg');
let labelGroup = svg.querySelector('#myIdInfo');
let colorGroup = ['#CF0ACF', '#E95C87', '#AED9C5', '#FDFCFD', '#F8AF3F'];
let decimals = 1;
let labelGroupMarkup = '';
//get svg viewBox dimensions for rotation checks;
let svgBB = svg.getAttribute('viewBox').split(' ');
let [svgCx, svgCy] = [(svgBB[0] + svgBB[2]) / 2, (svgBB[1] + svgBB[3] / 2)];
// count point checks for debugging
let checks = 0;
let pointHits = 0;
let notInFill = 0;
// loop colors
colorGroup.forEach(function(color, colorIndex) {
// find shapes
let shapes = svg.querySelectorAll('[data-color-group="' + color + '"] path');
shapes.forEach(function(shape, i) {
let bb = shape.getBBox();
let [x, y, w, h] = [bb.x, bb.y, bb.width, bb.height];
let cx = +(x + w / 2).toFixed(decimals);
let cy = +(y + h / 2).toFixed(decimals);
let l = +(x).toFixed(decimals);
let r = +(x + w).toFixed(decimals);
let t = +(y).toFixed(decimals);
let b = +(y + h).toFixed(decimals);
// label coordinates in fill?
let inFill = checkPointIntersection(svg, shape, [cx, cy]);
checks++;
//not in fill: find alternative coordinates
if (!inFill) {
notInFill++; //
let rMid = (w + h) / 2;
let angles = [0, 45, 90, 135, 180, 225, 270, 315];
// check quarter position to reduce angle checkpoints
let classRotate = '';
if (t < svgCy && b < svgCy && l < svgCx && r > svgCx) {
classRotate = 'topCenter';
angles = [0, 180]
} else if (l > svgCx && b < svgCy) {
classRotate = 'topRight';
angles = [45, 90];
} else if (l > svgCx && b > svgCy && t < svgCy && b > svgCy) {
classRotate = 'centerRight';
angles = [90, 0]
} else if (l > svgCx && t > svgCy) {
classRotate = 'bottomRight';
angles = [135, 180];
} else if (l < svgCx && t > svgCy && r > svgCx) {
classRotate = 'bottomCenter';
angles = [180, 0];
} else if (r < svgCx && t > svgCy) {
classRotate = 'bottomLeft';
angles = [225, 270];
} else if (r < svgCx && b > svgCy) {
classRotate = 'centerLeft';
angles = [270, 0];
} else if (r < svgCx && b < svgCy) {
classRotate = 'topLeft';
angles = [315, 270];
} else {
classRotate = 'center';
angles = [0];
}
//shape.classList.add(classRotate);
let labeCoords = checkCircleIntersects(svg, shape, angles, cx, cy, rMid / 4);
cx = labeCoords[0]
cy = labeCoords[1]
}
let value = colorIndex;
labelGroupMarkup +=
`<text x="${cx}" y="${cy}" dy="2" >${value}</text>`;
//test eventListener: set colors by color group
shape.addEventListener('click', function(e) {
let current = e.currentTarget;
let g = current.closest('[data-color-group]');
let color = g.getAttribute('data-color-group');
let shapeColor = current.getAttribute('fill');
if (!shapeColor) {
current.setAttribute('fill', color)
} else {
current.removeAttribute('fill')
}
})
})
// add labels
labelGroup.innerHTML = labelGroupMarkup;
});
console.log('totalchecks: ' + checks + ' notInFill: ' + notInFill + ' pointHits: ' + pointHits)
// helpers
function checkCircleIntersects(svg, shape, percentages, cx, cy, r, percentageToAngel = false) {
let interpoints = [];
let interpointspercent = [];
percentages.forEach(function(percent) {
// check intersections on for different radii
let pArr = [];
let steps = [0.75, 1, 1.25, 1.5, 1.75, 2, 2.25];
for (let i = 0; i < steps.length; i++) {
let p = getPosOnCircle(cx, cy, percent, r * steps[i], percentageToAngel);
let inFill = checkPointIntersection(svg, shape, p);
checks++;
if (inFill) {
pArr.push(p);
pointHits++;
}
}
// add matches to array
interpointspercent.push(pArr);
});
// return best match x/y coordinates
let bestMatchArr = getBestMatchArr(interpointspercent);
let bestMatch = getMidPoints(bestMatchArr);
if (!bestMatch.length) {
shape.setAttribute('fill', 'red')
console.log(`no match: ${cx} ${cy}`)
bestMatch = [cx, cy]
}
return bestMatch
}
function checkPointIntersection(svg, shape, coords, strokeIntersection = false) {
let svgP = svg.createSVGPoint();
svgP.x = coords[0];
svgP.y = coords[1];
let inFill = shape.isPointInFill(svgP);
let inStroke = strokeIntersection ? shape.isPointInStroke(svgP) : false;
//let inStroke = shape.isPointInStroke(svgP);
let intersecting = false;
if (inFill && !inStroke) {
intersecting = true;
}
return intersecting;
}
// helper: get x/y coordinates according to angle or percentage
function getPosOnCircle(cx, cy, value, radius, valueToPercent = false, decimals = 3, offset = -90) {
// convert percentages to angles
let angle = valueToPercent ? 360 / (100 / value) + offset : value + offset;
let x = +(cx + Math.cos((angle * Math.PI) / 180) * radius).toFixed(decimals);
let y = +(cy + Math.sin((angle * Math.PI) / 180) * radius).toFixed(decimals);
return [x, y];
}
// find longest intersection array
function getBestMatchArr(arrays) {
let max = 0;
let longestArr = [];
for (let i = 0; i < arrays.length; i++) {
let current = arrays[i];
let len = current.length;
if (len > max) {
max = len;
}
}
for (let i = 0; i < arrays.length; i++) {
let current = arrays[i];
let len = current.length;
if (len == max) {
longestArr.push(current);
}
}
let midIndex = longestArr.length > 1 ? Math.floor((longestArr.length - 1) / 2) : 0;
return longestArr[midIndex];
}
// interpolate first and last x/y
function getMidPoints(coords) {
let l = coords.length - 1;
let midIndex = Math.floor(l / 2);
let [x1, y1] = coords[0];
let [x2, y2] = coords[coords.length - 1];
let middle = [ +((x1 + x2) / 2).toFixed(1) , +((y1 + y2) / 2).toFixed(1) ];
return middle;
}
// debug helper: render coordinates as markers
function renderPoint(svg, coords, fill = 'red', r = '2') {
let marker =
'<circle cx="' +
coords[0] +
'" cy="' +
coords[1] +
'" r="' + r + '" fill="' + fill + '" ><title>' +
coords.join(", ") +
"</title></circle>";
svg.insertAdjacentHTML("beforeend", marker);
}
svg {
width: 50em;
border: 1px solid #ccc;
display: block;
}
text {
font-family: Arial;
font-weight: bold;
font-size: 6px;
text-shadow: -0.1em -0.1em 0 #fff, -0.1em 0 0 #fff, 0em -0.1em 0 #fff, 0em 0.1em 0 #fff, 0.1em -0.1em 0 #fff, -0.1em 0.1em 0 #fff, 0.1em 0.1em 0 #fff;
}
<svg viewBox="0 0 1144.4 1144.4">
<g class="wrap-stroke" stroke-width="1" stroke="#000" fill="#fff">
<g data-color-group="#E95C87" data-fillable="true">
<path d="M572.2 381.5c-14.5 0-27.7 3-37 15.2-7 9.2-9.4 20.5-7.7 31.7a65 65 0 0 1-18.7-17.1c5.3-21.6 25-35.2 37.9-52.3a172.1 172.1 0 0 0 25.5-49 172.1 172.1 0 0 0 25.5 49c12.9 17.1 32.5 30.7 37.9 52.3a65 65 0 0 1-18.7 17.1 41.3 41.3 0 0 0-7.7-31.7c-9.3-12.2-22.5-15.2-37-15.2z"/>
<path d="M707 437.3c-10.2-10.2-21.7-17.4-36.9-15.4a41.3 41.3 0 0 0-27.8 17c-2-8.3-2.4-16.9-1.1-25.3 19-11.5 42.6-7.2 63.8-10.2 18.4-2.6 36.1-8.4 52.6-16.6-8.2 16.6-14 34.2-16.6 52.6-3 21.2 1.3 44.7-10.2 63.8-8.4 1.3-17 .9-25.3-1.1a41.9 41.9 0 0 0 17-27.8c1.9-15.3-5.3-26.7-15.5-37z"/>
<path d="M437.4 437.3C427.2 447.5 420 459 422 474.2a41.3 41.3 0 0 0 17 27.8c-8.3 2-16.9 2.4-25.3 1.1-11.5-19-7.2-42.6-10.2-63.8a173.5 173.5 0 0 0-16.6-52.6c16.6 8.2 34.2 14 52.6 16.6 21.2 3 44.7-1.3 63.8 10.2 1.3 8.4.9 17-1.1 25.3a41.9 41.9 0 0 0-27.8-17c-15.3-1.9-26.7 5.3-37 15.5z"/>
<path d="M572.2 115.6a18.6 18.6 0 0 0-15 30 20.6 20.6 0 0 0-.5 27.9 20.6 20.6 0 0 0-6.5 23 85.8 85.8 0 0 0-33.4-7.7c-6.5-19.9-11.2-40.6 3.3-58.3a65.2 65.2 0 0 1 52.1-23.5c20.3 0 39 7.5 52.1 23.5 14.5 17.7 9.8 38.3 3.3 58.3-11.5.3-22.9 3-33.4 7.7 3.2-8.6.2-17.5-6.5-23 7.2-8 7-20.2-.5-27.9 9.3-12.3 1.2-30-15-30z"/>
<path d="M895 249.3a18.6 18.6 0 0 0-31.9 10.6c-9.9.1-19.2 7.7-20.1 19.4-8.6-.8-17 3.4-20.8 11.7a88 88 0 0 0-18.1-29.1c9.5-18.7 20.7-36.6 43.6-38.9 20.6-2 39.1 5.9 53.4 20.2a65.7 65.7 0 0 1 20.2 53.4c-2.3 22.8-20.2 34-38.9 43.6a86.3 86.3 0 0 0-29.1-18.1c8-3.7 12.7-12.1 11.7-20.8a20.3 20.3 0 0 0 19.4-20.1 18.5 18.5 0 0 0 10.6-31.9z"/>
<path d="M249.4 249.3a18.6 18.6 0 0 0 10.6 31.9c.1 9.9 7.7 19.2 19.4 20.1-.8 8.6 3.4 17 11.7 20.8a88 88 0 0 0-29.1 18.1c-18.7-9.5-36.6-20.7-38.9-43.6a65.6 65.6 0 0 1 20.2-53.4 65.6 65.6 0 0 1 53.4-20.2c22.8 2.3 34 20.2 43.6 38.9a86.3 86.3 0 0 0-18.1 29.1 20.4 20.4 0 0 0-20.8-11.7 20.3 20.3 0 0 0-20.1-19.4 18.5 18.5 0 0 0-31.9-10.6z"/>
<path d="M572.2 472.3c-3.8-9.5-9.8-18-17.6-24.6-5.8-7.8-10-16.5-7.3-26.5 3-11.1 13.9-16.3 24.9-16.2 11-.2 21.9 5.1 24.9 16.2 2.7 10-1.5 18.7-7.3 26.5a62.7 62.7 0 0 0-17.6 24.6z"/>
</g>
<g data-color-group="#AED9C5" data-fillable="true">
<path d="M572.2 268.5a17.8 17.8 0 0 0-17.9 17.7c0 8.4 6 15.3 13.8 17.2a136.8 136.8 0 0 1-29.8 48.9 33 33 0 0 1-21.5-29.7 70.6 70.6 0 0 1 11.8-40.6c12.9-19.5 31.3-34.6 43.5-54.6 12.2 20 30.6 35.1 43.5 54.6a69.1 69.1 0 0 1 11.8 40.6 33 33 0 0 1-21 29.5l-.5.2a136.8 136.8 0 0 1-29.8-48.9 18 18 0 0 0 13.8-17.2c.2-9.8-8-17.8-17.7-17.7z"/>
<path d="M786.9 357.4c-6.8-6.9-18.3-7-25.1-.2a18 18 0 0 0-2.4 21.9c-17.4 8.4-36.4 13-55.7 13.5l-.2-.5a33 33 0 0 1 6-35.7 68.6 68.6 0 0 1 37.1-20.3c23-4.7 46.6-2.3 69.4-7.8-5.5 22.8-3.2 46.5-7.8 69.4a70.3 70.3 0 0 1-20.3 37.1 33 33 0 0 1-35.7 6l-.5-.2c1.4-19.3 4.3-38.4 13.5-55.7 6.8 4.2 16 3.5 21.9-2.4 6.8-7 6.8-18.2-.2-25.1z"/>
<path d="M357.5 357.4c-6.9 6.8-7 18.3-.2 25.1a18 18 0 0 0 21.9 2.4c8.4 17.4 13 36.4 13.5 55.7l-.5.2a33 33 0 0 1-35.7-6 68.6 68.6 0 0 1-20.3-37.1c-4.7-23-2.3-46.6-7.8-69.4 22.8 5.5 46.5 3.2 69.4 7.8a70.3 70.3 0 0 1 37.1 20.3 33 33 0 0 1 6 35.7l-.2.5c-19.3-.5-38.3-5.1-55.7-13.5 4.2-6.8 3.5-16-2.4-21.9-7-6.8-18.2-6.7-25.1.2z"/>
</g>
<g data-color-group="#FDFCFD" data-fillable="true">
<path d="M572.2 402.4c-11.1 0-23.3 5.1-27.3 16.2-3 8.2-1 16.3 3 23.5-5.1-4-11.2-7.7-17.2-11.6a39 39 0 0 1 8.4-34.2c9.1-10 20.4-12.1 33.2-12.1s24.1 2.1 33.2 12.1a39 39 0 0 1 8.4 34.2c-6 3.9-12.1 7.6-17.2 11.6 3.9-7.2 6-15.3 3-23.5-4.2-11.1-16.3-16.2-27.5-16.2z"/>
<path d="M692.2 452.1c-7.9-7.9-20-12.8-30.8-7.9a27.8 27.8 0 0 0-14.5 18.7c-.8-6.4-2.5-13.4-3.9-20.4a38.9 38.9 0 0 1 30.1-18.2c13.5-.7 23 5.9 32 14.9s15.6 18.5 14.9 32c-.6 12.5-8 23.4-18.2 30.1-7-1.5-14-3.1-20.4-3.9 7.9-2.3 15.1-6.6 18.7-14.5 5-10.8 0-22.9-7.9-30.8z"/>
<path d="M452.2 452.1c-7.9 7.9-12.8 20-7.9 30.8a27.8 27.8 0 0 0 18.7 14.5c-6.4.8-13.4 2.5-20.4 3.9a38.9 38.9 0 0 1-18.2-30.1c-.7-13.5 5.9-23 14.9-32s18.5-15.6 32-14.9c12.5.6 23.4 8 30.1 18.2-1.5 7-3.1 14-3.9 20.4-2.3-7.9-6.6-15.1-14.5-18.7-10.8-5-22.9 0-30.8 7.9z"/>
<path d="M563.7 551.7a27 27 0 0 1 17 0c5.2 2.6 9.4 6.8 12 12 .9 2.8 1.4 5.7 1.4 8.5s-.5 5.7-1.4 8.5a26.8 26.8 0 0 1-12 12 27 27 0 0 1-17 0 26.8 26.8 0 0 1-12-12c-.9-2.8-1.4-5.7-1.4-8.5s.5-5.7 1.4-8.5c2.6-5.2 6.8-9.4 12-12zm8.5 5.8a16 16 0 0 0-5.3.9l-.3.1-.3.1a17.1 17.1 0 0 0-7.6 7.6l-.1.3-.1.3a16 16 0 0 0 0 10.6l.1.3.1.3a17.1 17.1 0 0 0 7.6 7.6l.3.1.3.1a16 16 0 0 0 10.6 0l.3-.1.3-.1a17.1 17.1 0 0 0 7.6-7.6l.1-.3.1-.3a16 16 0 0 0 0-10.6l-.1-.3-.1-.3a17.1 17.1 0 0 0-7.6-7.6l-.3-.1-.3-.1a16 16 0 0 0-5.3-.9z"/>
<path d="M572.2 210.7a93.6 93.6 0 0 0-13.1-9.6l-.4-.7c-10.7-12-1-27.1 13.5-27.1s24.2 15.1 13.5 27.1l-.4.7c-4.6 2.8-9 6-13.1 9.6z"/>
<path d="M827.7 316.6a86 86 0 0 0-2.5-16l.2-.8c.9-16 18.4-19.9 28.7-9.6 10.3 10.3 6.5 27.8-9.6 28.7l-.8.2a78.4 78.4 0 0 0-16-2.5z"/>
<path d="M316.7 316.6a86 86 0 0 0-16 2.5l-.8-.2c-16-.9-19.9-18.4-9.6-28.7s27.8-6.5 28.7 9.6l.2.8a78.4 78.4 0 0 0-2.5 16z"/>
<path d="M572.2 168.1c-4.1 0-7.8.9-11 2.5a15 15 0 0 1 11-25.9 15 15 0 0 1 11 25.9 26 26 0 0 0-11-2.5z"/>
<path d="M857.9 286.5c-2.7-2.7-6-4.8-9.6-6a15 15 0 0 1 26.1-10.5 15 15 0 0 1-10.5 26.1 24.8 24.8 0 0 0-6-9.6z"/>
<path d="M286.6 286.5c-2.7 2.7-4.8 6-6 9.6a15 15 0 0 1-10.5-26.1 15 15 0 0 1 26.1 10.5c-3.7 1.2-7 3.2-9.6 6z"/>
<path d="M572.2 139.4a22 22 0 0 0-10.9 2.9 13.4 13.4 0 0 1 10.9-21.5 13.3 13.3 0 0 1 10.9 21.5 22 22 0 0 0-10.9-2.9z"/>
<path d="M878.1 266.2a21.2 21.2 0 0 0-9.8-5.7 13.3 13.3 0 0 1 22.9-7.5 13.3 13.3 0 0 1-7.5 22.9c-.8-3.4-2.6-6.8-5.6-9.7z"/>
<path d="M266.3 266.2a21.2 21.2 0 0 0-5.7 9.8 13.3 13.3 0 0 1-7.5-22.9 13.3 13.3 0 0 1 22.9 7.5c-3.4.8-6.8 2.6-9.7 5.6z"/>
<path d="m572.2 298.5-1.3-.1c-13.2-1.3-12.7-22.2 1.3-22.1 14-.1 14.5 20.8 1.3 22.1l-1.3.1z"/>
<path d="m765.7 378.6-.9-1c-8.4-10.3 6.7-24.6 16.5-14.7 10 9.8-4.4 25-14.7 16.5-.3-.1-.6-.4-.9-.8z"/>
<path d="m378.7 378.6-1 .9c-10.3 8.4-24.6-6.7-14.7-16.5 9.8-10 25 4.4 16.5 14.7-.1.3-.4.6-.8.9z"/>
<path d="M572.2 68c-14.6 0-14.5-22.3 0-22.1 14.5-.2 14.6 22.1 0 22.1z"/>
<path d="M928.7 215.6c-10.3-10.3 5.5-26 15.7-15.7 10.2 10.2-5.4 26-15.7 15.7z"/>
<path d="M215.7 215.6c-10.3 10.3-26-5.5-15.7-15.7 10.2-10.2 26 5.4 15.7 15.7z"/>
<path d="M472 330.1c18.2 14.1 38.9 23 61.3 27.9l-.4.4c-4.3 4.8-8.6 9.5-12.8 14.4a130.5 130.5 0 0 1-37.8-20.8c-.5-.4-1-.4-1.4-.3-.4.2-.8.6-.8 1.2a133.7 133.7 0 0 1-12 41.5c-6.4-.5-12.8-.8-19.2-1.1h-.5a153.1 153.1 0 0 0 23.6-63.2z"/>
<path d="M672.4 330.1c3.1 22.5 11.1 44 23.6 63h-.5c-6.4.4-12.8.6-19.2 1.1a128.5 128.5 0 0 1-12-41.5c-.1-.6-.4-1-.8-1.2s-1-.1-1.4.3c-11.4 9-24.2 16.1-37.9 20.8-4.1-4.9-8.5-9.6-12.8-14.4l-.3-.4a147.9 147.9 0 0 0 61.3-27.7z"/>
<path d="M461.6 305c15.6 12.1 33 20.9 51.8 26.8 2.9 9.7 9 18.1 18.6 23.2-21.9-5-42.4-14-60.1-28.2-.5-.4-1-.4-1.4-.3-.4.2-.8.6-.8 1.2a149 149 0 0 1-22.5 62.5c3-9.9 1.8-20.6-3.2-29.6a168 168 0 0 0 17.6-55.6z"/>
<path d="M682.9 305a163 163 0 0 0 17.7 55.6c-5 9-6.2 19.7-3.2 29.6-12-19-20.1-39.9-22.5-62.5-.1-.6-.4-1-.8-1.2-.4-.2-1-.1-1.4.3a146.6 146.6 0 0 1-60.1 28.2 39 39 0 0 0 18.7-23.2 164.9 164.9 0 0 0 51.6-26.8z"/>
<path d="M443.3 260.8a177.2 177.2 0 0 0 72.4 31.8h.1l-1 2.5a67 67 0 0 0-3 12.5 170.3 170.3 0 0 1-60.7-31.2c-.5-.4-1-.4-1.4-.3-.4.2-.8.6-.8 1.2a174 174 0 0 1-20.9 65 65.1 65.1 0 0 0-11-6.8l-2.5-1.1.1-.1c15.1-22.1 24.6-47 28.7-73.5z"/>
<path d="M701.2 260.8a177.4 177.4 0 0 0 28.7 73.7l.1.1-2.5 1.1a65.1 65.1 0 0 0-11 6.8 174 174 0 0 1-20.9-65c-.1-.6-.4-1-.8-1.2-.4-.2-1-.1-1.4.3a177.9 177.9 0 0 1-60.7 31.2c-.6-4.3-1.5-8.5-3-12.5l-1-2.5h.1a181 181 0 0 0 72.4-32z"/>
<path d="M451.2 279.9c18.1 14.1 38.4 24 60.4 30.4l-.3 5.1c-.1 4.5.3 9 1.2 13.3-18.6-6-35.7-14.8-51-27.1-.5-.4-1-.4-1.4-.3-.4.2-.8.6-.8 1.2a158 158 0 0 1-16.9 55.3 52.4 52.4 0 0 0-8.5-10.3l-3.8-3.4c11-19.9 18.1-41.7 21.1-64.2-.1 0 0 0 0 0z"/>
<path d="M693.3 279.9a178.1 178.1 0 0 0 21.2 64.2 59.5 59.5 0 0 0-12.3 13.7 158 158 0 0 1-16.9-55.3c-.1-.6-.4-1-.8-1.2-.4-.2-1-.1-1.4.3a157.7 157.7 0 0 1-51 27.1c1.5-6 1.8-12.3.9-18.4a177.7 177.7 0 0 0 60.3-30.4z"/>
<path d="M482.4 355.2c11 8.5 23 14.9 36 19.6-3.4 4.1-6.6 8.4-9.4 13-5.7-3.1-11.2-6.7-16.3-10.8-.5-.4-1-.4-1.4-.3-.4.2-.8.6-.8 1.2-.7 6.5-2 12.9-3.8 19.2a121 121 0 0 0-15.8-2.6c5.7-12.5 9.7-25.5 11.5-39.3z"/>
<path d="M662 355.2c1.8 13.6 5.7 26.9 11.6 39.3-5.4.5-10.6 1.3-15.8 2.6-1.8-6.3-3.1-12.6-3.8-19.2-.1-.6-.4-1-.8-1.2-.4-.2-1-.1-1.4.3-5.1 4.1-10.5 7.7-16.3 10.8-2.8-4.6-6-8.9-9.4-13 13-4.7 24.9-11.1 35.9-19.6z"/>
<path d="M492.8 380.4c4.7 3.6 9.6 6.9 14.8 9.8-2.3 4-4.2 8.2-5.6 12.6a66.2 66.2 0 0 0-12.8-4.9c1.6-5.7 2.8-11.6 3.6-17.5z"/>
<path d="M651.6 380.3c.7 5.9 1.9 11.7 3.6 17.4a66.2 66.2 0 0 0-12.8 4.9 64.5 64.5 0 0 0-5.6-12.6c5.2-2.7 10.1-6 14.8-9.7z"/>
</g>
<g data-color-group="#F8AF3F" data-fillable="true">
<path d="M572.2 98.6c-4 0-7.9.3-11.8.9 2.2-4.1 2.2-8.9.4-13.7-4.8-12.8-18.5-21-15-34.2 10-11.4 18.7-23.7 26.4-36.8 7.6 13 16.5 25.4 26.4 36.8 3.5 13.3-10.1 21.4-15 34.2-1.8 4.8-1.8 9.6.4 13.7-3.9-.6-7.8-.9-11.8-.9zm0-58.1c-9-.1-16.5 7.4-16.5 16.3a16.5 16.5 0 0 0 33 0c.1-8.9-7.5-16.3-16.5-16.3z"/>
<path d="M907 237.3a73.2 73.2 0 0 0-9-7.7 16 16 0 0 0 9.9-9.4c5.6-12.5 1.8-27.9 13.6-34.8 15.1-1 30-3.6 44.7-7.4a249.8 249.8 0 0 0-7.4 44.7c-6.9 11.9-22.3 8-34.8 13.6a16 16 0 0 0-9.4 9.9 71.5 71.5 0 0 0-7.6-8.9zm41.1-41.1a16.5 16.5 0 0 0-23.3-.1 16.6 16.6 0 0 0 .1 23.3 16.6 16.6 0 0 0 23.3.1c6.4-6.4 6.3-17-.1-23.3z"/>
<path d="M237.4 237.3a73.2 73.2 0 0 0-7.7 9 16 16 0 0 0-9.4-9.9c-12.5-5.6-27.9-1.8-34.8-13.6-1-15.1-3.6-30-7.4-44.7 14.7 3.8 29.6 6.3 44.7 7.4 11.9 6.9 8 22.3 13.6 34.8a16 16 0 0 0 9.9 9.4 64.9 64.9 0 0 0-8.9 7.6zm-41.1-41.1a16.5 16.5 0 0 0-.1 23.3 16.6 16.6 0 0 0 23.3-.1c6.3-6.3 6.5-16.9.1-23.3-6.4-6.4-17-6.2-23.3.1z"/>
<path d="M568.6 563.4c2.3-.8 4.9-.8 7.2 0 2.2 1.2 4 3 5.2 5.2.8 2.3.8 4.9 0 7.2a13 13 0 0 1-5.2 5.2c-2.3.8-4.9.8-7.2 0a13 13 0 0 1-5.2-5.2c-.8-2.3-.8-4.9 0-7.2 1.2-2.2 3-4 5.2-5.2z"/>
<path d="M530.1 67.8c.9 12.3 19 26.8 11.4 36.8a72 72 0 0 0-10.7 5.5c1-3.5 1.3-7.2.6-11.1-1-5.8-10.6-17.8-8.1-24.8l6.8-6.4z"/>
<path d="M185.9 245.3c9.4 8.1 32.4 5.6 34 18a75.5 75.5 0 0 0-3.6 11.4c-1.8-3.2-4.2-6-7.4-8.3-4.8-3.3-20.1-5.1-23.3-11.9l.3-9.2z"/>
<path d="M899 185.8c-8.1 9.4-5.6 32.4-18 34a75.5 75.5 0 0 0-11.4-3.6c3.2-1.8 6-4.2 8.3-7.4 3.3-4.8 5.1-20.1 11.9-23.3l9.2.3z"/>
<path d="M614.3 67.8c-.9 12.3-19 26.8-11.4 36.8a72 72 0 0 1 10.7 5.5c-1-3.5-1.3-7.2-.6-11.1 1-5.8 10.6-17.8 8.1-24.8l-6.8-6.4z"/>
<path d="M245.4 185.8c8.1 9.4 5.6 32.4 18 34 3.7-1.5 7.5-2.8 11.4-3.6-3.2-1.8-6-4.2-8.3-7.4-3.3-4.8-5.1-20.1-11.9-23.3l-9.2.3z"/>
<path d="M958.5 245.3c-9.4 8.1-32.4 5.6-34 18 1.5 3.7 2.8 7.5 3.6 11.4 1.8-3.2 4.2-6 7.4-8.3 4.8-3.3 20.1-5.1 23.3-11.9l-.3-9.2z"/>
<path d="M508.1 88.7c-.1 10.9 12.7 21.7 9.2 32.6-1.5 1.6-3 3.3-4.4 5.2-.4-1.9-1.2-3.8-2.3-5.4-1.5-2.4-3.7-4-5.7-6-5-4.7-7.8-10.1-6.1-16.3a104 104 0 0 1 7.1-7.8l2.2-2.3z"/>
<path d="M185.1 275.6c7.6 7.7 24.3 6.4 29.6 16.6.1 2.2.3 4.5.6 6.7-1.6-1-3.4-1.8-5.5-2.2-2.8-.6-5.5-.2-8.3-.2-6.9.2-12.7-1.7-15.8-7.2l-.6-10.5v-3.2z"/>
<path d="M868.7 185c-7.7 7.6-6.4 24.3-16.6 29.6-2.2.1-4.5.3-6.7.6 1-1.6 1.8-3.4 2.2-5.5.6-2.8.2-5.5.2-8.3-.2-6.9 1.7-12.7 7.2-15.8 4.6-.4 9.1-.6 13.7-.6z"/>
<path d="M636.3 88.7c.1 10.9-12.7 21.7-9.2 32.6 1.5 1.6 3 3.3 4.4 5.2.4-1.9 1.2-3.8 2.3-5.4 1.5-2.4 3.7-4 5.7-6 5-4.7 7.8-10.1 6.1-16.3-2.2-2.7-4.6-5.3-7-7.8l-2.3-2.3z"/>
<path d="M275.7 185c7.7 7.6 6.4 24.3 16.6 29.6 2.2.1 4.5.3 6.7.6-1-1.6-1.8-3.4-2.2-5.5-.6-2.8-.2-5.5-.2-8.3.2-6.9-1.7-12.7-7.2-15.8l-10.5-.6h-3.2z"/>
<path d="M959.3 275.6c-7.6 7.7-24.3 6.4-29.6 16.6-.1 2.2-.3 4.5-.6 6.7 1.6-1 3.4-1.8 5.5-2.2 2.8-.6 5.5-.2 8.3-.2 6.9.2 12.7-1.7 15.8-7.2l.6-10.5v-3.2z"/>
<path d="M505.1 173.5c.7 3.4 1.6 6.8 2.6 10.2-7.1-3.6-16.5-3.4-22.2-8.4a66.6 66.6 0 0 1-4.2-13.8c.9.8 1.8 1.5 2.8 2.1 3.4 1.9 7.2 2.1 10.8 3.2 4.4 1.3 7.7 3.5 10.2 6.7z"/>
<path d="M242.9 337.7c2.9 1.9 6 3.7 9.1 5.4-7.5 2.5-14.1 9.3-21.7 9.7a77.5 77.5 0 0 1-12.7-6.8c1.2 0 2.4-.2 3.5-.5 3.8-1 6.6-3.6 9.9-5.4 3.9-2.1 7.9-2.9 11.9-2.4z"/>
<path d="M806.6 242.8c-1.9 2.9-3.7 6-5.4 9.1-2.5-7.5-9.3-14.1-9.7-21.7 1.9-4.4 4.1-8.7 6.8-12.7 0 1.2.2 2.3.5 3.5 1 3.8 3.6 6.6 5.4 9.9 2.1 3.9 2.9 7.9 2.4 11.9z"/>
<path d="M639.3 173.5c-.7 3.4-1.6 6.8-2.6 10.2 7.1-3.6 16.5-3.4 22.2-8.4 1.9-4.6 3.3-9.2 4.2-13.8-.8.8-1.8 1.5-2.8 2.1-3.4 1.9-7.2 2.1-10.8 3.2-4 1.1-7.6 3.4-10.2 6.7z"/>
<path d="M337.8 242.8c1.9 2.9 3.7 6 5.4 9.1 2.5-7.5 9.3-14.1 9.7-21.7a77.5 77.5 0 0 0-6.8-12.7c0 1.2-.2 2.4-.5 3.5-1 3.8-3.6 6.6-5.4 9.9-2 3.6-2.9 7.8-2.4 11.9z"/>
<path d="M901.5 337.7c-2.9 1.9-6 3.7-9.1 5.4 7.5 2.5 14.1 9.3 21.7 9.7 4.4-1.9 8.7-4.1 12.7-6.8-1.2 0-2.4-.2-3.5-.5-3.8-1-6.6-3.6-9.9-5.4-3.6-2-7.8-2.9-11.9-2.4z"/>
<path d="M504.5 144c-.9 3.5-1.3 7.1-1.4 10.7-1.8-1.8-4-3.3-6.2-4.7-7-4.2-17.6-8.9-14.9-19v-.2c.5-2.4 1.2-4.8 2-7.2l1.9-4.6c.2 2.7.9 5.4 2.3 8 3.2 6.5 12.1 10.9 16.3 17z"/>
<path d="M221.6 317.3c1.9 3.1 4.1 5.9 6.5 8.5-2.6.1-5.2.4-7.7 1.1-7.9 2-18.8 6.2-24-2.9l-.1-.1-3.7-6.5-1.9-4.5c2 1.7 4.5 3.1 7.3 4 7 2.2 16.3-.9 23.6.4z"/>
<path d="M827 221.5c-3 1.9-5.9 4.1-8.5 6.5-.1-2.6-.4-5.2-1.1-7.7-2-7.9-6.2-18.8 2.9-24l.1-.1 6.5-3.7 4.5-1.9c-1.7 2-3.1 4.5-4 7.3-2.2 7 1 16.3-.4 23.6z"/>
<path d="M639.9 144a55 55 0 0 1 1.4 10.7c1.8-1.8 4-3.3 6.2-4.7 7-4.2 17.6-8.9 14.9-19v-.2c-.6-2.4-1.2-4.8-2-7.2l-1.9-4.6c-.2 2.7-1 5.4-2.3 8-3.2 6.5-12 10.9-16.3 17z"/>
<path d="M317.4 221.5c3.1 1.9 5.9 4.1 8.5 6.5 0-2.6.5-5.1 1.1-7.7 2-7.9 6.2-18.8-2.9-24l-.1-.1-6.5-3.7-4.5-1.9c1.7 2 3.1 4.5 4 7.3 2.2 7-.9 16.3.4 23.6z"/>
<path d="M922.8 317.3c-1.9 3-4.1 5.9-6.5 8.5 2.6 0 5.1.5 7.7 1.1 7.9 2 18.8 6.2 24-2.9l.1-.1 3.7-6.5 1.9-4.5c-2 1.7-4.5 3.1-7.3 4-6.9 2.2-16.3-.9-23.6.4z"/>
</g>
</g>
<g class="myIdInfo" id="myIdInfo" text-anchor="middle"/>
</svg>
helpers:
getPosOnCircle() – get arc coordinates (based upon Paul LeBeau's answer
– Pure svg pie chart, text align center ) – also helpful for pie chart labelling
checkPointIntersection() – for singular x/y intersection checking
checkCircleIntersects() – checking points at several angles and radii. Returns an array of intersecting points
getBestMatchArr() – find best match by comparing intersection arrays' length
svg optimizations:
reduce unnecessary background elements
inherit properties by parent groups
You can reduce the svg data significantly by removing inner/counter shapes from the background layers (~ from 400KB to 150 KB(incliuding labels) – still not lightweight).
However, as #the Hutt already pointed out:
You should rather cache or store the retrieved label coordinates statically to avoid expensive isPointInFill() calculations every time you load your site/view.
codepen example
I have a SVG image of a person which I want to animate slightly. I want to make the arm point towards the mouse. However I can't seem to get it to work. Currently I have this:
View on Codepen
As you can see the hand is fixed but the shoulder is loose which should be the opposite. Only when I point my mouse towards the shoulder the hand is correct again.
I use the following code
document.querySelector('#app')
.addEventListener('mousemove', mascotArm);
function mascotArm() {
var arm = document.querySelectorAll('.arm');
arm.forEach(function(arm) {
let x = (arm.getBoundingClientRect().right);
let y = (arm.getBoundingClientRect().top);
let radian = Math.atan2(event.pageX - x, event.pageY + y);
let rot = (radian * (90 / Math.PI))
arm.style.transform = 'rotate('+ rot + 'deg)';
})
}
I've tried the following code, but I wasn't able to implement it correctly in the SVG image
var cv = document.createElement('canvas');
var ctx = cv.getContext('2d');
cv.width = 1224;
cv.height = 768;
document.body.appendChild(cv);
var centerX = 300, centerY = 200;
var arm = new Image();
arm.onload = function() {
drawArrow(0);
};
var arm = document.querySelectorAll('.arm')
function drawArm(angle) {
ctx.clearRect(0, 0, cv.width, cv.height);
ctx.save();
ctx.translate(centerX, centerY);
ctx.rotate(-Math.PI / 2);
ctx.rotate(angle);
ctx.drawImage(arm, -arm.width / 2, -arm.height / 2);
ctx.restore();
}
document.onmousemove = function(e) {
var dx = e.pageX - centerX;
var dy = e.pageY - centerY;
var theta = Math.atan2(dy, dx);
drawArm(theta);
};
Desired solution
My desired solution would be that I can move my mouse on the page and that the arm is pointing towards my mouse. If possible it would be awesome if it can only move 90 degrees so that it doesn't make weird rotations.
Many thanks!
You will need a transform origin for the rotation of the .arm. For example you may try .arm{transform-origin: 280px 200px;}. In the code I've added a small red circle to mark the rotation hub. You can delete the circle and change the position of the hub. Please observe that I'm using the hub position in JavaScript. You will have to change it there too.
In JavaScript it's Math.atan2(y,x) not Math.atan2(x,y). Please read about Math.atan2.
Also the arm has a different angle inside the .arm box. You will need to to take in consideration this angle too. In order to understand what happens I've added a black rectangle as big as the bounding box of the arm. You may try arm.style.transform = 'rotate('+ (rot - 20) + 'deg)';
Also you ar listening the mouse over the app. As you can see I'm listening the mouse over the svg elemet. I suppose you need the doctorat the right side of the app. In order to keep it there I have #app {height:100vh; The app is now as wide as it's parent. Also svg{width:100%; height:100%} This will stretch the svg element over the app. In order to keep the doctor to the right I'm using preserveAspectRatio="xMaxYMax meet"
let svg = document.querySelector('#svg'); svg.addEventListener('mousemove', mascotArm);
//the hub position
let X = 280;
let Y = 200;
function mascotArm(event) {
var arm = document.querySelector('.arm');
let p = getMousePositionSVG(event)
let x = p.x;
let y = p.y;
let radian = Math.atan2(Y-y, X-x);
let rot = (radian * (180 / Math.PI))
arm.style.transform = 'rotate('+ (rot - 20) + 'deg)';
}
//a function to calculate the mouse position over an svg element
function getMousePositionSVG(event) {
var point = svg.createSVGPoint();
point.x = event.clientX;
point.y = event.clientY;
point = point.matrixTransform(svg.getScreenCTM().inverse());
return point;
}
#app {
background: #efefef;
height:100vh
}
svg{width:100%; height:100%}
.arm{transform-origin: 280px 200px;}
<div id="app">
<svg viewBox="0 0 458 753" fill="none" id="svg" preserveAspectRatio="xMaxYMax meet">
<g class="Layer 1">
<g class="Group">
<g class="Group_2">
<g class="Group_3">
<path d="M286.306 353l-18.063 197.3-14.569 144.54s7.896 11 37.606 6l15.695-151.5 19.149-124.5h15.299l10.167 276s12.831 10 36.619 1l-4.737-355.3-97.166 6.46z" fill="#303942" class="Vector_7"/>
<path d="M373.265 701.34a48.73 48.73 0 0014.609-2.5l-4.639-347.6-89.033 5.9-17.767 193.7-14.312 142.4c2.171 1.6 7.6 4.7 18.853 4.7a73.728 73.728 0 0010.462-.8l15.3-148.3 19.741-128.2h22.998l10.266 277.8a29.95 29.95 0 0013.522 2.9z" fill="#252D33" class="Vector_8"/>
<path d="M274.856 199.44s3.257 100.3 9.673 151.2c0 0 24.479 11.1 63.566 9.5 27.638-1.1 35.534-7.1 35.534-7.1l40.075-162.7s-20.432-11.9-62.481-11.9l-19.543 18.3s-5.331-14.2-15.793-17c-15.793 1.1-32.277 6-50.834 9.1l-.197 10.6z" fill="#148C78" class="Vector_9"/>
<path d="M341.778 196.64l5.034-17.8 11.154 5.2-16.188 12.6z" fill="#056351" class="Vector_10"/>
<path d="M349.477 161.24c4.936-2.4 9.476-6.9 12.931-13l.493 2.6.296 25.5c-8.982 1.2-19.247-4.1-28.526-14.6a17.467 17.467 0 007.458 1.399 17.467 17.467 0 007.348-1.899z" fill="#F2957C" class="Vector_11"/>
<path d="M340.298 180.44l1.48 16.2-9.179-11.5 7.699-4.7z" fill="#056351" class="Vector_12"/>
<path d="M350.168 185.14a41.914 41.914 0 01-13.226.5l-6.219 7.5 5.429 7.9-21.222 125.3 16.385 16.6 20.038-14.5-4.639-126.6 6.81-9.8-3.356-6.9z" fill="#73C8D2" class="Vector_13"/>
<path d="M315.029 179.34l13.72 18.8 11.549-17.7-18.162-12.3-7.107 11.2z" fill="#0C7561" class="Vector_14"/>
<path d="M412.353 247.44l-19.445 75 6.712 198.2-66.33 14.6-9.674-19.7-9.673 20.9-54.683-13.8s13.424-289.4 15.892-333.6l28.032-9.1 34.547 115.5 41.299-118.2s43.43 11.8 53.794 14.4" fill="#E5E5E5" class="Vector_16"/>
<path d="M335.165 164.64c17.964-2.3 38.199-17.3 42.838-27a17.044 17.044 0 012.863-4.6c16.385 3 24.38-31.4 13.621-36.1-.395-.2-.888-.3-1.283-.5a10.522 10.522 0 017.6.5c10.759 4.7 2.863 39.1-13.621 36.1a15.652 15.652 0 00-2.863 4.6c-4.639 9.8-24.873 24.7-42.838 27a33.045 33.045 0 01-7.699.1c.463.016.926-.017 1.382-.1z" fill="#F4876C" class="Vector_17"/>
<path d="M399.225 102.84c-5.626-2.9-10.562 6.3-10.858 16.1 4.639-.7 5.429 4.7 2.764 8.6 9.278 1.9 14.115-21.6 8.094-24.7z" fill="#F2957C" class="Vector_18"/>
<path d="M432.884 191.64c-8.094-2.1-40.174-13.5-53.795-14.4l-41.259 118.1-34.547-115.5-17.471 44c-2.171 40.1-18.359 258.6-20.235 295l46.491 12.4 11.154-23.6 11.943 22.3 61.888-15.3 4.442-196.4 14.411-98.3" fill="#F2F2F2" class="Vector_19"/>
<g class="Group_6">
<path d="M375.733 274.74v-8.2h-6.811a2.956 2.956 0 01-1.923-1.186 3.028 3.028 0 01-.544-2.214 2.887 2.887 0 01.808-1.681 2.824 2.824 0 011.659-.819h19.544a2.935 2.935 0 012.018.674c.567.47.942 1.136 1.053 1.87a3.035 3.035 0 01-.455 2.103 2.964 2.964 0 01-1.728 1.253h-7.6v8.2a3.118 3.118 0 01-1.064 1.796 3.04 3.04 0 01-3.893 0 3.118 3.118 0 01-1.064-1.796zm-6.811-12.8a1.664 1.664 0 00-1.215.427c-.333.3-.535.722-.561 1.173-.027.451.125.894.421 1.231.296.338.713.542 1.158.569h8.39v9.4c.038.446.243.861.573 1.159.331.298.762.455 1.204.441a1.774 1.774 0 001.066-.519c.287-.291.468-.672.513-1.081v-9.4h8.094c.445.027.882-.127 1.215-.427.333-.3.535-.722.561-1.173a1.711 1.711 0 00-.421-1.231 1.674 1.674 0 00-1.158-.569h-19.84z" fill="#006983" class="Vector_20"/>
<path d="M368.922 260.64h19.544a2.935 2.935 0 012.018.674c.567.47.942 1.136 1.053 1.87a3.035 3.035 0 01-.455 2.103 2.964 2.964 0 01-1.728 1.253h-7.6v8.2a3.007 3.007 0 01-1.171 1.949 2.931 2.931 0 01-2.185.551 2.943 2.943 0 01-1.636-.843 3.015 3.015 0 01-.832-1.657v-8.2h-6.771a2.954 2.954 0 01-1.924-1.186 3.028 3.028 0 01-.543-2.214 2.433 2.433 0 01.629-1.721 2.375 2.375 0 011.641-.779h-.04zm.04-1.2c-1.1 0-2.154.443-2.932 1.23a4.23 4.23 0 00-1.214 2.97 4.23 4.23 0 001.214 2.97 4.118 4.118 0 002.932 1.23h5.626v6.9a4.254 4.254 0 001.361 2.904 4.147 4.147 0 002.982 1.096 4.073 4.073 0 002.751-1.213 4.174 4.174 0 001.197-2.787v-6.9h5.626c1.1 0 2.154-.442 2.932-1.23a4.23 4.23 0 001.214-2.97 4.23 4.23 0 00-1.214-2.97 4.123 4.123 0 00-2.932-1.23h-19.543z" fill="#fff" class="Vector_21"/>
<path d="M368.922 259.44h19.544c1.1 0 2.154.443 2.931 1.23a4.227 4.227 0 011.215 2.97 4.227 4.227 0 01-1.215 2.97 4.114 4.114 0 01-2.931 1.23h-5.626v6.9a4.254 4.254 0 01-1.361 2.904 4.147 4.147 0 01-2.982 1.096 4.069 4.069 0 01-2.751-1.213 4.17 4.17 0 01-1.197-2.787v-6.9h-5.627a4.15 4.15 0 01-2.923-1.239 4.258 4.258 0 01-1.222-2.961 4.187 4.187 0 011.202-2.982 4.095 4.095 0 012.943-1.218zm0-1.3a5.35 5.35 0 00-2.08.413 5.41 5.41 0 00-1.764 1.192 5.485 5.485 0 00-1.177 1.787 5.554 5.554 0 00-.407 2.108 5.475 5.475 0 00.391 2.117 5.424 5.424 0 001.175 1.796 5.334 5.334 0 001.772 1.19 5.28 5.28 0 002.09.397h4.343v5.7a5.492 5.492 0 001.686 3.646 5.354 5.354 0 003.694 1.484 5.354 5.354 0 003.694-1.484 5.496 5.496 0 001.685-3.646v-5.7h4.343a5.351 5.351 0 002.081-.413 5.42 5.42 0 001.764-1.192 5.482 5.482 0 001.176-1.787 5.536 5.536 0 00.408-2.108 5.475 5.475 0 00-.391-2.117 5.424 5.424 0 00-1.175-1.796 5.328 5.328 0 00-3.863-1.587h-19.445z" fill="#006983" class="Vector_22"/>
<path d="M378.595 249.44c.391 0 .773.117 1.097.337a2.019 2.019 0 01.299 3.077 1.956 1.956 0 01-3.037-.303 2.017 2.017 0 01.246-2.525 1.96 1.96 0 011.395-.586zm0-1.2c-.644 0-1.273.194-1.809.556a3.295 3.295 0 00-1.2 1.481 3.343 3.343 0 00-.185 1.907c.125.64.436 1.228.891 1.689a3.219 3.219 0 003.55.716 3.27 3.27 0 001.462-1.216c.358-.542.549-1.18.549-1.833a3.32 3.32 0 00-.24-1.268 3.268 3.268 0 00-.705-1.074 3.216 3.216 0 00-2.313-.958z" fill="#006983" class="Vector_23"/>
<path d="M378.595 248.24c.645 0 1.274.194 1.81.556.536.363.953.878 1.2 1.481.246.603.311 1.267.185 1.907a3.316 3.316 0 01-.891 1.689 3.219 3.219 0 01-3.55.716 3.27 3.27 0 01-1.462-1.216 3.327 3.327 0 01-.549-1.833 3.423 3.423 0 01.982-2.306 3.334 3.334 0 012.275-.994zm0-1.3c-.878 0-1.737.264-2.467.758a4.489 4.489 0 00-1.636 2.02 4.56 4.56 0 00-.253 2.6 4.508 4.508 0 001.216 2.304 4.389 4.389 0 004.84.975 4.45 4.45 0 001.994-1.657c.488-.74.748-1.61.748-2.5a4.585 4.585 0 00-1.315-3.168 4.461 4.461 0 00-3.127-1.332z" fill="#fff" class="Vector_24"/>
<path d="M378.595 246.94c.879 0 1.738.264 2.468.758a4.489 4.489 0 011.636 2.02 4.56 4.56 0 01.253 2.6 4.523 4.523 0 01-1.216 2.304 4.389 4.389 0 01-4.84.975 4.45 4.45 0 01-1.994-1.657 4.542 4.542 0 01-.748-2.5 4.636 4.636 0 011.331-3.151 4.522 4.522 0 013.11-1.349zm0-1.2c-1.132 0-2.239.34-3.18.977a5.794 5.794 0 00-2.109 2.603 5.875 5.875 0 00-.325 3.352 5.818 5.818 0 001.566 2.969 5.66 5.66 0 006.239 1.257 5.742 5.742 0 002.57-2.136 5.854 5.854 0 00.964-3.222 5.84 5.84 0 00-1.676-4.101 5.688 5.688 0 00-4.049-1.699z" fill="#006983" class="Vector_25"/>
</g>
<path d="M303.184 179.84l34.547 115.5-30.302-37.4 2.369-24.6-16.089-4.9 1.579-47.3 7.896-1.3z" fill="#E5E5E5" class="Vector_26"/>
<path d="M303.382 180.14l-4.343.7-1.086 43.8 15.892 5-2.567 25.4 22.999 28.4-30.895-103.3z" fill="#EAEAEA" class="Vector_27"/>
<path d="M333.092 318.34c2.508 0 4.541-2.059 4.541-4.6 0-2.541-2.033-4.6-4.541-4.6-2.507 0-4.54 2.059-4.54 4.6 0 2.541 2.033 4.6 4.54 4.6z" fill="#E8E8E8" class="Vector_28"/>
<path d="M331.019 349.04c2.508 0 4.541-2.06 4.541-4.6 0-2.541-2.033-4.6-4.541-4.6-2.507 0-4.54 2.059-4.54 4.6 0 2.54 2.033 4.6 4.54 4.6z" fill="#E8E8E8" class="Vector_29"/>
<path d="M329.637 381.04c2.508 0 4.541-2.06 4.541-4.6 0-2.541-2.033-4.6-4.541-4.6-2.507 0-4.54 2.059-4.54 4.6 0 2.54 2.033 4.6 4.54 4.6z" fill="#E8E8E8" class="Vector_30"/>
<path d="M327.565 411.74c2.507 0 4.54-2.06 4.54-4.6 0-2.541-2.033-4.6-4.54-4.6-2.508 0-4.541 2.059-4.541 4.6 0 2.54 2.033 4.6 4.541 4.6z" fill="#E8E8E8" class="Vector_31"/>
<path d="M326.676 439.34c2.508 0 4.541-2.059 4.541-4.6 0-2.541-2.033-4.6-4.541-4.6-2.507 0-4.54 2.059-4.54 4.6 0 2.541 2.033 4.6 4.54 4.6z" fill="#E8E8E8" class="Vector_32"/>
<path d="M324.505 470.04c2.507 0 4.54-2.06 4.54-4.6 0-2.541-2.033-4.6-4.54-4.6-2.508 0-4.541 2.059-4.541 4.6 0 2.54 2.033 4.6 4.541 4.6z" fill="#E8E8E8" class="Vector_33"/>
<path d="M323.222 498.24c2.507 0 4.54-2.06 4.54-4.6 0-2.541-2.033-4.6-4.54-4.6-2.508 0-4.541 2.059-4.541 4.6 0 2.54 2.033 4.6 4.541 4.6z" fill="#E8E8E8" class="Vector_34"/>
<path d="M352.142 88.24c2.567-2.3 8.686-1.8 10.364.6.889.6 0 1.8-1.776 1.8h-3.415a3.91 3.91 0 00-2.567.6c-1.717-.1-4.343-1.9-2.606-3z" fill="#65433F" class="Vector_35"/>
<path d="M332.895 120c.789 0 2.27 1.6 3.06 1.6 1.48 0 2.27 0 3.059-.8.79-.8 2.271 0 1.58 1.6-.691 1.6-3.06 2.5-4.639 2.5-1.58 0-4.64-1.6-5.33-3.3.789-.76 1.48-1.6 2.27-1.6z" fill="#F4876C" class="Vector_36"/>
<path d="M332.796 153.74l1.086-1.1c1.086 0 2.171 2.3 1.086 2.3h-2.172c0-.1-1.086-.1 0-1.2z" fill="#F4876C" class="Vector_37"/>
<path d="M396.955 104.84a4.065 4.065 0 00-1.913-.537 4.062 4.062 0 00-1.937.437c1.777-2 3.948-2.8 6.219-1.6 5.231 2.7 2.171 21-4.738 24.3 5.172-5.7 6.909-20.2 2.369-22.6z" fill="#E58370" class="Vector_38"/>
<path d="M322.037 88.34c-2.566-2.4-8.686-1.8-10.364.6-.888.6 0 1.8 1.777 1.8h3.454a3.91 3.91 0 012.567.6c1.776-.1 4.343-1.9 2.566-3z" fill="#65433F" class="Vector_39"/>
<path d="M378.99 177.24l6.811.3 3.948 42.4-19.642 4.4 6.712 26.4-37.212 39.3 39.383-112.8z" fill="#E5E5E5" class="Vector_40"/>
<path d="M373.167 247.94l-6.91-27.4 19.939-4.5-3.554-38.6-3.454-.2-35.534 101.9 29.513-31.2z" fill="#EAEAEA" class="Vector_41"/>
<path d="M296.176 190.54h-.395a19.546 19.546 0 00-13.621 5.5c-10.463 10.1-9.377 30.6-9.278 31.5.093.656.432 1.251.947 1.66.514.41 1.165.603 1.816.54a2.41 2.41 0 001.754-.723 2.49 2.49 0 00.714-1.777c0-.3-1.086-19.4 7.897-28a13.675 13.675 0 014.593-2.975 13.54 13.54 0 015.376-.925h.197a13.562 13.562 0 018.291 3.1c4.146 3.3 9.18 10.9 9.575 27.9a2.61 2.61 0 00.921 1.718c.516.43 1.177.638 1.843.582a2.36 2.36 0 001.798-.635 2.423 2.423 0 00.768-1.765c-.395-15.1-4.244-25.7-11.549-31.4a18.149 18.149 0 00-11.647-4.3z" fill="#006983" class="Vector_67"/>
<g class="Group_13">
<path d="M293.807 255.34a2.381 2.381 0 00-.714-1.647 2.311 2.311 0 00-1.655-.653l-4.245.5c-1.283.4-1.283 1.1-1.283 2 0 1 0 1.7 1.481 2l4.145.2a2.36 2.36 0 001.609-.74c.423-.447.66-1.041.662-1.66z" fill="#151E31" class="Vector_68"/>
<path d="M290.55 255.44a2.712 2.712 0 012.27 1c-.418.429-.984.68-1.579.7l-2.566-.1c-.099-1.2.592-1.6 1.875-1.6z" fill="#fff" class="Vector_69"/>
<path d="M289.563 254.24c-1.875.3-2.566 1.6-2.566 3.3-1.185-.3-1.185-1-1.185-1.9 0-.9 0-1.6 1.283-2l4.245-.5c.522 0 1.03.177 1.441.504.411.326.703.782.829 1.296a4.596 4.596 0 00-4.047-.7z" fill="#808184" class="Vector_70"/>
</g>
<g class="Group_14">
<path d="M298.841 255.24a2.375 2.375 0 01.645-1.677 2.32 2.32 0 011.626-.723l4.343.3c1.381.3 1.283 1 1.381 1.9 0 1 0 1.7-1.381 2.1l-4.146.4a2.458 2.458 0 01-1.676-.663 2.523 2.523 0 01-.792-1.637z" fill="#151E31" class="Vector_71"/>
<path d="M302.099 255.14a2.272 2.272 0 00-2.172 1.1c.429.401.996.616 1.579.6l2.567-.3c0-1.2-.691-1.54-1.974-1.4z" fill="#fff" class="Vector_72"/>
<path d="M303.027 253.84c.379.016.751.11 1.094.277a2.8 2.8 0 01.897.692 2.851 2.851 0 01.674 2.131c1.184-.4 1.184-1.1 1.086-2-.099-.9 0-1.6-1.382-1.9l-4.343-.3a2.218 2.218 0 00-1.428.549c-.397.348-.66.826-.744 1.351a5.713 5.713 0 014.146-.8z" fill="#808184" class="Vector_73"/>
</g>
</g>
</g>
<g class="ster-ogen">
<path d="M318.43 112.35l8.72 3.42-3.63-8.61 6-7.27-9.34.73-5-7.89-2.18 9-9 2.28 8 4.88-.62 9.34 7.05-5.88z" fill="#F9FF00" class="Vector_74"/>
<path d="M361.98 119.3l-.62-10 8.51-5.19-9.65-2.49-2.24-9.62-5.3 8.31-9.86-.83 6.33 7.68-3.84 9.13 9.24-3.63 7.43 6.64z" fill="#F9FF00" class="Vector_75"/>
</g>
<g class="blij">
<path d="M334.671 148.64c-11.055-1.1-12.733-9-11.055-11.2 1.678-2.2 19.939-2.3 22.209 0 1.619 1.7-.592 11.2-11.154 11.2z" fill="#AA312D" class="Vector_76"/>
<path d="M346.319 139.14a1.93 1.93 0 00-.592-1.7c-2.271-2.3-19.939-2.3-22.209 0 0 0-.593 1.1 0 1.7 7.304 2.2 15.102 1.7 22.801 0z" fill="#fff" class="Vector_77"/>
<path d="M330.723 147.84a12.667 12.667 0 01-4.836-2.6c.493-.5 1.085-.5 1.579-1.1a17.076 17.076 0 015.527-.6 13.086 13.086 0 018.588 3.2 12.866 12.866 0 01-6.91 1.9 13.294 13.294 0 01-3.454-.7.884.884 0 01-.494-.1z" fill="#902622" class="Vector_78"/>
</g>
<g class="ogen">
<path d="M358.065 113.64c4.143 0 7.501-3.627 7.501-8.1 0-4.474-3.358-8.1-7.501-8.1-4.143 0-7.502 3.626-7.502 8.1 0 4.473 3.359 8.1 7.502 8.1z" fill="#F2957C" class="Vector_79"/>
<path d="M358.065 112.44c3.543 0 6.416-3.089 6.416-6.9 0-3.811-2.873-6.9-6.416-6.9-3.544 0-6.416 3.089-6.416 6.9 0 3.811 2.872 6.9 6.416 6.9z" fill="#5E3536" class="Vector_80"/>
<path d="M360.039 104.14c.872 0 1.579-.761 1.579-1.7s-.707-1.7-1.579-1.7-1.579.761-1.579 1.7.707 1.7 1.579 1.7z" fill="#fff" class="Vector_81"/>
<path d="M316.707 113.64c4.143 0 7.502-3.627 7.502-8.1 0-4.474-3.359-8.1-7.502-8.1s-7.502 3.626-7.502 8.1c0 4.473 3.359 8.1 7.502 8.1z" fill="#F2957C" class="Vector_82"/>
<path d="M316.707 112.44c3.543 0 6.416-3.089 6.416-6.9 0-3.811-2.873-6.9-6.416-6.9s-6.416 3.089-6.416 6.9c0 3.811 2.873 6.9 6.416 6.9z" fill="#5E3536" class="Vector_83"/>
<path d="M318.681 104.14c.872 0 1.579-.761 1.579-1.7s-.707-1.7-1.579-1.7-1.579.761-1.579 1.7.707 1.7 1.579 1.7z" fill="#fff" class="Vector_84"/>
</g>
<g class="arm" id="kk">
<rect y="109" width="282" height="128" fill="black"/>
<path d="M75.77 140.4l-8.785-3.8s-8.983-13.4-21.222-17.2a79.917 79.917 0 01-8.193-2.9 16.65 16.65 0 01-6.81-7.5s-5.627.5-1.481 7.8a22.565 22.565 0 006.613 6.4 67.371 67.371 0 01-10.759-3.4c-1.776-.8-12.437-5-16.385-6.9-1.875-.9-6.712-3.3-8.489.4-1.974 4.2 7.897 7.6 10.068 8.4 4.738 1.9 16.78 8.8 16.78 8.8s-8.093-2.6-9.475 2.2a4.26 4.26 0 00.296 3.1c1.184 2.4 2.862 2.5 2.862 2.5a4.809 4.809 0 00-1.579 2.521 4.86 4.86 0 00.197 2.979 5.87 5.87 0 001.962 2.366 5.76 5.76 0 002.875 1.034s-4.442 5.6 3.948 9c2.863 1.2 4.935 1.3 7.897 1.8 2.888.601 5.843.802 8.784.6a48.873 48.873 0 009.377-.9c1.876-.4 7.009 3.1 9.772 5.2a22.152 22.152 0 005.824 3.2l11.845-23.4-5.923-2.3z" fill="#F2AB8F" class="Vector_85"/>
<path d="M84.949 140.3l-8.982-4.2-14.806 31.4 9.377 5.2 14.41-32.4z" fill="#148C78" class="Vector_86"/>
<path d="M273.97 233.6l8.193-41.3s-168.984-14.9-194.55-56.5c0 0-19.938 21.6-22.307 37.7-.098 0 175.795 76.3 208.664 60.1z" fill="#F2F2F2" class="Vector_87"/>
<path d="M254.328 237.2c-36.028-1.5-144.308-43-190.403-62.3 1.875-3.4 2.171-8.1 4.639-11.6 18.556 14.8 66.034 33.9 116.867 43.9 29.908 5.9 78.965 10.9 95.35 12.8l-.691 16c-5.231 1.2-25.071 1.2-25.762 1.2z" fill="#E5E5E5" class="Vector_88"/>
</g>
</g>
<circle cx="280" cy="200" r="10" fill="red"/>
</svg>
</div>
I have a NodeList of DOM elements with id's conforming to the following pattern:
prefix-number
(e.g. square-115, circle-15, triangle-2, etc.)
From a certain id, I need a reference to all the elements in the NodeList that have the same number but a different prefix.
For example, from the element with id="ellipse-25", how can I reference all the elements that are with the same number but a different prefix (e.g. polygon-25, square-25), if any?
In JavaScript, what is the most efficient way to do this? Can it be achieved without multiple or no NodeList iterations?
P.S. Here is the sample NodeList, as asked by Gangadhar Jannu, though it is not necessary, as it is more a conceptual question rather than a practical one:
<NodeList length="36">
<path class="segm-lad segm-stroke" id="psax-1" POINTER-EVENTS="auto" d="M 436.508 173.867 A 192.267 192.267 0 0 0 270 77.7333 L 270 130 A 140 140 0 0 1 391.244 200 L 436.508 173.867 Z"></path>
<path class="segm-lad segm-stroke" id="psax-2" POINTER-EVENTS="auto" d="M 270 77.7333 A 192.267 192.267 0 0 0 103.492 173.867 L 148.756 200 A 140 140 0 0 1 270 130 L 270 77.7333 Z"></path>
<path class="segm-rca segm-stroke" id="psax-3" POINTER-EVENTS="auto" d="M 103.492 173.867 A 192.267 192.267 0 0 0 103.492 366.133 L 148.756 340 A 140 140 0 0 1 148.756 200 L 103.492 173.867 Z"></path>
<path class="segm-rca segm-stroke" id="psax-4" POINTER-EVENTS="auto" d="M 103.492 366.133 A 192.267 192.267 0 0 0 270 462.267 L 270 410 A 140 140 0 0 1 148.756 340 L 103.492 366.133 Z"></path>
<path class="segm-rca-cx segm-stroke" id="psax-5" POINTER-EVENTS="auto" d="M 270 462.267 A 192.267 192.267 0 0 0 436.508 366.133 L 391.244 340 A 140 140 0 0 1 270 410 L 270 462.267 Z"></path>
<path class="segm-lad-cx segm-stroke" id="psax-6" POINTER-EVENTS="auto" d="M 436.508 366.133 A 192.267 192.267 0 0 0 436.508 173.867 L 391.244 200 A 140 140 0 0 1 391.244 340 L 436.508 366.133 Z"></path>
<path class="segm-lad segm-stroke" id="psax-7" POINTER-EVENTS="auto" d="M 391.244 200 A 140 140 0 0 0 270 130 L 270 182.267 A 87.7333 87.7333 0 0 1 345.979 226.133 L 391.244 200 Z"></path>
<path class="segm-lad segm-stroke" id="psax-8" POINTER-EVENTS="auto" d="M 270 130 A 140 140 0 0 0 148.756 200 L 194.021 226.133 A 87.7333 87.7333 0 0 1 270 182.267 L 270 130 Z"></path>
<path class="segm-rca-lad segm-stroke" id="psax-9" POINTER-EVENTS="auto" d="M 148.756 200 A 140 140 0 0 0 148.756 340 L 194.021 313.867 A 87.7333 87.7333 0 0 1 194.021 226.133 L 148.756 200 Z"></path>
<path class="segm-rca segm-stroke" id="psax-10" POINTER-EVENTS="auto" d="M 148.756 340 A 140 140 0 0 0 270 410 L 270 357.733 A 87.7333 87.7333 0 0 1 194.021 313.867 L 148.756 340 Z"></path>
<path class="segm-rca-cx segm-stroke" id="psax-11" POINTER-EVENTS="auto" d="M 270 410 A 140 140 0 0 0 391.244 340 L 345.979 313.867 A 87.7333 87.7333 0 0 1 270 357.733 L 270 410 Z"></path>
<path class="segm-lad-cx segm-stroke" id="psax-12" POINTER-EVENTS="auto" d="M 391.244 340 A 140 140 0 0 0 391.244 200 L 345.979 226.133 A 87.7333 87.7333 0 0 1 345.979 313.867 L 391.244 340 Z"></path>
<path class="segm-lad segm-stroke" id="psax-13" POINTER-EVENTS="auto" d="M 354.744 247.293 A 87.7333 87.7333 0 0 0 247.293 185.256 L 260.821 235.742 A 35.4667 35.4667 0 0 1 304.258 260.821 L 354.744 247.293 Z"></path>
<path class="segm-lad segm-stroke" id="psax-14" POINTER-EVENTS="auto" d="M 247.293 185.256 A 87.7333 87.7333 0 0 0 185.256 292.707 L 235.742 279.179 A 35.4667 35.4667 0 0 1 260.821 235.742 L 247.293 185.256 Z"></path>
<path class="segm-lad segm-stroke" id="psax-15" POINTER-EVENTS="auto" d="M 185.256 292.707 A 87.7333 87.7333 0 0 0 292.707 354.744 L 279.179 304.258 A 35.4667 35.4667 0 0 1 235.742 279.179 L 185.256 292.707 Z"></path>
<path class="segm-lad-cx segm-stroke" id="psax-16" POINTER-EVENTS="auto" d="M 292.707 354.744 A 87.7333 87.7333 0 0 0 354.744 247.293 L 304.258 260.821 A 35.4667 35.4667 0 0 1 279.179 304.258 L 292.707 354.744 Z"></path>
<path class="segm-lad" id="a3c-2" POINTER-EVENTS="auto" d="M 174.4 72.6 c -2.2 1.1 -3.9 -0.9 -6.1 -0.8 c -1.1 0 -2 0.6 -2.9 1 c -4.5 1.9 -9.2 3 -13.8 3.8 c -3.6 0.7 -7.3 1.1 -11 2.3 c -1.6 0.5 -3.2 0.8 -4.8 0.9 l 2.1 19.8 c 4.9 -0.7 10.4 -1.9 15.9 -3.5 c 1.8 -0.5 8.2 -2.5 9.9 -3.2 c 6.2 -2.7 8.9 -4.3 14.8 -7.1 c 1.6 -0.8 4.4 -2.4 5.8 -3.4 c 1 -0.7 6.1 -4.2 6.1 -8.2 c 0 -2.5 -9.3 -5.1 -11.6 -4.3 C 177.2 70.4 176.1 71.8 174.4 72.6 Z"></path>
<path class="segm-rca-cx" id="a3c-5" POINTER-EVENTS="auto" d="M 152.3 201 c 13.2 1.4 25.6 -2.5 39 -2.7 c 4.6 0 9.1 0.6 13.5 -0.5 c 2.6 -0.7 5.3 -1 7.7 -2.4 c 1.1 -0.6 2.1 -1.3 3.1 -2 c 3.6 -2.3 5.5 -6.5 5 -10.7 c -0.5 -3.9 -2 -7.6 -5.1 -10.5 c -2.2 -2 -4.8 -2.7 -7.7 -3.1 c -1.4 -0.1 -2.8 -0.2 -4.2 -0.2 c -1.7 0.9 -3.6 1.4 -5.5 2.2 c -0.8 0.3 -1.6 0.9 -2.4 1.2 c -3 1.1 -5.8 2.2 -8.8 3.2 c 0 -0.1 0 -0.2 0 -0.3 c -3.2 0.9 -6.3 1.9 -9.7 2 c -3.7 0.1 -7.1 0.6 -10.8 0.6 c -1.2 0 -3.5 -0.6 -4.7 -0.5 c -3.9 0.2 -2.9 1.3 -6.8 1.6 c -1.4 0.1 -6 -1.5 -7.7 -1.8 c -3.4 -0.7 -6.8 -1.3 -10.2 -2.1 l -5.7 22.1 C 138.4 199.3 145.2 200.2 152.3 201 Z"></path>
<path class="segm-rca-cx" id="a3c-11" POINTER-EVENTS="auto" d="M 83.9 177.3 c 3 0.8 13.5 5.8 15.7 6.8 c 4.5 2.1 6.4 2.9 10.3 4.6 c 8.3 3.6 11.1 4.8 17.1 7 c 1.5 0.6 3 1 4.5 1.5 l 5.7 -22.1 c -0.8 -0.2 -1.6 -0.4 -2.4 -0.6 c -5.1 -1.4 -10 -3.5 -14.5 -6.3 c -5.4 -0.5 -5.8 -3.8 -8.6 -7.7 c -1.1 -1.5 -3.3 -2.2 -3.5 -3.2 c -0.2 -0.9 1.1 -1.5 0.8 -2.4 c -1 -2.8 -3.9 -2.8 -6 -4 c -0.6 -0.4 -1.3 -1.2 -2 -1.5 c -2.2 -0.7 -4.2 -1.5 -6.4 -2.1 c -2.8 -0.7 -5.7 -0.8 -8.4 -1.5 s -4.9 -1.9 -5.8 -2.2 c -2.6 -0.6 -4.9 -1.1 -7 -1.7 l -8.9 28.4 C 70.2 173 76.5 175.3 83.9 177.3 Z"></path>
<path class="segm-lad" id="a3c-8" POINTER-EVENTS="auto" d="M 127.4 80.3 c -3.2 0.4 -6.2 -0.1 -9.4 -0.1 c -0.6 0.3 -1.3 0.5 -2 0.5 c -9.9 -0.8 -26 0 -38.9 0.9 l 2.7 19.7 c 5.4 -0.9 10.9 -0.6 16.5 -0.7 c 6.8 -0.1 13 0.4 19.4 0.2 c 4 -0.1 8.1 -0.5 12.1 -0.4 c 2.7 0.1 6.2 -0.2 10.1 -0.7 l -2.1 -19.8 C 133.1 80.1 130.2 79.9 127.4 80.3 Z"></path>
<path class="segm-lad-cx" id="a3c-16" POINTER-EVENTS="auto" d="M 23 147.9 c 1.4 0.9 2.8 1.8 4.2 2.6 c 14.1 8.1 24.7 14.6 37.1 19.9 l 8.9 -28.4 c -6.6 -1.7 -11.4 -3.7 -18 -9.6 c -0.7 -0.6 -0.9 -1.7 -0.3 -2.5 c 0.8 -1 2.1 -1.5 3.1 -2.5 c 0.9 -0.9 0.7 -2.4 -0.6 -2.9 c -6.2 -2.3 -11.9 2.2 -18 1.7 c -1.6 -0.1 -2.4 -0.4 -2.6 -0.7 H 23 V 147.9 Z"></path>
<path class="segm-lad" id="a3c-14" POINTER-EVENTS="auto" d="M 75.2 81.6 c -12.1 0.9 -24 4 -35 9.2 c -6.3 3 -13 6.4 -17.3 9 v 25.7 h 13.9 c -0.4 -0.4 0.4 -0.9 0.6 -1 c 2.8 -1.1 7.9 0.6 8.3 -3 c 0.2 -1.3 -2.3 -1.5 -2.7 -2.8 c -0.5 -2 2.4 -1.5 3.4 -2.3 c 1 -0.8 0.9 -2.7 2.3 -2.9 c 1.7 -0.3 3.7 0.4 5 -0.9 c 0.5 -0.5 0.6 -1.3 1 -1.8 c 0.5 -0.6 1.6 -0.6 2.3 -1.1 c 0.9 -0.7 3.3 -2.2 4.1 -2.8 c 2 -1.4 2.6 -1.8 5.1 -2.8 c 0.6 -0.3 1.7 -0.5 2.4 -0.5 c 3 0 5.9 -0.1 8.8 -2 c 0.8 -0.2 1.6 -0.3 2.4 -0.5 L 77 81.5 C 76.4 81.5 75.8 81.6 75.2 81.6 Z"></path>
<path class="segm-rca-lad" id="a4c-9" POINTER-EVENTS="auto" d="M 74.6 93.2 c 1.4 2.5 -2.2 4.7 -1.8 7.6 c 0.3 2.1 3 1.2 3.4 2.9 c 1.3 6.3 1.2 13 3.2 18.1 c 1.9 4.8 0 15.4 5.9 19 c 1.2 0.8 -1.2 1.2 -1.6 1.9 c -0.6 1.1 -0.5 2 -0.2 2.8 l 23.9 -3.1 c -0.2 -2.4 0.9 -5.1 -0.7 -7.3 c -0.8 -1.1 -1.8 -2.1 -2.8 -3.1 c -0.9 -0.9 0.3 -1.8 1.1 -2.7 c 0.8 -0.9 0.3 -2.2 0.5 -4.2 c 0.4 -4.2 -0.8 -8.2 -2.6 -12.1 c -0.6 -1.3 1.1 -3.2 0.3 -4.8 c -3.4 -6.5 -4.8 -13 -5.8 -20.1 H 72 C 72.7 89.7 73.6 91.4 74.6 93.2 Z"></path>
<path class="segm-rca" id="a4c-3" POINTER-EVENTS="auto" d="M 86.5 149.7 c 3.9 6.2 3.3 13 6.3 19.4 c 0 0.1 0.1 0.1 0.1 0.2 c 2.1 4.5 4.3 9.7 4.9 15.1 c 0.4 3.2 0.8 7.1 0.8 7.1 c 0.3 2.4 2.4 7.5 3 8 c 1.4 1 3.6 0.9 5 0 c 1 -0.7 1.4 -1.6 2 -3 c 0.7 -1.6 2 -5 2 -5 s 1.1 -2.8 2.2 -5.7 c 1 -5.4 0.4 -10.9 1.3 -16.3 c 1.7 -9.8 -3.2 -17.7 -6.5 -25.9 c -0.2 -0.4 -0.3 -0.9 -0.3 -1.3 l -23.9 3.1 C 84.1 146.9 85.6 148.2 86.5 149.7 Z"></path>
<path class="segm-lad" id="a4c-14" POINTER-EVENTS="auto" d="M 72.8 25.9 c -1.4 2.5 -2.4 5.1 -2.8 7.6 c -1.5 8.7 -1.8 27.8 -1.8 27.8 c 0.3 6.3 0.2 15.1 2 21.4 c 0.5 1.9 1.1 3.5 1.8 5.2 h 25.3 c 0 -0.3 -0.1 -0.5 -0.1 -0.8 c -0.4 -2.7 0.3 -5.6 0.2 -8.4 c -2.7 -7.7 -4 -14.4 -4.8 -19.3 c -1.5 -10.6 -1.8 -17.1 0 -20 c 2.6 -4.4 2 -7.4 2.3 -8.7 c 0.3 -1.6 3.3 -1.1 3.7 -1.3 c 0.6 -0.4 1.2 -0.7 1.8 -1 l -2.3 -8.8 L 72.8 25.9 Z"></path>
<path class="segm-lad" id="a4c-17" POINTER-EVENTS="auto" d="M 98 19 l 0.2 0.7 l 31.6 -7.7 c -11.4 -5.6 -24.1 -8.2 -37.2 -5.6 C 88.5 7.2 78 16.2 72.8 25.9 l 25.4 -6.2 L 98 19 Z"></path>
<path class="segm-lad-cx" id="a4c-6" POINTER-EVENTS="auto" d="M 225.1 158.2 c -0.3 -4.3 -0.8 -8.5 -1.4 -12.7 c -1.7 -11.4 -7 -21.7 -12.6 -32.2 l -29 12.9 c 0.3 0.5 0.7 1 1 1.5 c 0.6 0.8 0.5 2.4 0.8 3.7 c 0.7 4.3 4.9 6.7 6.5 10.7 c 1.9 4.9 6.5 9.2 7.9 14.5 c 0 0 1 3.9 2.4 9.4 c 0.6 2.4 1.6 4.6 3 6.6 c 1.7 2.4 3.4 4.4 5 5 c 3.5 1.5 7.2 1.5 9 1 c 3.2 -0.9 5.8 -4.6 7.4 -10.3 c 0.3 -0.9 0.4 -1.9 0.4 -2.8 C 225.4 163 225.3 160.6 225.1 158.2 Z"></path>
<path class="segm-lad-cx" id="a4c-12" POINTER-EVENTS="auto" d="M 205.9 103.4 c -8.5 -16.7 -18 -32.5 -29.8 -46.9 L 149.3 77 c 0.3 1.5 1.1 3.1 1.3 4.5 c 2.9 4.4 1.6 9.8 1.4 21.7 c -0.1 4.4 0 9.8 0.6 16.3 c 1.4 16.3 8.6 8.1 12 3 c 4 -6 4.9 -16.9 6 -16 c 4.1 3.4 -1.2 5.3 3.9 7.9 c 3.6 1.9 4.9 7.6 7.5 11.8 l 29 -12.9 C 209.3 110 207.6 106.7 205.9 103.4 Z"></path>
<path class="segm-lad-cx" id="a4c-16" POINTER-EVENTS="auto" d="M 161.2 40.6 c -4.2 -4 -6 -9.7 -10.3 -13.7 c -6.3 -5.9 -13.4 -11 -21.2 -14.8 l -31.6 7.7 l 2.3 8.8 c 2.9 -1.3 5.9 -1.2 9.2 -0.1 c 1.1 0.3 2.1 2.7 3 3.1 c 2.1 0.8 1 -3 5.6 0.6 c 3.4 2.7 6.5 4.6 8.4 6.4 c 8.3 8.2 12.6 9.4 16 19 c 4.5 12.7 9.6 13.3 7 17 c -0.5 0.7 -0.5 1.6 -0.3 2.5 L 176 56.5 C 171.5 51 166.6 45.6 161.2 40.6 Z"></path>
<path class="segm-lad" id="a2c-15" POINTER-EVENTS="auto" d="M 54.6 30 c -0.1 0.1 -0.1 0.2 -0.2 0.3 c -5 7.1 -13.9 24.4 -17.4 32.5 c -1.7 3.9 -4.2 9.5 -6.8 15.5 l 29.4 8.4 c 0.3 -0.3 1.8 -2.1 2.2 -5 c 0.5 -3.3 0 -9.3 0 -9.3 s 2.5 0 4 -2.8 c 1.5 -2.8 1.5 -7.1 2.8 -9.1 c 1.3 -2 2.8 -3 4.8 -3.5 c 2 -0.5 2.8 -2 3.3 -3.5 c 0.5 -1.5 1.8 -7.1 1.8 -7.1 s 0.5 3.8 3 3.8 c 0.1 0 0.2 0 0.3 0 V 30 H 54.6 Z"></path>
<path class="segm-lad" id="a2c-17" POINTER-EVENTS="auto" d="M 107.9 30 c -7 -8.4 -19.6 -18.3 -29 -18.3 c -10.4 0 -19.1 11.3 -24.2 18.3 h 27.2 H 107.9 Z"></path>
<path class="segm-rca" id="a2c-4" POINTER-EVENTS="auto" d="M 3.3 169.9 c -0.3 4.8 -0.8 4.5 0 11.6 c 0.8 7.1 5 23.7 9.8 33.8 c 4.1 8.6 18.8 19.6 21.4 17.3 c 9 -8 0.6 -16 -0.6 -19.5 c -1.3 -3.5 -6.3 -11.1 -7.1 -17.6 c -0.8 -6.5 0 -12.6 -0.3 -15.6 c -0.3 -3 -1 -5.8 -2 -6.8 c -1 -1 1.8 0.3 1.8 0.3 s 0.8 -6.8 1.3 -10.8 c 0.5 -4 2 -2.5 2 -2.5 c 0.4 -2 0.9 -4.6 1.4 -7.6 l -24 -7 C 5.2 153.4 3.6 162.7 3.3 169.9 Z"></path>
<path class="segm-rca" id="a2c-10" POINTER-EVENTS="auto" d="M 22.9 96.6 c -3.5 10.1 -11.3 30.7 -13.9 40.3 c -0.7 2.5 -1.4 5.4 -2 8.4 l 24 7 c 1.6 -8.3 4.1 -19.1 8.5 -25.7 c 2.3 -3.5 0.3 10.8 3 19 c 3 9 9 3 11 -5 c 4 -10 5.8 -31.8 5.8 -37.9 s 0.3 -15.9 0.3 -15.9 s 0 0 0.1 -0.1 l -29.4 -8.4 C 27.5 84.6 24.7 91.3 22.9 96.6 Z"></path>
<path class="segm-lad" id="a2c-13" POINTER-EVENTS="auto" d="M 128.7 70.1 c -3.5 -13.9 -12.3 -28.5 -18.6 -37.3 c -0.6 -0.9 -1.4 -1.9 -2.2 -2.8 H 81.8 v 20.2 c 2.3 -0.1 3.7 -1.2 3.7 -1.2 s 0.3 3.3 3.3 5.3 c 3 2 4.3 0 4.3 0 s 1.8 3.8 2.8 5 c 1 1.3 1.8 4.5 3 8.8 c 1.3 4.3 4.9 13.6 5 16.9 c 0 0.2 0 0.3 0 0.5 l 26.8 -6.9 C 130.1 75.5 129.4 72.7 128.7 70.1 Z"></path>
<path class="segm-lad" id="a2c-7" POINTER-EVENTS="auto" d="M 138.1 119.5 c -1 -10.3 -4.2 -27.4 -7.3 -40.9 l -26.8 6.9 c 0.3 6 2.5 4.8 2.5 4.8 s 1.3 10.8 1.3 18.6 c 0 7.8 -2.3 22.4 -0.8 29.7 c 0.7 3.4 2.5 8.3 4.4 13.5 l 28.6 -7.4 C 139.3 136.2 138.8 126.6 138.1 119.5 Z"></path>
<path class="segm-lad" id="a2c-1" POINTER-EVENTS="auto" d="M 141.6 160.8 c -0.7 -3.4 -1.2 -9.4 -1.7 -16.1 l -28.6 7.4 c 2.1 5.8 4.3 11.8 4.9 16.3 c 1.3 8.3 2.8 14.6 2 22.7 c -0.4 4.4 0.2 9.7 -0.8 13.5 c -0.8 3.1 -4.6 13.2 2 16 c 7 3 16.8 -10.8 19 -14 c 4 -6 3.7 -8.2 6 -17 C 146.8 180.7 143.1 168.6 141.6 160.8 Z"></path>
</NodeList>
Given the NodeList in your scenario already exists, it's hard to see how it can be done without iterations.
However, an alternative could be to create the NodeList according to the desired id, in the first place.
For example:
let getRelatedElements = id =>
document.querySelectorAll('[id$="-'+id.replace(/\D/g, '')+'"]:not(#'+id+')');
This uses a combination of an attribute-selector to select elements with the same numerical suffix and a :not selector to ignore the element with the original id.
I'm reading characters from an image into 20x20 chunks to perform optical character recognition (OCR) and am wondering how to implement the best way of centering the binary data matrix.
For example, the character h might be converted into the following one-dimensional array (spaces and newlines added for clarity):
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0
0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0
0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0
0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0
0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
As far as I know, there are two alternatives:
Center of mass
var mass = 0,
sum = {
x: 0,
y: 0
};
for(y = 0; y < size; y++) {
for(x = 0; x < size; x++) {
if(chunk[size * y + x]) {
sum.x += x;
sum.y += y;
mass++;
}
}
}
// diff center of mass and center of matrix
var diff = {
x: Math.round((size / 2) - (sum.x / mass)),
y: Math.round((size / 2) - (sum.y / mass))
};
// move 1's accordingly
Question is how to handle if this type of centering causes any of the 1's to be placed outside of the chunk and therefore corrupting the data?
Bounding box
Calculate center of min(x, y) and max(x, y) and diff with center of matrix.
Which of these would yield the best (most consistent) results if the input characters are randomly distorted (slightly) in both dimensions?
The resulting chunk is used in training a multi-layer perceptron (MLP) neural network, if that helps.
Ended up using the bounding box method:
var min = {
x: size,
y: size
};
var max = {
x: 0,
y: 0
};
for(y = 0; y < size; y++) {
for(x = 0; x < size; x++) {
if(chunk[size * y + x]) {
if(min.x > x)
min.x = x;
if(min.y > y)
min.y = y;
if(max.x < x)
max.x = x;
if(max.y < y)
max.y = y;
}
}
}
var diff = {
x: Math.floor((size / 2) - (min.x + (max.x - min.x) / 2)),
y: Math.floor((size / 2) - (min.y + (max.y - min.y) / 2))
};
// move 1's accordingly
I have drawn two path lines using SVG and I've saved these elements into two variables in my javascript code: 'Line1', and 'Line2', and I need to merge the two lines into one single path element. Is there a way to do so?
Are your paths defined relatively (small letters) or absolutely (capitals)? If absolute, joining two paths is trivial, just append the values of the d attribute. If you have two paths like this:
<path id="Line1" d="M50,50
A30,30 0 0,1 35,20
L100,100"
style="stroke:#660000; fill:none;"/>
<path id="Line2" d="M110,110
L100,0"
style="stroke:#660000; fill:none;"/>
Then this JavaScript code:
var Line1 = document.getElementById("Line1");
var Line2 = document.getElementById("Line2");
//Add paths together
Line1.setAttribute('d', Line1.getAttribute('d') + ' ' + Line2.getAttribute('d'));
//Remove unnecessary second path
Line2.parentNode.removeChild(Line2);
Will lead to you having a single path like this:
<path id="Line1" d="M50,50
A30,30 0 0,1 35,20
L100,100 M110,110
L100,0"
style="stroke:#660000; fill:none;"/>
Here's a jsFiddle, it works in Firefox 4 (needs an HTML5 parser so you can have inline SVG).
If your paths are relative then you're going to have to add something between the appended paths so that the second one starts in the correct place.
Concatenate d attributes
Usually, you can just concatenate the pathdata d attribute of several <path> elements to get a combined path.
Unfortunately, you might encounter some »bad practices« using M or m as interchangeable commands.
Common misconceptions about M or m:
M (moveto) can be absolute or relative.
Unlike the z (closepath) command (lowercase/uppercase – doesn't matter).
Relative m commands can be used used for compound paths like e.g the inner "hole" of the letter "o" referring to the previous command's end coordinate.
In fact, every first m or M command uses absolute coordinates – since there are no preceding points.
However, the first M command can be uppercase or lowercase – doesn't matter
(blame the specs)
Exception: the lowercase m command introduces a row of implicit relative l lineto commands. (But you can/should also avoid this)
Example 1: paths starting with (unnecessary) relative m command
svg{
border:1px solid #ccc;
width:25%;
}
path{
fill:#555;
}
<p>Seperate paths</p>
<svg viewBox="0 0 50 10">
<path id="path1" d="m 20 0 l 10 0 l 0 10 l -10 0z" />
<path id="path2" d="m 40 0 l 10 0 l 0 10 l -10 0z" />
<path id="path3" d="m 0 0 l 10 0 l 0 10 l -10 0z" />
</svg>
<p>Merged paths</p>
<svg viewBox="0 0 50 10">
<path id="pathConcat"
d="
m 20 0 l 10 0 l 0 10 l -10 0z
m 40 0 l 10 0 l 0 10 l -10 0z
m 0 0 l 10 0 l 0 10 l -10 0z
" />
</svg>
<p>Merged paths - fixed</p>
<svg viewBox="0 0 50 10">
<path id="pathConcat"
d="
M 20 0 l 10 0 l 0 10 l -10 0z
M 40 0 l 10 0 l 0 10 l -10 0z
M 0 0 l 10 0 l 0 10 l -10 0z
" />
</svg>
Fix: just replace each starting m with an absolute M
Example 2: m command for adjacent linetos
The exception are m commands followed by coordinates – used as a shorthand for succeeding l (relative linetos). (See also w3c specs.)
svg{
border:1px solid #ccc;
width:25%;
}
path{
fill:#555;
}
<p>Seperate paths</p>
<svg viewBox="0 0 50 10">
<path id="path1" d="m 20 0 10 0 0 10 -10 0z" />
<path id="path2" d="m 40 0 10 0 0 10 -10 0z" />
<path id="path3" d="m 0 0 10 0 0 10 -10 0z" />
</svg>
<p>Merged paths</p>
<svg viewBox="0 0 50 10">
<path id="pathConcat"
d="
m 20 0 10 0 0 10 -10 0z
m 40 0 10 0 0 10 -10 0z
m 0 0 10 0 0 10 -10 0z
" />
</svg>
<p>Merged paths - fixed</p>
<svg viewBox="0 0 50 10">
<path id="pathConcat"
d="
m 20 0 10 0 0 10 -10 0z
M 40 0 l 10 0 0 10 -10 0z
M 0 0 l 10 0 0 10 -10 0z
" />
</svg>
Fix: insert l commands
<path d="m 20 0 10 0 0 10 -10 0z" />
equals
<path d="M 20 0 l 10 0 l 0 10 l -10 0z" />
or
<path d="M 20 0 l 10 0 0 10 -10 0z" />
Example 3: fix pseudo relative m commands via getPathData()
Currently still a draft and not natively supported by major browser.
However you can use Jarek Foksa's polyfill..
getPathData() will return an array of command objects and normalize
repeated commands like this:
[
{type: 'm', values:[20, 0] },
{type: 'l', values:[10, 0]},
{type: 'l', values:[0, 10]},
{type: 'l', values:[-10, 0]}
]
function concatSimple(){
let d1= path1.getAttribute('d')
let d2= path2.getAttribute('d')
let d3= path3.getAttribute('d')
pathConcat.setAttribute('d', d1+d2)
}
function concatPathData(){
let pathData1= fixFirstM(path1.getPathData());
let pathData2= fixFirstM(path2.getPathData());
let pathData3= fixFirstM(path3.getPathData());
let pathDataConcat = pathData1.concat(pathData2).concat(pathData3);
pathConcat.setPathData(pathDataConcat);
}
// change first m to absolute M
function fixFirstM(pathData){
pathData[0].type='M';
return pathData;
}
svg{
border:1px solid #ccc;
width:25%;
}
path{
fill:#555;
}
<p><button onclick="concatSimple()">concat d simple</button>
<button onclick="concatPathData()">concat d pathData</button>
</p>
<svg viewBox="0 0 50 10">
<path id="path1" d="m 20 0 10 0 0 10 -10 0z" />
<path id="path2" d="m 40 0 10 0 0 10 -10 0z" />
<path id="path3" d="m 0 0 10 0 0 10 -10 0z" />
</svg>
<svg viewBox="0 0 50 10">
<path id="pathConcat" d="" />
</svg>
<script src="https://cdn.jsdelivr.net/npm/path-data-polyfill#1.0.4/path-data-polyfill.min.js"></script>
To fix the first relative m we can convert by changing the first command type
pathData[0].type='M';
Recommendation: only use relative m commands if they are actually relative:
if you need a shorthand for following l commands (like m 20 0 10 0 0 10 -10 0z)
for relative (subpath) starting points in compound paths – like the letter "o"
Actually merging shapes: removing overlapping shapes
If you need to merge shapes - paper.js has some powerful path operations like unite, subtract etc.
Explained here: "Merging two bezier-based shapes into one to create a new outline"