JSPM

  • Created
  • Published
  • Downloads 56
  • Score
    100M100P100Q63736F
  • License MIT

Real-time LOD time series rendering engine for the browser.

Package Exports

  • blazeplot
  • blazeplot/linked
  • blazeplot/package.json
  • blazeplot/plugins/annotations
  • blazeplot/plugins/crosshair
  • blazeplot/plugins/interactions
  • blazeplot/plugins/legend
  • blazeplot/plugins/navigator
  • blazeplot/plugins/selection
  • blazeplot/plugins/tooltip
  • blazeplot/react

Readme

BlazePlot

npm version npm downloads license

Fast WebGL2 plotting engine for the browser 🔥

Built for people who have hit the performance ceiling of Chart.js, Plotly, and similar browser charting libraries. BlazePlot keeps the hot path GPU-native and the DOM minimal, so large streaming datasets stay interactive instead of turning into a slideshow.

Built on WebGL2 + regl.

Installation

bun install blazeplot

Quick start

A chart only needs a host element. For regular arrays, wrap your data in a StaticDataset; capacity is only needed when you want a streaming ring buffer.

<div id="chart" style="width:100%;height:400px"></div>

<script type="module">
  import { Chart, StaticDataset } from "blazeplot";

  const el = document.getElementById("chart");
  if (!el) throw new Error("Missing #chart element");

  const x = Array.from({ length: 1000 }, (_, i) => i);
  const y = x.map((value) => Math.sin(value * 0.02));

  const chart = new Chart(el);
  chart.addLine({ dataset: new StaticDataset(x, y), name: "sine" });
  chart.setViewport({ xMin: x[0], xMax: x[x.length - 1], yMin: -1.5, yMax: 1.5 });
  chart.start();
</script>

Features

WebGL2 rendering GPU-accelerated plot rendering from the ground up. No Canvas2D fallback. Axis labels use lightweight DOM layers.
Flexible data model Streaming ring buffer or static arrays. Bring your own data shape.
LOD downsampling Min/max pyramid for efficient line rendering at any zoom level — sparse views show raw points, dense views show vertical segments.
Pan & zoom Pointer/touch pan and wheel zoom via Camera2D. Customizable viewport policies.
Grid lines Data-anchored grid rendered as WebGL line lists.
Axis labels Smart tick generation with DOM labels. Per-axis inside/outside positioning; outside axes reserve real layout gutters.
Multi-series Independent buffers, styles, and visibility per series. Line, area, scatter, and bar modes are supported.
Plugin-ready UI Optional built-in legendPlugin() and tooltipPlugin() use the same public state and hover APIs available to custom plugins.
Benchmark overlay Built-in fps, frame time, vertex count, draw calls.
ResizeObserver Automatic DPR-aware canvas sizing.

API reference

This section is generated by bun run docs:readme from TypeScript declaration files and JSDoc comments. Do not edit it by hand.

Package entry points

Import Contents
blazeplot Core chart, data, interaction, rendering types, and low-level primitives.
blazeplot/react React wrapper component and hooks.
blazeplot/linked Linked chart layout helpers.
blazeplot/plugins/legend Built-in legend plugin.
blazeplot/plugins/tooltip Built-in tooltip plugin.
blazeplot/plugins/interactions Built-in pan, zoom, axis interaction, and reset plugin.
blazeplot/plugins/annotations Built-in annotation overlay plugin.
blazeplot/plugins/selection Built-in brush/range selection plugin.
blazeplot/plugins/crosshair Built-in crosshair and ruler plugin.
blazeplot/plugins/navigator Built-in overview/navigator plugin.

Selected generated declarations

These member tables are generated from TypeScript declarations.

