An chart library specialized for large-scale time-series data, built on WebGL.
Flexable. Realtime monitor. High performance interaction.
Taking advantage of the newest WebGL technology, we can directly talk to GPU, pushing the limit of the performance of rendering chart in browser. This library can display almost unlimited data points, and handle user interactions (pan / zoom) at 60 fps.
We compare the performance of this library and some other popular libraries. See Performance
Use npm
npm install timechart
Use HTML script tag
This library depends on D3 to draw axes and something else. It needs to be included seperatedly.
<script src="https://cdn.jsdelivr.net/npm/d3-array@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-color@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-format@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-interpolate@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-time@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-time-format@4"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-scale@4"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-selection@3"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-axis@3"></script>
<script src="https://huww98.github.io/TimeChart/dist/timechart.min.js"></script>
Display a basic line chart with axes.
<div id="chart" style="width: 100%; height: 640px;"></div>
const el = document.getElementById('chart');
const data = [];
for (let x = 0; x < 100; x++) {
data.push({x, y: Math.random()});
}
const chart = new TimeChart(el, {
series: [{ data }],
});
New in v1.
TimeChart comes with a modular design. Almost all functions are implemented as plugins. You can pick the plugins you need, so that you don’t pay for functions you don’t use.
Offical plugins:
As an example, to assemble your own chart with all offical plugins added:
import TimeChart from 'timechart/core';
import { lineChart } from 'timechart/plugins/lineChart';
import { d3Axis } from 'timechart/plugins/d3Axis';
import { legend } from 'timechart/plugins/legend';
import { crosshair } from 'timechart/plugins/crosshair';
import { nearestPoint } from 'timechart/plugins/nearestPoint';
import { TimeChartZoomPlugin } from 'timechart/plugins/chartZoom';
const el = document.getElementById('chart');
const chart = new TimeChart(el, {
data: {...},
plugins: {
lineChart,
d3Axis,
legend,
crosshair,
nearestPoint,
zoom: new TimeChartZoomPlugin({...}),
tooltip: new TimeChartTooltipPlugin({...}),
}
});
This is almost equivalent to just import TimeChart from 'timechart';
, except:
TimeChartZoomPlugin
.chart.plugins.zoom.options
instead of original chart.options.zoom
.You can also write your own plugins. Read the guide.
For users who use HTML script tag to import TimeChart, use this instead:
<!-- D3 scripts -->
<script src="https://huww98.github.io/TimeChart/dist/timechart.min.js"></script>
<script>
const el = document.getElementById('chart');
const chart = new TimeChart.core(el, {
data: {...},
plugins: {
lineChart: TimeChart.plugins.lineChart,
...
}
});
</script>
To add/remove data dynamically, just change the data array with conventional array prototype methods, then call chart.update()
.
Some restrictions to the data manipulations:
push
, pop
, shift
, unshift
, splice
.
The behavior is undefined if the length of the array is changed by any other means.update
, the data will be synchronized to GPU. Then these data cannot be modified, and can only be deleted from both ends.
Illegal modification by the overrode splice
prototype method will lead to an exception. Other Illegal modifications will lead to undefined behavior.const data = [...]; // Assume it contains 10 data points
const chart = new TimeChart(el, {
series: [{ data }],
});
data.push({x, y}, {x, y}, {x, y}); // OK
data.splice(-2, 1); // OK, data not synced yet
chart.update();
data.splice(-2, 1); // RangeError
data.splice(-2, 2); // OK, delete the last two data points
data.pop(); // OK, delete the last data point
data.splice(0, 2); // OK, delete the first two data points
chart.update(); // See data deleted
Array.prototype.pop.call(data) // Wrong. Only the overridden methods should be used
data.length = 3; // Wrong. Changes cannot be tracked
data[3] = {x, y}; // Wrong unless data[3] is already in array and not synced to GPU
Date.now()
), you may need to use baseTime
option (see below) to make the chart render properly.
let startTime = Date.now(); // Set the start time e.g. 1626186924936
let bar = []; // holds the series data
// build the chart
const chart = new TimeChart(el, {
series: [{
name: 'foo',
data: bar
}],
baseTime: startTime,
});
// update data
bar.push({x: 1, y: 10}); // 1ms after start time
bar.push({x: 43, y: 6.04}); // 43ms after start time
bar.push({x: 89, y: 3.95}); // 89ms after start time
// update chart
chart.update();
Specify these options in top level option object. e.g. to specify lineWidth
:
const chart = new TimeChart(el, {
series: [{ data }],
lineWidth: 10,
});
lineWidth (number): default line width for every data series.
default: 1
backgroundColor (CSS color specifier or d3-color instance)
default: ‘transparent’
color (CSS color specifier or d3-color instance): line color
default: color
CSS property value at initialization.
paddingTop / paddingRight / paddingLeft / paddingBottom (number): Padding to add to chart area in CSS pixel. Also reserve space for axes.
default: 10 / 10 / 45 / 20
renderPaddingTop / renderPaddingRight / renderPaddingLeft / renderPaddingBottom (number): Like the padding* counterpart, but for WebGL rendering canvas.
default: 0
xRange / yRange ({min: number, max: number} or ‘auto’): The range of x / y axes. Also use this to control pan / zoom programmatically. Specify 'auto'
to calculate these range from data automatically. Data points outside these range will be drawn in padding area, to display as much data as possible to user.
default: ‘auto’
realTime (boolean): If true, move xRange to newest data point at every frame.
default: false
baseTime (number): Milliseconds since new Date(0)
. Every x in data are relative to this. Set this option and keep the absolute value of x small for higher floating point precision.
default: 0
xScaleType (() => Scale): A factory method that returns an object conforming d3-scale interface. Can be used to customize the appearance of x-axis.
scaleTime
,
scaleUtc
,
scaleLinear
from d3-scale are known to work.
default: d3.scaleTime
debugWebGL (boolean): If true, detect any error in WebGL calls. Most WebGL calls are asynchronized, and detecting error will force synchronization, which may slows down the program. Mainly used in development of this library.
default: false
legend (boolean): If true, show the legend.
default: true
Specify these options in series option object. e.g. to specify lineWidth
:
const chart = new TimeChart(el, {
series: [{
data,
lineWidth: 10,
}],
});
data ({x: number, y: number}[]): Array of data points to be drawn. x
is the time elapsed in millisecond since baseTime
lineWidth (number or undefined): If undefined, use global option.
default: undefined
default: LineType.Line
stepLocation (number): Only effective if lineType === LineType.Step
. Where to draw the vertical line. Specified as a ratio of the distance between two adjacent data points. Usually in the range of [0, 1].
default: 0.5
name (string): The name of the series. Will be shown in legend and tooltips.
default: ‘’
color (CSS color specifier or d3-color instance or undefined): line color. If undefined, use global option.
default: undefined
visible (boolean): Whether this series is visible
default: true
These options enable the builtin touch / mouse / trackpad interaction support. The x, y axis can be enabled separately.
Specify these options in zoom option object. e.g. to specify autoRange
:
const chart = new TimeChart(el, {
series: [{ data }],
zoom: {
x: {
autoRange: true,
},
y: {
autoRange: true,
}
}
});
New in v1. If you are using the plugins, pass these options to the TimeChartZoomPlugin
plugin.
import TimeChart from 'timechart/core';
import { TimeChartZoomPlugin } from 'timechart/plugins/chartZoom';
const chart = new TimeChart(el, {
series: [{ data }],
plugins: {
zoom: new TimeChartZoomPlugin({x: {autoRange: true}})
},
});
Then old chart.options.chart
is not available. Use chart.plugins.zoom.options
instead.
panMouseButtons (number): allowed mouth buttons to trigger panning. see MouseEvent.buttons
default: 1 | 2 | 4 |
touchMinPoints (number): minimum number of touch points needed for the chart to respond to the gesture. Useful if you want to reserve some gesture for other plugins (e.g. selectZoom).
default: 1
autoRange (boolean): Per axis. Determine maxDomain, minDomain automatically.
default: false
maxDomain / minDomain (number): Per axis. The limit of xRange / yRange
default: Infinity / -Infinity
maxDomainExtent / minDomainExtent (number): Per axis. The limit of max - min
in xRange / yRange
default: Infinity / 0
const chart = new TimeChart({
...,
tooltip: { enabled: true }
})
Or
import TimeChart from 'timechart/core';
import { TimeChartTooltipPlugin } from 'timechart/plugins/tooltip';
const chart = new TimeChart(el, {
...,
plugins: {
tooltip: new TimeChartTooltipPlugin({ enabled: true, xLabel: 'Time' })
},
});
enabled (boolean): Whether to enable the tooltip on hover
default: false
xLabel (string): Label for the X axis in the tooltip
default: “X”
xFormatter ((number) => string): Function to format the X axis value in the tooltip
default: x => x.toLocaleString()
chart.update()
: Request update after some options have been changed. You can call this as many times as needed. The actual update will only happen once per frame.
chart.dispose()
: Dispose all the resources used by this chart instance.
Note: We use shadow root to protect the chart from unintended style conflict. However, there is no easy way to remove the shadow root after dispose.
But you can reuse the same HTML element to create another TimeChart. Example
chart.onResize()
: Calculate size after layout changes.
This method is automatically called when window size changed.
However, if there are some layout changes that TimeChart is unaware of, you need to call this method manually.
With touch screen:
With mouse:
With trackpad:
The chart is in a shadow root so that most CSS in the main document can not affect it. But we do provide some styling interface.
For example, we can support dark theme easily:
<div id="chart" class="dark-theme"></div>
.dark-theme {
color: white;
background: black;
--background-overlay: black;
}
The --background-overlay
CSS property is used in some non-transparent element on top on the chart.
The background of the chart is transparent by default. So it’s easy to change the background by setting the background of parent element.
All foreground elements will change color to match the color
CSS property.
However, chart is drawn in canvas and cannot respond to CSS property changes.
You need to change the color manually if you want to change the color
after initialiation.
npm install
to install dependenciesnpm start
to automatically build changesnpm run demo
then open http://127.0.0.1:8080/demo/index.html to test changesnpm test
to run automatic tests