Fabric.js高級點的教程3--添加遮罩和裁剪的方法

寫這篇文章的時候我就要說一下了,這個遮罩和裁剪耗費了我真的是九牛二虎之力react

裁剪的插件不少,不管你用原生JS,JQuery, Vue仍是React.總能找到一款裁剪插件。今天我要說的是本身寫一個截圖功能,直接就在操做的畫布中操做須要裁剪的圖片,而不是跳一個新頁面裁剪後再挪過來。Fabricjs 提供了不少方式的裁剪,最多見的是Object屬性的上的clipTo,然而有弊端.canvas

好比google一下比較好的一個demo: http://jsfiddle.net/hellomaya/kNEaX/1/svg

  1. 發現沒有,裁剪後的選框依然和原圖片同樣大,不管用啥操做都無法使其變小(或許有辦法我沒試出來)

  1. 看源碼,會發現他的clipTo一方面不完善,一方面只能是矩形的裁剪。無法實現遮罩。好比以下圖:

這個時候發現官方demo有個其餘方式的遮罩。 http://fabricjs.com/patterns fabric.Pattern 這個捏,文檔寫的卻是挺含含糊糊,網上的例子也是不多,不過功能是很強大,不管字體,形狀,圖片都通通能夠給你遮罩上去。可是離咱們最後要實現的功能仍是有點距離post

首先理清一下思路,字體

  1. 一個是選擇圖片的時候觸發遮罩功能
  2. 添加遮罩形狀,往遮罩形狀裏面添加圖片,至關於一個圖層
  3. 隱藏選中的圖片,添加一個備份的圖片放在下面當一個底部的圖層,做爲參考。這裏加一個備份圖片有其道理,看了我後面的代碼就會明白,這一步很重要
  4. 調整裁剪(遮罩)形狀和位置,裁剪
  5. 肯定裁剪,隱藏備份圖片。這個時候要注意,假如裁剪後的圖片移動或者放大縮小,備份的圖片也要跟着改變
  6. 再次點擊顯示備份的圖片

是否是我直接能夠貼代碼了,裏面主要涉及瞭如何移動,放大縮小的邏輯。吼吼。。。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);

這樣你差很少也能明白個差很少了,讓你單獨本身寫個裁剪插件適應其餘項目也是沒問題了。插件

相關文章
相關標籤/搜索