¿Cómo puedo representar un solo elemento SVG (a diferencia de todo el documento SVG o partes de él) en una imagen o un lienzo?
Tengo un documento SVG con muchos nodos. Si renderizo todo el SVG o una parte de él, la imagen resultante contendrá otras piezas de gráficos que no me interesan. Estoy interesado en un elemento SVG específico y me gustaría renderizarlo todo sin nada más.
Ejemplo:
<!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> ¿Cómo puedo renderizar target solo? Me gustaría obtener una imagen que no tenga rastros de los otros dos círculos, un fondo transparente y el tamaño adecuado para que se ajuste perfectamente al target .
Puede eliminar todos los elementos menos el que desea renderizar. Para ajustar el SVG al elemento restante, debe calcular una nueva posición y tamaño. Para su ejemplo, el código podría verse así:
<!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>Tenga en cuenta que debe incluir el ancho del trazo de su elemento para calcular correctamente su nueva posición y el nuevo tamaño del SVG.
Aquí, el elemento de destino simplemente se copia utilizando outerHTML en una nueva URL de datos que representa el nuevo SVG, se carga en un objeto de imagen, se dibuja en un lienzo y se exporta como una imagen 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" />