将单个 SVG 元素呈现为 canvas 或图像
Render a single SVG element to canvas or image
如何将单个 SVG 元素(而不是整个 SVG 文档或其中的一部分)呈现为图像或 canvas?
我有一个包含很多节点的 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
。
您可以删除所有元素,但要呈现的元素除外。
要使 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 的新大小。
这里只是使用 outerHTML
将目标元素复制到表示新 SVG 的新数据 URL 中,加载到图像对象中,在 canvas 中绘制并导出为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" />
如何将单个 SVG 元素(而不是整个 SVG 文档或其中的一部分)呈现为图像或 canvas?
我有一个包含很多节点的 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
。
您可以删除所有元素,但要呈现的元素除外。 要使 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 的新大小。
这里只是使用 outerHTML
将目标元素复制到表示新 SVG 的新数据 URL 中,加载到图像对象中,在 canvas 中绘制并导出为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" />