Question

I'm having different SHapes on my Stage and i'd like to make them resizable when they are selected.

I thought of "converting" the shape into a group and add resizers to it. When the SHape is deselected i could remove the resizers and then remove the shape from the group and add it back to its old parent.

I tried that, and it doesn't really work since the coordinate origin changes for the Shape and if it has a dragBoundFunc it's worse. So it seems to be a lot of work and it feels wrong. I thought there must be a better approach to such a thing which is probably wide spread.

So my question is, what is the best way to add resizers to an existing shape on the fly, and remove them when the shape is not selected anymore?

Was it helpful?

Solution

Agreed, resizing "anchors" are visually unappealing and complex to code

Adding separate resizers to an image is visually awkward

(o/s windows don't add clunky looking resizers to enable resizing).

Adding separate resizers also gets quickly complicated.

Metaphorically, you have to manage separate resizer-planets orbiting about your sun-shape.

Managing those satellites when the shape is restricted by dragBoundFunc is complicated.

Managing those satellites when the shape is rotated gets amazingly complicated because of KineticJS's use of offsets to define the rotation point.

An alternative: use the bounding-box of the shape itself to manage resizing.

  • Listen for mouse events on the stage.
  • When the user does mousedown on a border of the shape, start a resizing operation.
  • As the user drags, resize the shape based on how far the mouse has been dragged from the side opposing the dragged side.

Benefits:

  • No anchors needed
  • Uses the same resizing method the user is familiar with when resizing o/s windows
  • Only the shape itself is involved, so complex "satellite-anchor" management is not necessary.

Here's an example: http://jsfiddle.net/m1erickson/T4E9Y/

Define a shape (this example uses an image).

kImage = new Kinetic.Image({
    image:img,
    x:10,
    y:10,
    width:img.width,
    height:img.height,
});
layer.add(kImage);
layer.draw();

Save the bounding area for the shape at its current size

Listen for mousedown events on the stage.

Save the starting drag position when the user mousedowns inside a shape boundingbox border

$(stage.getContent()).on('mousedown', function (event) {
    var pos=stage.getPointerPosition();
    var mouseX=parseInt(pos.x);
    var mouseY=parseInt(pos.y);
    var ipos=kImage.position();
    var isize=kImage.getSize();
    var right=ipos.x+isize.width;
    if(mouseX>right-10 && mouseX<right+10){
        startRight=mouseX;
        startWidth=isize.width;
        startHeight=isize.height;
    }
});

Listen for mousemove events on the stage.

Scale the shape based on the distance dragged from the starting drag position.

$(stage.getContent()).on('mousemove', function (event) {
    if(startRight>=0){
        var pos=stage.getPointerPosition();
        var mouseX=parseInt(pos.x);
        var mouseY=parseInt(pos.y);
        var dx=mouseX-startRight;
        var scaleFactor=(mouseX-(startRight-startWidth))/startWidth;
        kImage.width(startWidth*scaleFactor);
        kImage.height(startHeight*scaleFactor);
        layer.draw();
    }
});

Listen for mouseup events on the stage.

End the drag-resizing when the user releases the mouse

$(stage.getContent()).on('mouseup', function (event) {
    startRight=-1;
});

Where to go from here:

This example activates a resizer from the right border. You can similarly enable the other borders.

You can change which shape is being resized by changing the target in mousedown.

For very irregular shapes, you could display the bounding box of the shape when the user moves into that bounding box. Then let the user resize using the bounding box borders.

You could display the bounding box for all types of shapes as a highlight when the mouse is in the drag-border. The bounding box becomes a useful visual for the user.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top