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);

这样你差很少也能明白个差很少了,让你单独本身写个裁剪插件适应其余项目也是没问题了。插件

相关文章
相关标签/搜索