2

I am using Konva.js for the annotation of data visualizations in the browser. A common use case is to draw lines between a shape (rectangle, ellipse) and its description (a text node). Lines need to be dragged, rotated and resized by users. Resizing is limited to line width.

Lines and their transformers are currently being added as follows:

var line = new Konva.Line({
    x: stage.getWidth() / 2,
    y: stage.getHeight() / 2,
    points: [0, 0, 100, 0],
    stroke: '#000',
    strokeWidth: 3,
    lineCap: 'round',
    lineJoin: 'round',
    draggable: true,
    id: id,
    strokeScaleEnabled: false,
    hitStrokeWidth: 15
});

layer.add(line);

var tr = new Konva.Transformer({
    node: line,
    enabledAnchors: ['middle-left', 'middle-right']
});

layer.add(tr);

Correctly positioning a line is not very intuitive at the moment since it requires a user to separately rotate and resize the line using the rotate, middle-left and middle-right anchors.

Instead, I'm looking for a way to use the middle-left and middle-right anchors to rotate and resize a line at the same time. My inspiration for this is PowerPoint - lines only have anchors on both ends which can be used to resize and rotate at the same time:

Lines in PowerPoint

I've tried combining the rotater and middle-left/middle-right functionality in Konva's Transformer _handleMouseMove function, but this does not work as expected.

Has anyone perhaps found a way to use the left and right anchors to do both things at the same time?

ACDSL
  • 87
  • 2
  • 7

1 Answers1

7

At the current moment, I don't recommend to use Konva.Transformer for a simple line. It is simple to build a custom solution with a couple of circles:

const line = new Konva.Line({
  points: [50, 50, 250, 50],
  stroke: 'green'
});
layer.add(line);

const anchor1 = new Konva.Circle({
  x: line.points()[0],
  y: line.points()[1],
  radius: 10,
  fill: 'red',
  draggable: true
})
layer.add(anchor1);

const anchor2 = new Konva.Circle({
  x: line.points()[2],
  y: line.points()[3],
  radius: 10,
  fill: 'red',
  draggable: true
})
layer.add(anchor2);


function updateLine() {
  const points = [
    anchor1.x(),
    anchor1.y(),
    anchor2.x(),
    anchor2.y(),
  ]
  line.points(points);
  layer.batchDraw();
}

anchor1.on('dragmove', updateLine);
anchor2.on('dragmove', updateLine);

Demo: https://jsbin.com/wahetunepa/edit?html,js,output

lavrton
  • 18,973
  • 4
  • 30
  • 63
  • That looks like an excellent alternative solution, thank you very much! Do you know if there is any easy way to style the circles just like the regular Transformer anchors? That way it would be possible to sort of mimic this without the user noticing the difference. – ACDSL Apr 16 '19 at 12:19
  • 1
    You can style them as you want. You can also use rectangles instead of circles. Take a look into docs for all styling props. – lavrton Apr 16 '19 at 12:59