【问题标题】:Applying clipTo path on image in fabric.js incorrectly repositions the image在 fabric.js 中的图像上应用 clipTo 路径会错误地重新定位图像
【发布时间】:2015-11-30 18:42:37
【问题描述】:

请看一下这个小提琴:

http://jsfiddle.net/2ktvyk4e/5/

    var imgUrl, snapshotCanvas;

    imgUrl = 'http://cdn-development.wecora.com/boards/backgrounds/000/001/388/cover/ocean-background.jpg';

    snapshotCanvas = new fabric.StaticCanvas('snapshotCanvas', {
      backgroundColor: '#e0e0e0',
      width: 1000,
      height: 1500
    });

    fabric.Image.fromURL(imgUrl, function(img) {
      img.set({
        width: 1000,
        left: 0,
        top: 0,
        clipTo: function(ctx) {
          return ctx.rect(0, 0, 1000, 400);
        }
      });
      return snapshotCanvas.add(img).renderAll();
    }, {
      crossOrigin: 'Anonymous'
    });

这很简单。我正在加载图像,然后尝试对其进行剪辑,以便画布的全宽但被剪辑,因此仅显示前 400 个像素。由于某种原因,clipTo 导致图像莫名其妙地移动和调整大小:

如您所见,当应用剪切路径时,图像会莫名其妙地重新定位在画布上。如果我删除clipTo,那么图像加载完整的画布宽度没有问题(当然它也是完整的高度,这是我们不想要的)。

我不知道这里发生了什么,也不知道为什么会这样,因此感谢您的帮助。

【问题讨论】:

    标签: fabricjs clipping


    【解决方案1】:

    确保在画布和图像上都有originXoriginYtopleft。另外 - 你真的不需要在画布上剪辑任何东西。我发现 clipTo 的唯一真正用途是将拼贴图像剪裁到它们的边界形状。如果您想限制图像被拖动到​​ 400 像素以上,我建议在其下方渲染一个矩形(evented = falseselectable = false),然后剪切到该矩形。

    我在没有clipTo 的情况下将其放在一起(并更改了一些数字,因此我没有横向滚动)。它在画布的一半处渲染图像。

    http://jsfiddle.net/2ktvyk4e/6/

    编辑:

    我翻阅了一些源代码,找到了clipByName 方法和两个查找东西的辅助方法。我用它来跟踪拼贴图像及其边界矩形(“图像”和“剪辑”)。我将它们存储在一个对象中:

    imageObjects: { 
        'collage_0': http://some.tld/to/image.ext,
        'collage_1': http://some.tld/to/image2.ext 
    }
    

    查找剪辑或图像的辅助方法:

    findClipByClipName: function (clipName) {
        var clip = _(canvas.getObjects()).where({ clipFor: clipName }).first();
    
        return clip;
    },
    
    findImageByClipFor: function (clipFor) {
        var image = _(canvas.getObjects()).where({ clipName: clipFor }).first();
    
        return image;
    }, 
    

    实际剪裁方法:

    clipByName: function (ctx) {
        this.setCoords();
        var clipRect, scaleXTo1, scaleYTo1;
        clipRect = collage.findClipByClipName(this.clipName);
        scaleXTo1 = (1 / this.scaleX);
        scaleYTo1 = (1 / this.scaleY);
        ctx.save();
    
        var ctxLeft, ctxTop;
        ctxLeft = -(this.width / 2) + clipRect.strokeWidth;
        ctxTop = -(this.height / 2) + clipRect.strokeWidth;
    
        ctx.translate(ctxLeft, ctxTop);
    
        ctx.rotate(degToRad(this.angle * -1));
        ctx.scale(scaleXTo1, scaleYTo1);
        ctx.beginPath();
        ctx.rect(
            clipRect.left - this.oCoords.tl.x,
            clipRect.top - this.oCoords.tl.y,
            clipRect.width,
            clipRect.height
        );
        ctx.closePath();
        ctx.restore();
    
        function degToRad(degrees) {
            return degrees * (Math.PI / 180);
        }
    },
    

    最后将图像添加到画布中,所有这些都融合在一起:

    var clipName, clip, image;
    
    clipName = helpers.findKeyByValue(url, this.imageObjects);
    clip = this.findClipByClipName(clipName);
    
    image = new Image();
    image.onload = function () {
        var collageImage = new fabric.Image(image, $.extend({}, collage.commonImageProps, {
            left: clip.left,
            top: clip.top,
            clipName: clipName,
            clipTo: function (ctx) {
                return _.bind(collage.clipByName, collageImage)(ctx);
            }
        }));
    
        collage.scaleImagesToClip(collageImage);
        canvas.add(collageImage);
    };
    

    【讨论】:

    • 谢谢,但我认为您没有完全理解用例。这是一个 HEADER 图像(请参阅staging.wecora.com/boards/_Mwn5zsfpo1XB7RQpyPa)作为示例。我希望标题图像是画布宽度,但只有前 300 个像素可见。我在画布和图像上尝试了 offsetX/Y 没有效果。此外,您的其他解决方案似乎对此有点过分了。这似乎是一个 fabricjs 错误,但不知道如何修复。
    • @JoshL 来自该站点,看起来您根本不需要使用画布。
    • 我们使用 HTML 画布来创建页面的缩略图,这就是我们需要这个功能的原因。
    猜你喜欢
    • 2019-04-12
    • 1970-01-01
    • 2019-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多