Search code examples
konvajs

Konvajs custom shapes and transformers


What I am trying to achieve is showing the transformer around the custom shape itself. I took the code directly from the API docs for creating the custom shape and adding the transformer. The transformer works great for rectangles, circles, etc but for custom shapes, it doesn't seem to appear properly.

Here is a link to a demo app with the issue with custom shapes and transformer: https://jsfiddle.net/5zpua740/

var stage = new Konva.Stage({
      container: 'container',
      width: window.innerWidth,
      height: window.innerHeight
    });

var layer = new Konva.Layer();

/*
* create a triangle shape by defining a
* drawing function which draws a triangle
*/
var triangle = new Konva.Shape({
  sceneFunc: function (context) {
    context.beginPath();
    context.moveTo(120, 150);
    context.lineTo(320, 180);
    context.quadraticCurveTo(250, 200, 360, 270);
    context.closePath();

    // Konva specific method
    context.fillStrokeShape(this);
  },
  fill: '#00D2FF',
  stroke: 'black',
  strokeWidth: 4,
  draggable: true
});

// add the triangle shape to the layer
layer.add(triangle);

// add the layer to the stage
stage.add(layer);

stage.on('click', function (e) {
  // if click on empty area - remove all transformers
  if (e.target === stage) {
    stage.find('Transformer').destroy();
    layer.draw();
    return;
  }

  // remove old transformers
  // TODO: we can skip it if current rect is already selected
  stage.find('Transformer').destroy();

  // create new transformer
  var tr = new Konva.Transformer();
  layer.add(tr);
  tr.attachTo(e.target);
  layer.draw();
})

In this sample, you can see that if you click on the object, the transformer appears in the corner. You can still use it to manipulate the object but it's not around the object itself.

Any help appreciated! Thanks in advance.


Solution

  • Konva can't detect bounding box of a custom shape. But we can simply help it. We just need to define a method getSelfRect.

    The method should return bounding box of a shape without transforming applied (like the shape has no rotation, no scaling and placed in x =0, y=0).

    We can do this by just looking at sceneFunc:

    triangle.getSelfRect = function() {
      return {
        // sceneFunc started from moving to 120, 150 point
        // so it is our top left point
        x: 120, 
        y: 150,
        // the bottom right point finished with quadraticCurveTo
        // I will use the coordinates to calculate size of the shape
        width: 360 - 120,
        height: 270 - 150
      };
    }
    

    Demo: http://jsbin.com/lazuhowezi/2/edit?js,output