【发布时间】:2016-12-29 15:38:06
【问题描述】:
我正在使用 KineticJS 并试图完成一些看起来很简单的事情:尝试让一个形状随着当前被拖动的形状改变位置。
这个想法是:
• 您在画布上拾取一个形状。这会触发 mousedown 事件侦听器,它会保存您拾取的形状的当前位置。
• 按住形状时,如果您在另一个形状上触发mouseover,则会触发该形状的事件并根据当前形状的保存位置交换其位置。
这是我编写的相关代码以尝试使其正常工作:
电路板设置: 只需在此处设置板并调用所需的功能。我还没有对舞台、gameBoard 或 ctx 做任何事情(部分原因是我试图让 drawImage 在多个画布上工作,但现在已经放弃了)。
class BoardView {
constructor(stage, gameBoard, ctx) {
this.stage = stage;
this.gameBoard = gameBoard;
this.ctx = ctx;
this.orbs = [[], [], [], [], []];
this.setupBoard();
}
板设置功能: 这是我设置电路板并为每个 Kinetic Circle 提供在图层上渲染所需的属性的地方。也许我在这里遗漏了一些明显的东西?
setupBoard () {
for (let colIdx = 0; colIdx < 5; colIdx++) {
this.addRow(colIdx);
}
this.renderBoard();
}
addRow (colIdx) {
for (let rowIdx = 0; rowIdx < 6; rowIdx++) {
let orbType = Math.round(Math.random() * 5);
let orbColor;
if (orbType === 0) {
orbColor = "#990000";
} else if (orbType === 1) {
orbColor = "#112288";
} else if (orbType === 2) {
orbColor = "#005544";
} else if (orbType === 3) {
orbColor = "#776611";
} else if (orbType === 4) {
orbColor = "#772299";
} else {
orbColor = "#dd2277";
}
let orbject = new Kinetic.Circle({
x: (rowIdx + 0.5) * 100,
y: (colIdx + 0.5) * 100,
width: 100,
height: 100,
fill: orbColor,
draggable: true
});
this.orbs[colIdx].push(orbject);
}
}
棋盘渲染功能: 这是我将所有 Kinetic Circle 对象添加到新层的地方,并在我调用事件处理程序时为这些层提供所有自己的属性以供使用。在将图层添加到舞台后,我还在这里设置了事件处理程序。我可能是因为添加了太多层而把事情搞砸了?
renderBoard () {
for (let row = 0; row < this.orbs.length; row++) {
for (let orb = 0; orb < this.orbs[row].length; orb++) {
let layer = new Kinetic.Layer();
layer.add(this.orbs[row][orb]);
layer.moving = false;
layer.orbId = `orb${row}${orb}`;
layer.pos = [this.orbs[row][orb].attrs.x, this.orbs[row][orb].attrs.y];
this.stage.add(layer);
layer.on("mousedown", this.handleMouseDown);
layer.on("mouseup", this.handleMouseUp);
layer.on("mouseout", this.handleMouseOut);
layer.on("mousemove", this.handleMouseMove);
}
}
}
鼠标事件处理程序: 这是我认为我的主要问题所在。我如何处理移动鼠标改变球体的事件,也许我做错了什么?
handleMouseDown (e) {
window.currentOrb = this;
console.log(window.currentOrb.orbId);
this.moving = true;
}
//handleMouseUp (e) {
// window.currentOrb = undefined;
// this.moving = false;
//}
//handleMouseOut (e) {
//}
handleMouseMove (e) {
if (window.currentOrb !== undefined && window.currentOrb.orbId != this.orbId) {
this.children[0].attrs.x = window.currentOrb.pos[0];
this.children[0].attrs.y = window.currentOrb.pos[1];
this.children[0].draw();
} else {
}
}
}
module.exports = BoardView;
我尝试查看 KineticJS 文档和许多 StackOverflow 答案,希望能找到适合我的解决方案,但到目前为止我没有看到和尝试过(包括我提出的建议)写了这个问题)似乎有帮助,而且我知道到目前为止我所做的事情可能远非完成我想要的最佳方式,所以我愿意接受任何建议、指点和回答问题,或者任何可以为我指明正确方向的问题,以便让这个工作正常进行。
如果这有帮助,这里还有一个可视化的板子渲染时的外观。
这些圆圈都是动态圆圈(用于我要达到的目的的球体),单击并拖动一个到另一个,没有被拖动但悬停的那个应该移动到原始位置拖动圆圈。
谢谢!
编辑:
从那时起,我对代码进行了一些更改。首先,我将在舞台上添加许多层改为仅一层:
renderBoard () {
let layer = new Kinetic.Layer();
for (let row = 0; row < this.orbs.length; row++) {
for (let orb = 0; orb < this.orbs[row].length; orb++) {
layer.add(this.orbs[row][orb]);
this.orbCanvases.push(orbCanvas.id);
}
}
this.stage.add(layer);
}
我改为将侦听器添加到 orb 对象:
addRow (colIdx) {
for (let rowIdx = 0; rowIdx < 6; rowIdx++) {
//same code as before
let orbject = new Kinetic.Circle({
x: (rowIdx + 0.5) * 100, y: (colIdx + 0.5) * 100,
width: 100, height: 100,
fill: orbColor, draggable: true, pos: [rowIdx, colIdx]
});
orbject.on("mousedown", this.handleMouseDown);
orbject.on("mouseup", this.handleMouseUp);
orbject.on("mouseout", this.handleMouseOut);
orbject.on("mousemove", this.handleMouseMove);
this.orbs[colIdx].push(orbject);
}
}
这样做的好处是让拖放变得更快,而之前的速度非常慢,但我仍然无法让我的对象交换位置。
需要明确的是,我的主要问题是知道我应该更改哪些 x、y 值。目前在handleMouseMove,我一直在尝试改变:
e.target.attrs.x = newX;
e.target.attrs.y = newY;
// newX and newY can be any number
但是,无论我将其更改为什么,它都没有效果。所以它会帮助我知道我是否改变了错误的东西/位置,例如,也许我应该从我存储的数组中改变 Kinetic Circle?再次感谢。
编辑 2:
我想我明白了!但是,我必须将this.orbs 设置在window.orbs 的窗口中,然后进行测试:
window.orbs[0][0].x(450);
window.orbs[0][0].draw();
这导致 x 位置发生变化。但是把它放在一个窗口中似乎不是一个好习惯?
编辑 3:
我现在可以连续交换球体,除非在mouseover 继续开火时再次交换相同的球体。但是,在mouseup,它可以再次交换。我还必须再次设置多个层,以使 mouseover 事件在持有另一个球体时起作用,但性能似乎有所提高。
我将尝试弄清楚如何让它们能够在同一个鼠标按住时连续交换,但与此同时,这是我为实现此目的而编写的代码:
addRow (colIdx) {
for (let rowIdx = 0; rowIdx < 6; rowIdx++) {
// same code as before, changed attr given to Kinetic.Circle
let orbject = new Kinetic.Circle({
x: (rowIdx + 0.5) * 100, y: (colIdx + 0.5) * 100,
width: 100, height: 100,
fill: orbColor, draggable: true, orbId: `orb${colIdx}${rowIdx}`
});
}
}
handleMouseDown (e) {
window.currentOrb = window.orbs[e.target.attrs.orbId];
window.newX = e.target.attrs.x;
window.newY = e.target.attrs.y;
}
鼠标向下按 ID 及其 X 和 Y 保存 currentOrb
handleMouseUp (e) {
window.currentOrb.x(window.newX);
window.currentOrb.y(window.newY);
window.currentOrb.parent.clear();
window.currentOrb.parent.draw();
window.currentOrb.draw();
window.currentOrb = undefined;
for (let i = 0; i < 5; i++) {
for (let j = 0; j < 6; j++) {
window.orbs[`orb${i}${j}`].draw();
}
}
}
当鼠标被释放时,目前所有的球体都被重新绘制,所以它们都可以被使用。我计划对此进行重构,以便只有悬停在上面的球体才能进行此更改。
handleMouseMove (e) {
if (window.currentOrb !== undefined && (window.currentOrb.attrs.orbId !== e.target.attrs.orbId)) {
window.orbMove.pause();
window.currentTime = 0;
window.orbMove.play();
let targOrbX = e.target.attrs.x;
let targOrbY = e.target.attrs.y;
// This is the target orb that's being changed's value
// We're storing this in targOrb
e.target.x(window.newX);
e.target.y(window.newY);
e.target.parent.clear();
e.target.parent.draw();
e.target.draw();
// Here we have the previously set current orb's position becoming
// the target orb's position
window.newX = targOrbX;
window.newY = targOrbY;
// Now that the move is made, we can set the newX and Y to be the
// target orb's position once mouseup
}
}
球体交换逻辑,适用于一次通过球体,但如果它们在同一回合中再次通过,则无效。
【问题讨论】:
标签: javascript html canvas kineticjs