How to Generate SVG Code in Node.js

Programmatically generating Scalable Vector Graphics (SVG) within a Node.js backend allows developers to dynamically render charts, diagrams, avatars, and custom graphics without relying on client-side rendering or heavy raster-image processing. This guide covers the primary methods to construct and output SVG strings in Node.js, including native JavaScript template literals, virtual DOM implementations like JSDOM, and data-visualization libraries like D3.js.


1. Native Template Literals

For straightforward or template-driven graphics, native ES6 template literals are the fastest and most lightweight approach since they require zero external dependencies.

function generateCircleSvg(radius, color) {
  const size = radius * 2;
  return `
    <svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}">
      <circle cx="${radius}" cy="${radius}" r="${radius}" fill="${color}" />
    </svg>
  `.trim();
}

const svgCode = generateCircleSvg(50, '#007ACC');
console.log(svgCode);

When to use: Simple shapes, static icons with dynamic color fills, or when minimizing dependency overhead is critical.


2. Virtual DOM via JSDOM

When building complex vector graphics that require programmatic node manipulation, traversing, or standard browser DOM APIs, you can emulate the DOM using jsdom.

Installation

npm install jsdom

Implementation

const { JSDOM } = require('jsdom');

function createSvgDocument() {
  const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
  const document = dom.window.document;
  const svgNS = 'http://www.w3.org/2000/svg';

  const svg = document.createElementNS(svgNS, 'svg');
  svg.setAttribute('width', '200');
  svg.setAttribute('height', '100');
  svg.setAttribute('viewBox', '0 0 200 100');

  const rect = document.createElementNS(svgNS, 'rect');
  rect.setAttribute('x', '10');
  rect.setAttribute('y', '10');
  rect.setAttribute('width', '180');
  rect.setAttribute('height', '80');
  rect.setAttribute('fill', '#4CAF50');
  rect.setAttribute('rx', '8');

  svg.appendChild(rect);
  return svg.outerHTML;
}

const svgCode = createSvgDocument();
console.log(svgCode);

When to use: When you need standard W3C DOM methods (createElementNS, setAttribute, appendChild) to build or modify existing SVG trees programmatically.


3. Server-Side D3.js

For data-driven graphics, charts, and complex math-based visualizations, D3.js can be combined with JSDOM on the backend to render complete SVG code.

Installation

npm install d3 jsdom

Implementation

const d3 = require('d3');
const { JSDOM } = require('jsdom');

function generateBarChart(data) {
  const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
  const body = d3.select(dom.window.document).select('body');

  const width = 300;
  const height = 150;
  const margin = 20;

  const svg = body.append('svg')
    .attr('xmlns', 'http://www.w3.org/2000/svg')
    .attr('width', width)
    .attr('height', height);

  const x = d3.scaleBand()
    .domain(data.map((_, i) => i))
    .range([margin, width - margin])
    .padding(0.2);

  const y = d3.scaleLinear()
    .domain([0, d3.max(data)])
    .range([height - margin, margin]);

  svg.selectAll('rect')
    .data(data)
    .enter()
    .append('rect')
    .attr('x', (_, i) => x(i))
    .attr('y', d => y(d))
    .attr('width', x.bandwidth())
    .attr('height', d => (height - margin) - y(d))
    .attr('fill', '#FF5722');

  return body.select('svg').node().outerHTML;
}

const chartSvg = generateBarChart([25, 40, 15, 80, 55]);
console.log(chartSvg);

When to use: Generating analytical charts, graphs, maps, or data-bound visualizations.


Outputting Generated SVG

Once the SVG string is constructed, it can be written to disk or returned through an HTTP response.

Saving to Disk

const fs = require('fs');
fs.writeFileSync('output.svg', svgCode, 'utf-8');

Serving over HTTP (Express.js)

app.get('/dynamic-image.svg', (req, res) => {
  const svg = generateCircleSvg(50, '#FF0000');
  res.setHeader('Content-Type', 'image/svg+xml');
  res.send(svg);
});