简体   繁体   中英

Svg scaling rotated elements on mouse drag

I'm playing around with svgs and matrixes for a project I'd like to work on and I'm trying to implement a free transform with vanilla javascript. As of now I am able to do all transformations with javascript and this library https://www.npmjs.com/package/transformation-matrix#transform ,to help me dealing with matrixes. My code for now is only working with rect elements, but I assume most of the code did will be of use for other elements with some changes.

The problem arise when I try to scale a rotated rect. In my code, when I click on an element I give it a path around the element, some circles that represent the direction you can scale the rect, 1 for the center and 1 for the rotation.

As I've said I don't have any problem with whatever transformation, be it to translate a rotated/scaled shape or anything else, the only thing i can't figure out how to do is how to scale a rotated shape keeping it's rotation.

If a rect has 0 rotation, depending on which direction i decide to scale i just do a mix of translate and scale after i get the new width/height based on mouse pointer. This works great and as intended. If a rect has rotation this breaks and i tought maybe using the euclidean distance between the point from which i scale and the mouse pointer would work but it doesn't. so i am kinda lost on this.

        const elem = document.getElementById('rect2');
        const x = elem.x.baseVal.value;
        const y = elem.y.baseVal.value;
        const width = elem.width.baseVal.value;
        const height = elem.height.baseVal.value;

        // this is a function that return the mouse coords on the canvas- 
        // svg
        const m = this.getCanvasMousePos(e);

        if(type === 'bottom-center'){
            const newH = (m.y - y) / height;
            const s = scale(1,newH);
            const form = toSVG(s);
            elem.setAttribute('transform', form);
        }else if (type === 'top-center'){
            const newH = (y+height - m.y) / height;
            const s = scale(1,newH);
            const t = translate(0,m.y-y)
            const comp = compose(t,s);
            const form = toSVG(comp);
            elem.setAttribute('transform', form);
        }else if (type === 'middle-left') {
            const newW = (x+width - m.x) / width;
            const s = scale(newW,1);
            const t = translate(m.x-x, 0);
            const comp = compose(t,s)
            const form = toSVG(comp);
            elem.setAttribute('transform', form);
        }else if (type === 'middle-right') {
            const newW = (m.x - x) / width;
            const s = scale(newW,1);
            const form = toSVG(s);
            elem.setAttribute('transform', form);
        }else if (type === 'bottom-right') {
            const newW = (m.x - x) / width;
            const newH = (m.y - y) / height;
            const s = scale(newW,newH);
            const form = toSVG(s);
            elem.setAttribute('transform', form);
        }else if (type === 'bottom-left'){
            const newW = ((x + width) - m.x) / width;
            const newH = (m.y - y) / height;
            const t = translate(m.x - x,0);
            const s = scale(newW,newH);
            const comp = compose(t,s)
            const form = toSVG(comp);
            elem.setAttribute('transform', form);
        }else if (type === 'top-left') {
            const newW = ((x + width) - m.x) / width;
            const newH = ((y + height) - m.y) / height;
            const t = translate(m.x-x,m.y-y);
            const s = scale(newW,newH);
            const comp = compose(t,s)
            const form = toSVG(comp);
            elem.setAttribute('transform', form);
        }else if (type === 'top-right') {
            const newW = (m.x - x) / width;
            const newH = ((y + height) - m.y) / height;
            const t = translate(0,m.y-y);
            const s = scale(newW,newH);
            const comp = compose(t,s)
            const form = toSVG(comp);
            elem.setAttribute('transform', form);
        };

This is the code for the non-rotated svgs.

Hopefully someone can help, thank you very much

I have found a solution.

Whenever a shape is rotated you should translate your mouse pointer and the shape as if they are not rotated, do your scaling normally then translating back and rotating at the end. My problem was that i was trying to rotate before translating back!

If you use this method the order should be transform(rotate translate scale) because the last one you put is the first to happen!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM