返回介绍

Part 8:裁切 和 ClipPath 裁切路径

发布于 2024-11-08 20:01:31 字数 12324 浏览 0 评论 0 收藏 0

ClipPaths basics

The new clipPath property 新的 clipPath 属性

在 2.4.0 中,我们为所有对象引入了 clipPath 属性。 ClipPath 将替换 clipTo:funcion(){} ,以实现相同的灵活性,但具有更好的兼容性。

ClipPath 需要对象缓存。

How to use it 如何使用

将您自己的 clipPath 创建为普通的 Fabric 对象,并将其分配给您要裁剪的对象的 clipPath 属性。 根据 SVG 规范中的定义,clipPath 没有 stroke,并用黑色填充,与黑色像素重叠的对象的像素将是可见的,而其他像素则不可见。

让我们从一些基本示例开始,然后看看它的外观。 在此第一个示例中,红色的 rect 被一个圆圈夹住,只有圆形内的部分可见。虽然不是很有用,但是基本功能是这样的。

请注意:clipPath 从对象的中心开始定位,对象 originX 和 originY 不起任何作用,而 clipPath originX 和 originY 起作用。定位逻辑与 fabric.Group 相同。

<template>
  <div class="groups">
    <canvas id="canvas"></canvas>
  </div>
</template>
<script>
import { fabric } from "fabric";
export default {
  data() {
    return {
      canvas: "",
    };
  },
  mounted() {
    this.canvas = new fabric.Canvas("canvas", {
      width: 400,
      height: 400,
      backgroundColor: "#ddd",
    });

    var clipPath = new fabric.Circle({
        radius:40,
        left:-40,
        top:-40
    })

    var rect = new fabric.Rect({
        width:200,
        height:100,
        fill:"red"
    })

    rect.clipPath = clipPath;
    this.canvas.add(rect)
  },
};
</script>
<style>
</style>

我们可以剪辑一个组:

mounted() {
    this.canvas = new fabric.Canvas("canvas", {
      width: 300,
      height: 300,
      backgroundColor: "#ddd",
    });

    var clipPath = new fabric.Circle({
        radius:100,
        top:-100,
        left:-100
    })

    var group = new fabric.Group([
        new fabric.Rect({width :100,height:100,fill:"red"}),
        new fabric.Rect({width :100,height:100,fill:"yellow",left:100}),
        new fabric.Rect({width :100,height:100,fill:"blue",top:100}),
        new fabric.Rect({width :100,height:100,fill:"green",left:100,top:100}),
    ]);

    group.clipPath = clipPath;
    this.canvas.add(group)
  },

或者我们可以使用组进行剪辑。如果是组,请记住组中的每个对象在逻辑上或与其他对象成对,否则就不会有非零或奇数的裁剪规则。

mounted() {
    this.canvas = new fabric.Canvas("canvas", {
      width: 300,
      height: 300,
      backgroundColor: "#ddd",
    });

    var clipPath = new fabric.Group([
        new fabric.Circle({radius:70,top:-70,left:-70}),
        new fabric.Circle({radius:40,top:-95,left:-95}),
        new fabric.Circle({radius:40,top:15,left:15}),
    ],{left:-95,top:-95})

    var group = new fabric.Group([
        new fabric.Rect({width:100,height:100,fill:"red"}),
        new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
        new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
        new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
    ])

    group.clipPath = clipPath;
    this.canvas.add(group);
  },

Continue with more examples

More advanced use cases 更多高级用法

Nesting clipPaths 折叠 clipPaths

clipTo 和 canvas.clip()用法的一个问题是您一次最多只能有一个 clipPath。

通过此实现,clippaths 可以具有自己的剪切路径。尽管手动编程不太直观,但它允许将 clipPaths 与 gheter 相交。

mounted() {
    this.canvas = new fabric.Canvas("canvas", {
      width: 300,
      height: 300,
      backgroundColor: "#ddd",
    });

    var clipPath = new fabric.Circle({radius:70,top:-50,left:-50});
    var innerClipPath = new fabric.Circle({radius:70,top:-90,left:-90});
    clipPath.clipPath = innerClipPath;

    var group = new fabric.Group([
        new fabric.Rect({width:100,height:100,fill:"red"}),
        new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
        new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
        new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
    ])

    group.clipPath = clipPath;
    this.canvas.add(group)
  },

组内对象中的 ClipPath 应与组本身的 clipPath 隔离:

mounted() {
    this.canvas = new fabric.Canvas("canvas", {
      width: 300,
      height: 300,
      backgroundColor: "#ddd",
    });

      var clipPath = new fabric.Circle({radius:100,top:-100,left:-100});

    var small = new fabric.Circle({radius:50,top:-50,left:-50})

    var group = new fabric.Group([
        new fabric.Rect({width:100,height:100,fill:"red",clipPath:small}),
        new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
        new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
        new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
    ])

    group.clipPath = clipPath;
    this.canvas.add(group)
  },

Clipping with Text

同样,使用 clipTo 也无法进行文本剪切,因此开发人员通常不得不依靠这种模式。

mounted() {
    this.canvas = new fabric.Canvas("canvas", {
      width: 300,
      height: 300,
      backgroundColor: "#ddd",
    });

    var clipPath = new fabric.Text(
        'Hi I\'m the \nnew ClipPath!\nI hope we\'ll\nbe friends',
        {top:-100,left:-100}
    );

    var group = new fabric.Group([
        new fabric.Rect({width:100,height:100,fill:"red"}),
        new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
        new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
        new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
    ])

    group.clipPath = clipPath;
    this.canvas.add(group)
  },

Continue with more examples

