meteor - Fabric.js : Use SVG as a pattern & adjust fill of SVG pattern

标签 meteor html5-canvas fabricjs

我正在将 Fabric.js 与 Meteor 一起使用。

我有以下 SVG 图像,我将其用作路径组内路径上的图案。

enter image description here

正如您所看到的,它具有一定的透明度。

我想要做的是用这个图案填充路径,然后使用颜色选择器来操纵它的颜色。到目前为止,我已经能够通过将 SVG 添加为图案,然后复制路径并使用不透明度为 50% 的颜色填充该路径来做到这一点,但是当然,这会改变整个区域的颜色,而不仅仅是图案的颜色。基本上,由于模式已经是路径的“填充”,我将如何填充模式本身?

这是一个可以更好地解释的图表...

enter image description here

这是我在从下拉列表中选择特定模式时用来添加模式的代码(使用 Meteor 事件)...

'change .shapeTopPattern': function(e, template){ e.preventDefault();

      var textureID = e.target.value;

      if(textureID != '') { //If this shape has a texture selected.
          var texture = Textures.findOne(textureID);

          //Get the image
          var textureIMG = new Image;
          textureIMG.crossOrigin = "anonymous";
          textureIMG.src = texture.image;

          var patternURL = textureIMG.src;
          fabric.Image.fromURL(patternURL, function(img) {

              var obj = canvas.getActiveObject();
              var paths = obj.paths;

              paths.forEach(function(p) {
                if (p.pathName == "shapeTopTexture") {
                    img.width = p.width;
                    img.height = p.height

                    var patternSourceCanvas = new fabric.StaticCanvas();
                    patternSourceCanvas.add(img);
                    patternSourceCanvas.setDimensions({
                        width: p.width,
                        height: p.height
                      });
                    var texture = patternSourceCanvas.getElement();

                    var pattern = new fabric.Pattern({
                      source: texture,
                      repeat: 'no-repeat',
                      offsetX: p.width/2,
                      offsetY: p.height/2
                    });

                    obj.setFill();

                    if (obj instanceof fabric.PathGroup) {
                        p.fill = pattern;
                        obj.perPixelTargetFind = false;
                    } else {
                        obj.setFill(pattern);
                    }
                    canvas.renderAll();
                }
              });
           });

      }
  },

这是我在颜色选择器的更改事件上使用的函数。 “shapeTopPatternColour”是圆柱体路径组中的复制路径(圆柱体顶部)。我知道这显然就是为什么颜色覆盖整个区域而不仅仅是图案的原因,但它是我最接近我想要的。

changeTopPatternColour = function(o, color, opacity) {
    /*
    * o = object
    * color = rgbcolor data
    * opacity = .5
    */
    var paths = o.paths;
    paths.forEach(function(p) {
      if (p.pathName == "shapeTopPatternColour") {
        p.setFill(color);
        p.opacity = opacity;
      }
    });
    canvas.renderAll();
};

那我怎样才能...

  • 添加图案并将其维护为 SVG(仅在需要时)
  • 仅用颜色填充图案 Alpha,而不填充透明部分?

提前致谢。

最佳答案

不幸的是,我无法找到一种方法来将 svg 文件用作模式而不必对其进行光栅化,我很抱歉。在下面的示例中,您可以亲眼看到我总是完全重写表面。 我没有像图像一样加载 svg,而是正常加载 svg,然后使用路径组将其添加到 Canvas 中。对于此代码片段,我使用您的文件作为字符串,以避免烦人的 CORS 问题。

Here you can find the bitbucket repository

祝一切顺利。

