I have two SVG rectangles; two of their corners are connected by a SVGLine, and I am trying to animate the whole.
Now the rectangles are moving to a new position using the Element.animate()
function (the new positions have to be computed at runtime so I think it is only possible with the animate()
function in JS?).
Until that point everything works fine, but when I try to animate the line so that it is still connecting the corners during the animation, it won´t move.
Is there any way to animate the lines movement to the new position? (I can´t just set the attribute to the new position).
If I have to use a <path>
or <polyline>
or something for that a quick explanation on how I should do that would be great, as path.animate([{points:...},{points:...}],{...})
also didn’t move the path as i wanted.
This is a quick code example which I think should work, but the line won’t move.
let svg = document.querySelector("#theSVG"); const SVGNS = "http://www.w3.org/2000/svg"; function drawing() { let rect = document.createElementNS(SVGNS, "rect"); rect.setAttribute("x", 100); rect.setAttribute("y", 100); rect.setAttribute("width", 100); rect.setAttribute("height", 100); rect.setAttribute("stroke", "black"); svg.appendChild(rect); let rect2 = document.createElementNS(SVGNS, "rect"); rect2.setAttribute("x", 10); rect2.setAttribute("y", 10); rect2.setAttribute("width", 50); rect2.setAttribute("height", 25); rect2.setAttribute("stroke", "black"); svg.appendChild(rect2); let line = document.createElementNS(SVGNS, "line"); line.setAttribute("x1", rect.x.baseVal.value); line.setAttribute("x2", rect2.x.baseVal.value); line.setAttribute("y1", rect.y.baseVal.value); line.setAttribute("y2", rect2.y.baseVal.value); line.setAttribute("stroke", "darkgray"); svg.appendChild(line); rect.animate([{ x: rect.x.baseVal.value }, { x: '200px' }], { duration: 5000, iterations: 1 }); rect2.animate([{ y: rect2.y.baseVal.value }, { y: '300px' }], { duration: 5000, iterations: 1 }); line.animate([{ x1: line.x1.baseVal.value, y2: line.y2.baseVal.value }, { x1: '200px', y2: '300px' }], { duration: 5000, iterations: 1 }); } drawing();
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 700 360" id="theSVG"> </svg>
Advertisement
Answer
You can only animate()
CSS properties. From SVG, only presentational attributes are mapped to CSS. <line>
‘s x1
,x2
,y1
and y2
are (weirdly) absent of this list…
You should be able to replace this element with a <path>
though, animating its d
attribute.
let svg = document.querySelector("#theSVG"); const SVGNS = "http://www.w3.org/2000/svg"; function drawing() { let rect = document.createElementNS(SVGNS, "rect"); rect.setAttribute("x", 100); rect.setAttribute("y", 100); rect.setAttribute("width", 100); rect.setAttribute("height", 100); rect.setAttribute("stroke", "black"); svg.appendChild(rect); let rect2 = document.createElementNS(SVGNS, "rect"); rect2.setAttribute("x", 10); rect2.setAttribute("y", 10); rect2.setAttribute("width", 50); rect2.setAttribute("height", 25); rect2.setAttribute("stroke", "black"); svg.appendChild(rect2); let line = document.createElementNS(SVGNS, "path"); line.setAttribute("d", ` M${ rect.x.baseVal.value } ${ rect.y.baseVal.value } L${ rect2.x.baseVal.value } ${ rect2.y.baseVal.value } `); line.setAttribute("stroke", "darkgray"); svg.appendChild(line); rect.animate([{ x: '200px' }], { duration: 5000, iterations: 1 }); rect2.animate([{ y: '300px' }], { duration: 5000, iterations: 1 }); line.animate([{ d: `path("M200 ${ rect.y.baseVal.value }L${ rect2.x.baseVal.value } 300")` }], { duration: 5000, iterations: 1 }); } drawing();
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 700 360" id="theSVG"> </svg>
But only Chromium based browsers do support CSS path()
for the d
property…
So you may have to switch to SMIL animations instead:
let svg = document.querySelector("#theSVG"); const SVGNS = "http://www.w3.org/2000/svg"; function drawing() { const rect = document.createElementNS(SVGNS, "rect"); rect.setAttribute("x", 100); rect.setAttribute("y", 100); rect.setAttribute("width", 100); rect.setAttribute("height", 100); rect.setAttribute("stroke", "black"); svg.appendChild(rect); const rectAnimateX = document.createElementNS(SVGNS, "animate"); rectAnimateX.setAttribute("attributeName", "x"); rectAnimateX.setAttribute("values", "100;200"); rectAnimateX.setAttribute("dur", "5s"); rect.append(rectAnimateX); let rect2 = document.createElementNS(SVGNS, "rect"); rect2.setAttribute("x", 10); rect2.setAttribute("y", 10); rect2.setAttribute("width", 50); rect2.setAttribute("height", 25); rect2.setAttribute("stroke", "black"); svg.appendChild(rect2); const rectAnimateY = document.createElementNS(SVGNS, "animate"); rectAnimateY.setAttribute("attributeName", "y"); rectAnimateY.setAttribute("values", "10;300"); rectAnimateY.setAttribute("dur", "5s"); rect2.append(rectAnimateY); const line = document.createElementNS(SVGNS, "line"); line.setAttribute("x1", rect.x.baseVal.value); line.setAttribute("y1", rect.y.baseVal.value); line.setAttribute("x2", rect2.x.baseVal.value); line.setAttribute("y2", rect2.y.baseVal.value); line.setAttribute("stroke", "darkgray"); svg.appendChild(line); const lineAnimateX1 = document.createElementNS(SVGNS, "animate"); lineAnimateX1.setAttribute("attributeName", "x1"); lineAnimateX1.setAttribute("values", `${rect.x.baseVal.value};200`); lineAnimateX1.setAttribute("dur", "5s"); line.append(lineAnimateX1); const lineAnimateY2 = document.createElementNS(SVGNS, "animate"); lineAnimateY2.setAttribute("attributeName", "y2"); lineAnimateY2.setAttribute("values", `${rect2.y.baseVal.value};300`); lineAnimateY2.setAttribute("dur", "5s"); line.append(lineAnimateY2); } drawing();
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 700 360" id="theSVG"> </svg>