Make arm point towards mouse direction - javascript

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>

Related

Adding numbering to SVG path shapes in JavaScript using .getBBox() method

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

SVG: how to draw multiple semicircles (arcs) path

Using the answer from this thread I was able to draw a semicircle (arc):
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}
function describeArc(x, y, radius, startAngle, endAngle) {
var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);
var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
var d = [
"M", start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");
console.log(d)
return d;
}
window.onload = function() {
document.getElementById("arc1").setAttribute("d", describeArc(100, 100, 50, -90, 90));
};
<svg width="1000" height="1000">
<path id="arc1" fill="red" stroke="#446688" stroke-width="2" />
</svg>
What I'm trying to achieve is to be able to draw an SVG as a path consistent with many arcs (semicircles) and be able to set fill on them.
Something like this:
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 50 100 A 10 10 0 0 1 100 100 M 100 100 A 10 10 0 0 1 150 100 M 150 100 A 10 10 0 0 1 200 100 M 200 100 A 10 10 0 0 1 250 100" fill="red" stroke="blue" stroke-width="3" />
</svg>
Is there a better way to achieve a simpler path? For now, it looks like this:
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 50 100 A 10 10 0 0 1 100 100 M 100 100 A 10 10 0 0 1 150 100 M 150 100 A 10 10 0 0 1 200 100 M 200 100 A 10 10 0 0 1 250 100" fill="red" stroke="blue" stroke-width="3" />
</svg>
Or do I have to generate a longer and longer path when there are, let's say, 30 semicircles?
Edit: the IE9+ support is required. Also, those elements will be clickable, draggable and controllable. By controllable I mean that their number and size will change when mouse clicking/moving.
I choose my first approach with a dynamic very long path.
Thanks!
For this I would use lower case commands. For example this is drawing the arc you need: an arc with a radius of 25 and an ending point 50 units ( 2 * 25 ) away from the starting point of the arc.
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 50 100 a 25 25 0 0 1 50 0" fill="red" stroke="blue" stroke-width="3" />
</svg>
In order to get a path of 4 arcs you need to repeat the arc (a 25 25 0 0 1 50 0) 4 times something like this:
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 50 100 a 25 25 0 0 1 50 0
a 25 25 0 0 1 50 0
a 25 25 0 0 1 50 0
a 25 25 0 0 1 50 0 " fill="red" stroke="blue" stroke-width="3" />
</svg>
It's easy to see how you can use javascript to generate the d attribute you need:
let d ="M 50 100";
for(let i=0; i<4;i++){d +="a 25 25 0 0 1 50 0 "}
document.querySelector("path").setAttribute("d",d);
<svg xmlns="http://www.w3.org/2000/svg">
<path d="M 50 100" fill="red" stroke="blue" stroke-width="3" />
</svg>
You can use a vanilla JavaScript Web Component (supported in all modern Browsers) to create the SVG
Your Custom Element <svg-arcs repeat="7"></svg-arcs> then creates:
<style>
svg { background: pink }
svg path { stroke-width: 3 }
</style>
<svg-arcs repeat="30"></svg-arcs>
<script>
customElements.define("svg-arcs", class extends HTMLElement {
connectedCallback() {
let repeat = this.getAttribute("repeat") || 5;
let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
for (let x = 0; x < repeat; x++) {
let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute("d", `M${3 + 50*x} 100 A 10 10 0 0 1 ${50+50*x} 100`);
path.setAttribute("fill", "red");
path.setAttribute("stroke", "blue");
svg.append(path);
}
svg.setAttribute("viewBox", `0 0 ${50*repeat + 3} 150`);
this.append(svg);
}
})
</script>
For more dynamic control over individual arcs see the Web Component in SO post:
Firefox: shadow-DOM compatibility
You could use a pattern and size your patterned object appropriately. Here is one that accomodates 4 iterations.
Edit & Update:
If you want those arcs to be independently clickable/draggable, then they need to be separately addressable in the DOM. The "use" element might be what you're looking for.
svg {
background: grey;
}
<svg width="800px" height="600px">
<defs>
<path id="arc-template" d="M1.5 50 a 10 10 0 0 1 97 0" fill="red" stroke="blue" stroke-width="3" />
</defs>
<use id="arc1" href="#arc-template" x="50" y="100"/>
<use id="arc2" href="#arc-template" x="150" y="100"/>
<use id="arc3" href="#arc-template" x="250" y="100"/>
<use id="arc4" href="#arc-template" x="350" y="100"/>
</svg>

