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

为什么80%的码农都做不了架构师?>>> hot3.png

写这篇文章的时候我就要说一下了,这个遮罩和裁剪耗费了我真的是九牛二虎之力

裁剪的插件很多,无论你用原生JS,JQuery, Vue还是React.总能找到一款裁剪插件。今天我要说的是自己写一个截图功能,直接就在操作的画布中操作需要裁剪的图片,而不是跳一个新页面裁剪后再挪过来。Fabricjs 提供了很多方式的裁剪,最常见的是Object属性的上的clipTo,然而有弊端.

比如google一下比较好的一个demo: http://jsfiddle.net/hellomaya/kNEaX/1/

  1. 发现没有,裁剪后的选框依然和原图片一样大,无论用啥操作都没法使其变小(或许有办法我没试出来)

Fabric.js高级点的教程3--添加遮罩和裁剪的方法_第1张图片

  1. 看源码,会发现他的clipTo一方面不完善,一方面只能是矩形的裁剪。没法实现遮罩。比如如下图:

Fabric.js高级点的教程3--添加遮罩和裁剪的方法_第2张图片

这个时候发现官方demo有个其他方式的遮罩。 http://fabricjs.com/patterns fabric.Pattern 这个捏,文档写的倒是挺含含糊糊,网上的例子也是很少,不过功能是很强大,无论字体,形状,图片都统统可以给你遮罩上去。但是离我们最后要实现的功能还是有点距离

首先理清一下思路,

  1. 一个是选择图片的时候触发遮罩功能
  2. 添加遮罩形状,往遮罩形状里面添加图片,相当于一个图层
  3. 隐藏选中的图片,添加一个备份的图片放在下面当一个底部的图层,作为参考。这里加一个备份图片有其道理,看了我后面的代码就会明白,这一步很重要
  4. 调整裁剪(遮罩)形状和位置,裁剪
  5. 确定裁剪,隐藏备份图片。这个时候要注意,假如裁剪后的图片移动或者放大缩小,备份的图片也要跟着改变
  6. 再次点击显示备份的图片

是不是我直接可以贴代码了,里面主要涉及了如何移动,放大缩小的逻辑。吼吼。。。

首先是触发裁剪遮罩。这里只是随意定义了一个react 矩形的遮罩形状,后面你可以自己自定义。

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

    }

接着是确定裁剪

	let activeObject = state.canvas.getActiveObject();
        state.isClipping = false
        activeObject.clipClone.visible = false
        state.canvas.remove(state.clipActiveObj);

这样你差不多也能明白个差不多了,让你单独自己写个裁剪插件适应其他项目也是没问题了。

转载于:https://my.oschina.net/xmqywx/blog/2246082

你可能感兴趣的:(Fabric.js高级点的教程3--添加遮罩和裁剪的方法)