请看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值,确保所有节点下移到拖拽节点下方。
这个插件的核心逻辑就说到这里了,读者可以自己解决如下一些问题:
- 缩放限制,达到最小宽度就不能再继续缩放了。
- 拖拽控制滚动条。