When data changes every second, the expensive path is rebuilding markup or redrawing a canvas. With st-core@v2, the chart is already pure CSS (clip-path fill/line driven by --st-p1 … --st-pN). Live updates only need JavaScript to rewrite those variables on the chart layers.
Template: templates/live-shift
JS: dashboard.js
Why this is low-overhead
| Approach | Cost on each tick |
|---|---|
| Rebuild table / SVG nodes | DOM create/destroy, layout |
| Full chart library redraw | Often heavy paint + JS |
| st-core live shift | Set element.style CSS variables; browser composites the existing layers |
You need real-time, low-overhead updates: for fast-changing streaming data (crypto or stock ticker), updating an st-core chart means modifying the CSS custom properties on the fill/line elements. No list re-render, no virtual DOM diff for the plot itself.
How the template is split
| File | Role |
|---|---|
dashboard.fscss |
@arr priceData[...], @st-chart-fill / line / grid, phone shell |
dashboard.css |
Compiled CSS |
dashboard.js |
Random-walk series → --st-pN + labels |
index.html |
Markup only |
Initial geometry and series length are declared in FSCSS:
@arr priceData[42, 55, 48, 68, 61, 79, 72, 85]
@st-chart-fill(.chart-fill, priceData)
@st-chart-line(.chart-line, priceData)
JS keeps the same length and only pushes new values into the same --st-p* slots.
The update path
Normalize human values (0–100 “up is higher”) into st-core’s inverted Y vars, then assign in one cssText pass:
function normalize(v) {
return 100 - Math.max(0, Math.min(100, v)) + '%';
}
function applySeries(arr) {
const vars = arr
.map((v, i) => `--st-p${i + 1}: ${normalize(v)};`)
.join(' ');
fill.style.cssText = vars;
line.style.cssText = vars;
}
Each tick: shift the window, append a new sample, apply:
function shift() {
const last = series[series.length - 1];
const next = /* stream or random-walk */;
series = [...series.slice(1), next];
applySeries(series);
// optional: text for P&L, allocation bar vars
}
setInterval(shift, 1200); // or your websocket handler
Allocation bars in the same demo use another token:
barEl.style.setProperty('--st-cat-bar-fill-range', eq + '%');
Still no chart DOM rebuild — width/fill is CSS.
Wiring a real stream
Replace the random walk with your feed:
socket.addEventListener('message', (ev) => {
const price = JSON.parse(ev.data).price; // map to 0–100 or your scale
series = [...series.slice(1), scale(price)];
applySeries(series);
});
Keep N fixed (or regenerate CSS when N changes). Transitions on .chart-fill / .chart-line (clip-path transition in the template) give you motion “for free.”
When to use this
- Tickers, live dashboards, status charts where N is stable
- You already like CSS-first charts from st-core
- You want updates that are basically style invalidation, not tree updates
When N changes often or you need hit-testing/tooltips per point, you may still add a thin JS layer — but the series itself can stay on CSS variables.
Try it
git clone https://github.com/fscss-ttr/st-core.fscss.git
cd st-core.fscss/templates/live-shift
# open index.html after dashboard.css is built, or use FSCSS runtime on dashboard.fscss
Source
Top comments (0)