【问题标题】:Render a single SVG element to canvas or image将单个 SVG 元素渲染到画布或图像
【发布时间】:2021-11-09 17:24:14
【问题描述】:

如何将单个 SVG 元素(而不是整个 SVG 文档或其中的一部分)渲染到图像或画布上?

我有一个包含很多节点的 SVG 文档。如果我渲染整个 SVG 或其中的一部分,生成的图像将包含我不感兴趣的其他图形。我对一个特定的 SVG 元素感兴趣,并希望在没有其他任何内容的情况下渲染所有元素。

例子:

<!DOCTYPE html>
<html>
<body>

  <svg height="150" width="150">
    <circle cx="50" cy="50" r="25" stroke="green" stroke-width="3" fill="gray" />
    <circle id="IWantToRenderThis" cx="75" cy="75" r="25" stroke="red" stroke-width="3" fill="white" />
    <circle cx="100" cy="100" r="25" stroke="blue" stroke-width="3" fill="black" />
  </svg>

  <script>
    const target = document.getElementById("IWantToRenderThis");
    // how can I render *target* into a texture?
  </script>

</body>
</html>

如何单独渲染target?我想获得一张没有其他两个圆圈痕迹、透明背景和适合target 的大小的图像。

【问题讨论】:

  • 将其他内容设置为 display:none 或完全从 DOM 中删除

标签: javascript html svg browser render


【解决方案1】:

您可以删除所有元素,但要渲染的元素除外。 为了使 SVG 适合其余元素,您需要计算新的位置和大小。对于您的示例,代码可能如下所示:

<!DOCTYPE html>
<html>
<body>

  <svg height="150" width="150" id="svg">
    <circle cx="50" cy="50" r="25" stroke="green" stroke-width="3" fill="gray" />
    <circle id="IWantToRenderThis" cx="75" cy="75" r="25" stroke="red" stroke-width="3" fill="white" />
    <circle cx="100" cy="100" r="25" stroke="blue" stroke-width="3" fill="black" />
  </svg>

  <script>
    const svg = document.getElementById("svg");
    const target = document.getElementById("IWantToRenderThis");
    const children = svg.children;
    
    // Remove all child elements but the target
    for(let index = 0; index < children.length; index++) {
      const child = children[index];
            if(child.id !== 'IWantToRenderThis') {
        child.remove()
      }
    }
    
    // Recalculate element position and svg size
    const targetSize = parseInt(target.getAttribute('r'))    
    const targetStroke = parseInt(target.getAttribute('stroke-width'))
    target.setAttribute('cx', targetSize + (targetStroke/2))
    target.setAttribute('cy', targetSize + (targetStroke/2))
    
    svg.setAttribute('width', targetSize*2 + targetStroke)
    svg.setAttribute('height', targetSize*2 + targetStroke)
  </script>

</body>
</html>

请注意,您必须包含元素的笔划宽度才能正确计算其新位置和 SVG 的新大小。

【讨论】:

  • 不错!您是否知道是否有更通用的方法来计算元素的大小?它并不总是一个圆圈:通常是一个&lt;g&gt;,里面有很多孩子。
【解决方案2】:

此处的目标元素只是使用outerHTML 复制到表示新 SVG 的新数据 URL 中,加载到图像对象中,在画布中绘制并导出为 PNG 图像。

let img = document.getElementById('img');
let target = document.getElementById("IWantToRenderThis");
let svg = target.closest('svg');
let width = svg.attributes['width'].value;
let height = svg.attributes['height'].value;
let image = new Image();
let canvas = document.getElementById('canvas');
canvas.height = height;
canvas.width = width;
let ctx = canvas.getContext('2d');

image.addEventListener('load', e => {
  ctx.drawImage(e.target, 0, 0, e.target.width, e.target.height);
  img.src = canvas.toDataURL("image/png");
});
image.src = `data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"
             width="${width}" height="${height}">${target.outerHTML}</svg>`;
<p>Original SVG:</p>
<svg id="svg" height="150" width="150">
  <circle cx="50" cy="50" r="25" stroke="green" stroke-width="3" fill="gray" />
  <circle id="IWantToRenderThis" cx="75" cy="75" r="25" stroke="red" stroke-width="3" fill="white" />
  <circle cx="100" cy="100" r="25" stroke="blue" stroke-width="3" fill="black" />
</svg>
<p>SVG rendered in canvas:</p>
<canvas id="canvas"></canvas>
<p>PNG image based on canvas:</p>
<img id="img" />

【讨论】:

    猜你喜欢
    • 2018-05-05
    • 1970-01-01
    • 1970-01-01
    • 2017-04-26
    • 1970-01-01
    • 2015-04-25
    相关资源
    最近更新 更多