@lemonadejs/charts · 30+ chart types

JavaScript charts in HTML, CSS and SVG

Bars are flexbox. Everything else is one scaling SVG. No canvas, no redraw loop, no dependencies, and every prop is reactive: change it and only the dependent bindings re-render.

  • Zero dependencies
  • MIT licensed
  • No build step
  • Inspectable DOM
chart.js: the whole page
import { html, mount } from 'lemonadejs';
import Charts from '@lemonadejs/charts';

const series = [
    { name: 'Product A', data: [120, 190, 80, 220] },
    { name: 'Product B', data: [80, 105, 130, 140] },
];

const App = () => html`<${Charts} type="bar"
    categories="${['Q1', 'Q2', 'Q3', 'Q4']}"
    series="${series}" legend labels />`;

mount(App, document.getElementById('app'));

● live: this exact code, running on this page

One data definition, every chart

Switching charts is changing one word. And because type is a live prop like any other, you can switch it at runtime: pick a type below.

type is a state
const App = (props, { state }) => {
    const type = state('line');       // a live prop: change it, the chart follows
    return html`<div>
        <select onchange="${(e) => (type.value = e.target.value)}">
            <option value="line">line</option>
            <option value="bar">bar</option>
            <option value="stackedarea">stacked area</option>
            <option value="heatmap">heatmap</option>
        </select>
        <${Charts} type="${type}" categories="${months}"
            series="${series}" smooth legend />
    </div>`;
};

● live

Live by construction

Props are states. Assign to a state and the chart updates. There is no chart.update() and no imperative object to keep in sync with your data.

streaming points
const App = (props, { state }) => {
    const series = state([{ name: 'Live', data: [30, 45, 38, 52, 44] }]);
    const push = () => {
        const data = series.value[0].data.slice(-19);
        data.push(Math.round(30 + Math.random() * 40));
        series.value = [{ name: 'Live', data }];   // assign: the chart updates
    };
    return html`<div>
        <button onclick="${push}">Add point</button>
        <${Charts} type="line" series="${series}" smooth
            markers="${false}" legend="${false}" height="${220}" />
    </div>`;
};

● live

Why it is this small

▤

Bars are flexbox

Bar and stacked charts are plain HTML and CSS: percentage heights in a flex row. Responsive on both axes with zero JavaScript; the browser does the layout.

◎

SVG scales itself

Radial, hierarchy and flow types render one <svg viewBox>. The viewBox scales the scene, so there is no resize handling anywhere in the package.

◫

No canvas

Nothing rasterizes. Everything is inspectable DOM you can style with CSS, test with selectors and screen-read.

⟁

The engine's reactive model

The chart is a regular LemonadeJS component: a computed scene over live props. Works by value, by name, or as the <lm-charts> custom element in any framework.

Thirty chart types, one import.