Creating text out of SVG <path>'s [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 2 years ago.
Improve this question
I'm wondering if theres any tools to create text out of SVG <path> elements. I found this codepen I really like and would like to be able to use it with my own text.
Sorry if this is a stupid question but I tried looking on google and couldn't find anything
https://codepen.io/robin-dela/pen/KKPYoBq
Yes, you can there are a lot of tools to help you in that by entering the text and it will convert it to SVG path for example Google font to SVG path tool.
every time you want to change the text just use Google font to SVG path to generate your word SVG path and put it into your code.
here is an example based on your Codepen:
var vertex = `
attribute vec2 uv;
attribute vec2 position;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 0, 1);
}
`;
var fragment = `
precision highp float;
precision highp int;
uniform sampler2D tWater;
uniform sampler2D tFlow;
uniform float uTime;
varying vec2 vUv;
uniform vec4 res;
uniform vec2 img;
vec2 centeredAspectRatio(vec2 uvs, vec2 factor){
return uvs * factor - factor /2. + 0.5;
}
void main() {
// R and G values are velocity in the x and y direction
// B value is the velocity length
vec3 flow = texture2D(tFlow, vUv).rgb;
vec2 uv = .5 * gl_FragCoord.xy / res.xy ;
// vec2 uv = .5 * gl_FragCoord.xy / res.xy ;
vec2 myUV = (uv - vec2(0.5))*res.zw + vec2(0.5);
myUV -= flow.xy * (0.15 * 1.2);
vec2 myUV2 = (uv - vec2(0.5))*res.zw + vec2(0.5);
myUV2 -= flow.xy * (0.125 * 1.2);
vec2 myUV3 = (uv - vec2(0.5))*res.zw + vec2(0.5);
myUV3 -= flow.xy * (0.10 * 1.4);
vec3 tex = texture2D(tWater, myUV).rgb;
vec3 tex2 = texture2D(tWater, myUV2).rgb;
vec3 tex3 = texture2D(tWater, myUV3).rgb;
gl_FragColor = vec4(tex.r, tex2.g, tex3.b, 1.0);
}
`;
{
var _size = [2048, 1638];
var renderer = new ogl.Renderer({ dpr: 2 });
var gl = renderer.gl;
document.body.appendChild(gl.canvas);
// Variable inputs to control flowmap
var aspect = 1;
var mouse = new ogl.Vec2(-1);
var velocity = new ogl.Vec2();
function resize() {
gl.canvas.width = window.innerWidth * 2.0;
gl.canvas.height = window.innerHeight * 2.0;
gl.canvas.style.width = window.innerWidth + "px";
gl.canvas.style.height = window.innerHeight + "px";
var a1, a2;
var imageAspect = _size[1] / _size[0];
if (window.innerHeight / window.innerWidth < imageAspect) {
a1 = 1;
a2 = window.innerHeight / window.innerWidth / imageAspect;
} else {
a1 = window.innerWidth / window.innerHeight * imageAspect;
a2 = 1;
}
mesh.program.uniforms.res.value = new ogl.Vec4(
window.innerWidth,
window.innerHeight,
a1,
a2);
renderer.setSize(window.innerWidth, window.innerHeight);
aspect = window.innerWidth / window.innerHeight;
}
var flowmap = new ogl.Flowmap(gl, {
falloff: 0.3,
dissipation: 0.92,
alpha: 0.5 });
// Triangle that includes -1 to 1 range for 'position', and 0 to 1 range for 'uv'.
var geometry = new ogl.Geometry(gl, {
position: {
size: 2,
data: new Float32Array([-1, -1, 3, -1, -1, 3]) },
uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) } });
var texture = new ogl.Texture(gl, {
minFilter: gl.LINEAR,
magFilter: gl.LINEAR });
var img = new Image();
img.onload = () => texture.image = img;
img.crossOrigin = "Anonymous";
img.src = "https://robindelaporte.fr/codepen/bg3.jpg";
var a1, a2;
var imageAspect = _size[1] / _size[0];
if (window.innerHeight / window.innerWidth < imageAspect) {
a1 = 1;
a2 = window.innerHeight / window.innerWidth / imageAspect;
} else {
a1 = window.innerWidth / window.innerHeight * imageAspect;
a2 = 1;
}
var program = new ogl.Program(gl, {
vertex,
fragment,
uniforms: {
uTime: { value: 0 },
tWater: { value: texture },
res: {
value: new ogl.Vec4(window.innerWidth, window.innerHeight, a1, a2) },
img: { value: new ogl.Vec2(_size[1], _size[0]) },
// Note that the uniform is applied without using an object and value property
// This is because the class alternates this texture between two render targets
// and updates the value property after each render.
tFlow: flowmap.uniform } });
var mesh = new ogl.Mesh(gl, { geometry, program });
window.addEventListener("resize", resize, false);
resize();
// Create handlers to get mouse position and velocity
var isTouchCapable = ("ontouchstart" in window);
if (isTouchCapable) {
window.addEventListener("touchstart", updateMouse, false);
window.addEventListener("touchmove", updateMouse, { passive: false });
} else {
window.addEventListener("mousemove", updateMouse, false);
}
var lastTime;
var lastMouse = new ogl.Vec2();
function updateMouse(e) {
e.preventDefault();
if (e.changedTouches && e.changedTouches.length) {
e.x = e.changedTouches[0].pageX;
e.y = e.changedTouches[0].pageY;
}
if (e.x === undefined) {
e.x = e.pageX;
e.y = e.pageY;
}
// Get mouse value in 0 to 1 range, with y flipped
mouse.set(e.x / gl.renderer.width, 1.0 - e.y / gl.renderer.height);
// Calculate velocity
if (!lastTime) {
// First frame
lastTime = performance.now();
lastMouse.set(e.x, e.y);
}
var deltaX = e.x - lastMouse.x;
var deltaY = e.y - lastMouse.y;
lastMouse.set(e.x, e.y);
var time = performance.now();
// Avoid dividing by 0
var delta = Math.max(10.4, time - lastTime);
lastTime = time;
velocity.x = deltaX / delta;
velocity.y = deltaY / delta;
// Flag update to prevent hanging velocity values when not moving
velocity.needsUpdate = true;
}
requestAnimationFrame(update);
function update(t) {
requestAnimationFrame(update);
// Reset velocity when mouse not moving
if (!velocity.needsUpdate) {
mouse.set(-1);
velocity.set(0);
}
velocity.needsUpdate = false;
// Update flowmap inputs
flowmap.aspect = aspect;
flowmap.mouse.copy(mouse);
// Ease velocity input, slower when fading out
flowmap.velocity.lerp(velocity, velocity.len ? 0.15 : 0.1);
flowmap.update();
program.uniforms.uTime.value = t * 0.01;
renderer.render({ scene: mesh });
}
}
body {
position: fixed;
height: 100%;
overflow: hidden;
}
canvas {
position: absolute;
width: 100%;
height: 100vh;
top: 0;
left: 0;
}
.mask {
position: absolute;
z-index: 2;
background: white;
height: 100vh;
width: 100vw;
mix-blend-mode: screen;
/* display: none; */
}
svg {
width: 90%;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
<script src="https://robindelaporte.fr/codepen/bundle.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
<div class="mask">
<svg id="Layer_1" width="500.25" height="300.401" viewBox="0 0 124.25 35.401" xmlns="http://www.w3.org/2000/svg"><g id="svgGroup" stroke-linecap="round" fill-rule="evenodd" font-size="9pt" stroke="#000" stroke-width="0.25mm" fill="" ><path class="st0" d="M 0.287 14.019 A 28.282 28.282 0 0 0 0 18.15 A 32.323 32.323 0 0 0 0.167 21.511 Q 0.796 27.521 3.8 31 Q 7.6 35.4 14.525 35.4 Q 21.45 35.4 25.875 30.575 Q 30.3 25.75 30.3 16.75 Q 30.3 12.5 29.225 9.3 Q 28.579 7.375 27.769 5.984 A 10.057 10.057 0 0 0 26.625 4.375 Q 25.1 2.65 22.95 1.625 A 22.239 22.239 0 0 0 22.015 1.205 Q 21.254 0.884 20.556 0.663 A 11.47 11.47 0 0 0 19.1 0.3 Q 17.4 0 15.55 0 A 14.963 14.963 0 0 0 10.221 0.967 A 17.387 17.387 0 0 0 5.45 3.75 A 10.119 10.119 0 0 0 4.91 4.213 Q 3.765 5.263 2.846 6.738 A 17.31 17.31 0 0 0 1.5 9.425 A 17.43 17.43 0 0 0 1.384 9.722 Q 0.631 11.696 0.287 14.019 Z M 15.1 30.7 Q 24.05 30.7 24.05 17.55 A 28.133 28.133 0 0 0 23.703 12.915 Q 22.273 4.4 14.95 4.4 A 9.734 9.734 0 0 0 12.536 4.685 A 7.198 7.198 0 0 0 9.675 6.125 Q 7.6 7.85 6.8 10.425 Q 6 13 6 16.4 A 33.631 33.631 0 0 0 6.32 21.26 Q 7.706 30.7 15.1 30.7 Z" id="0" vector-effect="non-scaling-stroke"/><path class="st0" d="M 33.7 13.4 L 33.7 10.8 A 1.08 1.08 0 0 1 33.737 10.503 Q 33.833 10.17 34.172 10.082 A 1.105 1.105 0 0 1 34.45 10.05 L 41.3 10.05 A 0.819 0.819 0 0 1 41.618 10.108 Q 41.978 10.258 42.05 10.8 L 42.45 13.7 A 8.722 8.722 0 0 1 45.429 10.703 Q 47.085 9.726 49.233 9.542 A 11.966 11.966 0 0 1 50.25 9.5 A 9.347 9.347 0 0 1 52.894 9.848 Q 55.914 10.738 57.1 13.9 A 9.588 9.588 0 0 1 59.583 11.134 Q 61.533 9.704 64.18 9.526 A 11.433 11.433 0 0 1 64.95 9.5 A 10.083 10.083 0 0 1 68.146 9.963 Q 72.659 11.47 72.7 17.882 A 18.445 18.445 0 0 1 72.7 18 L 72.7 30.85 L 75.55 30.85 A 1.08 1.08 0 0 1 75.847 30.887 Q 76.18 30.983 76.268 31.322 A 1.105 1.105 0 0 1 76.3 31.6 L 76.3 34.05 A 1.08 1.08 0 0 1 76.263 34.347 Q 76.168 34.68 75.828 34.768 A 1.105 1.105 0 0 1 75.55 34.8 L 64.55 34.8 A 1.08 1.08 0 0 1 64.253 34.763 Q 63.921 34.668 63.832 34.328 A 1.105 1.105 0 0 1 63.8 34.05 L 63.8 31.6 A 1.08 1.08 0 0 1 63.837 31.303 Q 63.933 30.97 64.272 30.882 A 1.105 1.105 0 0 1 64.55 30.85 L 67.1 30.85 L 67.1 20.5 A 19.73 19.73 0 0 0 67.04 18.905 Q 66.916 17.374 66.531 16.396 A 4.228 4.228 0 0 0 66.3 15.9 A 2.552 2.552 0 0 0 64.913 14.738 Q 64.155 14.45 63.075 14.45 A 7.356 7.356 0 0 0 61.458 14.618 Q 60.129 14.917 59.2 15.75 A 4.704 4.704 0 0 0 58.275 16.857 A 3.756 3.756 0 0 0 57.75 18.8 L 57.75 30.85 L 60.15 30.85 A 1.08 1.08 0 0 1 60.447 30.887 Q 60.78 30.983 60.868 31.322 A 1.105 1.105 0 0 1 60.9 31.6 L 60.9 34.05 A 1.08 1.08 0 0 1 60.863 34.347 Q 60.768 34.68 60.428 34.768 A 1.105 1.105 0 0 1 60.15 34.8 L 49.9 34.8 A 1.08 1.08 0 0 1 49.603 34.763 Q 49.271 34.668 49.182 34.328 A 1.105 1.105 0 0 1 49.15 34.05 L 49.15 31.6 A 1.08 1.08 0 0 1 49.187 31.303 Q 49.283 30.97 49.622 30.882 A 1.105 1.105 0 0 1 49.9 30.85 L 52.15 30.85 L 52.15 20.5 A 19.73 19.73 0 0 0 52.09 18.905 Q 51.966 17.374 51.581 16.396 A 4.228 4.228 0 0 0 51.35 15.9 A 2.534 2.534 0 0 0 50.001 14.758 Q 49.535 14.575 48.943 14.501 A 6.978 6.978 0 0 0 48.075 14.45 A 6.698 6.698 0 0 0 46.432 14.641 A 4.652 4.652 0 0 0 44.175 15.925 A 5.128 5.128 0 0 0 43.106 17.519 A 4.719 4.719 0 0 0 42.75 19.35 L 42.75 30.85 L 45.8 30.85 A 1.08 1.08 0 0 1 46.097 30.887 Q 46.43 30.983 46.518 31.322 A 1.105 1.105 0 0 1 46.55 31.6 L 46.55 34.05 A 1.08 1.08 0 0 1 46.513 34.347 Q 46.418 34.68 46.078 34.768 A 1.105 1.105 0 0 1 45.8 34.8 L 34.5 34.8 A 1.08 1.08 0 0 1 34.203 34.763 Q 33.871 34.668 33.782 34.328 A 1.105 1.105 0 0 1 33.75 34.05 L 33.75 31.6 A 1.08 1.08 0 0 1 33.787 31.303 Q 33.883 30.97 34.222 30.882 A 1.105 1.105 0 0 1 34.5 30.85 L 37.15 30.85 L 37.15 14.15 L 34.45 14.15 A 1.08 1.08 0 0 1 34.153 14.113 Q 33.821 14.018 33.732 13.678 A 1.105 1.105 0 0 1 33.7 13.4 Z" id="1" vector-effect="non-scaling-stroke"/><path class="st0" d="M 93.5 19.95 L 93.5 18.2 A 9.647 9.647 0 0 0 93.39 16.682 Q 93.268 15.915 93.008 15.33 A 2.968 2.968 0 0 0 91.5 13.75 A 4.051 4.051 0 0 0 90.823 13.539 Q 90.105 13.377 89.09 13.354 A 15.117 15.117 0 0 0 88.75 13.35 A 5.387 5.387 0 0 0 87.177 13.563 Q 85.452 14.089 84.826 15.917 A 5.734 5.734 0 0 0 84.65 16.55 A 1.491 1.491 0 0 1 84.559 16.851 Q 84.37 17.287 83.927 17.3 A 0.936 0.936 0 0 1 83.9 17.3 L 80.7 17.3 Q 79.9 17.3 80 16.55 A 7.966 7.966 0 0 1 80.439 14.271 A 5.867 5.867 0 0 1 82.95 11.2 A 10.731 10.731 0 0 1 86.13 9.912 Q 87.507 9.584 89.115 9.517 A 20.158 20.158 0 0 1 89.95 9.5 A 14.16 14.16 0 0 1 93.383 9.879 Q 97.836 10.995 98.695 15.405 A 12.019 12.019 0 0 1 98.9 17.7 L 98.9 30.85 L 101.05 30.85 A 1.08 1.08 0 0 1 101.347 30.887 Q 101.68 30.983 101.768 31.322 A 1.105 1.105 0 0 1 101.8 31.6 L 101.8 34.05 A 1.08 1.08 0 0 1 101.763 34.347 Q 101.668 34.68 101.328 34.768 A 1.105 1.105 0 0 1 101.05 34.8 L 95.15 34.8 A 0.819 0.819 0 0 1 94.832 34.742 Q 94.472 34.592 94.4 34.05 L 94.05 31.75 A 8.78 8.78 0 0 1 87.642 35.327 A 12.938 12.938 0 0 1 86.25 35.4 A 10.061 10.061 0 0 1 83.832 35.124 A 7.408 7.408 0 0 1 80.95 33.725 A 5.2 5.2 0 0 1 79.256 31.211 Q 78.964 30.324 78.882 29.235 A 11.781 11.781 0 0 1 78.85 28.35 Q 78.85 23.553 82.812 21.74 A 8.786 8.786 0 0 1 82.9 21.7 A 17.364 17.364 0 0 1 86.701 20.474 Q 88.465 20.11 90.481 20.017 A 29.489 29.489 0 0 1 90.9 20 Q 91.628 20 92.765 19.971 A 162.373 162.373 0 0 0 93.5 19.95 Z M 93.6 27.25 L 93.6 23.4 A 81.655 81.655 0 0 0 91.93 23.416 Q 88.594 23.484 87.7 23.85 A 25.7 25.7 0 0 0 86.663 24.3 A 18.714 18.714 0 0 0 85.75 24.75 Q 84.15 25.6 84.15 27.85 A 4.287 4.287 0 0 0 84.374 29.298 Q 85.054 31.195 87.791 31.295 A 8.517 8.517 0 0 0 88.1 31.3 A 8.903 8.903 0 0 0 89.683 31.168 Q 90.569 31.008 91.273 30.653 A 4.486 4.486 0 0 0 92.15 30.075 A 4.729 4.729 0 0 0 92.976 29.189 A 3.301 3.301 0 0 0 93.6 27.25 Z" id="2" vector-effect="non-scaling-stroke"/><path class="st0" d="M 124.25 10.8 L 124.25 17.55 A 1.08 1.08 0 0 1 124.213 17.847 Q 124.118 18.18 123.778 18.268 A 1.105 1.105 0 0 1 123.5 18.3 L 120.25 18.3 A 1.082 1.082 0 0 1 119.976 18.269 Q 119.52 18.149 119.549 17.573 A 1.474 1.474 0 0 1 119.55 17.55 L 119.75 14.65 Q 119.502 14.6 118.91 14.6 A 13.297 13.297 0 0 0 118.9 14.6 A 4.593 4.593 0 0 0 115.438 16.087 A 6.025 6.025 0 0 0 115.1 16.475 A 6.486 6.486 0 0 0 113.914 18.887 Q 113.661 19.831 113.612 20.948 A 12.535 12.535 0 0 0 113.6 21.5 L 113.6 30.85 L 119.1 30.85 A 1.08 1.08 0 0 1 119.397 30.887 Q 119.73 30.983 119.818 31.322 A 1.105 1.105 0 0 1 119.85 31.6 L 119.85 34.05 A 1.08 1.08 0 0 1 119.813 34.347 Q 119.718 34.68 119.378 34.768 A 1.105 1.105 0 0 1 119.1 34.8 L 105.35 34.8 A 1.08 1.08 0 0 1 105.053 34.763 Q 104.721 34.668 104.632 34.328 A 1.105 1.105 0 0 1 104.6 34.05 L 104.6 31.6 A 1.08 1.08 0 0 1 104.637 31.303 Q 104.733 30.97 105.072 30.882 A 1.105 1.105 0 0 1 105.35 30.85 L 108 30.85 L 108 14.15 L 105.3 14.15 A 1.08 1.08 0 0 1 105.003 14.113 Q 104.671 14.018 104.582 13.678 A 1.105 1.105 0 0 1 104.55 13.4 L 104.55 10.8 A 1.08 1.08 0 0 1 104.587 10.503 Q 104.683 10.17 105.022 10.082 A 1.105 1.105 0 0 1 105.3 10.05 L 111.9 10.05 A 0.966 0.966 0 0 1 112.25 10.109 Q 112.642 10.261 112.75 10.8 L 113.3 14.35 A 8.128 8.128 0 0 1 115.482 11.384 A 9.875 9.875 0 0 1 116.05 10.925 Q 117.95 9.5 120.2 9.5 A 20.41 20.41 0 0 1 121.444 9.535 Q 122.636 9.608 123.432 9.833 A 4.92 4.92 0 0 1 123.65 9.9 Q 124.123 10.058 124.223 10.525 A 1.309 1.309 0 0 1 124.25 10.8 Z" id="3" vector-effect="non-scaling-stroke"/></g> <style type="text/css">
.st0 {
fill-rule: evenodd;
clip-rule: evenodd;
}
</style>
</svg>
</div>
I think you need to write text in Svg Like this if you don't want to use path.
<svg height="90" width="200">
<text x="10" y="20" style="fill:red;">Several lines:
<tspan x="10" y="45">First line.</tspan>
<tspan x="10" y="70">Second line.</tspan>
</text
</svg>

Automatically scale an SVG to its parent

I'm trying to get an SVG to automatically scale down and fit vertically into its parent container.
The SVG is of a signature, and I want it to shrink vertically to fix into the div in question. Once this happens the width of the div will always be more than large enough to accommodate the rest of the svg.
The fiddle I have is here, and the markup is below.
http://jsfiddle.net/3v4e4/2/
Just messing with it, it looks like setting the viewBox equal to "0,0,1100,100" is about right, but I can't for the life of me generalize a rule for calculating that.
<div style="border: 1px solid black; width: 370px; height: 30px; margin: 30px;">
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"><path fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M 1 80 c 0.11 -0.19 3.59 -7.64 6 -11 c 5.2 -7.24 11.51 -13.76 17 -21 c 1.92 -2.53 3 -5.62 5 -8 c 6.6 -7.87 14.55 -15.43 21 -23 c 0.93 -1.09 1.95 -4.23 2 -4 c 0.14 0.71 -0.63 9.58 0 14 c 0.66 4.6 2.28 9.6 4 14 c 1.22 3.11 3 6.5 5 9 c 1.79 2.23 4.59 4.25 7 6 c 1.17 0.85 2.68 1.83 4 2 c 3.55 0.44 8.37 0.86 12 0 c 7.09 -1.67 14.75 -6.24 22 -8 c 4.65 -1.13 15 -1 15 -1"/><path fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M 21 52 c 0.12 -0.07 4.58 -3 7 -4 c 3.13 -1.29 6.72 -2.51 10 -3 c 3.14 -0.47 10 0 10 0"/><path fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M 108 64 c -0.02 -0.75 -0.75 -28.06 -1 -43 c -0.09 -5.56 -0.26 -10.84 0 -16 c 0.07 -1.33 0.21 -3.74 1 -4 c 2.11 -0.7 7.51 -0.39 11 0 c 2.31 0.26 4.63 1.58 7 2 c 3.27 0.58 6.88 0.08 10 1 c 11.18 3.3 23.97 7.93 34 12 c 1.18 0.48 2.27 1.86 3 3 c 2.16 3.35 4.65 7.3 6 11 c 1.2 3.3 1.61 7.33 2 11 c 0.28 2.63 0.68 5.63 0 8 c -1.82 6.37 -4.98 13.73 -8 20 c -1.21 2.51 -2.98 5.17 -5 7 c -5.02 4.56 -11.2 9.21 -17 13 c -2.67 1.75 -5.93 3.14 -9 4 c -5.08 1.42 -10.52 2.26 -16 3 c -7.11 0.96 -13.85 1.58 -21 2 l -13 0"/><path fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M 185 85 c 0.1 -0.26 4.17 -9.78 6 -15 c 2.97 -8.48 4.86 -16.77 8 -25 c 2.24 -5.89 5.71 -11.27 8 -17 c 1.01 -2.51 1.01 -6.02 2 -8 c 0.43 -0.86 2.4 -2.3 3 -2 c 1.31 0.65 3.69 3.81 5 6 c 3.61 6.01 7.11 12.56 10 19 c 1.4 3.13 2.26 6.59 3 10 c 0.93 4.3 0.84 8.79 2 13 c 3.16 11.44 11 34 11 34"/><path fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M 247 78 c 0.04 -0.05 2 -2.16 2 -3 c 0 -1.04 -1.01 -3.46 -2 -4 c -2.03 -1.11 -6.17 -0.95 -9 -2 c -6.05 -2.24 -11.84 -5.89 -18 -8 c -6.45 -2.21 -13.17 -3.73 -20 -5 c -7.69 -1.43 -23 -3 -23 -3"/><path fill="none" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M 280 87 c 0.04 -0.32 1.03 -11.97 2 -18 c 0.72 -4.44 2.28 -8.54 3 -13 c 1.31 -8.08 1.67 -16.57 3 -24 c 0.25 -1.37 1.71 -2.7 2 -4 c 0.32 -1.46 -0.11 -5.14 0 -5 c 0.2 0.27 2.38 6.09 3 9 c 0.33 1.54 -0.35 3.42 0 5 c 3.87 17.56 11.56 49.11 13 54 c 0.09 0.32 1.93 -1.97 2 -3 c 0.8 -11.75 -0.18 -27.39 1 -41 c 0.82 -9.44 3.67 -24.16 5 -28 c 0.21 -0.6 3.43 0.92 4 2 c 4.46 8.42 9.16 21.76 14 32 c 0.69 1.47 2.39 2.63 3 4 c 0.62 1.4 0.27 3.58 1 5 c 4.32 8.37 10.8 17.06 15 26 c 3.4 7.25 8 23 8 23"/></svg>
</div>
For scaling of an svg to work, you absolutely have to supply a viewBox which matches the bounding box of the contained elements. In your case that would be something like viewBox="0 0 360 100".
The bounding box can be calculated via javascript, but as I have read the getBBox() method is buggy in some cases. I can't comment further on that, but in this case and on chrome it works, see: http://jsfiddle.net/3v4e4/7/
Note that both getBBox() and setAttribute() are native methods and for setting the viewBox you absolutely have to use these. Using the jquery ´.attr()` method will not work as the SVG DOM is different from the HTML DOM which jquery is designed for: http://keith-wood.name/svg.html#dom
If you're using a modern browser, you might be able to just use your SVG as the src for an IMG and set the height to 100%.
Example: http://jsfiddle.net/kj7Wh/
<div style="border: 1px solid black; width: 370px; height: 30px; margin: 30px;">
<img src="http://openclipart.org/people/StefanvonHalenbach/StefanvonHalenbach_Battle_axe_medieval.svg" height="100%" />
</div>
might not work everywhere, but the zoom command on the svg element
svg{zoom:32%;}
or, you can save the this as an svg file and edit this inside illustrator

Is there a way to merge two path elements (svg) using Javascript?

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"

Categories

Resources