Web Animations API - How to solve parent rotate + child translate in svg elements?

79 Views Asked by At

Whenever I group (<g>) two or more SVG elements (e.g. two rects) and transform this group through rotation, I'm unable to correctly transform the individual children.

After a group rotation, an individual translation gives me two wrong behaviors:

  1. Both the rectangles move when I call r.translate(130,0).
  2. The translation movement is completely wrong, moving trought y axis even with ty = 0.

Is there a way to solve this within this API? Also: is this a good API to play with svg animation from JS?

var svg = document.getElementById('svg');
const svgNS = svg.namespaceURI;

class Object{

    constructor(type){
        this.element = document.createElementNS(svgNS, type)
        svg.appendChild(this.element)
    }

    setAttributes(list){
        for (let k in list)
            this.element.setAttribute(k, list[k])
    }

    gen_animation(keyframes){
        let options = {duration:1000, fill:"forwards", composite:'accumulate',
            easing: "cubic-bezier(0.42, 0, 0.58, 1)"}
        let currAnimation = this.element.animate(keyframes,options)
        this.promise = currAnimation.finished.then(a => {
                a.commitStyles();
                a.cancel();
          })
        return this.promise;
    }

    translate(x,y){
        return this.gen_animation([{ transform: `translate(${x}px, ${y}px) `}]);
    }
    rotate(angle){
        return this.gen_animation([{ transform: `rotate(${angle}deg)`}]);
    }
}

class Group extends Object{
    constructor(...args){
        super('g')
        for (let e of args){
            this.element.appendChild(e.element)
        }
    }
}

class Rectangle extends Object{
    constructor(x,y,w,h){
        super('rect')
        this.setAttributes({'x':x,'y':y,'width':w,'height':h,'fill':'none',
            stroke:'black','stroke-width':5})
    }
}

var r = new Rectangle(20,40,50,50)
var r2 = new Rectangle(80,40,50,50)
var g = new Group(r,r2)

 setTimeout(async ()=>{
    await g.rotate(45);
    r.translate(130,0)
},1) 
svg * {
    transform-box: fill-box;
    transform-origin: center;
}
<!DOCTYPE HTML>

<svg viewbox="0 0 250 150" version="1.1" width="250" height="150" id="svg" xmlns="http://www.w3.org/2000/svg"></svg>

1

There are 1 best solutions below

1
On

so have a look at this post

<g transform="scale(1,-1) translate(0,-200)">
  ...
</g>

Obviously you have to adjust the translate values. This is common use case as in computer graphics the y=0 is on the top (opposite to Cartesian coordinate system).

I used it extensively in an open source library I created. Have a look how it works in my project accessible-svg-graphs project. There is a full demo in my website.