class Chart
Member
constructor(target: HTMLElement, options?: ChartOptions)
get canvas(): HTMLCanvasElement
get rootElement(): HTMLElement
get plotElement(): HTMLElement
get xAxisElement(): HTMLElement
get yAxisElement(): HTMLElement
get y2AxisElement(): HTMLElement
get theme(): ResolvedChartTheme
`getWebGLContext(): WebGL2RenderingContext \
getCamera(yAxis?: SeriesYAxis): Camera2D
dataToPlot(x: number, y: number, yAxis?: SeriesYAxis): [ number, number ]
`clientToData(clientX: number, clientY: number, yAxis?: SeriesYAxis): [ number, number ] \
getViewport(yAxis?: SeriesYAxis): Viewport
pan(intent: PanIntent): void
zoom(intent: ZoomIntent): void
addSeries(config: SeriesConfig, style?: Partial<SeriesStyle>): SeriesStore
addLine(config: TypedSeriesConfig, style?: Partial<SeriesStyle>): SeriesStore
addArea(config: TypedSeriesConfig, style?: Partial<SeriesStyle>): SeriesStore
addScatter(config: TypedSeriesConfig, style?: Partial<SeriesStyle>): SeriesStore
addBar(config: TypedSeriesConfig, style?: Partial<SeriesStyle>): SeriesStore
addOhlc(config: TypedSeriesConfig, style?: Partial<SeriesStyle>): SeriesStore
addCandlestick(config: TypedSeriesConfig, style?: Partial<SeriesStyle>): SeriesStore
removeSeries(series: SeriesStore): boolean
setSeriesVisible(series: SeriesStore, visible: boolean): boolean
getSeriesState(): ChartSeriesState[]
setViewport(v: { xMin?: number; xMax?: number; yMin?: number; yMax?: number; }): void
setYViewport(yAxis: SeriesYAxis, v: { yMin?: number; yMax?: number; }): void
resize(dpr?: number): boolean
getFrameStats(target?: ChartFrameStats): ChartFrameStats
`getHoverState(): ChartHoverState \
`setLayoutReservation(id: string, reservation: ChartLayoutReservation \
`subscribe(event: "hover", callback: (state: ChartHoverState \
subscribe(event: "serieschange", callback: () => void): () => void
subscribe(event: "themechange", callback: () => void): () => void
subscribe(event: "render", callback: (chart: Chart) => void): () => void
subscribe(event: "viewportchange", callback: (event: ChartViewportChangeEvent) => void): () => void
subscribe(event: "select", callback: (event: ChartSelectEvent) => void): () => void
subscribe(event: "seriesclick", callback: (event: ChartSeriesClickEvent) => void): () => void
subscribe(event: ChartPointerEventType, callback: (event: ChartPointerEventState) => void): () => void
emitSelect(selection: unknown): void
setTheme(theme?: ChartTheme): void
setGridVisible(visible: boolean): void
getGridVisible(): boolean
setAxes(axes: ChartOptions["axes"]): void
`pick(clientX: number, clientY: number, options?: ChartPickOptions): ChartHoverState \
screenshot(options?: ChartScreenshotOptions): Promise<Blob>
start(): void
stop(): void
dispose(): void
interface ChartOptions
Member
viewportPolicy?: ViewportPolicy
grid?: boolean
gridStyle?: Partial<SeriesStyle>
`axes?: boolean \
`title?: string \
`subtitle?: string \
hover?: ChartPickOptions
plugins?: readonly ChartPlugin[]
theme?: ChartTheme
interface ChartTheme
Member
backgroundColor?: ThemeColor
gridColor?: ThemeColor
axisColor?: string
axisFont?: string
seriesColors?: readonly ThemeColor[]
tooltipBackgroundColor?: string
tooltipTextColor?: string
tooltipFont?: string
legendBackgroundColor?: string
legendBorderColor?: string
legendTextColor?: string
legendMutedTextColor?: string
legendFont?: string
titleColor?: string
titleFont?: string
subtitleColor?: string
subtitleFont?: string
axisTitleColor?: string
axisTitleFont?: string
interface AxisConfig
Member
visible?: boolean
position?: AxisPosition
scale?: AxisScale
tickFormat?: AxisTickFormat
timezone?: AxisTimeZone
`title?: string \
class SeriesStore
Member
config: SeriesConfig
style: SeriesStyle
constructor(dataset: Dataset, config: SeriesConfig, style: SeriesStyle)
get hasLOD(): boolean
get dirty(): boolean
get length(): number
get visible(): boolean
setVisible(visible: boolean): void
append(x: ArrayLike<number>, y: ArrayLike<number>): void
appendY(y: ArrayLike<number>): void
markDirty(): void
clear(): void
rebuildPyramid(): void
query(viewport: Viewport, pixelWidth: number): LODView
visibleSampleCount(viewport: Viewport): number
`sampleAt(index: number): SeriesSample \
`nearestSampleByX(x: number, viewport?: Viewport): SeriesSample \
`nearestSampleByPoint(x: number, y: number, viewport: Viewport, plotWidth: number, plotHeight: number, maxDistancePx?: number): SeriesSample \
copyRawVisible(viewport: Viewport, target: Float32Array, maxPoints: number, xOrigin?: number): number
copyScatterVisible(viewport: Viewport, target: Float32Array, maxPoints: number, pixelWidth: number, pixelHeight: number, pointSize: number, xOrigin?: number): number
copyScatterRange(start: number, end: number, viewport: Viewport, target: Float32Array, maxPoints: number, xOrigin?: number, pixelHeight?: number, pointSize?: number): number
copyRawVisibleClipped(viewport: Viewport, target: Float32Array, maxPoints: number, xOrigin?: number): number
copyRawVisibleClipSpace(viewport: Viewport, target: Float32Array, maxPoints: number): number
copyRawRange(start: number, end: number, target: Float32Array, maxPoints: number, xOrigin?: number): number
copyAreaVisible(viewport: Viewport, target: Float32Array, maxPoints: number, baseline?: number, xOrigin?: number): number
copyAreaRange(start: number, end: number, target: Float32Array, maxPoints: number, baseline?: number, xOrigin?: number): number
copyMinMaxVisible(viewport: Viewport, target: Float32Array, maxSegments: number, xOrigin?: number): number
copyMinMaxInstanced(viewport: Viewport, target: Float32Array, maxSegments: number, xOrigin?: number): number
copyOhlcRange(start: number, end: number, target: Float32Array, maxCandles: number, tickWidth: number, xOrigin?: number): number
copyOhlcTuplesRange(start: number, end: number, target: Float32Array, maxCandles: number, xOrigin?: number): number
`visibleIndexRange(viewport: Viewport \
interface SeriesConfig
Member
mode: SeriesMode
capacity?: number
downsample?: LODStrategy
overflow?: BufferOverflowStrategy
dataset?: Dataset
yAxis?: SeriesYAxis
id?: string
name?: string
interface SeriesStyle
Member
color: readonly [ number, number, number, number ]
lineWidth: number
pointSize?: number
barWidth?: number
baseline?: number
fillColor?: readonly [ number, number, number, number ]
tickWidth?: number
upColor?: readonly [ number, number, number, number ]
downColor?: readonly [ number, number, number, number ]
wickColor?: readonly [ number, number, number, number ]
class UniformRingBuffer
Member
capacity: number
xStep: number
constructor(capacity: number, options?: UniformRingBufferOptions)
get length(): number
`get range(): TimeRange \
push(x: number, y: number): void
append(x: ArrayLike<number>, y: ArrayLike<number>): void
appendY(y: ArrayLike<number>): void
clear(): void
getX(index: number): number
getY(index: number): number
lowerBoundX(x: number): number
upperBoundX(x: number): number
`rangeMinMaxY(start: number, end: number): { minY: number; maxY: number; } \
copyVisibleSamples(viewport: Viewport, target: Float32Array, maxPoints: number, layout: SampleLayout, baseline: number, xOrigin: number): number
copySamplesRange(start: number, end: number, target: Float32Array, maxPoints: number, layout: SampleLayout, baseline: number, xOrigin: number): number
copyMinMaxSegments(viewport: Viewport, target: Float32Array, maxSegments: number, layout: MinMaxLayout, xOrigin: number): number
class RingBuffer
Member
capacity: number
constructor(capacity: number, options?: RingBufferOptions)
get length(): number
`get range(): TimeRange \
push(x: number, y: number): void
append(x: ArrayLike<number>, y: ArrayLike<number>): void
`get(index: number): { x: number; y: number; } \
getX(index: number): number
getY(index: number): number
lowerBoundX(x: number): number
upperBoundX(x: number): number
`rangeMinMaxY(start: number, end: number): { minY: number; maxY: number; } \
clear(): void
class StaticDataset
Member
constructor(xData: ArrayLike<number>, yData: ArrayLike<number>)
get length(): number
`get range(): TimeRange \
getX(index: number): number
getY(index: number): number
lowerBoundX(x: number): number
upperBoundX(x: number): number
class OhlcRingBuffer
Member
capacity: number
constructor(capacity: number, options?: OhlcRingBufferOptions)
get length(): number
`get range(): TimeRange \
push(x: number, open: number, high: number, low: number, close: number): void
append(x: ArrayLike<number>, open: ArrayLike<number>, high: ArrayLike<number>, low: ArrayLike<number>, close: ArrayLike<number>): void
clear(): void
getX(index: number): number
getY(index: number): number
getOpen(index: number): number
getHigh(index: number): number
getLow(index: number): number
getClose(index: number): number
lowerBoundX(x: number): number
upperBoundX(x: number): number
interface Dataset
Member
length: number
`range: TimeRange \
getX(index: number): number
getY(index: number): number
lowerBoundX(x: number): number
upperBoundX(x: number): number
interface ViewportPolicy
Member
`beforePan(camera: Camera2D, intent: PanIntent): PanIntent \
`beforeZoom(camera: Camera2D, intent: ZoomIntent): ZoomIntent \
beforeRender(camera: Camera2D): void

All public exports

Generated from dist/index.d.ts after the package build
Export Kind Source JSDoc summary
AcceleratedDataset interface ./core/types Convenience contract for maximum-performance custom datasets. Implement this when a dataset can provide fast exact sample copies, stable viewport sampling, range min/max queries, and renderer-ready min/max buckets.
AppendableDataset interface ./core/types
AxisConfig interface ./ui/Chart
AxisController class ./interaction/AxisController
AxisControllerAxisOptions interface ./interaction/AxisController
AxisControllerOptions interface ./interaction/AxisController
AxisPosition type ./ui/ChartLayout
AxisRenderTarget type ./interaction/AxisController
AxisScale type ./interaction/AxisController
AxisTickFormat type ./interaction/AxisController
AxisTickFormatter type ./interaction/AxisController
AxisTimeZone type ./interaction/AxisController
AxisTitleConfig interface ./ui/Chart
BufferOverflowStrategy type ./core/types
BuiltInAxisScale type ./interaction/AxisController
Camera2D class ./interaction/Camera2D
Chart class ./ui/Chart
ChartFrameStats interface ./ui/Chart
ChartHoverState interface ./ui/Chart
ChartLayoutReservation interface ./ui/Chart
ChartOptions interface ./ui/Chart
ChartPickGroup type ./ui/Chart
ChartPickItem interface ./ui/Chart
ChartPickMode type ./ui/Chart
ChartPickOptions interface ./ui/Chart
ChartPlugin interface ./ui/Chart
ChartPluginHandle interface ./ui/Chart
ChartPointerEventState interface ./ui/Chart
ChartPointerEventType type ./ui/Chart
ChartScreenshotOptions interface ./ui/Chart
ChartSelectEvent interface ./ui/Chart
ChartSeriesClickEvent interface ./ui/Chart
ChartSeriesState interface ./ui/Chart
ChartTheme interface ./ui/theme
ChartTitleConfig interface ./ui/Chart
ChartViewportChangeEvent interface ./ui/Chart
CssColor type ./ui/theme
CustomAxisScale interface ./interaction/AxisController
Dataset interface ./core/types
DEFAULT_CHART_THEME const ./ui/theme
LODBucket interface ./core/types
LODStrategy type ./core/types
LODView interface ./core/types
MinMaxPyramid class ./core/MinMaxPyramid
MinMaxSegmentCopyDataset interface ./core/types Optional high-performance min/max extraction capability for dense rendering. Implementations can use pyramids, segment trees, database aggregates, or analytic/procedural envelopes to emit renderer-ready min/max buckets.
MinMaxSegmentLayout type ./core/types
OhlcDataset interface ./core/types
OhlcRingBuffer class ./core/OhlcDataset
OhlcRingBufferOptions interface ./core/OhlcDataset
PanIntent interface ./interaction/types
RangeMinMaxDataset interface ./core/types
RangeSampleCopyDataset interface ./core/types Optional high-performance extraction capability for datasets that can copy raw samples without going through repeated getX/getY calls. Implement this for very large datasets, implicit-X datasets, or remote/memory-mapped sources.
ResolvedChartTheme interface ./ui/theme
RgbaColor type ./ui/theme
RingBuffer class ./core/RingBuffer
RingBufferOptions interface ./core/RingBuffer
RingBufferOverflow type ./core/RingBuffer
SampleCopyLayout type ./core/types
SeriesConfig interface ./core/types
SeriesMode type ./core/types
SeriesSample interface ./core/types
SeriesStore class ./core/SeriesStore
SeriesStyle interface ./core/types
SeriesYAxis type ./core/types
StaticDataset class ./core/StaticDataset
StaticOhlcDataset class ./core/OhlcDataset
TextOverlayConfig interface ./ui/Chart
ThemeColor type ./ui/theme
TimeRange interface ./core/types
TypedSeriesConfig type ./ui/Chart
UniformRingBuffer class ./core/UniformRingBuffer High-throughput ring buffer for uniformly spaced X values. Store only Y samples and derive X as xStart + index * xStep. This is the fastest built-in dataset for live telemetry, signals, and other fixed-rate streams because appends copy a single typed array and min/max extraction uses a block segment tree over the physical ring.
UniformRingBufferOptions interface ./core/UniformRingBuffer
Viewport interface ./core/types
ViewportPolicy interface ./interaction/types
VisiblePointCopyDataset interface ./core/types Optional high-performance extraction capability for point/scatter datasets. Implementations should cull against the full 2D viewport and may sample in screen space so dense point clouds respond to both X and Y zoom.
VisibleSampleCopyDataset interface ./core/types Optional high-performance stable visible sampling capability. Unlike copySamplesRange, this method may stride/downsample, but should choose samples anchored to data coordinates so streamed appends do not make existing sampled points jitter.
YAppendableDataset interface ./core/types
ZoomAxis type ./interaction/types
ZoomIntent interface ./interaction/types

Architecture

src/
  core/          # Data model — series, datasets, LOD
  render/        # GPU abstraction + regl backend
  interaction/   # Camera, axis ticks, interaction intent types
  ui/            # Orchestrator (Chart)

Contributing

Keep pull requests small and focused. One feature or fix per PR.

Branch flow:

  • development is the integration branch for regular work.
  • Open feature/fix PRs into development.
  • Open release PRs from development into main with the version and changelog already updated.
  • Merging an unpublished version to main runs CI, publishes npm, creates the vX.Y.Z tag, and creates the GitHub Release.

Development

bun install
bun run dev             # Vite dev server → preview/
bun run ci              # Typecheck + tests + package build
bun run build           # Package build (JS + declarations)
bun test                # Tests
bun run typecheck       # TypeScript strict check
bun run version:patch   # Prepare package.json + changelog for a patch release PR