KonvaJS:如何根据鼠标移动画一条线来连接两个形状?
KonvaJS : How to draw a line to connect two shape based on mouse move?
我正在尝试根据鼠标移动画一条线来连接两个形状。我知道如何使用原生 canvas 来重新利用它。但是不知道如何使用 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();
}
}
有很多方法可以做到这一点。基本思路:
- 在源对象
mousedown
上创建一行
- 在
mousemove
事件 上更新行位置
- 检查
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();
看来你真正的问题是在鼠标移动或鼠标松开操作过程中如何检查鼠标下方是否有形状。
Konva 有一个命中检测方法,我会让@lavarton 解释一下。如果您正在处理纯矩形 - 而不是例如圆形 - 您可以使用形状位置和 运行 一些简单的数学检查来进行自己的命中测试。请参阅我对这个关于 的问题的解决方案,它涵盖了相同的命中测试基础,应该会向您展示一个简单的前进方向。
关于 'pure rectangles' 的要点涉及这样一个事实,即这种方法很容易用于非旋转的矩形形状。但是,旋转的矩形或非矩形形状需要更多工作,如果这是您的用例,那么 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 应该像上面那样修改他的例子并获得正确答案。
我正在尝试根据鼠标移动画一条线来连接两个形状。我知道如何使用原生 canvas 来重新利用它。但是不知道如何使用 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();
}
}
有很多方法可以做到这一点。基本思路:
- 在源对象
mousedown
上创建一行 - 在
mousemove
事件 上更新行位置
- 检查
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();
看来你真正的问题是在鼠标移动或鼠标松开操作过程中如何检查鼠标下方是否有形状。
Konva 有一个命中检测方法,我会让@lavarton 解释一下。如果您正在处理纯矩形 - 而不是例如圆形 - 您可以使用形状位置和 运行 一些简单的数学检查来进行自己的命中测试。请参阅我对这个关于
关于 'pure rectangles' 的要点涉及这样一个事实,即这种方法很容易用于非旋转的矩形形状。但是,旋转的矩形或非矩形形状需要更多工作,如果这是您的用例,那么 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 应该像上面那样修改他的例子并获得正确答案。