Optimizing performance
Here you can find some common pointers towards ensuring best application performance when using LightningChart JS.
Several charts visible at once
LightningChart JS excels at applications that require several charts to be visible on the same web page.
See Grouping charts for more details.
Progressive XY Series
Oftentimes, XY Series are used to visualize data that is progressive in 1 dimension. For example, in date-time use cases, the data is generally in increasing time order. LightningChart JS XY Series are massively optimized for this particular scenario, where data is ordered.
See Line series data patterns for more details.
If for some reason your data is not ordered, but it could be, consider this a strong suggestion to sort it, as the performance difference can't be understated.
Mapping data to correct format
These days LightningChart JS can directly consume most common kinds of incoming data formats. However, historically this has not been the case, and now there are likely many references of highly inefficient data mapping that were previously needed.
❌ bad:
// data: Array<{ timestamp: number, value: number }>
lineSeries.appendJSON(data.map((p) => ({ x: p.timestamp, y: p.value })))
This seemingly innocent operation can be extremely performance intensive. For example, if your data set has millions of samples, this effectively makes a duplicate Array of the entire data set - extremely wasteful on memory usage!
❎ good:
// data: Array<{ timestamp: number, value: number }>
lineSeries.appendJSON(data, { whitelist: ['timestamp', 'value'] })
For more examples of available data consume APIs, see Adding data
Columnar data formats
For performance reasons, we recommend applications to manage data in columnar format:
// Example of columnar data format
const data = {
xValues: [x1, x2, x3, ...]
yValues: [y1, y2, y3, ...]
}
Rather than row-oriented format:
// Example of row-oriented format
const data = [
{ x: x1, y: y1 },
{ x: x2, y: y2 },
{ x: x3, y: y3 },
...
]
Column oriented data can be consumed by LCJS significantly faster and more memory efficiently.
Multi-threading
If you are using XY Line series, then you can consider enabling multi-threading. It allows you to utilize all available CPU cores, rather than doing everything on the same UI thread.
This not only massively speeds up chart loading times (generally 6x faster), but also comes with the advantage of dropping CPU utilization on the main thread to negligible amounts.
Data Transfer
Transferring data to the frontend can be a massive performance bottleneck. Please refer to the WebSocket section for the latest pointers on effective real-time data transfer.
Effects
The default Themes built into LightningChart JS come with shadow and glow effects enabled. These are pretty performance heavy, so for best performance they can be disabled.
Effects can be disabled from 1 component (series, title, axis, legend, etc.) by using setEffect(enabled: boolean) methods. The exact method might have a prefix added to it, e.g. setTitleEffect().
// Example, disable effects from a point series
pointSeries.setEffect(false)
All effects can be disabled via Theme:
const chart = lightningChart().ChartXY({
theme: disableThemeEffects(Themes.darkGold)
})
Gradients
If final client hardware (to be clear, the hardware connected to the display peripheral that shows the charts) has absolutely no GPU or is extremely weak, then even disabling gradients may increase performance significantly.
Most commonly, gradients are present in default background fill styles, which can be disabled (and replaced with solid colors) like this:
chart.engine.setBackgroundFillStyle(transparentFill)
chart.setBackgroundFillStyle(new SolidFill({ color: ColorRGBA(0, 0, 0) }))
chart.setSeriesBackgroundFillStyle(new SolidFill({ color: ColorRGBA(0, 0, 0) }))
In addition, gradients can also be found by default in bar charts, rectangle series, map charts, legends, etc. but these are less common and generally smaller render areas and thus less impactful.
For configuring background colors, using the separate Themes library is recommended.
Text shadows
Since v7.0, built-in dark themes display subtle shadows behind text for improved contrast.
In applications that display lots of text elements and charts, this can add considerable extra load.
Text shadows can be conveniently disabled with disableTextShadows function.
// Example, disable text shadows for improved performance
const chart = lightningChart().ChartXY({
theme: disableTextShadows(Themes.darkGold)
})
WebGL text rendering
By default, all LightningChart JS text elements are rendered using WebGL. This gives best performance. Alternatively, HTML text rendering can be enabled but its slower. More details here.
Mozilla Firefox
There is currently a performance problem specific to Mozilla Firefox, where it performs significantly worse than almost all other browsers. It is reported that enabling the "Shared canvas mode" greatly alleviates these problems:
const lc = lightningChart({
sharedContextOptions: {
// Shared canvas mode
useIndividualCanvas: false
}
})
Data sets with no gaps
If your data set doesn't include NaN values, then a slight performance increase can be enabled by informing of this:
const series = chart.addLineSeries({
includesNaN: false // <--
})
Pausing charts
Chart updates can be temporarily paused, moving them to an "hibernation" state where they don't process any updates. This can be useful in specific situations, most importantly in cases where you have real-time charts that will be temporarily out of sight (for example, hidden by an overlay).
chart.setPauseRendering(true)
While a chart is paused, you can continue to use all its APIs normally. It will postpone majority of heavy computations required for processing re-rendering until it is eventually unpaused.
By default, paused charts do not re-render even if their DOM layout is changed, which makes them appear as a blank canvas on the web page. If this is detrimental, there is an automatic feature that can re-render paused charts only when there is a resize happening:
chart.setPauseRendering(true, { unpauseDuringResize: true })