【问题标题】:KonvaJS : How to draw a line to connect two shape based on mouse move?KonvaJS:如何根据鼠标移动画一条线来连接两个形状?
【发布时间】:2020-07-20 08:21:18
【问题描述】:

我正在尝试根据鼠标移动画一条线来连接两个形状。而且我知道如何使用本机画布来实现它。但是不知道如何通过使用 KonvaJS 来实现它。 请帮我解决这个问题。

这张图片显示了我的结果:enter image description here

这是我试图实现我想要的代码。但它不起作用。

            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();
                }
            }

【问题讨论】:

    标签: javascript konvajs


    【解决方案1】:

    有很多方法可以做到这一点。基本思路:

    1. 在源对象的mousedown 上创建一行
    2. mousemove 事件上更新行位置
    3. 检查mouseup 上的目标形状。如果那是“可连接”的东西,请保留一条线,否则将其销毁。
    const stage = new Konva.Stage({
      container: 'container',
      width: window.innerWidth,
      height: window.innerHeight
    });
    
    const layer = new Konva.Layer();
    stage.add(layer);
    
    layer.add(new Konva.Text({ text: 'try to drag a green source into any red target', padding: 10}))
    
    const source = new Konva.Circle({
      x: 20,
      y: 50,
      radius: 10,
      fill: 'green'
    });
    layer.add(source);
    
    const target1 = new Konva.Circle({
      x: 20,
      y: 220,
      radius: 10,
      fill: 'red',
      name: 'target'
    });
    layer.add(target1);
    
    
    const target2 = new Konva.Circle({
      x: 120,
      y: 220,
      radius: 10,
      fill: 'red',
      name: 'target'
    });
    layer.add(target2);
    
    
    let drawingLine = false;
    let line;
    source.on('mousedown', () => {
      drawingLine = true;
      const pos = stage.getPointerPosition();
      line = new Konva.Line({
        stroke: 'black',
        // remove line from hit graph, so we can check intersections
        listening: false,
        points: [source.x(), source.y(), pos.x, pos.y]
      });
      layer.add(line);
    });
    
    stage.on('mouseover', (e) => {
      if (e.target.hasName('target')) {
        e.target.stroke('black');
        layer.draw();
      }
    });
    
    stage.on('mouseout', (e) => {
      if (e.target.hasName('target')) {
        e.target.stroke(null);
        layer.draw();
      }
    });
    
    stage.on('mousemove', (e) => {
      if (!line) {
        return;
      }
      const pos = stage.getPointerPosition();
      const points = line.points().slice();
      points[2] = pos.x;
      points[3] = pos.y;
      line.points(points);
      layer.batchDraw();
    });
    
    stage.on('mouseup', (e) => {
      if (!line) {
        return;
      }
      if (!e.target.hasName('target')) {
        line.destroy();
        layer.draw();
        line = null;
      } else {
        line = null;
      }
      
    });
    
    
    layer.draw();
    

    https://jsbin.com/rumizocise/1/edit?html,js,output

    【讨论】:

    • 谢谢!它帮助了我很多。但我想从一个形状的中心画一条线到另一个形状的中心。所以我需要mouseup时的形状位置。然后我发现e.target 在触发mouseup 事件时始终为Konva.line。有什么办法可以帮我拿到线下的位置吗?
    • 查看我的答案中的编辑,该编辑添加到@lavrton 的以目标形状为中心的答案。
    • @yanyusanqian 在我的回答中,您必须将listening: false 设置为该行。所以它不会影响e.targetmouseup
    • @Iavrton 我之前没有注意到这一点,这让我的问题变得更加复杂。非常感谢您的帮助!
    【解决方案2】:

    看来您真正的问题是如何在鼠标移动或鼠标向上操作期间检查鼠标下方是否有形状。

    Konva 有一个命中检测方法,我会让@lavarton 解释。如果您正在处理纯矩形 - 而不是例如圆形 - 您可以使用形状位置进行自己的命中测试并运行一些简单的数学检查。请参阅我对有关'Selecting by drawing a box around objects in konva' 的问题的解决方案,它涵盖了命中测试的相同基础,并且应该向您展示一个简单的前进方式。

    关于“纯矩形”的要点在于,这种方法很容易适用于非旋转的矩形形状。但是,旋转的矩形或非矩形形状需要更多的工作,如果这是您的用例,那么 Konva 的内置命中测试将为您的代码的学习和未来支持提供更低的时间成本。

    关于@lavrton 的回答缺少将线放置在连接形状的中心位置的要求,请在他的代码中更改 stage.on('mouseup') 监听器,如下所示。

    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;
      }
      
    });
    

    这通过获取目标形状的左上角(getClientRect 值),然后将形状宽度的一半添加到 x 并将形状高度的一半添加到 y 值来给出中心点。我们得到当前线点数组,设置槽 2 和 3 中的值,即 end.x 和 end.y,将其返回给线并重新绘制图层。

    @lavrton 应该像上面一样修改他的示例并获得正确答案。

    【讨论】:

    • 在原生画布中,我用这种方式检查鼠标下是否有形状来解决我的问题。但是我在konvaJS中没有找到什么办法,所以我找到了一种更简单但不是很严格的方法,让线条与鼠标拉出一定的距离。这样,这条线就不会覆盖下面的矩形。但是感谢您的帮助!非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2016-09-12
    • 1970-01-01
    • 2011-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多