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

chart-factory

v0.2.0

Published

Token-driven, responsive D3 chart library: area, line, slope, bar, scatter, dot, histogram, donut/pie, box plot / violin, calendar heatmap, sankey, treemap, funnel and radar charts plus sortable tables that fill their container by default.

Readme

chart-factory

A token-driven, responsive chart library built on D3 v7. One factory, 15 families of named builders (primitives plus one-line presets over them — docs/conformance-matrix.md is the generated census) — area, line, slope, bar, scatter, dot, histogram, donut/pie, box plot, calendar heatmap, sankey, treemap, funnel, and radar charts plus sortable tables — that fill whatever container you put them in and re-render crisply on resize.

  • Responsive by default — charts measure their container, render at true pixel size, and adapt density (font size, tick count, dot radius) to the available width. No config needed.
  • Design tokens — all styling flows through CSS custom properties in tokens.css; retheme everything by overriding variables.
  • No build required to consume — plain ES modules plus a prebuilt browser bundle, TypeScript definitions included.
  • Date-aware axes — pass Date objects (or ISO strings) as x values and trend charts switch to time scales with adaptive tick formatting automatically.

Install

npm install chart-factory d3

d3 (v7) is a peer dependency — install it alongside. React apps also want the adapter: npm install chart-factory-react.

npm install ../chart-factory            # sibling checkout (local development)
npm install github:jolsufka/chart-factory   # straight from git

Usage

With a bundler (ESM)

import { ChartFactory } from 'chart-factory';
import 'chart-factory/styles.css';   // everything (tokens + base + table), or import the pieces:
// import 'chart-factory/core/tokens.css';
// import 'chart-factory/core/base.css';

ChartFactory.Line.createBasic('#chart', {
    data,
    xAccessor: d => d.week,
    yAccessor: d => d.points
});

Script tag (no build)

<link rel="stylesheet" href="node_modules/chart-factory/dist/chart-factory.css">
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="node_modules/chart-factory/dist/chart-factory.js"></script>
<script>
    ChartFactory.Bar.createBasic('#chart', { data, categoryAccessor: d => d.name, valueAccessor: d => d.value });
</script>

The dist bundle uses the page's global d3, so load d3 first. Plugins that attach to the global (e.g. d3-hexbin, used by Scatter.createDensity / createHexbin) keep working.

Responsive behavior

Charts fill their container's width; height comes from a per-family aspect ratio (aspectRatio config to override, height: <number> for a fixed height). The container must be block-level with a real width:

.chart-container { display: block; width: 100%; max-width: 660px; }

Horizontal bar/dot charts and gantt derive height from row count (width-responsive only). Pass width: <number> or responsive: false to opt out into fixed-size rendering. size: 'mini' | 'full' | 'wide' pins the density tier that is otherwise auto-selected from measured width (≤340px → mini, ≤620px → full, else wide). A fourth tier, size: 'instagram', is opt-in only (never auto-selected): poster-scale geometry for 1080px social-feed exports, paired with <html data-size="instagram"> to scale the text/stroke tokens to match — see docs/API.md.

Every chart returns a facade: chart.setConfig({...}) merges config and re-renders (state survives resizes), chart.rerender(), chart.destroy().

Tables

import { ChartFactory } from 'chart-factory';
import { D3Table } from 'chart-factory/table';
import 'chart-factory/table/tokens.css';
import 'chart-factory/table/table.css';

ChartFactory.Table.register(D3Table);   // one-time
ChartFactory.Table.createSortable('my-table', { columns: [...] }).render(data);

In the browser without a bundler, import dist/chart-factory-table.js from a <script type="module"> (d3 already on the page).

Dark mode

Opt in by setting data-theme="dark" on the root element:

<html data-theme="dark">

Every color-bearing token (text, surfaces, chart palettes, table heatmap/bar ramps) has a dark value in core/tokens.css; spacing and sizing carry over. Charts read tokens live at render time, so switching themes at runtime needs a re-render — SVG attribute colors are baked in at draw:

document.documentElement.dataset.theme = 'dark';  // or delete it for light
ChartFactory.rerenderAll();  // re-resolves every live chart and table

(rerenderAll() tracks all charts and factory-created tables; individual handles work too: chart.rerender(), table.rerender().)

CSS-styled surfaces (containers, tooltip shell, table chrome) restyle immediately without a re-render. There is no automatic prefers-color-scheme switching — wire the attribute (and the re-render calls) to your app's theme state; in React/Next.js, next-themes with attribute="data-theme" pairs naturally.

Chart states

