Compares the features of the new DiscontinuousDateAxis to Numeric and Category Axis in SciChart.js, High Performance JavaScript Charts. This axis can collapse gaps like a category axis, but still allow varying point counts and multiple points at the same x value.
drawExample.ts
index.tsx
AxisSynchroniser.ts
theme.ts
1import {
2 CategoryAxis,
3 DiscontinuousDateAxis,
4 ENumericFormat,
5 EXyDirection,
6 EllipsePointMarker,
7 FastCandlestickRenderableSeries,
8 FastLineRenderableSeries,
9 MouseWheelZoomModifier,
10 NumberRange,
11 NumericAxis,
12 NumericLabelProvider,
13 OhlcDataSeries,
14 RolloverModifier,
15 SciChartSurface,
16 XyDataSeries,
17 XyScatterRenderableSeries,
18 ZoomExtentsModifier,
19 ZoomPanModifier,
20} from "scichart";
21import { appTheme } from "../../../theme";
22
23// Custom label provider for days of the week
24class DayOfWeekLabelProvider extends NumericLabelProvider {
25 private dayNames = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
26
27 public get formatLabel() {
28 return (dataValue: number): string => {
29 if (dataValue > 100) {
30 const date = new Date(dataValue * 1000);
31 const day = date.getUTCDay();
32
33 return `${this.dayNames[day]} ${date.getUTCDate()}`;
34 } else {
35 return `${this.dayNames[dataValue % 7]} ${dataValue}`;
36 }
37 };
38 }
39}
40
41// Helper function to create data series
42const createDataSeries = (wasmContext: any, isCategoryAxis: boolean) => {
43 // X values from the first series are used as baseXValues for the DiscontinuousDate axis, unless you specify them explicitly.
44 const startDate = new Date(Date.UTC(2024, 0, 6, 0, 0, 0, 0));
45 const startTime = startDate.getTime() / 1000;
46 const ohlcSeries = new OhlcDataSeries(wasmContext, {
47 containsNaN: false,
48 isSorted: true,
49 xValues: [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16].map((x) => startTime + x * 24 * 60 * 60),
50 openValues: [2, 5, 4, 6.2, 3, 3, 2.3, 3, 4, 5, 3, 3],
51 highValues: [4.2, 7.5, 6.8, 8.5, 5.5, 5.2, 4.8, 5.7, 6.9, 7.5, 5.8, 6.2],
52 lowValues: [0.8, 3.0, 2.0, 4.5, 1.0, 1.2, 0.5, 1.5, 2.5, 3.5, 1.5, 1.0],
53 closeValues: [3.5, 3.8, 6.0, 8.0, 2.0, 4.5, 1.2, 5.0, 6.2, 4.0, 5.0, 2.5],
54 });
55
56 // DiscontinuousDate axis supports data with values at the same x coordinate, and data in between baseValues
57 const dataSeries1 = new XyDataSeries(wasmContext, {
58 containsNaN: false,
59 isSorted: true,
60 xValues: [1, 2, 2, 5, 5.5, 8, 9, 9.5, 9.8, 11, 15, 16].map((x) => startTime + x * 24 * 60 * 60),
61 yValues: [2, 5, 4, 6.2, 3, 3, 2.3, 3, 4, 5, 3, 3],
62 });
63 if (!isCategoryAxis) {
64 dataSeries1.appendRange(
65 [5, 5, 9, 9, 15, 15].map((x) => startTime + x * 24 * 60 * 60),
66 [3, 4, 4, 5.5, 4.5, 1]
67 );
68 }
69
70 // DiscontinuousDate axis supports data with more or less x values than the baseValues
71 const dataSeries2 = new XyDataSeries(wasmContext, {
72 containsNaN: false,
73 isSorted: true,
74 xValues: [1, 3, 5, 8, 11, 16].map((x) => startTime + x * 24 * 60 * 60),
75 yValues: [3, 6, 5, 7.21, 4, 4],
76 });
77
78 return { ohlcSeries, dataSeries1, dataSeries2 };
79};
80
81// Helper function to add series to a chart
82const addSeriesToChart = (sciChartSurface: SciChartSurface, wasmContext: any, dataSeries: any) => {
83 sciChartSurface.renderableSeries.add(
84 new FastCandlestickRenderableSeries(wasmContext, {
85 dataSeries: dataSeries.ohlcSeries,
86 strokeThickness: 1,
87 brushUp: appTheme.VividGreen + "77",
88 brushDown: appTheme.MutedRed + "77",
89 strokeUp: appTheme.VividGreen,
90 strokeDown: appTheme.MutedRed,
91 })
92 );
93
94 sciChartSurface.renderableSeries.add(
95 new XyScatterRenderableSeries(wasmContext, {
96 dataSeries: dataSeries.dataSeries1,
97 stroke: appTheme.VividRed,
98 pointMarker: new EllipsePointMarker(wasmContext, {
99 width: 10,
100 height: 10,
101 fill: appTheme.VividRed,
102 strokeThickness: 0,
103 opacity: 0.8,
104 }),
105 })
106 );
107
108 sciChartSurface.renderableSeries.add(
109 new FastLineRenderableSeries(wasmContext, {
110 dataSeries: dataSeries.dataSeries2,
111 stroke: appTheme.VividSkyBlue,
112 opacity: 0.7,
113 strokeThickness: 4,
114 pointMarker: new EllipsePointMarker(wasmContext, {
115 width: 8,
116 height: 8,
117 fill: appTheme.VividSkyBlue,
118 strokeThickness: 0,
119 opacity: 0.7,
120 }),
121 })
122 );
123};
124
125// Create Discontinuous Date Axis Chart
126export const createDiscontinuousDateChart =
127 (customSettings: boolean) => async (rootElement: string | HTMLDivElement) => {
128 const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
129 theme: {
130 ...appTheme.SciChartJsTheme,
131 majorGridLineBrush: appTheme.MutedSkyBlue + "55",
132 minorGridLineBrush: appTheme.MutedSkyBlue + "22",
133 },
134 });
135
136 const xAxisDiscontinuous = new DiscontinuousDateAxis(wasmContext, {
137 growBy: new NumberRange(0.05, 0.05),
138 dataGap: 24 * 60 * 60, // This is auto-calculated using the minimum gap between baseXValues, but should be set where possible to avoid that calculation.
139 cursorLabelFormat: ENumericFormat.Date_DDMMHHMM,
140 axisTitle: "Discontinuous Date X Axis - Fixed gap between baseValues. Ideal for financial data.",
141 axisTitleStyle: {
142 fontSize: 16,
143 },
144 });
145 if (customSettings) {
146 xAxisDiscontinuous.labelProvider = new DayOfWeekLabelProvider({
147 cursorLabelFormat: ENumericFormat.Date_DDMMHHMM,
148 });
149 xAxisDiscontinuous.autoTicks = false;
150 xAxisDiscontinuous.majorDelta = 24 * 60 * 60;
151 xAxisDiscontinuous.minorDelta = 4 * 60 * 60;
152 }
153
154 const yAxisLinear = new NumericAxis(wasmContext, {
155 labelFormat: ENumericFormat.Decimal,
156 labelPrecision: 2,
157 drawMinorGridLines: false,
158 growBy: new NumberRange(0.1, 0.1),
159 });
160
161 sciChartSurface.xAxes.add(xAxisDiscontinuous);
162 sciChartSurface.yAxes.add(yAxisLinear);
163
164 const dataSeries = createDataSeries(wasmContext, false);
165 addSeriesToChart(sciChartSurface, wasmContext, dataSeries);
166
167 sciChartSurface.chartModifiers.add(
168 new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
169 new ZoomExtentsModifier(),
170 new ZoomPanModifier(),
171 new RolloverModifier({ showTooltip: false, showAxisLabel: true, modifierGroup: "Group1" })
172 );
173
174 sciChartSurface.zoomExtents();
175 return { sciChartSurface, wasmContext };
176 };
177
178// Create Numeric Axis Chart
179export const createNumericChart = (customSettings: boolean) => async (rootElement: string | HTMLDivElement) => {
180 const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
181 theme: {
182 ...appTheme.SciChartJsTheme,
183 majorGridLineBrush: appTheme.MutedSkyBlue + "55",
184 minorGridLineBrush: appTheme.MutedSkyBlue + "22",
185 },
186 });
187
188 const xAxisNumeric = new NumericAxis(wasmContext, {
189 labelFormat: ENumericFormat.Date_DDMM,
190 axisTitle: "Numeric X Axis - Cannot hide gaps",
191 axisTitleStyle: {
192 fontSize: 16,
193 },
194 });
195 if (customSettings) {
196 xAxisNumeric.labelProvider = new DayOfWeekLabelProvider({ cursorLabelFormat: ENumericFormat.Date_DDMMHHMM });
197 xAxisNumeric.autoTicks = false;
198 xAxisNumeric.majorDelta = 24 * 60 * 60;
199 xAxisNumeric.minorDelta = 4 * 60 * 60;
200 }
201
202 const yAxisLinear = new NumericAxis(wasmContext, {
203 labelFormat: ENumericFormat.Decimal,
204 labelPrecision: 2,
205 drawMinorGridLines: false,
206 growBy: new NumberRange(0.1, 0.1),
207 });
208
209 sciChartSurface.xAxes.add(xAxisNumeric);
210 sciChartSurface.yAxes.add(yAxisLinear);
211
212 const dataSeries = createDataSeries(wasmContext, false);
213 addSeriesToChart(sciChartSurface, wasmContext, dataSeries);
214
215 sciChartSurface.chartModifiers.add(
216 new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
217 new ZoomExtentsModifier(),
218 new ZoomPanModifier(),
219 new RolloverModifier({ showTooltip: false, showAxisLabel: true, modifierGroup: "Group1" })
220 );
221 sciChartSurface.zoomExtents();
222 return { sciChartSurface, wasmContext };
223};
224
225// Create Category Axis Chart
226export const createCategoryChart = (customSettings: boolean) => async (rootElement: string | HTMLDivElement) => {
227 const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
228 theme: {
229 ...appTheme.SciChartJsTheme,
230 majorGridLineBrush: appTheme.MutedSkyBlue + "55",
231 minorGridLineBrush: appTheme.MutedSkyBlue + "22",
232 },
233 });
234
235 const xAxisCategory = new CategoryAxis(wasmContext, {
236 autoTicks: false,
237 majorDelta: 1,
238 minorDelta: 0.2,
239 axisTitle: "Category X Axis. Hides gaps, but plots by index only",
240 axisTitleStyle: {
241 fontSize: 16,
242 },
243 });
244 if (customSettings) {
245 xAxisCategory.labelProvider = new DayOfWeekLabelProvider({ cursorLabelFormat: ENumericFormat.Date_DDMMHHMM });
246 }
247
248 const yAxisLinear = new NumericAxis(wasmContext, {
249 labelFormat: ENumericFormat.Decimal,
250 labelPrecision: 2,
251 drawMinorGridLines: false,
252 growBy: new NumberRange(0.1, 0.1),
253 });
254
255 sciChartSurface.xAxes.add(xAxisCategory);
256 sciChartSurface.yAxes.add(yAxisLinear);
257
258 const categoryDataSeries = createDataSeries(wasmContext, true);
259
260 addSeriesToChart(sciChartSurface, wasmContext, categoryDataSeries);
261
262 sciChartSurface.chartModifiers.add(
263 new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
264 new ZoomExtentsModifier(),
265 new ZoomPanModifier(),
266 new RolloverModifier({ showTooltip: false, showAxisLabel: true, modifierGroup: "Group1" })
267 );
268
269 sciChartSurface.zoomExtents();
270 return { sciChartSurface, wasmContext };
271};
272This example compares three different X-axis types in SciChart.js—NumericAxis, CategoryAxis, and the new DiscontinuousDateAxis—using the same financial-style dataset. The goal is to highlight how each axis handles gaps in time, uneven sampling, and multiple data points at the same timestamp.
This comparison is mirrored in the official SciChart.js documentation, which lays out key differences between these axis types: https://www.scichart.com/documentation/js/v5/2d-charts/axis-api/axis-types/discontinuous-date-axis/#comparison-discontinuousdateaxis-vs-categoryaxis-vs-numericaxis. :contentReference[oaicite:1]{index=1}
The NumericAxis treats date values as continuous numbers. This means:
While numerically accurate, this axis may not be ideal for financial or trading data.
The CategoryAxis treats points by index, completely collapsing time gaps:
However, it cannot support multiple points at the same X value or varying point densities without distortion.
The DiscontinuousDateAxis combines the benefits of both:
In short, it collapses gaps like the CategoryAxis but still supports true time-series behavior like the NumericAxis. This improved axis type is especially useful in financial or trading visualizations where non-trading periods should be hidden. :contentReference[oaicite:2]{index=2}
In this demo, the DiscontinuousDateAxis uses base X values derived from the first series (such as an OHLC candlestick series) and a fixed dataGap to control spacing between session values. Optional custom tick formatting shows how advanced label control can be applied using a NumericLabelProvider. Cursor and rollover modifiers display accurate date-time information even when gaps are collapsed.
Financial-Grade Time Axis: Hide weekends and non-trading periods without loss of temporal meaning.
Supports Complex Data Shapes: Multiple points per date and uneven sampling are correctly handled.
Accurate Interaction: Cursor labels, rollover modifiers, and zooming work as expected.
WebAssembly Performance: Axis and series calculations are fast, even with multiple series.
Use DiscontinuousDateAxis when visual space optimization and true date semantics are both required. For full details on axis comparison and configuration, see the official docs: https://www.scichart.com/documentation/js/v5/2d-charts/axis-api/axis-types/discontinuous-date-axis/#comparison-discontinuousdateaxis-vs-categoryaxis-vs-numericaxis. :contentReference[oaicite:3]{index=3}

