Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To export a D3 chart with html2canvas, wait until the chart and its custom fonts have loaded, capture the chart’s wrapper, then convert the resulting canvas to a PNG. Set the capture dimensions and scale explicitly to control cropping and pixel resolution. For images hosted on another origin, browser CORS rules still apply: useCORS: true is not a way to bypass them.

What html2canvas captures—and what it does not

D3 typically creates an SVG element in the page’s DOM, then adds chart marks, axes and labels to that SVG. You can capture the SVG itself or a wrapper containing the SVG and surrounding HTML. Capturing a wrapper is useful when the export should include a title, legend or other nearby elements.

html2canvas reconstructs a canvas from DOM information; it does not take a literal screenshot of the browser window. Its documentation cautions that the result may not exactly match the page, because the renderer uses the information available in the DOM and only supports properties it understands. That distinction matters when a chart relies on complex CSS, browser-specific effects or external assets.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The API is asynchronous: html2canvas(element, options) returns a Promise that resolves to a canvas. You can then serialize that canvas as a PNG. The example below waits for fonts, measures the chart wrapper, captures it and starts a browser download.

Prepare the chart and fonts

Give the chart a stable capture target

Wrap the SVG and any content meant to appear in the export in one element. Give that wrapper a background and dimensions that reflect the intended image. Avoid relying on a viewport-sized layout if the chart is larger than the visible window.

<div id="chart-export">
  <h2 class="chart-title">Monthly sign-ups</h2>
  <div id="chart"></div>
</div>

For example, a D3 chart can append an SVG to #chart and set its dimensions explicitly:

const width = 900;
const height = 500;
const svg = d3.select('#chart')
  .append('svg')
  .attr('width', width)
  .attr('height', height)
  .attr('viewBox', `0 0 ${width} ${height}`)
  .attr('role', 'img')
  .attr('aria-label', 'Monthly sign-ups chart');

Build the axes, marks and labels on that SVG as usual. If responsive CSS changes the rendered size, measure the wrapper after the layout has settled rather than assuming its CSS width equals its pixel width.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Wait for the actual font to load

Starting capture while a web font is still loading can produce fallback-font labels or different text metrics. Wait for the browser’s font-loading set before capturing. If your chart depends on a particular family and weight, explicitly request that face as well; use the same CSS family and weight that the SVG labels use.

await document.fonts.load('600 14px "Chart Sans"');
await document.fonts.ready;

if (!document.fonts.check('600 14px "Chart Sans"')) {
  throw new Error('Chart Sans 600 is not available for the export');
}

Put the font-face declaration in the page stylesheet and ensure the font URL can be fetched by the page. Waiting cannot make an unavailable font available: if the request fails or the declared family does not match the chart’s CSS, inspect the browser network and console panels.

Capture and download the PNG

Load html2canvas in your application using your usual dependency setup, then run this code after D3 has finished drawing. The capture scale is set to 2 for a higher-density image; change it to 1 for one output pixel per CSS pixel, or choose another explicit value to suit the destination. A larger scale increases output dimensions and memory use.

async function exportChartAsPng() {
  const target = document.querySelector('#chart-export');
  if (!target) throw new Error('Chart export element was not found');

  await document.fonts.ready;

  const rect = target.getBoundingClientRect();
  const width = Math.ceil(rect.width);
  const height = Math.ceil(rect.height);
  if (!width || !height) throw new Error('Chart export element has no rendered size');

  const canvas = await html2canvas(target, {
    scale: 2,
    backgroundColor: '#ffffff',
    useCORS: true,
    width,
    height,
    windowWidth: Math.max(document.documentElement.clientWidth, width),
    windowHeight: Math.max(document.documentElement.clientHeight, height)
  });

  const blob = await new Promise((resolve, reject) => {
    canvas.toBlob(result => {
      if (result) resolve(result);
      else reject(new Error('The browser could not encode the canvas as PNG'));
    }, 'image/png');
  });

  const objectUrl = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = objectUrl;
  link.download = 'd3-chart.png';
  document.body.appendChild(link);
  link.click();
  link.remove();
  setTimeout(() => URL.revokeObjectURL(objectUrl), 1000);
}

exportChartAsPng().catch(error => {
  console.error('Chart export failed:', error);
});

Use canvas.toDataURL('image/png') instead if you specifically need a data URL, for example to assign to an image’s src. For a download, toBlob avoids building a large base64 string in memory. The browser may restrict downloads initiated outside a user action, so call the export from a button click when integrating this into an application.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose dimensions, scale and background deliberately

Prevent clipping

The measured width and height in the example are the wrapper’s rendered CSS dimensions. If the chart has overflowing content, a fixed-size parent, or a chart that extends beyond the visible area, correct the wrapper and its layout first. Set width and height to the intended capture region; these options do not reveal content that is hidden or outside the element’s layout.

For a chart larger than the viewport, windowWidth and windowHeight can help html2canvas render against a window size large enough for the capture. These values control the rendering context; they are not substitutes for sizing the chart wrapper itself.

Choose output resolution

The scale option controls the canvas pixel density relative to CSS dimensions. It defaults to window.devicePixelRatio, which can vary across displays. Set it explicitly when repeatable output dimensions matter. For example, a 900-by-500 CSS-pixel capture at scale 2 yields a canvas with twice those dimensions in each direction. Higher scale uses more memory, so especially large charts may fail or become slow if scaled excessively.