Dashboards hit three awkward moments; the chart owns all of them:

const chart = ChartFactory.Line.createBasic('#c', { state: 'loading' });  // skeleton now
fetch('/api/rows').then(r => r.json())
    .then(rows => chart.setData(rows))          // real chart (setData ends 'loading')
    .catch(() => chart.setConfig({ state: 'error' }));
// rows.length === 0 → the built-in empty state renders automatically

The loading skeleton is family-aware (trend silhouette for line/area, breathing columns/rows for bars, quiet dots elsewhere) and takes the chart's exact footprint, so the real chart swaps in with zero layout jump. emptyMessage / errorMessage override the state text. Live demo (all three states + a fetch simulator): examples/states-demo.html.

Chart catalog

| Factory | Variants | |---|---| | ChartFactory.Area | primitives: basic, stacked · presets (named configs over a primitive): smoothed, diverging (→ basic); normalized, streamgraph (→ stacked) | | ChartFactory.Line | primitives: basic, multi, band, bump · presets (named configs over a primitive): yearly, smoothed, area-gradient, combined, growth-rate (→ basic); YoY, textures, cumulative-vs-moving (→ multi); forecast-band, pulse-anomalies, dynamic-band (→ band) | | ChartFactory.Slope | primitive: basic · presets (named configs over basic): trend, categorical, highlight, animated, bands, indexed | | ChartFactory.Bar | primitives: basic, stacked, likert, gantt, vertical, vertical-stacked, waterfall-vertical · presets (named configs over a primitive): inline, label-above, progress, bullet, diverging (→ basic); grouped (→ stacked); pyramid (→ likert); range, waterfall (→ gantt); vertical-normalized (→ vertical-stacked) | | ChartFactory.Scatter | primitives: basic, beeswarm, trajectory, density, contour, heatmap · presets (named configs over a primitive): logos, animated, marginal, marginal-KDE, marginal-simple, quadrant, diagonal (→ basic); beeswarm-vertical, beeswarm-horizontal, beeswarm-logos (→ beeswarm); comet (→ trajectory); hexbin (→ density); KDE (→ contour) | | ChartFactory.Dot | primitives: basic, confidence, percentile, unit-histogram · presets (named configs over basic): dumbbell, gradient, comet | | ChartFactory.Histogram | primitives: basic (one series of rows), overlay (series[], shared bins) | | ChartFactory.Donut | primitive: basic (donut) · preset: pie (→ basic, no hole) | | ChartFactory.BoxPlot | basic (both orientations, raw or precomputed), violin (KDE silhouettes; inner box / points / quartiles) | | ChartFactory.Calendar | heatmap (weekly / monthRows / vertical layouts) | | ChartFactory.Sankey | primitive: basic (ribbon width = link value; d3-sankey optional) · preset: funnel-flow (→ basic, tapered ribbons) | | ChartFactory.Treemap | primitive: basic (branch-identity colors, group headers) · preset: metric (→ basic, color = a second measure) | | ChartFactory.Funnel | primitive: basic (length = stage value; shape × orientation) · preset: taper (→ basic, classic silhouette) | | ChartFactory.Radar | basic (circle/polygon grid, multi-series, stroke-only) | | ChartFactory.Table | primitive: basic · presets (named configs over basic): sortable, with-bars, with-heatmap, with-dot-rails, combined |

Live examples for every variant are in examples/ — serve the repo root (npm run serve) and open http://localhost:8000/examples/.

Upgrading from 0.1.x

0.2.0 is a breaking release with no compatibility shims. Most builders became thin presets over a few primitives, and their second spellings, retired classes and tokens, and datum-first formatters (valueFormat(datum) → valueFormat(value, datum)) were deleted rather than aliased. Every change is listed in migrations/0.2.0.md, which ships in the package, and the package's scanner applies the mechanical ones:

npx -p [email protected] chart-factory-migrate ./src         # inventory: file:line, old → new, auto-fixable
npx -p [email protected] chart-factory-migrate ./src --fix   # apply the mechanical rewrites only

Whatever it cannot rewrite is listed for a decision. ChartFactory.validate(builder, config) then confirms that a migrated config is clean.

Development

npm install        # installs esbuild
npm run build      # bundles src/ -> dist/ (also runs on npm prepare)
npm run watch      # rebuild on change
npm run serve      # static server for examples/

Source lives in src/ as plain ES modules; dist/ holds the generated browser bundles. All styling values must flow through the design tokens in src/core/tokens.css — never hardcode colors, spacing, or font sizes.

License

MIT