为了账号安全,请及时绑定邮箱和手机立即绑定

KonvaJS:如何根据鼠标移动画一条线来连接两个形状?

KonvaJS:如何根据鼠标移动画一条线来连接两个形状?

猛跑小猪 2022-11-27 16:39:59
我正在尝试根据鼠标移动画一条线来连接两个形状。我知道如何使用原生画布重新利用它。但是不知道如何使用 KonvaJS 来实现它。请帮我解决这个问题。此图像显示了我的结果:在此处输入图像描述这是我试图实现我想要的代码。但它不起作用。      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();                }            }
查看完整描述

2 回答

?
Smart猫小萌

TA贡献1911条经验 获得超7个赞

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

  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


查看完整回答
反对 回复 2022-11-27
?
青春有我

TA贡献1784条经验 获得超8个赞

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


Konva 有一种命中检测方法,我会让@lavarton 解释一下。如果您处理的是纯矩形 - 而不是例如圆形 - 您可以使用形状位置进行自己的命中测试并运行一些简单的数学检查。请参阅我对这个问题的解决方案“通过在 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 应该修改他的例子如上并获得正确答案。


查看完整回答
反对 回复 2022-11-27
  • 2 回答
  • 0 关注
  • 385 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信