
WebGL Chart is a low-level JavaScript WebGL charting library that renders interactive charts on an HTML canvas using GPU-backed buffers.
It works in Vanilla JavaScript through UMD bundles, and also includes Vue 3 and React wrappers for framework projects.
Features:
- Renders all chart drawing through WebGL on a canvas for GPU-accelerated output.
- Supports line, point, bar, area, bubble, range rectangle, and candlestick chart types.
- Hover tooltips with crosshair lines and nearest-point snap markers.
- Mouse wheel zoom and drag-to-pan interactions on both axes.
- Multiple y-axes on a single chart, with optional right-side axis placement.
- Stacked chart panels sharing one canvas and one event dispatcher.
- Rolling chart mode using circular buffers that overwrite old data at capacity.
- GPU-rendered axis labels, tick labels, and custom text overlays.
- Annotation support, including vertical lines, horizontal lines, shaded bands, boxes, and text labels.
Use Cases:
- Real-time sensor dashboards that stream telemetry data at high frame rates.
- Financial applications that display candlestick charts with a volume bar series on a secondary axis.
- Scientific instruments that need custom tick formatting for units like Hz, mV, or °C.
- Engineering tools that overlay multiple signal types across stacked panels on one canvas.
How to Use It:
1. Use the core chart package and the WebGL utility package in module-based projects.
# NPM npm i @tomsoftware/webgl-chart @tomsoftware/webgl-lib --save # Vue 3 npm i @tomsoftware/webgl-chart @tomsoftware/webgl-lib @tomsoftware/webgl-chart-vue --save # React npm i @tomsoftware/webgl-chart @tomsoftware/webgl-lib @tomsoftware/webgl-chart-react --save
2. Or load the UMD version via CDN (Vanilla JS, no build step).
After loading via CDN,
window.WebGLLibandwindow.WebGLChartbecome available as globals. Thewebgl-libscript must load beforewebgl-chart.
<script src="https://chart.hmilch.net/dist/1.1/webgl-lib.umd.js"></script> <script src="https://chart.hmilch.net/dist/1.1/webgl-chart.umd.js">
3. Create a basic line chart. The canvas element needs a real computed CSS width and height before the chart can render. Set these in your stylesheet or with an inline style.
<canvas id="chartCanvas" style="width: 100%; height: 400px;"></canvas>
const { GpuChart, BasicChartLayout, Scale, SeriesLine } = window.WebGLChart;
const { GpuGrowingBuffer, Color, LayoutCell, EventDispatcher } = window.WebGLLib;
// Bind the renderer to the canvas.
const canvas = document.getElementById('chartCanvas');
const chart = new GpuChart().bind(canvas);
// Bind pointer events to the same canvas.
const dispatcher = new EventDispatcher();
dispatcher.bind(canvas);
// Create x values for the chart.
const time = new GpuGrowingBuffer('float32', 1000)
.generate((i) => i * 0.01);
// Create y values from the x buffer.
const values = GpuGrowingBuffer.generateFrom('float32', time, (t) => {
return Math.sin(t) * Math.cos(t * 0.25);
});
// Create the line series.
const line = new SeriesLine(time, values)
.setColor(Color.darkGreen)
.setThickness(2);
// Define the visible data ranges.
const scaleX = new Scale(0, 10);
const scaleY = new Scale(-1.2, 1.2);
// Create the layout and axes.
const container = new LayoutCell();
const layout = new BasicChartLayout(dispatcher, container, scaleX);
layout.addYScale(scaleY, 'Signal');
layout.xAxis.label?.setText('Seconds');
// Draw every frame.
chart.setRenderCallback((context) => {
// Calculate chart areas before drawing.
context.calculateLayout(container);
// Process wheel, pan, and pointer events.
dispatcher.dispatch(context);
// Draw axes and grid lines.
layout.draw(context);
// Draw the data series inside the chart area.
line.draw(context, scaleX, scaleY, layout.chartCell);
});
// Limit redraw work.
chart.setMaxFrameRate(12);
// Start the render loop.
chart.render();4. All available configuration options.
canvas(HTMLCanvasElement): Sets the canvas target forGpuChart.bind().callback(function): Sets the drawing routine forsetRenderCallback().fps(number): Sets the maximum frame rate forsetMaxFrameRate().min(number): Sets the visible minimum value forScale.max(number): Sets the visible maximum value forScale.eventDispatcher(EventDispatcher): Routes pointer, wheel, and pan events to chart layouts.baseCell(LayoutCell): Defines the root layout area for a chart.xScale(Scale): Sets the horizontal scale forBasicChartLayout.scale(Scale): Adds a y-axis scale throughaddYScale().title(string): Sets the y-axis title inaddYScale().position(VerticalAxisOrientation): Places a y-axis on the left or right side.timeBuffer(Gpu buffer): Stores x positions for line, point, and area series.dataBuffer(Gpu buffer): Stores y values for line and point series.upperBuffer(Gpu buffer): Stores upper y values for area charts.lowerBuffer(Gpu buffer): Stores lower y values for area charts.xBuffer(Gpu buffer): Stores x positions for bars, bubbles, and range series.yBuffer(Gpu buffer): Stores y values for bars and bubbles.radiusBuffer(Gpu buffer): Stores bubble radius values.y1Buffer(Gpu buffer): Stores the first y value for range series.y2Buffer(Gpu buffer): Stores the second y value for range series.color(Color): Sets a series, axis, annotation, or tooltip color.upperColor(Color): Sets the top area color forSeriesArea.lowerColor(Color): Sets the bottom area color forSeriesArea.color1(Color): Sets the first conditional range rectangle color.color2(Color): Sets the second conditional range rectangle color.thickness(number): Sets line thickness in pixels.size(number): Sets point size in pixels.value(number): Sets bar width, offsets, zoom factors, or scale movement values.stripeWidth(number): Sets annotation band width.lineThickness(number): Sets annotation line thickness.radius(number): Sets annotation box corner radius.text(GpuText): Sets annotation or axis label text.padding(number): Sets annotation label padding.boxRadius(number): Sets annotation label background radius.margin(number): Sets annotation label offset.type(string): Sets buffer data type such asfloat32,vec2,vec3, orvec4.sizeOrValues(number or number[]): Sets buffer capacity or initial data.sourceBuffer(Gpu buffer): Sets the input buffer for derived data.pointSize(number): Sets tooltip marker size.
5. API methods:
// Create a chart renderer.
const chart = new GpuChart();
// Bind the renderer to a canvas.
chart.bind(document.getElementById('chartCanvas'));
// Set the drawing callback.
chart.setRenderCallback(function(context) {
context.calculateLayout(container);
});
// Cap the redraw rate.
chart.setMaxFrameRate(24);
// Read the configured frame rate.
chart.getMaxFrameRate();
// Start the render loop.
chart.render();
// Draw one frame manually.
chart.drawScene(performance.now());
// Dispose WebGL resources and listeners.
chart.dispose();
// Create a scale.
const scaleX = new Scale(0, 100);
// Move a scale by a fraction of its range.
scaleX.pan(0.1);
// Zoom a scale by a fraction of its range.
scaleX.zoom(0.05);
// Set scale bounds.
scaleX.setRange(10, 80);
// Convert a position back to a scale value.
scaleX.valueAt(0, 0.5, 1);
// Generate axis ticks.
scaleX.calculateTicks(10, 600, false);
// Create a standard chart layout.
const layout = new BasicChartLayout(dispatcher, container, scaleX);
// Add a y-axis.
layout.addYScale(scaleY, 'Temperature');
// Add a right-side y-axis.
layout.addYScale(scaleRight, 'Pressure', VerticalAxisOrientation.Right);
// Set the x-axis label.
layout.setXAxisLabel('Seconds');
// Draw axes and grid lines.
layout.draw(context);
// Create a line series.
const line = new SeriesLine(timeBuffer, valueBuffer);
// Set line color.
line.setColor(Color.darkGreen);
// Set line thickness.
line.setThickness(2);
// Connect the last point back to the first point.
line.setLineLoop(true);
// Draw the line series.
line.draw(context, scaleX, scaleY, layout.chartCell);
// Create a point series.
const points = new SeriesPoint(timeBuffer, valueBuffer);
// Set point color.
points.setColor(Color.red);
// Set point size.
points.setPointSize(4);
// Draw points.
points.draw(context, scaleX, scaleY, layout.chartCell);
// Create an area series.
const area = new SeriesArea(timeBuffer, upperBuffer, lowerBuffer);
// Set upper and lower fill colors.
area.setColor(Color.lightBlue, Color.lightGray);
// Draw the area.
area.draw(context, scaleX, scaleY, layout.chartCell);
// Create a bar series.
const bars = new SeriesBar(xBuffer, yBuffer);
// Set bar color.
bars.setColor(Color.orange);
// Set bar width in data units.
bars.setBarWidth(0.08);
// Offset bars for grouped columns.
bars.setOffsetX(0.04);
// Draw bars.
bars.draw(context, scaleX, scaleY, layout.chartCell);
// Create a bubble series.
const bubbles = new SeriesBubble(xBuffer, yBuffer, radiusBuffer);
// Set bubble color.
bubbles.setColor(Color.green.withAlpha(0.6));
// Scale bubble radius values.
bubbles.setBubbleScaling(1.2);
// Draw bubbles.
bubbles.draw(context, scaleX, scaleY, layout.chartCell);
// Create a range rectangle series.
const rangeRects = new SeriesRangeRect(xBuffer, lowBuffer, highBuffer);
// Set conditional range colors.
rangeRects.setColor(Color.darkGreen, Color.red);
// Set range rectangle width.
rangeRects.setBarWidth(0.5);
// Draw range rectangles.
rangeRects.draw(context, scaleX, scaleY, layout.chartCell);
// Create a range line series.
const rangeLines = new SeriesRangeLine(xBuffer, lowBuffer, highBuffer);
// Set range line color.
rangeLines.setColor(Color.black);
// Set range line width.
rangeLines.setLineWidth(2);
// Draw range lines.
rangeLines.draw(context, scaleX, scaleY, layout.chartCell);
// Create annotation storage.
const annotations = new Annotations();
// Add a shaded box.
annotations.addBox(2, 10, 5, -10, Color.orange.withAlpha(0.25), 4);
// Add a vertical marker line.
annotations.addVerticalLine(4.2, Color.red, 8, 2);
// Add a horizontal threshold line.
annotations.addHorizontalLine(12, Color.green, 5, 2);
// Draw annotations.
annotations.draw(context, scaleX, scaleY, layout.chartCell);
// Create a tooltip guide line.
const tooltipLine = new TooltipLine();
// Set tooltip guide color.
tooltipLine.setMouseColor(Color.gray);
// Show vertical and horizontal guide lines.
tooltipLine.showMouseLines(true, true);
// Draw tooltip guide lines.
tooltipLine.draw(context, dispatcher.getMousePosition(), layout.chartCell);
// Create tooltip markers.
const markers = new TooltipMarkers();
// Clear registered series.
markers.clearSeries();
// Register a series for hover lookup.
markers.addSeries(timeBuffer, valueBuffer, scaleX, scaleY, Color.darkGreen, 8);
// Draw nearest markers and labels.
markers.draw(context, dispatcher.getMousePosition(), layout.chartCell);
// Create a growing buffer.
const growing = new GpuGrowingBuffer('float32', 1000);
// Fill a buffer from an index callback.
growing.generate(function(i) {
return i * 0.01;
});
// Create a derived buffer.
const derived = GpuGrowingBuffer.generateFrom('float32', growing, function(value) {
return Math.sin(value);
});
// Add one or more values.
growing.push(1.25, 1.5, 1.75);
// Add a value array.
growing.pushRange([2, 2.25, 2.5]);
// Clear buffer data.
growing.clear();
// Read one component.
growing.getComponentAt(0, 0);
// Read one logical item.
growing.getAttributeAt(0);
// Write one component.
growing.setComponentAt(0, 0, 3.14);
// Write one logical item.
growing.setAttributeAt(0, [3.14]);
// Find the nearest index for a value.
growing.findIndex(2.5);
// Create a ring buffer for live charts.
const ring = new GpuRingBuffer('float32', 300);
// Break a false line segment after wrapping.
ring.setBreakAfterWritePosition(true);
// Copy the last value to the beginning during wrap.
ring.setCopyLastValueToBeginning(true);6. Events:
// Create the event dispatcher.
const dispatcher = new EventDispatcher();
// Bind mouse and touch input to the canvas.
dispatcher.bind(document.getElementById('chartCanvas'));
// Process queued events inside the render callback.
dispatcher.dispatch(context);
// Handle mouse wheel events over the chart area.
dispatcher.on(EventTypes.Wheel, layout.chartCell, function(event) {
scaleX.zoom(event.wheelDelta / 600);
});
// Handle drag pan events over the chart area.
dispatcher.on(EventTypes.Pan, layout.chartCell, function(event, node, area) {
scaleX.pan(event.panDeltaX / area.width);
});
// Handle pointer movement over the chart area.
dispatcher.on(EventTypes.MouseMove, layout.chartCell, function(event) {
console.log(event.position);
});
// Read the current pointer position for tooltips.
const pointer = dispatcher.getMousePosition();
// Read mouse button state.
const buttons = dispatcher.getMouseButtons();
// Remove event listeners when the chart leaves the page.
dispatcher.dispose();FAQs:
Q: How do I add zoom and pan?
A: Bind EventDispatcher to the canvas and call dispatcher.dispatch(context) inside the render callback. BasicChartLayout registers chart-area zoom and pan handlers.
Q: Can I build candlestick charts?
A: Yes. Use SeriesRangeRect for open and close bodies, then use SeriesRangeLine for high and low wicks.
Q: How do I handle live data?
A: Use GpuRingBuffer for fixed-history streams. Use setBreakAfterWritePosition(true) if line wrapping creates a false segment.
Q: How do I format axis tick labels as dates or currency?
A: Call setTickFormat() on the axis instance. The callback receives the raw numeric tick value and returns a display string. Store relative values in the GPU buffers (for example, milliseconds since a fixed epoch) and reconstruct absolute labels inside the formatter to preserve 32-bit float precision.







