点赞 + 关注 + 收藏 = 学会了
当你要复制一个 fabric
的元素时,你考虑到的是什么?是深拷贝当前选中对象再添加到画布中?
其实,fabric.js
提供了一个克隆方法,在 fabric.js
官网的案例里也有这个demo:Fabric.js demos · Copy and Paste。
这次就讲讲这个 demo。
动手之前,我们先理清思路。
canvas.getActiveObject()
方法获取当前被选中的元素。clone()
方法,将当前选中的元素对象克隆出来。canvas.add()
方法将克隆出来的元素添加到画布中。当然,实际开发中还有很多需要注意的小点,比如选中一个组的时候要怎么复制粘贴?框选一堆元素时要怎么复制粘贴?
这些问题后面都会讲到,我们先学习如何复制1个元素。
理解了前面的思路就能动手了!
<div> <button onclick="copy()">复制</button> <button onclick="paste()">粘贴</button> </div> <canvas id="c" width="500" height="400" style="border: 1px solid #ccc;"></canvas> <script src="https://unpkg.com/fabric@5.3.0/dist/fabric.min.js"></script> <script> const canvas = new fabric.Canvas('c') let rect = new fabric.Rect({ left: 100, top: 50, fill: '#D81B60', width: 100, height: 100, strokeWidth: 2, stroke: '#880E4F', rx: 10, ry: 10, angle: 45 }) canvas.add(rect) // 克隆对象 let _clipboard = null // 复制 function copy() { // 要复制的目标元素 let target = canvas.getActiveObject() // 有选中的元素时才进行克隆 if (target) { target.clone(function(cloned) { _clipboard = cloned // 将克隆出来的元素赋值给 _clipboard }) } } // 粘贴 function paste() { // 如果克隆对象不存在的话就终止粘贴执行 if (!_clipboard) return // 执行粘贴操作,将克隆出来的对象再克隆一遍,然后添加到画布中。 _clipboard.clone(function(clonedObj) { // 适当的位移 clonedObj.set({ left: clonedObj.left + 10, top: clonedObj.top + 10, evented: true, // 当设置为“ false”时,对象不能成为事件的目标。所有事件都会通过它传播。 }) canvas.add(clonedObj) // 将克隆的元素添加到画布中 // 修改克隆对象的位置,以便多次粘贴时更容易观察 _clipboard.top += 10 _clipboard.left += 10 // 将当前选中项修改到新克隆到画布的元素上 canvas.setActiveObject(clonedObj) // 刷新画布 canvas.requestRenderAll() }) } </script>
首先在页面中创建2个按钮和1个画布,在画布中创建一个元素。
在 JS
部分需要创建一个变量保存克隆对象,这个变量叫 _clipboard
。
在执行复制操作时要判断当前是否选中元素对象。
在执行粘贴操作时要判断当前是否克隆了元素对象。
其实复制组和复制单个元素时一样的。也是需要获取当前选中的对象,组可以看作是一个元素对象。
代码和上面的一样,只需把单个元素换成组即可,我引用 fabric.js
官网的 demo
// 省略部分代码 let circle1 = new fabric.Circle({ radius: 65, fill: '#039BE5', left: 0 }) let circle2 = new fabric.Circle({ radius: 65, fill: '#4FC3F7', left: 110, opacity: 0.7 }) let group = new fabric.Group([circle1, circle2, ], { left: 40, top: 250 }) canvas.add(group)
加上前面的复制粘贴代码即可。
复制框选元素的操作会相对复杂一丢丢,但也只是一丢丢而已。
因为选中的不止一个元素,所以在粘贴的时候要遍历所有元素出来,用到 fabric.js
提供的 forEachObject
方法。
// 省略部分代码 // 粘贴 function paste() { // 如果克隆对象不存在的话就终止粘贴执行 if (!_clipboard) return _clipboard.clone(function(clonedObj) { // 适当的位移 clonedObj.set({ left: clonedObj.left + 10, top: clonedObj.top + 10, evented: true }) // 遍历粘贴所有选中的元素 clonedObj.canvas = canvas clonedObj.forEachObject(function(obj) { canvas.add(obj) }) clonedObj.setCoords() // 适当的位移 _clipboard.top += 10 _clipboard.left += 10 // 将新粘贴出来的元素全部选中 canvas.setActiveObject(clonedObj) }) }
最后需要做的就是兼容选中单个元素或者框选多个元素的情况。
获取到当前选中对象后有个 type
属性,当框选多个元素时,type
的值会变成 activeSelection
,我们就可以通过这个来判断当前是选中单个元素还是框选了多个元素。
// 省略部分代码 // 粘贴 function paste() { // 如果克隆对象不存在的话就终止粘贴执行 if (!_clipboard) return _clipboard.clone(function(clonedObj) { // 适当的位移 clonedObj.set({ left: clonedObj.left + 10, top: clonedObj.top + 10, evented: true }) if (clonedObj.type === 'activeSelection') { // 框选了多个元素 // 遍历粘贴所有选中的元素 clonedObj.canvas = canvas clonedObj.forEachObject(function(obj) { canvas.add(obj) }) clonedObj.setCoords() } else { // 选中一个元素 canvas.add(clonedObj) _clipboard.top += 10 _clipboard.left += 10 } // 适当的位移 _clipboard.top += 10 _clipboard.left += 10 // 将新粘贴出来的元素全部选中 canvas.setActiveObject(clonedObj) // 刷新画布 canvas.requestRenderAll() }) }
除了上面的鼠标操作外,我们还可以通过监听键盘的 ctrl + c
和 ctrl + v
(mac监听 command) 来实现上面的效果。
这部分工作留给工友去实现吧,我先溜了。
本文完整代码可通过下方链接获取。
⭐ 复制粘贴元素