Search code examples
javascriptkonvajs

KonvaJS : How to draw a line to connect two shape based on mouse move?


I'am trying to draw a line to connect two shape based on mouse move. And I konw how to relize it by using native canvas. But have no idea how to realize it by using KonvaJS. Please help me on this.

This image shows what result i what : enter image description here

And this is the code that i try to realize what I want. But it doesn't work.

            stage.on('mousedown', function(e) {
                const a = e.target instanceof Konva.Rect;
                if (!a) {
                    return;
                } else {
                    
                    group.draggable(false);
                    group2.draggable(false);
                    
                    clickdot1 = e.target;
                    drawingLine = true;
                    }
            });

            stage.on('mousemove', function(e) {
                if (!drawingLine) {
                    return;
                }else{
                    if(clickdot1!=null&&drawingLine){
                        let lastLine = new Konva.Line({
                            stroke: '#df4b26',
                            strokeWidth: 5,
                            lineCap: 'round',
                            lineJoin: 'round',
                            points: [e.target.x(), e.target.y()],
                        });
                        connections.push(lastLine);
                        drawthings();
                    }
                }   
            });
            
            function drawthings(){
                for(let i = 0;i<connections.length;i++){
                    animLayer.add(connections[i]);
                    animLayer.batchDraw();
                }
            }

Solution

  • It seems that your real question is how to check if there is a shape under the mouse during mouse move or mouse up operations.

    Konva has a hit detection approach that I will let @lavarton explain. If you are dealing with pure rectangles - as opposed to for example circles - you can do your own hit testing using shape position and running some simple math checks. See my solution to this question about 'Selecting by drawing a box around objects in konva' which covers the same ground for hit testing and should show you a simple way forward.

    The point about 'pure rectangles' concerns the fact that this approach works easily for non-rotated, rectangular shapes. However, rotated rectangles or non-rectangular shapes would require more work and if that were your use-case then Konva's built-in hit testing would offer a lower time-cost for learning and future support of your code.

    Regarding @lavrton's answer missing the requirement to place the line into the centre position on the connected shape, change the stage.on('mouseup') listener in his code as below to achieve that.

    stage.on('mouseup', (e) => {
      if (!line) {
        return;
      }
      
      if (!e.target.hasName('target')) {
        line.destroy();
        
        layer.draw();
        line = null;
      } else {
        let pos = e.target.getClientRect();
        const points = line.points().slice();
        points[2] = pos.x + (e.target.width()/2);
        points[3] = pos.y + (e.target.height()/2);;
        line.points(points);
        layer.batchDraw();
       
        line = null;
      }
      
    });
    

    This works by getting the topleft of the target shape (the getClientRect value), then adding half the shape width to the x and half the shape height to the y value to give the centre point. We than get the current line points array, set the values in slot 2 & 3 which are the end.x and end.y, give that back to the line and redraw the layer.

    @lavrton should modify his example as above and be awarded the correct answer.