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

原文链接:https://my.oschina.net/xmqywx/blog/2246082

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

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

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

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

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

这个时候发现官方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

展开阅读全文
博主设置当前文章不允许评论。

cocos lua 圆环遮罩裁剪

10-19

rncocos2d使用的应该都知道 ClippingNode 和 ProgressTimer的使用方法,这个功能的实现就是基于他们实现的。rn需求(主题思路):一个完整的圆形的帧动画(非图片)对它进行裁剪,通过 ProgressTimer控制裁剪区控制帧动画的可视区域。加入到计时器中就可以实现可视化的缓慢增长的效果。rn注意:如果是一张图片 直接通过ProgressTimer就可以实现百分比显示进度条rn[color=#FF0000] 大神勿喷!!!![/color] 上代码rn-----------------此处应该有图片。-------------------------rn[color=#FF0000] 图片上传不上去!!!![/color][img=https://forum.csdn.net/PointForum/ui/scripts/csdn/Plugin/003/monkey/10.gif][/img]rnrn[code=c] rn local sprite = cc.Sprite:create("xx.png") ---- 一张圆环形状的图片rn local progress = cc.ProgressTimer:create(sprite) ----创建ProgressTimerrn progress:setPercentage(0) ----rn progress:setName("per")rnrn local holesStencil = cc.Node:create()rn holesStencil:setName("holesStencil")rn holesStencil:addChild(progress)rn local spriteBg = cc.Sprite:create("xx.png") ----背景用于放置帧动画 可以和上面用同一张图片rnrn spriteBg:setName("spriteBg")rn spriteBg:setOpacity(0)rnrn local eff = xxx -----帧动画rn spriteBg:addChild(eff)rn local clipS = cc.ClippingNode:create() ----创建ClippingNodern clipS:setStencil(holesStencil)rn clipS:addChild(spriteBg)rn clipS:setName("clipS")rnrnrn clipS:setInverted(false) ---设置可视区为裁剪区域,还是裁剪剩余区域rn clipS:setAlphaThreshold(1) ---根据alpha值控制显示rn clipS:setAnchorPoint(cc.p(0, 0)) rn Node:addChild(clipS) ----添加到节点rnrnrn============================================rn----rn local nodeClip = Node:getChildByName("clipS")rn local nodeStencil = nodeClip:getStencil()rn local nodeProgess = nodeStencil:getChildByName("per") rn -----通过设置ProgressTimer 控制显示区域rn nodeProgess:setPercentage(xx)rn[/code]rn位置的摆放和对齐需要根据自己的实际需求调整rn裁剪原理可参考下面的内容,这里不多说了rn[url=http://www.mamicode.com/info-detail-247772.html][/url] 论坛

没有更多推荐了,返回首页