Question

I have five anchors and the middle one is for rotating. It works well with the original size. But after resizing, when I click it, the anchor fly away from the image. I did set the position to new ones. http://jsfiddle.net/W9X8n/1/

  function update(activeAnchor) {
    var group = activeAnchor.getParent();

    var topLeft = group.get('.topLeft')[0];
    var topRight = group.get('.topRight')[0];
    var bottomRight = group.get('.bottomRight')[0];
    var bottomLeft = group.get('.bottomLeft')[0];

    //var rotateAnchor = group.get('.rotateAnchor')[0];
    var rotateAnchorNew = group.get('.rotateAnchorNew')[0];
    var image = group.get('Image')[0];

    var anchorX = activeAnchor.getX();
    var anchorY = activeAnchor.getY();
    var imageWidth = image.getWidth();
    var imageHeight = image.getHeight();

    // update anchor positions
    switch (activeAnchor.getName()) {
        //case 'rotateAnchor':

        //    break;
        case 'rotateAnchorNew':

            break;
        case 'topLeft':
            topRight.setY(anchorY);
            bottomLeft.setX(anchorX);
            break;
        case 'topRight':
            topLeft.setY(anchorY);
            bottomRight.setX(anchorX);
            break;
        case 'bottomRight':
            topRight.setX(anchorX);
            bottomLeft.setY(anchorY);
            break;
        case 'bottomLeft':
            topLeft.setX(anchorX);
            bottomRight.setY(anchorY);
            break;
    }

    if (topRight.getX() < topLeft.getX() + minImgSize) {
        topRight.setX(topLeft.getX() + minImgSize);
    }
    if (bottomRight.getX() < topLeft.getX() + minImgSize) {
        bottomRight.setX(topLeft.getX() + minImgSize);
    }
    if (bottomRight.getY() < topLeft.getY() + minImgSize) {
        bottomRight.setY(topLeft.getY() + minImgSize);
    }
    if (bottomLeft.getY() < topLeft.getY() + minImgSize) {
        bottomLeft.setY(topLeft.getY() + minImgSize);
    }

    var width = topRight.getX() - topLeft.getX();
    var height = bottomLeft.getY() - topLeft.getY();

    image.setPosition({ x: topLeft.getPosition().x, y: (topLeft.getPosition().y) });
    image.setWidth(width);
    image.setHeight(height);


    rotateAnchorNew.setX(width / 2 + topLeft.getX());
    rotateAnchorNew.setY(height / 2 + topLeft.getY());


}
Was it helpful?

Solution

KineticJS automatically adjusts the left & top position of an object based on the offset.

This is frustrating because this same offset must be used to set the rotation point.

As a result, it is difficult to coordinate the [x,y,offsetX,offsetY] of your image with the [x,y] of the anchors--especially when the image has been both resized and rotated.

If either your image or your anchors unexpectedly "jump", you are experiencing the side-effects of using KineticJS offsets.

Here's one way to deal with this difficulty:

  • Declare the rotation point as the centerpoint of the image.

  • Use this centerpoint-rotationpoint to position both the image and the anchors.

  • When any anchor is activated, use this centerpoint to reset the image's x,y & offsets.

  • When any anchor is activated, reposition all anchors relative to this centerpoint.

By making all transformations relative to the rotation point, you eliminate the need to coordinate the image's x,y with each anchor's x,y.

enter image description hereenter image description here

Here's annotated code and a Demo: http://jsfiddle.net/m1erickson/TWAj3/

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    <script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.1.min.js"></script>
<style>
body{padding:20px;background:lightgray}
#container{
  border:solid 1px green;
  margin-top: 10px;
  width:400px;
  height:400px;
}
</style>        
<script>
$(function(){

    // create the stage and layer
    var stage = new Kinetic.Stage({
        container: 'container',
        width: 400,
        height: 400
    });
    var layer = new Kinetic.Layer();
    stage.add(layer);

    // create an anchor used to drag-move the image
    var spotXY=new Kinetic.Circle({
        x:0,y:0,radius:10,
        fill: 'blue',stroke:'black',
        draggable: true
    });
    spotXY.on("dragmove",function(){
        setNode(image,this.x(),this.y(),image.width(),image.height(),image.rotation());
    });
    layer.add(spotXY);

    // create an anchor used to drag-resize the image
    var resizer=new Kinetic.Circle({
        x:0,y:0,radius:10,
        fill: 'red',stroke:'black',
        draggable: true
    });
    resizer.on("dragmove",function(){
        var dx=this.x()-spotXY.x();
        var dy=this.y()-spotXY.y();
        var w=Math.sqrt(dx*dx+dy*dy)*2;
        var h=w*hRatio;
        setNode(image,spotXY.x(),spotXY.y(),w,h,image.rotation());
    });
    layer.add(resizer);

    // create an anchor used to drag-rotate the image
    var rotator=new Kinetic.Circle({
        x:0,y:0,radius:10,
        fill: 'gold',stroke:'black',
        draggable: true
    });
    rotator.on("dragmove",function(){
        var dx=this.x()-spotXY.x();
        var dy=this.y()-spotXY.y();
        var angle=Math.atan2(dy,dx)*180/Math.PI;
        setNode(image,spotXY.x(),spotXY.y(),image.width(),image.height(),angle);
    });
    layer.add(rotator);

    // always resize the image proportionally to it's original aspect ratio
    // this variable is used to keep that proportion
    var hRatio;

    // load the image
    var img=new Image();
    img.onload=start;
    img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/facesSmall.png";
    function start(){

        // save the images original aspect ratio
        hRatio=img.height/img.width;

        // start
        loadK(150,150);
    };

    function loadK(x,y){

        // create an image element
        image=new Kinetic.Image({
            x:0,y:0,width:10,height:10,
            image:img,
            rotation:0,
        });
        layer.add(image);

        // setNode will reset all image and anchor properties when needed
        // This sets the initial properties at startup
        setNode(image,x,y,img.width,img.height,45);

        // make sure the anchors are on top of the z-index
        spotXY.moveToTop();
        rotator.moveToTop();
        resizer.moveToTop();

        layer.draw();
    }

    // Reset all image and anchor properties relative to the rotation point (x,y)
    // This is the key to simplifying KineticJS transformations with anchors
    function setNode(node,x,y,w,h,angle){

        // reset all size and position properties on the image
        node.width(w);
        node.height(h);
        node.x(x);
        node.y(y);
        node.offsetX(w/2);
        node.offsetY(h/2);
        node.rotation(angle);

        // postion the move anchor
        spotXY.position({x:x,y:y});

        // calculate the radian angle of the image
        var rAngle=angle*Math.PI/180;

        // position the rotation anchor
        var rotationRadius=(w/2+resizer.radius()*2);
        var xx=x+rotationRadius*Math.cos(rAngle);
        var yy=y+rotationRadius*Math.sin(rAngle);   
        rotator.position({x:xx,y:yy});

        // position the resizing anchor
        var xx=x+w/2*Math.cos(rAngle);
        var yy=y+w/2*Math.sin(rAngle);   
        resizer.position({x:xx,y:yy});

        layer.draw();    
    }

}); // end $(function(){});

</script>       
</head>
<body>
    <h4>Drag the dots to transform the image<br>Blue=Move, Red=Resize, Gold=Rotate<br>Image will always resize by maintaining aspect ratio</h4>
    <div id="container"></div>
</body>
</html>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top