请看dragrid.vue中的overlap方法:
overlap(node) {
// 下移节点
this.nodes.forEach(n => {
if(node !== n && n.y + n.h > node.y) {
n.y += node.h;
}
});
}
n.y + n.h > node.y 表示可以与拖拽节点发生碰撞,以及在拖拽节点下方的节点。
在dragdrop.drag中会调用该方法。
注意目前该方法会有问题,没有考虑到如果碰撞节点比较高,则 n.y += node.h 并没有将该节点下沉到拖拽节点下方,从而拖拽节点会叠加上去。后面会介绍解决方法。
缩放
上面的思路都理解之后,缩放其实也是一样的,主要还是要进行坐标转换,坐标发生变化后,就会调用overlap方法。
resize(event) {
const opt = this.dragrid.cfg;
// 之前
const x1 = this.currentNode.x * opt.cellW + this.offsetX,
y1 = this.currentNode.y * opt.cellH + this.offsetY;
// 之后
const x2 = event.pageX - this.containerOffset.left,
y2 = event.pageY - this.containerOffset.top;
// 偏移
const dx = x2 - x1, dy = y2 - y1;
// 新的节点宽和高
const w = this.currentNode.w * opt.cellW + dx,
h = this.currentNode.h * opt.cellH + dy;
// 样式设置
this.dragElement.style.cssText += ';width:' + w + 'px;height:' + h + 'px;';
// 坐标转换
const nodeW = Math.round(w / opt.cellW);
const nodeH = Math.round(h / opt.cellH);
let currentNode = this.dragrid.currentNode;
// 发生移动
if(currentNode.w !== nodeW || currentNode.h !== nodeH) {
currentNode.w = nodeW;
currentNode.h = nodeH;
this.dragrid.overlap(currentNode);
}
}
根据鼠标距拖拽容器的距离的偏移,来修改节点的大小(宽和高),其中x1为鼠标点击后距离容器的距离,x2为移动一段距离之后距离容器的距离,那么差值dx就为鼠标移动的距离,dy同理。
到这里,插件的核心逻辑基本上已经完成了。
[fix]解决碰撞位置靠上的大块,并没有下移的问题
overlap修改为:
overlap(node) {
let offsetUpY = 0;
// 碰撞检测,查找一起碰撞节点里面,位置最靠上的那个
this.nodes.forEach(n => {
if(node !== n && this.checkHit(node, n)){
const value = node.y - n.y;
offsetUpY = value > offsetUpY ? value : offsetUpY;
}
});
// 下移节点
this.nodes.forEach(n => {
if(node !== n && n.y + n.h > node.y) {
n.y += (node.h + offsetUpY);
}
});
}
offsetUpY 最终存放的是与拖拽节点发生碰撞的所有节点中,位置最靠上的节点与拖拽节点之间的距离。然后再下移过程中会加上该offsetUpY值,确保所有节点下移到拖拽节点下方。
这个插件的核心逻辑就说到这里了,读者可以自己解决如下一些问题:
- 缩放限制,达到最小宽度就不能再继续缩放了。
- 拖拽控制滚动条。