Clipping the canvas 剪裁画布

我们可以像对对象一样将 clipPath 应用于 StaticCanvas。在这种情况下,clipPath 受缩放和平移的影响,与 Object.clipPath 相反,它位于左上角。

mounted() {
    this.canvas = new fabric.Canvas("canvas", {
      width: 300,
      height: 300,
      backgroundColor: "#ddd",
    });

        var group = new fabric.Group([
        new fabric.Rect({width:100,height:100,fill:"red"}),
        new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
        new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
        new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
    ])

    var clipPath = new fabric.Circle({radius:100,top:0,left:50})

    this.canvas.clipPath = clipPath;
    this.canvas.add(group)
  },

与旧的 clipTo 函数一样,除非您将 canvas.controlsAboveOverlay 设置为 true,否则 clipPath 也是剪辑控件。

mounted() {
    this.canvas = new fabric.Canvas("canvas", {
      width: 300,
      height: 300,
      backgroundColor: "#ddd",
    });

        this.canvas.controlsAboveOverlay = true;

        var group = new fabric.Group([
        new fabric.Rect({width:100,height:100,fill:"red"}),
        new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
        new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
        new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
    ])

    var clipPath = new fabric.Circle({radius:100,top:0,left:50})

    this.canvas.clipPath = clipPath;
    this.canvas.add(group)
  },

Animating the clipPaths

ClipPath 可以像其他任何对象一样设置动画。画布 clipPath 动画非常有效,而为 Object 动画时,每次都会使对象缓存无效。

mounted() {
    var canvas = this.canvas = new fabric.Canvas("canvas", {
      width: 300,
      height: 300,
      backgroundColor: "#ddd",
    });

        var clipPath = new fabric.Rect({width:100,height:100,top:0,left:0})

    this.canvas.controlsAboveOverlay = true;

    function animateLeft(){
        clipPath.animate({
            left:200,
        },{
            duration:900,
            onChange: canvas.requestRenderAll.bind(canvas),
            onComplete:animateRight,
        })
    }
    function animateRight(){
        clipPath.animate({
            left:0,
        },{
            duration:1200,
            onChange:canvas.requestRenderAll.bind(canvas),
            onComplete:animateLeft,
        })
    }

    function animateDown(){
        clipPath.animate({
            top:100,
        },{
            duration:500,
            onChange:canvas.requestRenderAll.bind(canvas),
            onComplete:animateUp,
        })
    }

    function animateUp(){
        clipPath.animate({
            top:0,
        },{
            duration:400,
            onChange:canvas.requestRenderAll.bind(canvas),
            onComplete:animateDown
        })
    }

    var group = new fabric.Group([
        new fabric.Rect({width:100,height:100,fill:"red"}),
        new fabric.Rect({width:100,height:100,fill:"yellow",left:100}),
        new fabric.Rect({width:100,height:100,fill:"blue",top:100}),
        new fabric.Rect({width:100,height:100,fill:"green",left:100,top:100}),
    ],{
        scale:1.5
    })

    animateLeft();
    animateDown();

    this.canvas.clipPath = clipPath;
    this.canvas.add(group)
  },

Continue with more examples

Clipping the objects with absolute clipPaths 使用绝对定位的 clipPaths 剪切对象

我们可以对一个对象应用 clipPath,指定它应该是绝对定位的。这意味着 clipPath 不是相对于对象的中心,而是仅仅定位在画布上。 物体将不会移动,而 clipPath 将保持稳定。效果是 clipPath 在画布上创建了一个形状,并且只允许它自己的对象出现在画布中。

mounted() {
   var canvas =  this.canvas = new fabric.Canvas("canvas", {
      width: 500,
      height: 500,
      backgroundColor: "#ddd",
    });

    var clipPath = new fabric.Rect({width:500,height:250,top:0,left:0,absolutePositioned:true})

    var clipPath2 = new fabric.Rect({width:500,height:250,top:250,left:0,absolutePositioned:true})

    fabric.Image.fromURL("http://fabricjs.com/assets/dragon.jpg",function(img){
        img.clipPath = clipPath;
        img.scaleToWidth(500);
        canvas.add(img);
    })

    fabric.Image.fromURL("http://fabricjs.com/assets/dragon2.jpg",function(img){
        img.clipPath =clipPath2;
        img.scaleToWidth(500);
        img.top = 250;
        canvas.add(img)
    })
  },

Inverted clipPaths 颠倒的 clipPaths

我们还可以裁剪具有从 clipPath 定义的倒置形状的对象。 警告:如果创建一个组,则必须反转该组。反转组中用作 clipPath 的单个对象不会产生任何效果,因此不受支持。

您也可以使用单个对象的 globalCompositeOperation 获得很酷的效果,但是也不支持。

mounted() {
   var canvas =  this.canvas = new fabric.Canvas("canvas", {
      width: 500,
      height: 500,
      backgroundColor: "#ddd",
    });

    var clipPath = new fabric.Circle({radius:100,top:-200,left:-200});

    var clipPath2 = new fabric.Circle({radius:100,top:0,left:0})

    var clipPath3 = new fabric.Circle({radius:100,top:0,left:-200})

    var clipPath4 = new fabric.Circle({radius:100,top:-200,left:0})

    var g = new fabric.Group([clipPath,clipPath2,clipPath3,clipPath4])

    g.inverted = true;

    fabric.Image.fromURL("http://fabricjs.com/assets/dragon.jpg",function(img){
        img.clipPath = g;
        img.scaleToWidth(500);
        canvas.add(img);
    })
  },

不颠倒的效果 g.inverted = false 如下:

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文