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

@askrjs/charts

v0.4.0

Published

Typed Canvas 2D plots and SVG export for Askr applications.

Readme

@askrjs/charts

CI npm version

Typed Canvas 2D plots for Askr applications, with the same immutable scene available for SVG and data export.

Version 0.1 is a clean break from the old CSS-first chart catalog. JavaScript comes from @askrjs/charts; structural and theme-token styles come from @askrjs/charts/styles. There are no component, core, default, per-chart CSS, template, or generator compatibility entrypoints.

Install

npm install @askrjs/charts

Import the styles once at the application boundary:

@import "@askrjs/charts/styles";

Quick start

Create a typed plot namespace once at module scope, then compose marks inside its root:

import { createPlot } from "@askrjs/charts";

type RevenueRow = {
  id: string;
  day: Date;
  revenue: number;
  target: number;
};

const RevenuePlot = createPlot<RevenueRow>();

const revenue: readonly RevenueRow[] = [
  { id: "mon", day: new Date("2026-07-13T00:00:00Z"), revenue: 42, target: 48 },
  { id: "tue", day: new Date("2026-07-14T00:00:00Z"), revenue: 58, target: 50 },
  { id: "wed", day: new Date("2026-07-15T00:00:00Z"), revenue: 51, target: 52 },
];

export function RevenueTrend() {
  return (
    <RevenuePlot.Root
      data={revenue}
      rowKey="id"
      label="Daily revenue"
      title="Revenue"
      description="Actual revenue and target for the current week."
    >
      <RevenuePlot.Bar x="day" y="revenue" />
      <RevenuePlot.Line x="day" y="target" />
      <RevenuePlot.Point x="day" y="target" />
    </RevenuePlot.Root>
  );
}

Row drives field-name inference. A numeric mark channel cannot name a string field, and a factory's primitives cannot be mixed into another factory's root. Fields, accessors, and expressions can be combined without giving up row typing.

Public surface

createPlot<Row>() returns a stable namespace containing:

  • structure: Root, Scale, Axis, Grid
  • marks: Bar, Line, Area, Point, Arc, Cell, Rect, Rule, Text
  • interaction: Legend, Tooltip, Crosshair, Select, Zoom, Brush

The root owns responsive sizing, semantic labels, title and description, empty and summary states, controlled or uncontrolled view and selection, follow-latest behavior, activation, and export access through onApiChange.

Useful defaults are inferred from channels and mark context:

  • numbers use linear scales
  • Date values use local-time scales
  • categorical positions use band or point scales
  • categorical colors use ordinal scales; numeric colors use continuous scales
  • Cartesian marks receive default axes and tooltip behavior

Add explicit scale, axis, grid, legend, or tooltip children when the composition needs different behavior. Named scales support mixed plots and dual axes.

Tooltip supports nearest-mark inspection and shared nearest-x inspection with mode="mark" | "x"; auto chooses shared x for compatible Cartesian marks. Add Select for click/tap and Enter/Space selection. Its single default replaces the selection, while toggle adds or removes source keys. Selection updates before the additive onActivate(row, key, target) callback.

Mounted plots always respond to their container. width is the SSR and initial-layout fallback, not a fixed browser width; use a sized container for a fixed mounted chart.

Data rules

  • Signed finite numbers stay signed; negative values are not clamped to zero.
  • null, undefined, invalid dates, and non-finite numbers are missing values, not zero.
  • Log scales omit zero and negative values.
  • diagnostics opts into omitted-value warnings, and summary receives omittedRowCount for accessible reporting.
  • Stable row keys drive selection retention, transitions, and live updates.
  • Use constant("...") for a literal string channel. Bare strings identify row fields.

Migration from the old catalog

There are no compatibility wrappers in 0.1.

| Removed 0.0 surface | 0.1 composition | Worked example | | ------------------------------------------- | ----------------------------------------------------------------- | ------------------------------------------------- | | ChartShell | Plot.Root; keep product card or page chrome in the app | catalog | | ChartPanel | App-owned card/section plus Plot.Root title and description | catalog | | ChartEmptyState | Root empty="..."; keep loading and error ownership in the route | catalog | | ChartLegend | Plot.Legend | mark families | | AreaChart | Plot.Area | mark families | | BarChart | Plot.Bar | mark families | | LineChart | Plot.Line, optionally with Plot.Point | mark families | | DonutChart | Plot.Arc with innerRadius | mark families | | PieChart | Plot.Arc with innerRadius={0} | catalog recipes | | StackedBarChart | Plot.Bar stack="series"; use normalize for percent stacks | catalog recipes | | Sparkline | Compact Plot.Root with Plot.Line or Plot.Area | catalog recipes | | Heatmap | Plot.Cell | mark families | | Timeline | Plot.Rule, Plot.Point, and Plot.Text | mark families | | FlameGraph | Plot.Rect with partition(...) | mark families | | ProgressMeter | Bounded Plot.Bar plus Root meter={{ role: "meter", ... }} | mark families | | RadialGauge | Bounded Plot.Arc plus Root meter={{ role: "meter", ... }} | mark families | | @askrjs/charts/core | Helpers exported directly from @askrjs/charts | | @askrjs/charts/default or root CSS import | @askrjs/charts/styles | | Per-chart CSS, templates, and new:chart | One structural stylesheet and primitive composition |

More

@askrjs/themes is optional. The stylesheet defines self-contained --ak-chart-* tokens and uses compatible Askr theme tokens when they are present.