寫這篇文章的時候我就要說一下了,這個遮罩和裁剪耗費了我真的是九牛二虎之力react
裁剪的插件不少,不管你用原生JS,JQuery, Vue仍是React.總能找到一款裁剪插件。今天我要說的是本身寫一個截圖功能,直接就在操做的畫布中操做須要裁剪的圖片,而不是跳一個新頁面裁剪後再挪過來。Fabricjs 提供了不少方式的裁剪,最多見的是Object屬性的上的clipTo,然而有弊端.canvas
好比google一下比較好的一個demo: http://jsfiddle.net/hellomaya/kNEaX/1/svg
這個時候發現官方demo有個其餘方式的遮罩。 http://fabricjs.com/patterns fabric.Pattern 這個捏,文檔寫的卻是挺含含糊糊,網上的例子也是不多,不過功能是很強大,不管字體,形狀,圖片都通通能夠給你遮罩上去。可是離咱們最後要實現的功能仍是有點距離post
首先理清一下思路,字體
是否是我直接能夠貼代碼了,裏面主要涉及瞭如何移動,放大縮小的邏輯。吼吼。。。google
首先是觸發裁剪遮罩。這裏只是隨意定義了一個react 矩形的遮罩形狀,後面你能夠本身自定義。url
clipImage(state) { let activeObject = state.canvas.getActiveObject(); state.isClipping = true if (activeObject.type === 'image') { let clipBox = new fabric.Rect({ left: activeObject.left, top: activeObject.top, width: activeObject.width, height: activeObject.height, stroke: '#F5A623', strokeWidth: 1, fill: 'rgba(255, 255, 255, 0)', objectCaching: false, scaleX: activeObject.scaleX, scaleY: activeObject.scaleY, selectionBackgroundColor: 'rgba(255, 255, 255, 0)', padding: 0, angle: activeObject.angle }); state.clipBox = clipBox state.clipActiveObj = activeObject; // 區分是svg的img仍是普通img let url = activeObject.src ? activeObject.src : activeObject['xlink:href'] fabric.util.loadImage(url, function(img) { clipBox.fill = new fabric.Pattern({ source: img, repeat: 'no-repeat', offsetX: 0, offsetY: 0, }); state.canvas.add(clipBox); activeObject.set({ selectable: false, hoverCursor: 'default', evented: false, hasControls: false, perPixelTargetFind: false, }) activeObject.clone(function (clonedObj) { state.canvas.discardActiveObject(); clonedObj.set({ left: clonedObj.left, top: clonedObj.top, evented: false, opacity: 0.8 }); clipBox.clipClone = clonedObj; state.canvas.add(clonedObj); }); activeObject.visible = false; state.canvas.renderAll(); state.clipBox.on({ 'moving': () => { if (!state.isClipping) { clipBox.clipClone.left = clipBox.left - state.clipLeft clipBox.clipClone.top = clipBox.top - state.clipTop state.canvas.renderAll() return } let left =clipBox.left - clipBox.clipClone.left; let top = clipBox.top - clipBox.clipClone.top; state.clipLeft = left state.clipTop = top clipBox.fill.offsetX = -left / clipBox.clipClone.scaleX clipBox.fill.offsetY = -top / clipBox.clipClone.scaleY state.canvas.renderAll(); }, 'scaling': () => { if (!state.isClipping) { clipBox.clipClone.left = clipBox.left - state.clipLeft clipBox.clipClone.top = clipBox.top - state.clipTop clipBox.clipClone.scaleX = clipBox.scaleX clipBox.clipClone.scaleY = clipBox.scaleY state.canvas.renderAll() return } // let _width = clipBox.width / clipBox. let _width = clipBox.width * clipBox.scaleX / clipBox.clipClone.scaleX let _height = clipBox.height * clipBox.scaleY / clipBox.clipClone.scaleY let left =clipBox.left - clipBox.clipClone.left; let top = clipBox.top - clipBox.clipClone.top; state.clipLeft = clipBox.left state.clipTop = clipBox.top clipBox.fill.offsetX = -left / clipBox.clipClone.scaleX clipBox.fill.offsetY = -top / clipBox.clipClone.scaleX clipBox.scaleX = clipBox.clipClone.scaleX clipBox.scaleY = clipBox.clipClone.scaleY clipBox.width = _width clipBox.height = _height state.canvas.renderAll(); } }) setTimeout(() => { state.canvas.setActiveObject(state.clipBox); state.canvas.renderAll(); }, 300) }) } else { activeObject.clipClone.visible = true; state.canvas.renderAll(); } }
接着是肯定裁剪.net
let activeObject = state.canvas.getActiveObject(); state.isClipping = false activeObject.clipClone.visible = false state.canvas.remove(state.clipActiveObj);
這樣你差很少也能明白個差很少了,讓你單獨本身寫個裁剪插件適應其餘項目也是沒問題了。插件