Use a predictable background

backgroundColor sets the rendered canvas background; use a color such as white when the PNG should not be transparent. Set it to null when you need transparency, provided the chart and its page styling do not paint an opaque background elsewhere.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fonts, cloned documents and SVG text

html2canvas may clone the document to render the capture. If the cloned content needs a targeted adjustment, use the documented onclone callback to modify that clone without changing the live page. For example, you can apply an explicit font family to the cloned chart before rendering:

const canvas = await html2canvas(target, {
  scale: 2,
  onclone(clonedDocument) {
    const clonedChart = clonedDocument.querySelector('#chart-export');
    if (clonedChart) {
      clonedChart.style.fontFamily = '"Chart Sans", sans-serif';
    }
  }
});

Apply this only if the live page has the correct font but the cloned rendering does not. A clone-side CSS change cannot supply a missing font file or repair a failed font request. If the SVG’s text was converted to paths by your chart pipeline, it is no longer ordinary live text and font loading does not affect those paths.

The foreignObjectRendering option is available but defaults to false. The project source describes its foreign-object renderer as experimental, so test it in the browsers you support before relying on it. It is not a universal fix for text or CSS differences.

External images and browser security

Images from another origin are subject to browser content policy. html2canvas cannot circumvent those restrictions. For an external image to be included, the resource generally must be served from the same origin, served with appropriate CORS headers and loaded in a CORS-compatible way, or supplied through a proxy you control. Set useCORS: true when the remote server permits CORS; that option asks the browser to use CORS, but it does not grant permission by itself.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If a chart image is absent, check the request in the browser’s network panel and confirm the remote server’s response permits your page’s origin. If the canvas becomes tainted, browser security will prevent reading or encoding it. Do not treat a proxy as a way to evade access controls; use only assets you are allowed to retrieve, and configure any proxy with appropriate access and security limits.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

When direct SVG export is a better fit

html2canvas is useful when the output should represent a DOM region that includes the D3 SVG and nearby HTML. If the requirement is to export SVG semantics directly, or html2canvas’s supported-CSS boundary is causing fidelity problems, compare a direct SVG export approach. svg-exportJS advertises SVG-to-PNG, JPEG and PDF export, high-resolution scaling, external CSS inclusion and custom-font options.

Its documentation cautions that custom fonts embedded in an SVG using @font-face display correctly only when the system opening the SVG file has the font installed. That is an important portability distinction: embedding font-related CSS is not a guarantee that every recipient or rendering environment will have the font available. Test exported files in the environment where they will actually be opened.

Troubleshooting common export failures

Symptom Likely cause What to check or change
Labels use a fallback font or shift position Capture started before the font loaded, the requested family or weight is wrong, or the cloned rendering differs. Wait for document.fonts.ready, explicitly load and check the required face, then inspect the font request. If only the clone differs, test a scoped onclone style.
Chart is blank The target selector is wrong, the element has no rendered size, capture ran before D3 finished, or the renderer could not represent required DOM/CSS. Confirm the target exists and has nonzero dimensions, run capture after the drawing code completes, and test a simpler chart region to isolate unsupported styling.
External image or logo is missing The asset is cross-origin without a usable CORS response, or it was not loaded when capture began. Wait for the image to load, inspect its request and response headers, and use same-origin delivery or a properly configured proxy when appropriate. useCORS alone does not bypass browser policy.
PNG is cropped The wrapper is smaller than the visible chart, content overflows it, or capture dimensions reflect the wrong layout. Measure the intended wrapper after layout, give it sufficient dimensions, and set width, height and window dimensions deliberately.
PNG has an unexpected background The target or its children paint a background, or the capture’s background setting is unsuitable. Set the chart’s CSS background intentionally and choose a matching backgroundColor, or use null when transparency is required.
Canvas cannot be read or encoded A cross-origin asset tainted the canvas, or the browser could not produce the requested blob. Resolve the asset’s origin/CORS setup and check that the toBlob callback returned a value before attempting a download.
Export works on one display but has different dimensions elsewhere The default scale follows window.devicePixelRatio. Set an explicit scale and verify the output dimensions against the target use.

Or skip the browser setup

If your D3 chart is already published at a URL accessible to the capture service, ScreenshotNeo can capture the rendered page without wiring html2canvas into that page. It is a website screenshot API, so it does not export an unsaved chart that exists only in your local browser session. The chart route must be reachable by the service and render the chart in the page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For API parameters and response details, see the ScreenshotNeo documentation. Replace the example URL with your public chart page and your key with your API key:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://your-domain.com/chart -o shot.webp

ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets before capture; each of those steps can be turned off. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and responses identify the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Learn about ScreenshotNeo or sign up free.

Frequently Asked Questions

Can I use html2canvas to save a chart as JPEG instead?

Yes. A canvas can be serialized with a JPEG MIME type, such as canvas.toBlob(callback, 'image/jpeg'); choose a suitable background because JPEG does not preserve transparency.

Does an exported PNG retain D3 interactivity?

No. PNG is a raster image, so interactions, selectable text and SVG structure are not retained. Keep the original chart or export SVG when those properties are needed.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.