如何使用 Konva JS 检测图像和文本对象之间的碰撞
How to detect a collision between an Image and a Text object using Konva JS
我正在尝试构建一个简单的应用程序,用户可以在其中将一个词拖到相应的图像上。当用户将单词“放下”到图像上时,需要检测碰撞。我有一条 console.log 消息,它应该只在发生这种情况时记录。目前,即使没有碰撞,我的消息也在记录。我哪里出错了?这是我的代码:
//create stage to hold the text and image canvases
var stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
});
//*************************************** IMG CANVAS *************************************/
// // add img canvas element
var imgLayer = new Konva.Layer();
stage.add(imgLayer);
var imageObj = new Image();
imageObj.onload = function () {
var item = new Konva.Image({
x: 200,
y: 200,
image: imageObj,
width: 400,
height: 400,
stroke: 'black',
});
// add the shape to the layer
imgLayer.add(item);
};
imageObj.src = 'assets/apple.jpg';
//*************************************** TEXT CANVAS *************************************/
// add text canvas element
var textLayer = new Konva.Layer();
stage.add(textLayer);
// create text
var text = new Konva.Text({
x: 350,
y: 0,
text: 'apple',
fontSize: 40,
fontFamily: 'Calibri',
fill: 'blue',
draggable: true,
});
textLayer.add(text);
// add text cursor styling
text.on('mouseover', function () {
document.body.style.cursor = 'pointer';
});
text.on('mouseout', function () {
document.body.style.cursor = 'default';
});
//************************************* COLLISION ***************************************/
text.on('dragend', (e)=>{
const target = e.target;
console.log(target);
const targetImg = imgLayer;
console.log(targetImg);
if (haveIntersection(target, imgLayer)) {
console.log("collision");
} else {
console.log('no collision');
}
});
const haveIntersection= (r1, r2) => {
return !(
r2.x > r1.x + r1.width ||
r2.x + r2.width < r1.x ||
r2.y > r1.y + r1.height ||
r2.y + r2.height < r1.y
);
}
第一期:传递给 haveIntersection 的第二个参数是 imgLayer,它是一个 Konva.Layer 对象。由于图层与舞台大小相同,我认为这总是 return true.
第二个问题:您的 haveIntersection() 函数需要包含 x、y、宽度和高度的对象参数。传入 Konva 对象 here/like 这是不好的做法,因为它们没有这些属性。 Konva.Text 就是这种情况,它既没有宽度也没有高度属性。
对于 x 你会参考 shape.x(),宽度会是 shape.width(),等等。你有时可以通过传递 shape.getAttrs() 来逃避,它提供了一个普通的 JS 对象包含此类属性,但即使这样也可能会失败,因为某些形状(例如 Konva.Image 在 getAttrs() 的结果中没有宽度或高度属性。原来 Konva.Rect 和 Konva.Image do 有它们,同时 Konva.text() 没有,所以你不应该依赖这个。
相反,您应该明确并传入定义的对象(参见代码片段)。明确您的意图是值得的 - 库可以随着时间的推移添加或删除默认值和行为,如果它 'had' 有效,您的代码仍然可能是一个定时炸弹。
作为奖励:在您有多个对象要检查碰撞的情况下,一种有用的技术是使用 stage,find() 函数。为 drop-target 对象指定一个通用名称 attr,您可以通过 stage.find('.name_to_find') 搜索此类对象。在代码片段中,我将名称 'dropimage' 分配给 rects(代替图像对象以避免此处的图像获取问题)。然后你可以迭代找到的对象和运行碰撞检测等
最后,您在代码中使用了两层。每层都有处理开销,虽然使用多层是一种合法的技术,但您应该考虑在这种简单情况下是否需要两层。单层就可以了。
//create stage to hold the text and image canvases
var stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
});
//*************************************** IMG CANVAS *************************************/
// add img layer
var imgLayer = new Konva.Layer();
stage.add(imgLayer);
let r = new Konva.Rect({
x: 40,
y: 20,
width: 200,
height: 150,
fill: 'cyan',
name: 'dropimage'
})
imgLayer.add(r);
r = new Konva.Rect({
x: 340,
y: 60,
width: 200,
height: 150,
fill: 'magenta',
name: 'dropimage'
})
imgLayer.add(r);
//*************************************** TEXT CANVAS *************************************/
// add text canvas element
var textLayer = new Konva.Layer();
stage.add(textLayer);
// create text
var text = new Konva.Text({
x: 350,
y: 0,
text: 'apple',
fontSize: 40,
fontFamily: 'Calibri',
fill: 'blue',
draggable: true,
});
textLayer.add(text);
// add text cursor styling
text.on('mouseover', function () {
document.body.style.cursor = 'pointer';
});
text.on('mouseout', function () {
document.body.style.cursor = 'default';
});
//************************************* COLLISION ***************************************/
text.on('dragend', (e)=>{
const target = e.target;
let images = stage.find('.dropimage');
let cnt = 0;
for (let img of images){
cnt++;
if (haveIntersection({
x: target.x(),
y: target.y(),
width: target.width(),
height: target.height()
},
img.getAttrs()
)) {
console.log("collision on shape " + cnt);
} else {
console.log("no collision on shape " + cnt);
}
}
});
const haveIntersection= (r1, r2) => {
return !(
r2.x > r1.x + r1.width ||
r2.x + r2.width < r1.x ||
r2.y > r1.y + r1.height ||
r2.y + r2.height < r1.y
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/8.3.0/konva.min.js"></script>
<p>Drag text onto a rect and look in console</p>
<div id='container'></div>
我正在尝试构建一个简单的应用程序,用户可以在其中将一个词拖到相应的图像上。当用户将单词“放下”到图像上时,需要检测碰撞。我有一条 console.log 消息,它应该只在发生这种情况时记录。目前,即使没有碰撞,我的消息也在记录。我哪里出错了?这是我的代码:
//create stage to hold the text and image canvases
var stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
});
//*************************************** IMG CANVAS *************************************/
// // add img canvas element
var imgLayer = new Konva.Layer();
stage.add(imgLayer);
var imageObj = new Image();
imageObj.onload = function () {
var item = new Konva.Image({
x: 200,
y: 200,
image: imageObj,
width: 400,
height: 400,
stroke: 'black',
});
// add the shape to the layer
imgLayer.add(item);
};
imageObj.src = 'assets/apple.jpg';
//*************************************** TEXT CANVAS *************************************/
// add text canvas element
var textLayer = new Konva.Layer();
stage.add(textLayer);
// create text
var text = new Konva.Text({
x: 350,
y: 0,
text: 'apple',
fontSize: 40,
fontFamily: 'Calibri',
fill: 'blue',
draggable: true,
});
textLayer.add(text);
// add text cursor styling
text.on('mouseover', function () {
document.body.style.cursor = 'pointer';
});
text.on('mouseout', function () {
document.body.style.cursor = 'default';
});
//************************************* COLLISION ***************************************/
text.on('dragend', (e)=>{
const target = e.target;
console.log(target);
const targetImg = imgLayer;
console.log(targetImg);
if (haveIntersection(target, imgLayer)) {
console.log("collision");
} else {
console.log('no collision');
}
});
const haveIntersection= (r1, r2) => {
return !(
r2.x > r1.x + r1.width ||
r2.x + r2.width < r1.x ||
r2.y > r1.y + r1.height ||
r2.y + r2.height < r1.y
);
}
第一期:传递给 haveIntersection 的第二个参数是 imgLayer,它是一个 Konva.Layer 对象。由于图层与舞台大小相同,我认为这总是 return true.
第二个问题:您的 haveIntersection() 函数需要包含 x、y、宽度和高度的对象参数。传入 Konva 对象 here/like 这是不好的做法,因为它们没有这些属性。 Konva.Text 就是这种情况,它既没有宽度也没有高度属性。
对于 x 你会参考 shape.x(),宽度会是 shape.width(),等等。你有时可以通过传递 shape.getAttrs() 来逃避,它提供了一个普通的 JS 对象包含此类属性,但即使这样也可能会失败,因为某些形状(例如 Konva.Image 在 getAttrs() 的结果中没有宽度或高度属性。原来 Konva.Rect 和 Konva.Image do 有它们,同时 Konva.text() 没有,所以你不应该依赖这个。
相反,您应该明确并传入定义的对象(参见代码片段)。明确您的意图是值得的 - 库可以随着时间的推移添加或删除默认值和行为,如果它 'had' 有效,您的代码仍然可能是一个定时炸弹。
作为奖励:在您有多个对象要检查碰撞的情况下,一种有用的技术是使用 stage,find() 函数。为 drop-target 对象指定一个通用名称 attr,您可以通过 stage.find('.name_to_find') 搜索此类对象。在代码片段中,我将名称 'dropimage' 分配给 rects(代替图像对象以避免此处的图像获取问题)。然后你可以迭代找到的对象和运行碰撞检测等
最后,您在代码中使用了两层。每层都有处理开销,虽然使用多层是一种合法的技术,但您应该考虑在这种简单情况下是否需要两层。单层就可以了。
//create stage to hold the text and image canvases
var stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
});
//*************************************** IMG CANVAS *************************************/
// add img layer
var imgLayer = new Konva.Layer();
stage.add(imgLayer);
let r = new Konva.Rect({
x: 40,
y: 20,
width: 200,
height: 150,
fill: 'cyan',
name: 'dropimage'
})
imgLayer.add(r);
r = new Konva.Rect({
x: 340,
y: 60,
width: 200,
height: 150,
fill: 'magenta',
name: 'dropimage'
})
imgLayer.add(r);
//*************************************** TEXT CANVAS *************************************/
// add text canvas element
var textLayer = new Konva.Layer();
stage.add(textLayer);
// create text
var text = new Konva.Text({
x: 350,
y: 0,
text: 'apple',
fontSize: 40,
fontFamily: 'Calibri',
fill: 'blue',
draggable: true,
});
textLayer.add(text);
// add text cursor styling
text.on('mouseover', function () {
document.body.style.cursor = 'pointer';
});
text.on('mouseout', function () {
document.body.style.cursor = 'default';
});
//************************************* COLLISION ***************************************/
text.on('dragend', (e)=>{
const target = e.target;
let images = stage.find('.dropimage');
let cnt = 0;
for (let img of images){
cnt++;
if (haveIntersection({
x: target.x(),
y: target.y(),
width: target.width(),
height: target.height()
},
img.getAttrs()
)) {
console.log("collision on shape " + cnt);
} else {
console.log("no collision on shape " + cnt);
}
}
});
const haveIntersection= (r1, r2) => {
return !(
r2.x > r1.x + r1.width ||
r2.x + r2.width < r1.x ||
r2.y > r1.y + r1.height ||
r2.y + r2.height < r1.y
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/8.3.0/konva.min.js"></script>
<p>Drag text onto a rect and look in console</p>
<div id='container'></div>