Home > Mobile >  Render a single SVG element to canvas or image
Render a single SVG element to canvas or image

Time:09-18

How can I render a single SVG element (as opposed to the whole SVG document or parts of it) to an image or a canvas?

I have an SVG document with a lot of nodes. If I render the whole SVG or a part of it, the resulting image will contain other pieces of graphics I'm not interested in. I am interested in one specific SVG element and would like to render all of it without anything else.

Example:

<!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>

How can I render target alone? I would like to obtain an image which has no traces of the other two circles, a transparent background, and the right size to fit target perfectly.

CodePudding user response:

You could remove all elements but the one you want to render. To fit the SVG to the remaining element, you need to calculate a new position and size. For your example the code could look like this:

<!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>

Note that you have to include the stroke width of your element to properly calculate its new position and the SVG's new size.

CodePudding user response:

Here the target element is just copied using outerHTML into a new data URL representing the new SVG, loaded into an image object, drawn in a canvas and exported as a PNG image.

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" />

  • Related