Demonstrates Multiple X & Y Axis on a JavaScript Chart using SciChart.js. SciChart supports unlimited left, right, top, bottom X, Y axis with configurable alignment and individual zooming, panning

Demonstrates Secondary Y Axis on a JavaScript Chart using SciChart.js. SciChart supports unlimited, multiple left, right, top, bottom X, Y axis with configurable alignment and individual zooming, panning

Demonstrates alignment of Axis to create a vertical chart with SciChart.js - JavaScript Charts.

Demonstrates Central Axes on a JavaScript Chart using SciChart.js. SciChart supports unlimited left, right, top, bottom X, Y axis with configurable layout

Demonstrates isStaticAxis on a JavaScript Chart using SciChart.js.

Demonstrates Vertically Stacked Axes on a JavaScript Chart using SciChart.js, allowing data to overlap

Demonstrates Logarithmic Axis on a JavaScript Chart using SciChart.js. SciChart supports logarithmic axis with scientific or engineering notation and positive and negative values

Demonstrates BaseValue Axes on a JavaScript Chart using SciChart.js to create non-linear and custom-scaled axes such as log-like scales

Demonstrates the option of the transparent Axes customization on a JavaScript Chart using SciChart.js.

Demonstrates how to use arbitrary text for axis labels, rather than formatted data values, using the new TextLabelProvider

Demonstrates outer, inner, central and stacked axes, and use of axis alignment to create vertical charts