v6.x -> v7.x
When upgrading, please reference each of the below LCJS entries in your application (for example, using Search functionality in your code base).
For each code block found this way, refer to the corresponding migration guide.
Event API rework
Majority of LightningChart JS end user classes have a number of methods to trigger custom callbacks on different Events, for example:
- Axis zoom level changes
- User clicked on series
- Series was highlighted
In v7.0, all these APIs were changed to use a different API pattern. Previously each event had its own subscription and unsubscription methods that were named with unified naming patterns like:
Axis.onIntervalChangeAxis.offIntervalChangeSeries.onMouseClickSeries.onHighlight
Starting with v7.0, all these on... and off... methods are moved to following two methods:
addEventListenerremoveEventListener
They might seem familiar, and that would be because the new API pattern is symmetrical with the HTML standard EventTarget API.
Their usage works exactly like how you would monitor user interactions on a HTML object:
const handleClick = (event: MouseEvent) => {}
series.addEventListener('click', handleClick)
series.removeEventListener('click', handleClick)
Interaction events
For majority of events, the migration process is very simple:
// Before
series.onMouseEnter((_, event) => {})
// After
series.addEventListener('pointerenter', (event) => {})
However, the previous event API included some interaction events that were insymmetric with HTML standard.
More specifically, this refers to the "drag" event APIs: onMouseDragStart, onMouseDrag, onMouseDragStop.
In HTML standard, there are no events such as these. Instead, you would track the equivalent interaction by combining pointerdown, pointermove and pointerup events:
// Before
series.onMouseDrag((_, event, button, startLocation, delta) => {})
// After
series.addEventListener('pointerdown', (eventDown) => {
let prevCoord = eventDown
const handleMove = (eventMove: PointerEvent) => {
const delta = { x: eventMove.clientX - prevCoord.clientX, y: eventMove.clientY - prevCoord.clientY }
prevCoord = eventMove
}
const handleUp = (eventUp: PointerEvent) => {
series.chart.engine.container.removeEventListener('pointermove', handleMove)
series.chart.engine.container.removeEventListener('pointerup', handleUp)
}
series.chart.engine.container.addEventListener('pointermove', handleMove)
series.chart.engine.container.addEventListener('pointerup', handleUp)
})
Compared to before, custom drag interactions require more lines of code than before. This can be considered a convenience degradation, but in long term the new approach is better for everyone:
- No need to learn a new API. Most web developers are already familiar with
addEventListener/removeEventListenerpattern. - Easier to implement cross-device interactions. Previous mouse/drag/touch APIs worked inconsistently between devices and were difficult to understand.
All previous use of onTouchStart, onTouchMove, onTouchEnd methods is recommended to be replaced with pointerdown, pointermove and pointerup events.
Some chart elements, such as series backgrounds, chart backgrounds, chart titles have been added separate interaction handles to attach the interaction events:
// Before
chart.onSeriesBackgroundMouseClick((_, event) => {})
chart.onBackgroundMouseClick((_, event) => {})
chart.axisY.onTitleMouseClick((_, event) => {})
// After
chart.seriesBackground.addEventListener('click', (event) => {})
chart.background.addEventListener('click', (event) => {})
chart.axisY.title.addEventListener('click', (event) => {})
Non-interaction events
LightningChart JS includes many events apart from standard pointerenter, pointermove, click, etc. (so called interaction events).
The migration steps for these are same as above, but additionally any event information is now supplied as part of an Event object instead of a list of parameters:
// Before
axis.onIntervalChange((_, start, end) => {})
// After
axis.addEventListener('intervalchange', (event) => {
// event.start
// event.end
})
// Before
chart.onCursorTargetChanged((_, hit, hits, mouseLocation) => {})
// After
chart.addEventListener('cursortargetchange', (event) => {
// event.hit
// event.hits
// event.mouseLocation
})
Available event keys and respective event types can be found from API documentation by viewing addEventListener method reference.
...or more conveniently, if your development environment has type checking, just write chart.addEventListener() and see possible parameter types right there.
Interactions rework
One of primary motivators for LightningChart JS v7.0 was the need to improve state of user interactions functionality. This refers to different requirements of panning, zooming and otherwise controlling the charts by means of user interactions.
First and foremost, the default user interactions of ChartXY have changed.
Before, there was only 1 interaction scheme with very limited configuration options (switch between left and right mouse buttons only).
This involved:
- Pan with RMB
- Rectangle zoom with LMB
- Zoom with mouse wheel
- Restore default view by dragging LMB to left and up
Starting with v7.0, there are total of 3 different built-in interaction schemes. These are automatically switched between based on the structure of the chart (i.e. is there a scrolling axis, is the data progressive or freeform, etc.) Here is a list of the most apparent behavior changes compared to before:
- "Restore default view by dragging LMB to left and up" interaction has been removed.
- This was not well received by our userbase, who found the interaction unintuitive
- As response, the interaction was removed and replaced with "Restore default view by double-clicking"
- With progressive data series, zooming, panning and rectangle zooming do not affect the opposite dimension by default.
- i.e. if X axis is Time, interactions in chart area don't affect Y axis by default.
- With scrolling axis, panning back to live data automatically continues scrolling.
- With scrolling axis, mouse wheel zoom doesn't stop axis from scrolling but instead just changes the axis interval to be smaller/larger.
- With scrolling axis, rectangle zoom interaction is disabled by default. Instead, panning is activated on both mouse buttons.
- The interaction felt clumsy in scrolling applications. Instead, mouse wheel is recommended, though rectangle zoom can also be re-enabled if desired.
One of the key goals of this refactoring was to improve out of box interaction behavior to match common expectations better.
Secondarily we wanted to introduce a large number of customization options so different users can tweak and choose their own interaction scheme when necessary.
This can be achieved with new setUserInteractions method found on charts and axes.
Documentation of this new functionality can be found here.
All following methods are removed and replaced by setUserInteractions:
ChartXY.setMouseInteractionPanChartXY.setMouseInteractionRectangleFitChartXY.setMouseInteractionRectangleZoomChartXY.setMouseInteractionWheelZoomAxis.setNibInteractionScaleByDraggingAxis.setNibInteractionScaleByWheelingAxis.setAxisInteractionPanByDraggingAxis.setAxisInteractionReleaseByDoubleClickingAxis.setAxisInteractionZoomByDraggingAxis.setAxisInteractionZoomByWheelingAxis.setChartInteractionFitByDragAxis.setChartInteractionPanByDragAxis.setChartInteractionZoomByDragAxis.setChartInteractionZoomByWheelAxis.setChartInteractionsChart3D.setMouseInteractionRotateChart3D.setMouseInteractionZoomDataGrid.setInteractionPanOnTouchDataGrid.setInteractionScrollOnWheelParallelCoordinateChart.setMouseInteractionRangeSelectorsParallelCoordinateAxis.setMouseInteractionRangeSelectorssetMouseInteractions(* only in cases where the method previously controlled a built-in user interaction, rather than mouse picking. For more details, see setMouseInteractions migration guide)
To learn more of setUserInteractions method and how to use it, please see this documentation.
OverrideInteractionMouseButtons
This interface is removed, and usage should be replaced with setUserInteractions:
// Before
const lc = lightningChart({
overrideInteractionMouseButtons: {
chartXYPanMouseButton: 0, // LMB
chartXYRectangleZoomFitMouseButton: 2, // RMB
}
})
const chart = lc.ChartXY()
// After
chart.setUserInteractions({
pan: {
lmb: { drag: {} },
rmb: false,
},
rectangleZoom: {
lmb: false,
rmb: {},
},
})
For more details and examples, please see setUserInteractions documentation.
setMouseInteractions
All setMouseInteraction methods are removed.
Historically this method has been named very confusingly. The previous setMouseInteraction methods can be split to two very different functionalities:
- Control whether a visual component is tracked by interaction events or not (series, chart components, bands, constant lines, custom ticks, etc.).
- Control whether built-in user interactions on a component are enabled or not (charts, axes, etc.).
In v7.0, these different functionalities are clearly separated to their own respective methods:
setPointerEvents- basically does the same thing as CSS pointer-events property.setUserInteractions- control and configure built-in user interactions.
Recommended migration steps:
- Comment out the previous usage of
setMouseInteractions - Check behavior regarding pointer event tracking and user interactions
- If needed, use either
setPointerEventsto control whether the object is tracked by interaction events orsetUserInteractionsto control user interactions.
ChartXY Axis default interval restrictions
In v7.0, a popular configuration to ChartXY axes has been applied as the default state.
The equivalent previous operation is this:
axis.setIntervalRestrictions((state) => ({
startMin: state.dataMin,
endMax: state.dataMax,
}))
This is now the default state, meaning any interaction can not move the axis view outside currently attached data set. The previous behavior can be restored with following snippet:
axis.setIntervalRestrictions(undefined)
If your applications interactions, or axis intervals are behaving strangely after version upgrade, this is the most likely change behind the change!
Interval restrictions are automatically disabled to avoid API usage conflicts if:
- Axis interval is explicitly set using
setIntervalorsetDefaultInterval AxisScrollStrategies.expansionis enabled
ChartXY axis tick labels fitting
After v7.0 axes ensure that their labels don't leak outside the axis bounds. If desired, old behavior can be restored by applying below on every axis:
chart.forEachAxis((axis) => axis.setKeepTickLabelsInAxisBounds(false))
Before, the only real tool to ensure that labels don't go outside chart boundaries was to use chart.setPadding to allocate extra space around the chart. However, this was bad for a few reasons:
- Hardcoded paddings don't adjust in case of font or formatting changes.
- This greatly reduced available size for the actual charts, which was often very undesirable.
Thus, the new functionality is strongly recommended, but it can result in slight changes in chart space usage compared to before.
Recommended migration steps:
- Remove any previous use of
chart.setPadding - Ensure charts look good, ticks don't go out of view, etc.
ChartXY axis tick behavior change for small axes
In order to avoid situations where a small Numeric axis would only display 1 tick label, after v7.0 axis will automatically fallback to displaying its start and end coordinate (so called "extreme ticks behavior").
This only applies for AxisTickStrategies.Numeric.
Previous behavior can be restored with:
chart.axisX.setTickStrategy(AxisTickStrategies.Numeric, (strategy) => strategy
.setFallBackToExtremeTicksAutomatically(false)
)
AxisTickStrategies.DateTime great ticks
Great ticks are now disabled by default. This is equivalent to previously using following code snippet:
Axis.setTickStrategy(AxisTickStrategies.DateTime, (strategy) => strategy.setGreatTickStyle(emptyTick))
Great ticks can be enabled like this:
chart.axisX.setTickStrategy(AxisTickStrategies.DateTime, (strategy) =>
strategy.setGreatTickStyle(strategy.getMajorTickStyle().setTickLength(28).setTickStyle(emptyLine)),
)
Touch device behavior changes
LightningChart JS now adds touch-action: none to its container <div> style when a chart is created.
This is required for touch interactions to work as expected.
As a side effect, native touch interactions such as scrolling page up/down no longer work on the charts.
Previous behavior can be restored by adding CSS touch-action: auto to the container <div>
Slight CSS behavior change
Previously, LightningChart JS added position: relative and boxSizing: corner-box CSS properties to its container DIVs as long as the container didn't have other values for these properties when chart creation was initiated.
However, this didn't consider case where those properties would have other values loaded by means of CSS stylesheets.
In this case, LCJS would override any value supplied by CSS, unless the CSS was using !important syntax.
This is now changed, so that the property values are also not overridden if the CSS is loaded at the time of chart creation.
FormattingFunctions, FormattingFunction, FormattingRange
The type definition of FormattingRange has changed, which can affect different use cases around using formatting functions, either custom ones or built-in ones.
Previously FormattingRange type was:
interface FormattingRange {
getInnerStart(): number
getInnerEnd(): number
}
It was simplified to:
interface FormattingRange {
start: number
end: number
}
There are 2 known cases where this API change can show in user applications:
Custom formatting functions
Before:
chart.axisY.setTickStrategy(AxisTickStrategies.Numeric, (strategy) => strategy
.setFormattingFunction((value, range, locale) => {
const start = range.getInnerStart()
const end = range.getInnerEnd()
// use `start` / `end` somehow...
})
)
After:
chart.axisY.setTickStrategy(AxisTickStrategies.Numeric, (strategy) => strategy
.setFormattingFunction((value, range, locale) => {
const { start, end } = range
// use `start` / `end` somehow...
})
)
Directly utilizing built-in formatting functions
Before:
const formatted = FormattingFunctions.NumericUnits(100000, { getInnerStart: () => chart.axisY.getInterval().start, getInnerEnd: () => chart.axisY.getInterval().end })
After:
const formatted = FormattingFunctions.NumericUnits(100000, chart.axisY.getInterval())
setMouseBackgroundStyle, setMouseZoomStyle, setMouseFitStyle, setMousePanStyle, setAxisMouseHoverStyle, setAxisMousePanStyle, setAxisMouseZoomStyle, setNibMouseHoverStyle, setNibMouseScaleStyle
These methods have been removed without a direct replacement. They were very rarely utilized and the functionality can still be achieved with custom application code (i.e. following user interaction events and changing cursor style).
If your application requires some of these functionalities, please contact us.
ChartXY Axis Nibs
Concept of Axis nibs has been removed without built-in replacement. These refer to small sections of XY axis lines located at the very ends of every XY axis.
List of removed APIs:
setNibStylesetNibLengthsetNibMouseScaleStylesetNibOverlayStylesetNibMouseHoverStylesetNibInteractionScaleByDraggingsetNibInteractionScaleByWheelingsetNibMousePickingAreaSize
For a long time now, nibs have been disabled by default, and with no identified utilization from user-base or significant utility the feature has been removed to simplify the library and internal logic.
Spider Chart
Spider Chart has been reworked to support different axis intervals within a single spider chart.
Spider chart has also been made to work more out of the box; the chart will automatically format and scale axis interval if the user does not override the default configuration.
Spider Axis nib interactions have been removed completely.
API changes:
- Changed
setAxisInterval- The parameter for this method is
AxisIntervalConfigurationinstead ofedgeandcentervalues
- The parameter for this method is
- Changed
addAxis- This method returns a reference to created
SpiderAxisinstead ofSpiderChart
- This method returns a reference to created
- Renamed
setAxisScrollStrategytosetScrollStrategy - Replaced
formatValuewith identicalSpiderAxismethod - Replaced
getAxisScrollStrategywith identicalSpiderAxismethod - Replaced
getOriginValuewithSpiderAxis.getInterval - Replaced
getEdgeValuewithSpiderAxis.getInterval
Changes to Theme interface
The following new properties have been added to Theme interface. If you are not using built-in themes or latest version of lcjs-themes, then you need to define these new properties in your custom theme(s):
textSeriesFillStyletextSeriesFontbarChartCornerRadiustreeMapChartCornerRadiuslegendBorderRadiuscursorResultTableBorderRadiuscursorResultTableHeaderBackgroundFillStylepolarRadialAxisMarginAfterTicksdataGridScrollBarThicknessparallelCoordinateChartBackgroundFillStyleparallelCoordinateChartBackgroundStrokeStyleparallelCoordinateChartTitleFontparallelCoordinateChartTitleFillStyleparallelCoordinateChartSeriesBackgroundFillStyleparallelCoordinateChartSeriesBackgroundStrokeStyleparallelCoordinateChartSeriesColorparallelCoordinateChartSeriesColorUnselectedparallelCoordinateChartSeriesLineThicknessparallelCoordinateChartPointedSeriesLineStyleparallelCoordinateAxisTitleFontparallelCoordinateAxisTitleFillStyleparallelCoordinateAxisNumericTicksparallelCoordinateAxisDateTimeTicksparallelCoordinateAxisTimeTicksparallelCoordinateAxisStrokeStyleparallelCoordinateAxisRangeSelectorFillStyleparallelCoordinateAxisRangeSelectorStrokeStyleparallelCoordinateAxisBackgroundFillStyle
Removed Theme properties:
chartXYFittingRectangleFillStylechartXYFittingRectangleStrokeStylexAxisNibStyleyAxisNibStyledataGridScrollBarButtonArrowStrokeStyle
Stacked Bar Chart default behavior changes
In v7.0 new functionality for displaying sum of all subcategories in stacked bar charts was added. This is the new default behavior for stacked bar charts. Previous default was to display each subcategory value with a separate label.
// Restore previous behavior
barChart.setValueLabels({
displayStackedSum: false,
displayStackedIndividuals: true,
position: 'after-bar',
})
BarChartLabelFormatter
Syntax for bar chart label formatting APIs has changed.
This affects following methods: BarChart.setValueLabels, BarChart.setCategoryLabels (but only if formatter property was used)
Before:
barChart.setValueLabels({
formatter: (bar, category, value) => `${value} €`
})
After:
barChart.setValueLabels({
formatter: (info) => `${info.value} €`
})
The info object includes all information required for formatting:
category: stringvalue: numberchart: BarChartsubCategory: string | undefinedbar: BarChartBar | undefined
Note that before a BarChartBar object was always available, now its not. This is the case only for stacked BarChart sum labels.