Our desk needed an intraday candlestick view that stays at 60fps when someone scrolls a full year of 1-minute bars. The obvious SVG version from the model died around 8k nodes, and the first canvas attempt redrew every frame on mousemove.
What fixed it was forcing a separation between a static price layer and a cheap overlay layer for the crosshair, plus an explicit rule that the y-scale is log for equities and linear for spreads. I also made it justify the wick vs body rendering order so thin bodies don't disappear under wicks.
How are people handling the gap between sessions? A continuous time axis leaves ugly overnight gaps, but an ordinal index axis makes the time ticks lie.
Build a candlestick chart on HTML canvas (no charting library) for arrays of {t, o, h, l, c}. Requirements:
Rendering: two stacked <canvas> elements sharing one coordinate space. Layer 1 (price) redraws ONLY on data change, zoom, or pan. Layer 2 (crosshair + hovered OHLC readout) redraws on pointer move. Never redraw layer 1 on mousemove.
Scales: x is a band scale over the bar index (not wall-clock time) so overnight gaps collapse; render time tick labels from the underlying t of the bars at those indices. y is configurable: log for prices, linear for spreads (opts.scale). devicePixelRatio-aware so it's crisp on retina.
Candle rules: draw the wick first (1px, then the body on top) so narrow bodies stay visible; up bars var --up #16a34a, down var --down #dc2626, doji as a 1px horizontal tick. Body width = 70% of band, min 1px.
Perf budget: must hold 60fps panning 50,000 bars; only draw candles whose x is within the viewport plus a 20-bar margin. Include a fps meter you can toggle. No per-frame allocations in the draw loop.
Deliver the code plus a note on which parts are the hot path.