Rendering

Cars scatterplot of horsepower and fuel economy
Quantitative positions with nominal color.

Render one fully materialized ChartProgram to Browser Canvas, a browser-safe SVG string, a Node PNG file, or a single-page vector PDF. Choose the target based on where the output runs and how it will be consumed.

At a glance

Target Environment Shortest call Use when
Browser Canvas Browser render(program, context) Drawing into an existing interactive page
SVG Browser or Node.js 20+ renderToSVG(program) Embedding or saving scalable markup
Node PNG Node.js 20+ renderToPNG(program, { output }) Producing a raster file at an explicit pixel density
Node PDF Node.js 20+ renderToPDF(program, { output }) Producing a selectable, single-page vector document

Rendering consumes a completed program’s graphicSpec. It does not read datasets, semantic encodings, context, or trace to infer missing output.

Complete example program

Every rendering fragment below continues from this complete program:

import { chart } from "ggaction";

const observations = [
  { displacement: 97, acceleration: 14.5, origin: "Japan" },
  { displacement: 140, acceleration: 15.5, origin: "USA" },
  { displacement: 86, acceleration: 16.4, origin: "Japan" }
];

const program = chart()
  .createCanvas({
    width: 640,
    height: 400,
    margin: { top: 30, right: 130, bottom: 60, left: 70 }
  })
  .createData({ values: observations })
  .createScatterPlot({
    x: "displacement",
    y: "acceleration",
    color: "origin",
    shape: "origin"
  });

Browser Canvas

In a browser page containing <canvas id="chart"></canvas>, render with its 2D context:

import { render } from "ggaction";

const context = document.querySelector("#chart").getContext("2d");
render(program, context);

The optional pixelRatio increases physical output density while retaining logical chart coordinates. For an HTML Canvas, ggaction also preserves the logical CSS width and height while enlarging the backing store:

render(program, context, { pixelRatio: 2 });

Raster backing dimensions are the logical dimension multiplied by pixelRatio, rounded to the nearest whole pixel with a minimum of one pixel. This leaves fractional logical dimensions unchanged in CSS and SVG output. Canvas and PNG preflight the complete allocation before changing the backing store: each physical side is limited to 32767 pixels and the complete image to 16777216 pixels.

SVG output

The browser-safe SVG entry returns a complete SVG document string without reading the DOM or filesystem. Assign it to a trusted application container or save the returned string with the file API available in your environment.

import { renderToSVG } from "ggaction/svg";

const svg = renderToSVG(program, {
  title: "Quarterly revenue",
  description: "Revenue by quarter",
  resourceNamespace: "quarterlyRevenue"
});

The root width, height, and viewBox use the program’s logical Canvas dimensions. Optional title and description strings become escaped <title> and <desc> children. Repeated calls with the same program and options return the same string. Resource IDs use a deterministic hash of graphicSpec by default. When multiple copies of the same chart will coexist in one HTML document, give each call a distinct resourceNamespace so their gradient and clipping IDs cannot collide. It must start with an ASCII letter and contain only ASCII letters, numbers, _, or -.

For example, a browser application can place the generated document in an existing output container:

document.querySelector("#svg-output").innerHTML = svg;

PNG output

The Node-only entry point writes a completed program directly to PNG.

import { renderToPNG } from "ggaction/png";

const result = await renderToPNG(program, {
  output: "./output/chart.png",
  pixelRatio: 2
});

Missing output directories are created. A logical 640×400 chart at ratio 2 produces a 1280×800 image. The result contains the absolute output, physical width and height, pixelRatio, and byte count.

PDF output

The Node-only PDF entry writes one completed chart as one vector PDF page:

import { renderToPDF } from "ggaction/pdf";

const result = await renderToPDF(program, {
  output: "./output/chart.pdf",
  metadata: {
    title: "Quarterly revenue",
    author: "Example",
    subject: "Revenue by quarter",
    keywords: ["revenue", "quarterly"]
  }
});

Missing output directories are created. The page width and height in PDF points use the program’s logical Canvas dimensions. The native vector backend represents page boxes as positive integers, so PDF output requires each logical dimension to be an integer no larger than 16777216; unsupported dimensions are rejected before replacing the output file. The frozen result contains the absolute output, logical width and height, pages: 1, and byte count. Metadata is optional; it accepts only non-empty title, author, and subject strings plus an array of non-empty keywords.

Text remains selectable/searchable PDF text. Paths, strokes, fills, clipping, opacity, dashes, and linear gradients remain vector output; the adapter does not rasterize the chart or accept pixelRatio. Nested Canvas translations apply to text as well as shapes, so concat children with different plot margins retain their distinct title and axis-label origins in PDF output.

The current renderers support concrete canvas, collection, circle, rect, line, text, and M/L/C/Z command-path graphics. Path and line strokes may use concrete dash arrays. They validate values with the same concrete property contract used by editGraphics.

Rect and closed-path fills may be solid strings or item-local linear-gradient paint values. Gradient endpoints are normalized against the final fill geometry; path stroke width does not expand that coordinate box. The renderer creates the Canvas gradient only for the current draw call and never stores backend objects in graphicSpec.

Canvas, PNG, and PDF share a native drawing backend. Before creating or changing native output, they require every geometry and style number passed to that backend—including path controls, nested translations, stroke/dash sizes, text size/rotation, and resolved gradient endpoints—to have magnitude no greater than 16777216 (2^24). Derived rect/circle and nested-clip extents, gradient direction lengths, cumulative translations, and pixel-ratio-scaled values use the same boundary. SVG remains browser-safe string serialization and preserves the complete finite JavaScript number range.

Line curve actions resolve interpolation into those commands before rendering. Canvas, SVG, and PDF execute L and cubic C segments but do not read curve names or calculate control points.

Errors and limitations

Rendering never reads semanticSpec. Every drawable property must already be concrete. Canvas/PNG pixelRatio must be positive at native precision, no greater than 16777216, and produce physical dimensions within the raster limits above. PDF is vector output and does not accept pixelRatio, but its page and drawing geometry use the Canvas-backed native limits. Native numeric range failures are rejected before Canvas mutation or PNG/PDF file replacement. SVG uses neither native nor raster limits. PDF options and metadata use closed key sets. SVG resourceNamespace follows the identifier form above, and SVG text, attributes, titles, and descriptions reject characters that XML 1.0 cannot represent; emoji, joiners, variation selectors, and right-to-left text remain unchanged.

Canvas · Semantic and graphical state · Primitive extension API