$(function() {
  var canvas = new fabric.Canvas('c');
  canvas.setWidth(600);
  canvas.setHeight(370);
  var tint = function(color) {
    canvas.clear();
    var svgObjectString = '<?xml version="1.0" encoding="utf-8"?>' +
      '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"' +
      ' viewBox="0 0 596 366" style="enable-background:new 0 0 596 366;" xml:space="preserve">' +
      '<style type="text/css">' +
      '.st0{fill:#E0E0E0;}' +
      ' .st1{fill:url(#SVGID_1_);}' +
      '</style>' +
      '<path class="st0" d="M596,103.5c0,32-41.7,60.5-107.2,79.5c-51.7,15-118.2,24-190.8,24s-139.1-9-190.8-24C41.7,164,0,135.4,0,103.5' +
      'c0-0.2,0-0.3,0-0.5C0.8,46.1,133.9,0,298,0s297.2,46.1,298,103C596,103.2,596,103.3,596,103.5z"/>' +
      '<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="0" y1="133.25" x2="596" y2="133.25" gradientTransform="matrix(1 0 0 -1 0 368)">' +
      '<stop  offset="0" style="stop-color:#E8E8E8"/>' +
      '<stop  offset="0.23" style="stop-color:#878787"/>' +
      '<stop  offset="0.6" style="stop-color:#D6D6D6"/>' +
      '<stop  offset="1" style="stop-color:#ADADAD"/>' +
      '</linearGradient>' +
      '<path class="st1" d="M596,103.5v159c0,0.2,0,0.3,0,0.5c-0.8,56.9-133.9,103-298,103S0.8,319.9,0,263c0-0.2,0-0.3,0-0.5v-159' +
      'c0,32,41.7,60.5,107.2,79.5c51.7,15,118.2,24,190.8,24s139.1-9,190.8-24C554.3,164,596,135.4,596,103.5z"/>' +
      '</svg>';
    fabric.loadSVGFromString(svgObjectString, function(svgobject) {
      //fabric.loadSVGFromURL('../../Content/object.svg', function (svgobject) {
      var objGroup = new fabric.PathGroup(svgobject, {
        width: 596,
        height: 500
      });
      canvas.add(objGroup);

      var svgPatternString = '<?xml version="1.0" encoding="utf-8"?>' +
        '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' +
        '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"' +
        ' width="576px" height="576px" viewBox="0 0 576 576" enable-background="new 0 0 576 576" xml:space="preserve">' +
        '<polygon fill="#848484" points="290.664,286.625 244.214,729.625 338.422,729.625 "/>' +
        '<polygon fill="#848484" points="290.711,286.625 337.16,-156.375 242.953,-156.375 "/>' +
        '<polygon fill="#848484" points="290.688,286.602 -152.312,240.152 -152.312,334.359 "/>' +
        '<polygon fill="#848484" points="290.688,286.648 733.688,333.098 733.688,238.89 "/>' +
        '<polygon fill="#848484" points="290.664,286.625 244.214,729.625 338.422,729.625 "/>' +
        '<polygon fill="#848484" points="290.711,286.625 337.16,-156.375 242.953,-156.375 "/>' +
        '<polygon fill="#848484" points="290.688,286.602 -152.312,240.152 -152.312,334.359 "/>' +
        '<polygon fill="#848484" points="290.688,286.648 733.688,333.098 733.688,238.89 "/>' +
        '<polygon fill="#848484" points="290.666,286.616 75.532,676.646 162.318,713.297 "/>' +
        '<polygon fill="#848484" points="290.709,286.634 505.843,-103.396 419.057,-140.047 "/>' +
        '<polygon fill="#848484" points="290.696,286.604 -99.334,71.469 -135.984,158.255 "/>' +
        '<polygon fill="#848484" points="290.679,286.646 680.709,501.78 717.359,414.994 "/>' +
        '<polygon fill="#848484" points="290.671,286.608 -59.646,561.716 5.948,629.336 "/>' +
        '<polygon fill="#848484" points="290.704,286.642 641.021,11.534 575.427,-56.086 "/>' +
        '<polygon fill="#848484" points="290.704,286.609 15.597,-63.709 -52.024,1.885 "/>' +
        '<polygon fill="#848484" points="290.671,286.641 565.778,636.958 633.398,571.364 "/>' +
        '<polygon fill="#848484" points="290.679,286.603 -137.942,407.811 -102.993,495.296 "/>' +
        '<polygon fill="#848484" points="290.696,286.647 719.315,165.439 684.367,77.954 "/>' +
        '<polygon fill="#848484" points="290.709,286.617 169.502,-142.004 82.016,-107.055 "/>' +
        '<polygon fill="#848484" points="290.666,286.634 411.873,715.253 499.358,680.305 "/>' +
        '</svg>';

      fabric.loadSVGFromString(svgPatternString, function(svgpattern) {
        //fabric.loadSVGFromURL('../../Content/pattern.svg',
        //    function (svgpattern) {
        svgpattern.map(function(item) {
          item.fill = color;
        });
        var ptnGroup = new fabric.PathGroup(svgpattern, {
          top: -190,
          width: 596,
          height: 500
        });
        var paths = objGroup.paths;
        var path = paths[0];
        svgpattern.width = path.width;
        svgpattern.height = path.height;
        var patternSourceCanvas = new fabric.StaticCanvas();
        patternSourceCanvas.add(ptnGroup);
        patternSourceCanvas.setDimensions({
          width: path.width,
          height: path.height
        });
        var texture = patternSourceCanvas.getElement();
        var pattern = new fabric.Pattern({
          source: texture,
          repeat: 'no-repeat',
          offsetX: path.width / 2,
          offsetY: path.height / 2
        });
        objGroup.setFill();
        objGroup.globalCompositeOperation = "source-over";
        path.setFill("#ff0000");
        path.fill = pattern;
        objGroup.perPixelTargetFind = false;
        canvas.renderAll();
      });
    });
  }
  $('button')
    .on('click',
      function(e, args) {
        tint(e.target.value);
      });
});
canvas {
  border: 1px solid #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.2/fabric.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
  <div class="row">
    <div class="col-md-7">
      <canvas id="c" style="border: solid 1px #ccc;"></canvas>
    </div>
    <div class="col-md-5">
      <button class="btn-danger" value="red">red</button>
      <button class="btn-success" value="green">green</button>
      <button class="btn-primary" value="blue">blue</button>
    </div>
  </div>
</div>

编辑:为了检索圆柱体顶部的尺寸,我使用 svgobject 的第一个路径

var paths = objGroup.paths;
var path = paths[0];
svgpattern.width = path.width;
svgpattern.height = path.height;
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(ptnGroup);
patternSourceCanvas.setDimensions({
  width: path.width,
  height: path.height
});

关于meteor - Fabric.js : Use SVG as a pattern & adjust fill of SVG pattern,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41234864/

相关文章:

reactjs - 从 cordova 迁移到 React Native 时如何让用户保持登录状态

javascript - 等待 Meteor.user()

javascript - 如何为 fabricjs 中的所有方法使用和访问多个 Canvas 的实例?

javascript - Fabric.js、Darkroom.js 和 devicePixelRatio 偏移量

fabricjs - 将 PDF 加载到 fabricjs Canvas 中

node.js - minimongo 是否存在于运行 Meteor 的服务器实例上?

meteor - 在事件链接的路由更改上重新运行辅助函数

javascript - Kineticjs::从 X 到 Y 距离继续动画形状

javascript - 通过 canvas.toDataURL 将 Canvas 保存到图像会导致黑色矩形

javascript - 尝试将视听器转换为代码笔未成功……需要劝告