【问题标题】:FabricJS Clipping and SVG ExportFabricJS 剪辑和 SVG 导出
【发布时间】:2018-02-09 13:49:09
【问题描述】:

我有一个小的fabricjs scene,它可以加载图像并将它们剪辑成 SVG 布局中定义的 SVG 形状。使用此stack 中指定的代码完成剪辑。

我有两个问题:

当我导出为 SVG(请参阅“导出为 SVG”按钮)时,剪辑不会持续存在。这可能吗,也许可以通过将剪辑转换为 SVG 来导出到 SVG?

let clippingSVG 变量中有一个 SVG 字符串。是否可以将此 SVG 用作整个画布(包括导出可能性)或图像组的另一个 clipPath?

提前致谢

【问题讨论】:

    标签: javascript fabricjs


    【解决方案1】:

    这是其他答案顶部的粗略实现,该答案提出了 toSVG 方法更改以使剪辑(固定)在 toSVG 中得到尊重。

    不固定的情况更难,我希望这会有所帮助。

    var img01URL = 'http://fabricjs.com/assets/printio.png';
    var img02URL = 'http://fabricjs.com/lib/pug.jpg';
    var img03URL = 'http://fabricjs.com/assets/ladybug.png';
    var img03URL = 'http://fabricjs.com/assets/ladybug.png';
    
    function toSvg() {
     document.getElementById('svg').innerHTML = canvas.toSVG();
    }
    
        fabric.Image.prototype.toSVG = function(reviver) {
          var markup = this._createBaseSVGMarkup(), x = -this.width / 2, y = -this.height / 2, clipUrl = '';
          if (this.clipPath) {
            var id = fabric.Object.__uid++;
            if (this.clipPath.fixed) {
              markup.push('<clipPath id="myClip' + id + '">\n',
              this.clipPath.toSVG(reviver),
              '</clipPath>\n');
            }
            clipUrl = ' clip-path="url(#myClip' + id + ')" ';
          }
          markup.push('<g ', clipUrl, '>',
            '<g transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '"', '>\n',
              '\t<image ', this.getSvgId(), 'xlink:href="', this.getSvgSrc(true),
                '" x="', x, '" y="', y,
                '" style="', this.getSvgStyles(),
                // we're essentially moving origin of transformation from top/left corner to the center of the shape
                // by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left
                // so that object's center aligns with container's left/top
                '" width="', this.width,
                '" height="', this.height,
              '"></image>\n'
          );
    
          if (this.stroke || this.strokeDashArray) {
            var origFill = this.fill;
            this.fill = null;
            markup.push(
              '<rect ',
                'x="', x, '" y="', y,
                '" width="', this.width, '" height="', this.height,
                '" style="', this.getSvgStyles(),
              '"/>\n'
            );
            this.fill = origFill;
          }
    
          markup.push('</g></g>\n');
    
          return reviver ? reviver(markup.join('')) : markup.join('');
        };
    
        fabric.Image.prototype._render = function(ctx) {
          // custom clip code
          if (this.clipPath) {
            ctx.save();
            if (this.clipPath.fixed) {
              var retina = this.canvas.getRetinaScaling();
              ctx.setTransform(retina, 0, 0, retina, 0, 0);
              // to handle zoom
              ctx.transform.apply(ctx, this.canvas.viewportTransform);
              //
              this.clipPath.transform(ctx);
            }
            this.clipPath._render(ctx);
            ctx.restore();
            ctx.clip();
          }
          
          // end custom clip code
        
        
          var x = -this.width / 2, y = -this.height / 2, elementToDraw;
    
          if (this.isMoving === false && this.resizeFilter && this._needsResize()) {
            this._lastScaleX = this.scaleX;
            this._lastScaleY = this.scaleY;
            this.applyResizeFilters();
          }
          elementToDraw = this._element;
          elementToDraw && ctx.drawImage(elementToDraw,
                                         0, 0, this.width, this.height,
                                         x, y, this.width, this.height);
          this._stroke(ctx);
          this._renderStroke(ctx);
        };
    
    var canvas = new fabric.Canvas('c');
    canvas.setZoom(0.5)
    fabric.Image.fromURL(img01URL, function(oImg) {
        oImg.scale(.25);
        oImg.left = 10;
        oImg.top = 10;
        oImg.clipPath = new fabric.Circle({radius: 40, top: 50, left: 50, fixed: true, fill: '', stroke: '' });
        canvas.add(oImg);
        canvas.renderAll();
    });
    
    fabric.Image.fromURL(img02URL, function(oImg) {
        oImg.scale(.40);
        oImg.left = 180;
        oImg.top = 0;
        oImg.clipPath = new fabric.Path('M85.6,606.2c-13.2,54.5-3.9,95.7,23.3,130.7c27.2,35-3.1,55.2-25.7,66.1C60.7,814,52.2,821,50.6,836.5c-1.6,15.6,19.5,76.3,29.6,86.4c10.1,10.1,32.7,31.9,47.5,54.5c14.8,22.6,34.2,7.8,34.2,7.8c14,10.9,28,0,28,0c24.9,11.7,39.7-4.7,39.7-4.7c12.4-14.8-14-30.3-14-30.3c-16.3-28.8-28.8-5.4-33.5-11.7s-8.6-7-33.5-35.8c-24.9-28.8,39.7-19.5,62.2-24.9c22.6-5.4,65.4-34.2,65.4-34.2c0,34.2,11.7,28.8,28.8,46.7c17.1,17.9,24.9,29.6,47.5,38.9c22.6,9.3,33.5,7.8,53.7,21c20.2,13.2,62.2,10.9,62.2,10.9c18.7,6.2,36.6,0,36.6,0c45.1,0,26.5-15.6,10.1-36.6c-16.3-21-49-3.1-63.8-13.2c-14.8-10.1-51.4-25.7-70-36.6c-18.7-10.9,0-30.3,0-48.2c0-17.9,14-31.9,14-31.9h72.4c0,0,56-3.9,70.8,26.5c14.8,30.3,37.3,36.6,38.1,52.9c0.8,16.3-13.2,17.9-13.2,17.9c-31.1-8.6-31.9,41.2-31.9,41.2c38.1,50.6,112-21,112-21c85.6-7.8,79.4-133.8,79.4-133.8c17.1-12.4,44.4-45.1,62.2-74.7c17.9-29.6,68.5-52.1,113.6-30.3c45.1,21.8,52.9-14.8,52.9-14.8c15.6,2.3,20.2-17.9,20.2-17.9c20.2-22.6-15.6-28-16.3-84c-0.8-56-47.5-66.1-45.1-82.5c2.3-16.3,49.8-68.5,38.1-63.8c-10.2,4.1-53,25.3-63.7,30.7c-0.4-1.4-1.1-3.4-2.5-6.6c-6.2-14-74.7,30.3-74.7,30.3s-108.5,64.2-129.6,68.9c-21,4.7-18.7-9.3-44.3-7c-25.7,2.3-38.5,4.7-154.1-44.4c-115.6-49-326,29.8-326,29.8s-168.1-267.9-28-383.4C265.8,13,78.4-83.3,32.9,168.8C-12.6,420.9,98.9,551.7,85.6,606.2z',{top: 0, left: 180, fixed: true, fill: '', stroke: '', scaleX: 0.2, scaleY: 0.2 });
        canvas.add(oImg);
        canvas.renderAll();
    });
    #c {
        border:1px solid #ccc;
    }
    <script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.17/fabric.min.js"></script>
    <button onClick='toSvg();'>TOSVG</button>
    <canvas id="c" width="400" height="400"></canvas>
    <div id="svg"></div>

    【讨论】:

    • 非常感谢..我只关注您的回答..我在添加多个对象时遇到问题。在图像之后我也尝试添加文本..但它显示在圆圈之外也..它没有裁剪..你能建议我吗? @AndreaBogazzi
    • 你能用所用的代码打开另一个问题,以便我们改进它吗?
    • 我在两天前问了这个问题。请看这个....stackoverflow.com/questions/46603510/…
    【解决方案2】:

    感谢 AndreaBogazzi 让我从右脚开始。我更喜欢使用 fabric.Image 的子类,而不是替换它的几个原型方法。剪切和粘贴可能很危险;事实上,最新版本的 fabricjs 已经与该解决方案不兼容。因此,这是同一解决方案的子类版本。在我的情况下,我总是使用固定的剪辑路径,所以我删除了所有对固定的引用。

    const ClippedImage = fabric.util.createClass(fabric.Image, {
        type: 'ClippedImage',
        initialized: function(options) {
            options || (options = {})
    
            this.callSuper('initialize', options)
        },
        _render: function(ctx) {
            if (this.clipPath) {
                ctx.save()
                var retina = this.canvas.getRetinaScaling()
                ctx.setTransform(retina, 0, 0, retina, 0, 0)
                ctx.transform.apply(ctx, this.canvas.viewportTransform)
                this.clipPath.transform(ctx)
                this.clipPath._render(ctx)
                ctx.restore()
                ctx.clip()
            }                    
            this.callSuper('_render', ctx)
        },
        toSVG: function(reviver) {
            let result = this.callSuper('toSVG')
            if(this.clipPath) {
                const clipId = `Clipped${fabric.Object.__uid++}`
                result = `
                    <clipPath id="${clipId}">
                        ${this.clipPath.toSVG(reviver)}
                    </clipPath>
                    <g clip-path="url(#${clipId})">${result}</g>`
            }
            return reviver ? reviver(result) : result
        }
    })
    

    【讨论】:

      猜你喜欢
      • 2018-07-19
      • 2018-11-28
      • 2013-09-09
      • 2014-11-12
      • 2013-06-27
      • 2017-11-10
      • 2016-01-06
      • 2020-09-24
      • 2016-03-24
      相关资源
      最近更新 更多