npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lightdash/visualization

v2.449.0

Published

Headless Lightdash chart engine: turns a saved chart's config and query results into ECharts options, table and big number models

Readme

@lightdash/visualization

The headless Lightdash chart engine. It turns a saved chart's config and the results of its query into what a renderer needs: an ECharts option for bar, line, area, scatter, pie, funnel, treemap, gauge and sankey charts, a table model, a big number model, and the data for a custom (Vega) visualization.

No React, no Mantine, no DOM. The Lightdash frontend renders every chart through this package, so a headless caller (a data app, a server-side render, a desktop app) draws exactly what the web app draws.

Installing

npm install @lightdash/visualization @lightdash/common echarts

@lightdash/common must be the same version as @lightdash/visualization: both are released together from the Lightdash monorepo, and the engine reads the saved chart and field types from it. echarts (5.6 or later 5.x) is a peer dependency for its option types; the engine never imports it at run time, so a caller that only builds tables or big numbers does not load it.

Node 20 or later. Both import and require work from plain Node: they load the CommonJS build, which ESM callers can import by name. Bundlers that honour the module field or condition (Vite, webpack, Rollup, esbuild) get the ES module build instead. The types resolve under node16, nodenext and bundler module resolution.

Using it

A chart and its data go in; what to draw comes out.

import { renderChart, toResultRows } from '@lightdash/visualization';
import * as echarts from 'echarts';

const rendered = renderChart(
    savedChart, // chartConfig, pivotConfig, tableConfig: a SavedChart as it is
    {
        rows: toResultRows(rawRows, fields),
        fields, // keyed by field id: Lightdash items, or { fieldType, type, label, format }
        query: metricQuery, // optional: field order and sorts
        pivotDetails, // when the query was pivoted
    },
    { theme, colors: { palette }, size: { width, height } },
);

switch (rendered.kind) {
    case 'echarts':     echarts.init(el).setOption(rendered.option); break;
    case 'table':       rendered.model.columns; rendered.model.rows; break;
    case 'bigNumber':   rendered.model.value; rendered.model.comparison; break;
    case 'custom':      rendered.spec; rendered.data; break;
    case 'empty':       rendered.reason; break; // noRows, incompleteConfig, needsPivotDetails, needsPivotTable
    case 'unsupported': break; // maps and data-app visualizations
}
  • ChartView: what the chart is. A SavedChart satisfies it.
  • ChartData: everything it is drawn from, all of it data. Values that took further queries (totals, groupedSubtotals, pivotTable) are fields of it. The engine never runs a query: what it needs and is not given comes back as an empty reason.
  • RenderOptions: how to draw, never what. theme, colors, size, animation, tooltip, legendSelection, parameters.
  • RenderedChart: the output, plus colorAssignments. Pass those back as colors.assignments to the next chart on the page, and the same group value keeps its colour. They are plain data: keep them, send them, compare them.

renderChart is resolveChart then buildChart. Call them apart to keep the resolved chart: its config is the saved config with defaults filled and stale fields repaired, the same config the explorer's editor settles on.

Entry points

  • @lightdash/visualization: the API above. Stable.
  • @lightdash/visualization/editor: the per-type helpers the Lightdash explorer's editor calls to offer, repair and default a config. Internal to Lightdash; it changes with the explorer.

Layout

  • render.ts: resolveChart, buildChart, renderChart and their types.
  • chartData.ts: ChartView, ChartData, and how they become the builders' inputs.
  • types.ts: VisualizationResults, the structural subset of the frontend's query results the builders read, and the inputs every builder shares.
  • theme.ts: VisualizationTheme and the light and dark defaults. Plain hex values, so options rasterise without a stylesheet.
  • colors/: series identifiers, colour assignments, the colour resolver.
  • pivot/, merge/: pivoted results and merged-query helpers.
  • One folder per chart type: config.ts (the resolver and the pure helpers the frontend's editor hook calls) and echartsOption.ts (the builder).

Working on it

The frontend hooks under packages/frontend/src/hooks/echarts and the use<Type>ChartConfig hooks are thin wrappers over this package; the editor state stays in the frontend. Keep a change here behaviour-neutral for the frontend, or change both together.

pnpm -F visualization build      # dist/esm, dist/cjs, dist/types
pnpm -F visualization test
pnpm -F visualization lint
pnpm -F visualization typecheck
pnpm -F visualization test:pack   # after build: pack, install outside the repo, import from Node and tsc

The unit tests also typecheck every ts sample in this README against the source.

In development the frontend resolves the package from src through a Vite alias, and pnpm dev runs a visualization-watch build for the backend and the SDK bundle.

Browser tests

browser/ draws every chart type through renderChart into real ECharts instances in Chromium, and Playwright asserts on what the browser produces: series marks, axis labels, legends, the tooltip HTML, the big number and table models, and the dark theme's colours. The report carries a gallery of every type in both themes.

pnpm -F visualization exec playwright install chromium   # once
pnpm -F visualization test:browser

The unit tests check the options the engine builds; the browser tests check that a browser draws them.