Interactivity & live data
Events
All event names are lowercase (the platform convention):
html`<${Charts} type="bar" series="${series}"
onpointclick="${(point, { seriesIndex, pointIndex }) => select(point)}"
onlegendclick="${(key, visible) => console.log(key, visible)}"
ondrilldown="${(key, depth) => console.log('into', key)}"
ondrillup="${(depth) => console.log('back to', depth)}" />`
Clicking a legend entry toggles that series’ visibility, and the chart rescales to the remaining data automatically.
Drilldown
Declarative: map a category (or slice) name to the chart it opens. Descending renders a breadcrumb for the way back, with no handlers needed:
import Charts from '@lemonadejs/charts';
const App = () => html`<${Charts} type="bar" title="Sales by region (click a bar)"
categories="${['Americas', 'EMEA', 'APAC']}"
series="${[{ name: 'Sales', data: [82, 61, 47] }]}" labels
drilldown="${{
Americas: { categories: ['US', 'CA', 'BR', 'MX'], series: [{ name: 'Sales', data: [40, 18, 15, 9] }] },
EMEA: { categories: ['DE', 'UK', 'FR', 'ES'], series: [{ name: 'Sales', data: [22, 17, 12, 10] }] },
APAC: { categories: ['CN', 'JP', 'IN', 'AU'], series: [{ name: 'Sales', data: [19, 12, 10, 6] }] },
}}" />`;Levels nest (a drilldown target can carry its own drilldown), and each
level may change type and title too.
Zoom and navigator
For dense series, zoom enables drag-select along the x-axis (with a
reset button), and navigator renders an overview strip below the plot
with a draggable, resizable window:
import Charts from '@lemonadejs/charts';
const data = Array.from({ length: 60 }, (_, i) =>
Math.round(70 + Math.sin(i / 5) * 20 + Math.random() * 8));
const App = () => html`<${Charts} type="line"
categories="${data.map((_, i) => 'D' + (i + 1))}"
series="${[{ name: 'Price', data }]}"
markers="${false}" zoom navigator legend="${false}" />`;Live data
Props are states, so live charts are just assignment. A polling dashboard, a websocket feed, or a simulation all look the same:
import Charts from '@lemonadejs/charts';
const App = (props, { state, onMount }) => {
const series = state([{ name: 'Load', data: [50] }]);
onMount(() => {
const timer = setInterval(() => {
const prev = series.value[0].data;
const next = [...prev.slice(-29),
Math.max(5, Math.min(95, prev[prev.length - 1] + (Math.random() - 0.5) * 14))];
series.value = [{ name: 'Load', data: next }];
}, 800);
return () => clearInterval(timer); // cleanup on unmount
});
return html`<${Charts} type="line" series="${series}" smooth
markers="${false}" legend="${false}" height="${220}"
ymin="${0}" ymax="${100}" />`;
};Remember the v6 contract: build a new array and assign. In-place
push alone does not trigger (or call .touch() after mutating).
animate (on by default) gives entrance/update transitions and respects
prefers-reduced-motion.
Export
toolbar shows a small toolbar with CSV download; SVG export is
available for the SVG-native types. Both work entirely client-side: the
chart is the document.