Search code examples
svgtransformscaling

fix scaling in rotate & scale function


I got this function working pretty well now (below) for rotation (it detects angle correctly etc). Now my struggle is to make scaling to work in such a way that the shape becomes super small the closer the user is to the initial center of the shape.

Basically right now when player move their touch/mouse to the center of the shape at some point scaling just stops (as we reached the center) ;/

Any advice what should be tuned? I am pretty sure it relates to these vars: - this.activeShape.scale.height (currently I take top most point of shape's bounding box; - this.activeShape.scale.point (this is currently the same as rotation point - center of shape's bounding box).

mainSVG.rotateMove = function(event) {
    this.eventObj = this.isTouchSupported? event.touches[0] : event;
    this.moveCoordsCache = this.globalToLocalCoordinates(this.eventObj.clientX, this.eventObj.clientY);
    let rdx = this.moveCoordsCache.x - this.activeShape.rotation.center.x;
    let rdy = this.moveCoordsCache.y - this.activeShape.rotation.center.y;
    let theta = Math.atan2(rdy, rdx) * 180 / Math.PI + 90;
    if (rdx < 0 && rdy < 0) { theta += 360 };
    theta -= 180;
    let sdx = this.activeShape.scale.point.x - this.moveCoordsCache.x;
    let sdy = this.activeShape.scale.point.y - this.moveCoordsCache.y;
    let distanceToMouse = Math.sqrt(sdx * sdx + sdy * sdy);
    let transform = "translate(" + this.activeShape.rotation.center.x + "," + this.activeShape.rotation.center.y + ") rotate(" + theta + ") scale(" + distanceToMouse / this.activeShape.scale.height + ") translate(" + (-this.activeShape.rotation.center.x) + "," + (-this.activeShape.rotation.center.y) + ")";
    this.domCtrl.write(()=>{
        this.activeShape.setAttribute("transform", transform);
    });

here is codepen I did to recreate. It is almost working as I want except that it keeps a bit of flicks here and there which I am not sure how to fix. Like I don't get what should be the scale height I think. Maybe it should be dynamic?

https://codepen.io/cmer41k/pen/rYMLBz


Solution

  • The only issue i see with your example is that the shape jumps a little and becomes smaller when you start dragging the rotator.

    In your transform, you calculate the scale as distanceToMouse / scaleHeight. Therefore, scaleHeight should be the initial "distance to mouse", and not the height of the item group as in your example.

    var rectBox = rectangle.getBBox(),
        rotBox = rotator.getBBox();
    rotateAndScaleAround = {
        x: rectBox.x + rectBox.width/2,
        y: rectBox.y + rectBox.height/2
    };
    scaleHeight = (rotBox.y + rotBox.height/2) - rotateAndScaleAround.y;
    

    Updated pen: https://codepen.io/Sphinxxxx/pen/EbgooY