【问题标题】:Fill svg path with canvas?用画布填充svg路径?
【发布时间】:2017-03-24 22:32:24
【问题描述】:

我正在使用 SVG 使用路径制作自定义形状:

例如<path d="M 180,160 0,218 0,0 180,0 z" >

我还使用 snap.svg 将悬停时的路径转换为:

m 180,34.57627 -180,0 L 0,0 180,0 z

我想要实现的是用我用 javascript 制作动画的画布填充该路径,并将其置于形状内,并在悬停时使用形状进行变换。

有什么办法吗?

【问题讨论】:

  • 您可以用图像填充路径并将画布数据写入您使用 javascript 制作动画的图像中。

标签: javascript canvas svg snap.svg


【解决方案1】:

您有多种选择,具体取决于您的具体需求。以下是其中一些选择:

  • 您可以使用<foreignObject> 将画布直接附加到您的 svg 中,然后在其上使用 clipPath,但这会将支持限制为 IE>=11。

<svg id="svg" width="300" height="300" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <style>
      #clickHandler {
        pointer-events: all;
      }
    </style>
    <clipPath id="myClip">
      <path id="yourPath" d="M 180,160 0,218 0,0 180,0 z" />
    </clipPath>
  </defs>
  <foreignObject id="fO" width="100%" height="100%" clip-path="url(#myClip)">
    <canvas xmlns="http://www.w3.org/1999/xhtml" id="canvas" width="600" height="300"></canvas>
  </foreignObject>
  <script>
    var pathes = ["M 180,160 0,218 0,0 180,0 z", "m 180,34.57627 -180,0 L 0,0 180,0 z"]
    var current = 0;
    fO.onclick = function() {
      current = (current + 1) % 2;
      yourPath.setAttribute('d', pathes[current]);
    };
     // canvas noise
    var ctx = canvas.getContext('2d');
    var imageData = ctx.createImageData(300, 300);

    function animCanvas() {
      requestAnimationFrame(animCanvas);
      imageData.data.forEach(function(v, i, a) {
        a[i] = Math.random() * 255;
      });
      ctx.putImageData(imageData, 0, 0);
    }
    animCanvas();
  </script>
</svg>
  • 您可以使用 CSS 和绝对定位将您的画布放在 svg 后面,您还必须在 svg 中附加一个背景,将您的路径设置为掩码,并复制您的路径来处理鼠标事件。在这里,您将获得所有 HTML5 浏览器的支持,但您会失去 svg z-index 定位。

var pathes = ["M 180,160 0,218 0,0 180,0 z", "m 180,34.57627 -180,0 L 0,0 180,0 z"]
var current = 0;
clickHandler.onclick = function() {
  current = (current + 1) % 2;
  yourPath.setAttribute('d', pathes[current]);
};
// canvas noise
var ctx = canvas.getContext('2d');
var imageData = ctx.createImageData(300, 300);

function animCanvas() {
  requestAnimationFrame(animCanvas);
  imageData.data.forEach(function(v, i, a) {
    a[i] = Math.random() * 255;
  });
  ctx.putImageData(imageData, 0, 0);
}
animCanvas();
canvas {
  position: absolute;
  z-index: 0;
}
svg {
  position: absolute;
  z-index: 1;
}
<canvas id="canvas" width="600" height="300"></canvas>
<svg id="svg" width="300" height="300" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <style>
      #clickHandler {
        pointer-events: all;
      }
    </style>
    <path id="yourPath" d="M 180,160 0,218 0,0 180,0 z" />
    <rect id="bg" x="-1%" y="-1%" width="102%" height="102%" />
    <mask id="myMask">
      <use xlink:href="#bg" fill="white" />
      <use xlink:href="#yourPath" fill="black" />
    </mask>
  </defs>

  <use xlink:href="#bg" mask="url(#myMask)" fill="white" />
  <use xlink:href="#yourPath" fill="none" id="clickHandler" />
</svg>
  • 或者你可以在画布上做任何事情。
    在下面的示例中,我使用了 Path2D 构造函数,该构造函数在早期的 canvas API 实现中不支持,但您也可以通过不同的函数调用来实现相同的功能,甚至还有一些 Path2D 填充。

var pathes = [
  new Path2D("M 180,160 0,218 0,0 180,0 z"),
  new Path2D("m 180,34.57627 -180,0 L 0,0 180,0 z")
];
var current = 0;

canvas.onclick = function(evt) {
  var x = evt.clientX - this.offsetLeft,
    y = evt.clientY - this.offsetTop;

  if (ctx.isPointInPath(pathes[current], x, y)) {
    current = (current + 1) % 2;
  }
};

function clipCanvas() {
  ctx.globalCompositeOperation = 'destination-in';
  ctx.fill(pathes[current]);
  ctx.globalCompositeOperation = 'source-over'; // not really needed with putImageData
}
// canvas noise
var ctx = canvas.getContext('2d');
var imageData = ctx.createImageData(300, 300);

function animCanvas() {
  requestAnimationFrame(animCanvas);
  imageData.data.forEach(function(v, i, a) {
    a[i] = Math.random() * 255;
  });
  ctx.putImageData(imageData, 0, 0);

  clipCanvas();

}

animCanvas();
&lt;canvas id="canvas" width="600" height="300"&gt;&lt;/canvas&gt;

【讨论】:

    猜你喜欢
    • 2017-08-14
    • 2020-03-14
    • 2013-01-23
    • 1970-01-01
    • 2017-08-15
    • 2017-04-02
    • 2019-12-16
    • 2015-02-03
    • 2018-10-02
    相关资源
    最近更新 更多