{"id":10713,"library":"d3-node","title":"Server-side D3 Visualization","description":"d3-node is a utility library designed to facilitate server-side rendering of D3.js visualizations within a Node.js environment. It enables developers to generate static SVG or HTML strings, or raster images (PNG) via the optional `node-canvas` library, entirely on the backend. This capability is crucial for use cases like pre-rendering charts and maps for improved initial page load performance, offloading data processing from client browsers, and creating static image outputs for reports or social media sharing. The current stable version is 4.0.1. The project demonstrates active maintenance with consistent updates, including enhancements like explicit SVG attribute parameters and robust canvas support. Its key differentiators include the ability to leverage the entire D3 ecosystem and npm packages, produce portable SVG with embedded stylesheets, and simplify the adaptation of existing D3 examples for server-side generation.","status":"active","version":"4.0.1","language":"javascript","source_language":"en","source_url":"ssh://git@github.com/bradoyler/d3-node","tags":["javascript","d3","isomorphic","maps","charts"],"install":[{"cmd":"npm install d3-node","lang":"bash","label":"npm"},{"cmd":"yarn add d3-node","lang":"bash","label":"yarn"},{"cmd":"pnpm add d3-node","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core D3.js library for data manipulation and visualization logic.","package":"d3","optional":false},{"reason":"Required for generating raster images (PNG) from D3 visualizations on the server-side. Must be installed separately.","package":"canvas","optional":true}],"imports":[{"note":"While CommonJS `require` is supported, ESM `import` is the recommended and modern approach for Node.js v16 and up. The library internally bundles D3, so you typically interact with D3 via `d3n.d3`.","wrong":"const D3Node = require('d3-node')","symbol":"D3Node","correct":"import { D3Node } from 'd3-node'"},{"note":"After initializing `D3Node`, access the D3 selection object through the `d3` property of the `D3Node` instance.","symbol":"D3 selection object","correct":"const d3 = d3n.d3"},{"note":"Used to retrieve the generated SVG as a string. For full HTML output including the container, use `d3n.html()`.","symbol":"SVG string output","correct":"d3n.svgString()"}],"quickstart":{"code":"import { D3Node } from 'd3-node';\nimport * as d3 from 'd3'; // Import D3 for specific utilities like scaleLinear\nimport fs from 'fs';\n\nconst options = { \n  selector: '#chart', \n  container: '<div id=\"container\"><div id=\"chart\"></div></div>', \n  styles: '.bar { fill: steelblue; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; }'\n};\n\nconst d3n = new D3Node(options);\nconst d3Local = d3n.d3; // Get the D3 instance associated with D3Node\n\nconst width = 400;\nconst height = 200;\nconst margin = { top: 20, right: 20, bottom: 30, left: 40 };\n\nconst svg = d3n.createSVG(width, height);\n\nconst data = [10, 20, 40, 60, 80];\n\nconst xScale = d3.scaleBand()\n  .range([margin.left, width - margin.right])\n  .padding(0.1)\n  .domain(data.map((d, i) => i));\n\nconst yScale = d3.scaleLinear()\n  .range([height - margin.bottom, margin.top])\n  .domain([0, d3.max(data)]);\n\nsvg.append('g')\n  .attr('fill', 'steelblue')\n  .selectAll('rect')\n  .data(data)\n  .join('rect')\n    .attr('class', 'bar')\n    .attr('x', (d, i) => xScale(i))\n    .attr('y', d => yScale(d))\n    .attr('height', d => yScale(0) - yScale(d))\n    .attr('width', xScale.bandwidth());\n\n// Add X axis\nsvg.append('g')\n  .attr('class', 'axis x-axis')\n  .attr('transform', `translate(0,${height - margin.bottom})`)\n  .call(d3.axisBottom(xScale).tickFormat(i => `Item ${i + 1}`));\n\n// Add Y axis\nsvg.append('g')\n  .attr('class', 'axis y-axis')\n  .attr('transform', `translate(${margin.left},0)`)\n  .call(d3.axisLeft(yScale));\n\nconst svgOutput = d3n.svgString();\nfs.writeFileSync('output.svg', svgOutput);\nconsole.log('SVG written to output.svg');\n\n// For canvas output (requires 'canvas' package):\n// import Canvas from 'canvas';\n// const d3nCanvas = new D3Node({ canvasModule: Canvas });\n// const canvas = d3nCanvas.createCanvas(width, height);\n// const context = canvas.getContext('2d');\n// // ... draw on context with D3-Canvas specific methods ...\n// canvas.createPNGStream().pipe(fs.createWriteStream('output.png'));","lang":"javascript","description":"This quickstart demonstrates how to create a simple bar chart SVG using d3-node, including setting up axes and styling, and then saving the output to a file. It shows integration with both d3-node's D3 instance and explicit D3 imports for scales."},"warnings":[{"fix":"Ensure your Node.js environment is at least version 16.0.0. Consider using a Node Version Manager (nvm) to easily switch between versions.","message":"d3-node is explicitly tested on Node.js v16 and up. Using older Node.js versions might lead to unexpected behavior or compatibility issues with underlying D3.js or other dependencies.","severity":"gotcha","affected_versions":"<16.0.0"},{"fix":"Install `canvas` via `npm install canvas` or `yarn add canvas` and initialize D3Node with `{ canvasModule: require('canvas') }`.","message":"When generating raster images (e.g., PNG), the `canvas` package must be installed separately as a peer dependency and passed to the D3Node constructor via the `canvasModule` option. It is not bundled directly with `d3-node`.","severity":"breaking","affected_versions":">=1.0.3"},{"fix":"Refer to D3.js migration guides for specific changes from older versions (e.g., v3 to v4). Pay close attention to naming conventions, module imports, and the data join pattern (e.g., `selection.merge()` in v4+).","message":"D3.js itself underwent significant breaking changes between v3 and v4 (and subsequent versions), including a modularized structure and changes to API calls (e.g., `d3.scale.linear()` became `d3.scaleLinear()`). If adapting older D3 code, you must port it to a modern D3.js API, which `d3-node` supports via its internal D3 instance.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Install `canvas` (`npm install canvas`) and initialize `D3Node` with `new D3Node({ canvasModule: require('canvas') })`.","cause":"The `canvasModule` option was not provided to the `D3Node` constructor, or the `canvas` package is not installed.","error":"TypeError: d3n.createCanvas is not a function"},{"fix":"Access D3 methods via the D3Node instance: `const d3Local = d3n.d3; d3Local.scaleLinear()` or explicitly `import * as d3 from 'd3';` if using specific D3 modules outside of the D3Node context.","cause":"Attempting to use the global `d3` object (e.g., `d3.scaleLinear()`) without properly accessing it from the `D3Node` instance or importing it directly.","error":"ReferenceError: d3 is not defined"},{"fix":"Ensure the `selector` matches an element in the `container` HTML string, and that you are appending to a valid D3 selection object obtained from `d3n.document.querySelector()` or `d3n.createSVG()`.","cause":"This error often occurs in D3.js when trying to append elements to a non-existent or invalid DOM element. In `d3-node`, it might mean the `selector` or `container` options are misconfigured, or D3 is trying to operate on an element that hasn't been created or selected correctly within the virtual DOM.","error":"Error: Node was not found"}],"ecosystem":"npm"}