I have been successful in animating stroke-dashoffset
with value as <length>
as folllowing
const svg = document.querySelector("svg"); // variable for the namespace const svgns = "http://www.w3.org/2000/svg" //assigning svg element attribute svg.setAttribute('class', 'layer1'); svg.setAttribute('xmlns', svgns); svg.setAttribute('viewBox', '0 0 400 200'); //make background var fill1 = '#e6e6e6'; let bg = document.createElementNS(svgns, 'rect'); bg.setAttribute('class', 'bg'); bg.setAttribute('id', 'bg'); bg.setAttribute('width', '400'); bg.setAttribute('height', '200'); bg.setAttribute('fill', fill1); svg.appendChild(bg); //wrapper dimension var x = 20; var y = 50; var width = 200; var height = 50; let wrapper = document.createElementNS(svgns, 'rect'); wrapper.setAttribute('class', 'wrapper'); wrapper.setAttribute('id', 'wrapper'); wrapper.setAttribute('x', x); wrapper.setAttribute('y', y); wrapper.setAttribute('width', width); wrapper.setAttribute('height', height); wrapper.setAttribute('fill', 'none'); wrapper.setAttribute('stroke', 'black'); wrapper.setAttribute('stroke-width', '1'); svg.appendChild(wrapper); let tube = document.createElementNS(svgns, 'line'); tube.setAttribute('class', 'tube'); tube.setAttribute('id', 'tube'); tube.setAttribute('x1', x); tube.setAttribute('x2', x + width); tube.setAttribute('y1', y + height / 2); tube.setAttribute('y2', y + height / 2); tube.setAttribute('stroke', 'brown'); tube.setAttribute('stroke-width', '1'); svg.appendChild(tube); var ln = document.querySelector("#tube"); var path = ln.getTotalLength(); ln.style.setProperty("--off", path + 'px'); var pct = 0.60; var pxl = path - (path * pct); ln.style.setProperty('--offset', pxl); ln.style.setProperty('--v1', (path / svg.viewBox.baseVal.width) * 100 + '%'); ln.style.setProperty('--v2', (pxl / svg.viewBox.baseVal.width) * 100 + '%'); var gridNum = 10; var gridStart = width / gridNum; var counter = gridStart; for (var i = 0; i < gridNum; i++) { let ln = document.createElementNS(svgns, 'line'); ln.setAttribute('class', 'axisLines' + i); ln.setAttribute('id', 'axisLines' + i); var x1 = x + counter; ln.setAttribute('x1', x1); ln.setAttribute('x2', x + counter); ln.setAttribute('y1', y); ln.setAttribute('y2', y + height); ((gridNum / 2) - 1) == i ? ln.setAttribute('stroke', 'red') : ln.setAttribute('stroke', 'green'); ln.setAttribute('stroke-width', '1.5'); svg.appendChild(ln); counter = counter + gridStart; let tl = document.createElementNS(svgns, 'title'); ((gridNum / 2) - 1) == i ? tl.textContent = `Middle Coordinate ${x1-x},${y}` : tl.textContent = `Coordinate ${x1-x},${y}`; svg.appendChild(tl); ln.appendChild(tl); }
.tube { stroke-dasharray: var(--off); stroke-dashoffset: var(--off); animation: effect 4s ease-out infinite forwards; } @keyframes effect { 100% { stroke-dashoffset: var(--offset); } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <link rel="stylesheet" href="style.css"> </link> <svg> <script href="index.js"></script> </svg> </body> </html>
However, I am trying to figure out how can I calculate the exact %
value in css if I decide to use <percentage>
instead of value
.
I came to know from this post that percentages are calculated in respect to the current viewport, which I tried as
ln.style.setProperty('--v1', (path / svg.viewBox.baseVal.width) * 100 + '%');
and
ln.style.setProperty('--v2', (pxl / svg.viewBox.baseVal.width) * 100 + '%');
But passing on the above to CSS as following does not produce the same animation
.tube { stroke-dasharray: var(--v1); stroke-dashoffset: var(--v1); animation: effect 4s ease-out infinite forwards; } @keyframes effect { 100% { stroke-dashoffset: var(--v2); } }
Advertisement
Answer
You need to calculate the normalised hypotenuse of the width and the height.
const svg = document.querySelector("svg"); // variable for the namespace const svgns = "http://www.w3.org/2000/svg" //assigning svg element attribute svg.setAttribute('class', 'layer1'); svg.setAttribute('xmlns', svgns); svg.setAttribute('viewBox', '0 0 400 200'); //make background var fill1 = '#e6e6e6'; let bg = document.createElementNS(svgns, 'rect'); bg.setAttribute('class', 'bg'); bg.setAttribute('id', 'bg'); bg.setAttribute('width', '400'); bg.setAttribute('height', '200'); bg.setAttribute('fill', fill1); svg.appendChild(bg); //wrapper dimension var x = 20; var y = 50; var width = 200; var height = 50; let wrapper = document.createElementNS(svgns, 'rect'); wrapper.setAttribute('class', 'wrapper'); wrapper.setAttribute('id', 'wrapper'); wrapper.setAttribute('x', x); wrapper.setAttribute('y', y); wrapper.setAttribute('width', width); wrapper.setAttribute('height', height); wrapper.setAttribute('fill', 'none'); wrapper.setAttribute('stroke', 'black'); wrapper.setAttribute('stroke-width', '1'); svg.appendChild(wrapper); let tube = document.createElementNS(svgns, 'line'); tube.setAttribute('class', 'tube'); tube.setAttribute('id', 'tube'); tube.setAttribute('x1', x); tube.setAttribute('x2', x + width); tube.setAttribute('y1', y + height / 2); tube.setAttribute('y2', y + height / 2); tube.setAttribute('stroke', 'brown'); tube.setAttribute('stroke-width', '1'); svg.appendChild(tube); var ln = document.querySelector("#tube"); var path = ln.getTotalLength(); ln.style.setProperty("--off", path + 'px'); var pct = 0.60; var pxl = path - (path * pct); ln.style.setProperty('--offset', pxl); let normalised_hypotenuse = Math.sqrt(svg.viewBox.baseVal.width ** 2 + svg.viewBox.baseVal.height ** 2) / Math.sqrt(2); ln.style.setProperty('--v1', (path / normalised_hypotenuse) * 100 + '%'); ln.style.setProperty('--v2', (pxl / normalised_hypotenuse) * 100 + '%'); var gridNum = 10; var gridStart = width / gridNum; var counter = gridStart; for (var i = 0; i < gridNum; i++) { let ln = document.createElementNS(svgns, 'line'); ln.setAttribute('class', 'axisLines' + i); ln.setAttribute('id', 'axisLines' + i); var x1 = x + counter; ln.setAttribute('x1', x1); ln.setAttribute('x2', x + counter); ln.setAttribute('y1', y); ln.setAttribute('y2', y + height); ((gridNum / 2) - 1) == i ? ln.setAttribute('stroke', 'red') : ln.setAttribute('stroke', 'green'); ln.setAttribute('stroke-width', '1.5'); svg.appendChild(ln); counter = counter + gridStart; let tl = document.createElementNS(svgns, 'title'); ((gridNum / 2) - 1) == i ? tl.textContent = `Middle Coordinate ${x1-x},${y}` : tl.textContent = `Coordinate ${x1-x},${y}`; svg.appendChild(tl); ln.appendChild(tl); }
.tube { stroke-dasharray: var(--v1); stroke-dashoffset: var(--v1); animation: effect 4s ease-out infinite forwards; } @keyframes effect { 100% { stroke-dashoffset: var(--v2); } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <link rel="stylesheet" href="style.css"> </link> <svg> <script href="index.js"></script> </svg> </body> </html>