2

我正在使用 Fabric.js 开发一个项目。

现在我需要创建一个自定义类并将其导出到 SVG。

我正在使用 Fabric.js 教程开始:

http://www.sitepoint.com/fabric-js-advanced/

这是javascript代码:

var LabeledRect = fabric.util.createClass(fabric.Rect, {
  type: 'labeledRect',
  initialize: function(options) {
    options || (options = { });
    this.callSuper('initialize', options);
    this.set('label', options.label || '');
  },
  toObject: function() {
    return fabric.util.object.extend(this.callSuper('toObject'), {
      label: this.get('label')
    });
  },
  _render: function(ctx) {
    this.callSuper('_render', ctx);
    ctx.font = '20px Helvetica';
    ctx.fillStyle = '#333';
    ctx.fillText(this.label, -this.width/2, -this.height/2 + 20);
  }
});

var canvas = new fabric.Canvas('container');

var labeledRect = new LabeledRect({
  width: 100,
  height: 50,
  left: 100,
  top: 100,
  label: 'test',
  fill: '#faa'
});
canvas.add(labeledRect);
document.getElementById('export-btn').onclick = function() {
canvas.deactivateAll().renderAll(); 
window.open('data:image/svg+xml;utf8,' + encodeURIComponent(canvas.toSVG()));

};

这里的HTML:

<canvas id="container" width="780" height="500"></canvas>
<a href="#" id="export-btn">Export SVG</a>

这是我的jsfiddle ..

http://jsfiddle.net/QPDy5/

我做错了什么?

提前致谢。

4

2 回答 2

3

Fabric 中的每个“类”(矩形、圆形、图像、路径等)都知道如何输出其 SVG 标记。负责它的方法是toSVG。例如,您可以看到toSVGof或fabric.Rectfabric.Textone

由于您在fabric.Rect此处创建了子类并且没有指定toSVGtoSVG因此使用原型链中的下一个对象。继承链中的下一个“类”恰好是fabric.Rect,因此您会看到fabric.Rect.prototype.toSVG.

解决方案很简单:toSVG在您的子类中指定。从理论上讲,您需要将 and 中的代码组合起来fabric.Rect#toSVGfabric.Text#toSVG但为了避免重复并保持可维护性,我们可以利用一些技巧:

toSVG: function() {
  var label = new fabric.Text(this.label, {
      originX: 'left',
      originY: 'top',
      left: this.left - this.width / 2,
      top: this.top - this.height / 2,
      fontSize: 20,
      fill: '#333',
      fontFamily: 'Helvetica'
  });
  return this.callSuper('toSVG') + label.toSVG();
}

当然,“fontSize”、“fill”和“fontFamily”应该理想地移动到实例级属性,以避免在那里重复它们。

这是一个修改后的测试——http://jsfiddle.net/fabricjs/QPDy5/1/

@Sergiu Paraschiv 向小组提出的建议是另一种可行的解决方案。

于 2013-09-18T08:55:48.417 回答
0

问题是没有 SVG 等价于fillText所以 FabricJS 似乎忽略了它。 我的解决方法是使用 afabric.Group并构建一个内部RectText

var LabeledRect = function(options) {
    var rect = new fabric.Rect({
        width: options.width,
        height: options.height,
        fill: options.fill
    });

    var label = new fabric.Text(options.label);

    var group = new fabric.Group([rect, label]);

    group.left = options.left;
    group.top = options.top;

    group.toSVG = function() {
        var e=[];
        for(var t = 0; t < this._objects.length; t++)
            e.push(this._objects[t].toSVG());

        return'<g transform="'+this.getSvgTransform()+'">'+e.join("")+"</g>"
    };

    return group;
};

我重写的原因toSVG是因为默认实现以相反的顺序(for(var t=this._objects.length;t--;))循环遍历子项。我不知道为什么会这样,但文本呈现在矩形下方。

于 2013-09-17T14:02:59.300 回答