Demonstrates how create JavaScript Charts with per-point coloring using SciChart.js, High Performance JavaScript Charts
drawExample.ts
index.html
vanilla.ts
RandomWalkGenerator.ts
theme.ts
1import { appTheme } from "../../../theme";
2import { RandomWalkGenerator } from "../../../ExampleData/RandomWalkGenerator";
3
4import {
5 BoxAnnotation,
6 ECoordinateMode,
7 EDataLabelSkipMode,
8 EHorizontalAnchorPoint,
9 ELabelPlacement,
10 EllipsePointMarker,
11 EStrokePaletteMode,
12 FastLineRenderableSeries,
13 HorizontalLineAnnotation,
14 IPointMarkerPaletteProvider,
15 IPointMetadata,
16 IRenderableSeries,
17 IStrokePaletteProvider,
18 NumberRange,
19 NumericAxis,
20 parseColorToUIntArgb,
21 SciChartSurface,
22 TextAnnotation,
23 Thickness,
24 TPointMarkerArgb,
25 XyDataSeries,
26 XyScatterRenderableSeries,
27} from "scichart";
28
29export const drawExample = async (rootElement: string | HTMLDivElement) => {
30 // Create a SciChartSurface
31 const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
32 theme: appTheme.SciChartJsTheme,
33 });
34
35 // Create the X,Y Axis
36 sciChartSurface.xAxes.add(new NumericAxis(wasmContext, { maxAutoTicks: 5 }));
37 sciChartSurface.yAxes.add(new NumericAxis(wasmContext, { maxAutoTicks: 5, growBy: new NumberRange(0.05, 0.2) }));
38
39 const { xValues, yValues } = new RandomWalkGenerator().Seed(1337).getRandomWalkSeries(50);
40
41 let THRESHOLD_HIGH_LEVEL = 0;
42 let THRESHOLD_LOW_LEVEL = -2;
43 // For performance reasons PaletteProviders require colors as Argb numbers e.g. 0xFFFF0000 = red
44 const THRESHOLD_LOW_COLOR_ARGB = parseColorToUIntArgb(appTheme.VividPink);
45 const THRESHOLD_HIGH_COLOR_ARGB = parseColorToUIntArgb(appTheme.VividTeal);
46
47 const getColor = (yValue: number) => {
48 if (yValue < THRESHOLD_LOW_LEVEL) {
49 return THRESHOLD_LOW_COLOR_ARGB;
50 }
51 if (yValue > THRESHOLD_HIGH_LEVEL) {
52 return THRESHOLD_HIGH_COLOR_ARGB;
53 }
54 // Undefined means use default series stroke on this data-point
55 return undefined;
56 };
57
58 // PaletteProvider API allows for per-point colouring, filling of points or areas based on a rule
59 // see PaletteProvider API for more details
60 const strokePaletteProvider: IStrokePaletteProvider = {
61 onAttached(parentSeries: IRenderableSeries): void {},
62 onDetached(): void {},
63 strokePaletteMode: EStrokePaletteMode.GRADIENT,
64 // This function called once per data-point for line stroke. Colors returned must be in ARGB format (uint) e.g. 0xFF0000FF is Red
65 overrideStrokeArgb(
66 xValue: number,
67 yValue: number,
68 index: number,
69 opacity?: number,
70 metadata?: IPointMetadata
71 ): number {
72 return getColor(yValue);
73 },
74 };
75
76 // Create a line series with threshold palette provider
77 sciChartSurface.renderableSeries.add(
78 new FastLineRenderableSeries(wasmContext, {
79 dataSeries: new XyDataSeries(wasmContext, { xValues, yValues }),
80 strokeThickness: 4,
81 stroke: appTheme.VividOrange,
82 dataLabels: {
83 style: { fontFamily: "Arial", fontSize: 13, padding: Thickness.fromNumber(5) },
84 color: appTheme.PaleSkyBlue,
85 skipMode: EDataLabelSkipMode.SkipIfOverlapPrevious,
86 },
87 paletteProvider: strokePaletteProvider,
88 })
89 );
90
91 const pointPaletteProvider: IPointMarkerPaletteProvider = {
92 strokePaletteMode: EStrokePaletteMode.SOLID,
93 onAttached(parentSeries: IRenderableSeries): void {},
94 onDetached(): void {},
95 // This function called once per data-point for scatter fill
96 overridePointMarkerArgb(
97 xValue: number,
98 yValue: number,
99 index: number,
100 opacity?: number,
101 metadata?: IPointMetadata
102 ): TPointMarkerArgb {
103 const color = getColor(yValue);
104 return { stroke: color, fill: color };
105 },
106 };
107
108 // Create a scatter series with threshold paletteprovider
109 sciChartSurface.renderableSeries.add(
110 new XyScatterRenderableSeries(wasmContext, {
111 dataSeries: new XyDataSeries(wasmContext, { xValues, yValues }),
112 pointMarker: new EllipsePointMarker(wasmContext, {
113 width: 7,
114 height: 7,
115 stroke: appTheme.VividOrange,
116 fill: appTheme.VividOrange,
117 }),
118 paletteProvider: pointPaletteProvider,
119 })
120 );
121
122 // Add annotations to fill the threshold areas
123 const boxHighAnnotation = new BoxAnnotation({
124 x1: 0,
125 x2: 1,
126 y1: THRESHOLD_LOW_LEVEL,
127 y2: -9999,
128 fill: appTheme.VividPink + "11",
129 strokeThickness: 0,
130 xCoordinateMode: ECoordinateMode.Relative,
131 });
132 sciChartSurface.annotations.add(boxHighAnnotation);
133 const boxLowAnnotation = new BoxAnnotation({
134 x1: 0,
135 x2: 1,
136 y1: THRESHOLD_HIGH_LEVEL,
137 y2: 9999,
138 fill: appTheme.VividTeal + "11",
139 strokeThickness: 0,
140 xCoordinateMode: ECoordinateMode.Relative,
141 });
142 sciChartSurface.annotations.add(boxLowAnnotation);
143 // Add annotations to show the thresholds
144 const thresholdHighAnnotation = new HorizontalLineAnnotation({
145 stroke: appTheme.VividTeal,
146 strokeThickness: 2,
147 strokeDashArray: [3, 3],
148 y1: THRESHOLD_HIGH_LEVEL,
149 labelPlacement: ELabelPlacement.TopRight,
150 labelValue: "High warning",
151 axisLabelFill: appTheme.VividTeal,
152 axisFontSize: 16,
153 showLabel: true,
154 isEditable: true,
155 onDrag: (args) => {
156 // When the vertical line is dragged, update the
157 // threshold palette and redraw the SciChartSurface
158 THRESHOLD_HIGH_LEVEL = thresholdHighAnnotation.y1;
159 boxLowAnnotation.y1 = thresholdHighAnnotation.y1;
160 sciChartSurface.invalidateElement();
161 },
162 });
163 sciChartSurface.annotations.add(thresholdHighAnnotation);
164 const thresholdLowAnnotation = new HorizontalLineAnnotation({
165 stroke: appTheme.VividPink,
166 strokeThickness: 2,
167 strokeDashArray: [3, 3],
168 labelPlacement: ELabelPlacement.BottomLeft,
169 y1: THRESHOLD_LOW_LEVEL,
170 labelValue: "Low warning",
171 axisLabelFill: appTheme.VividPink,
172 axisFontSize: 16,
173 showLabel: true,
174 isEditable: true,
175 onDrag: (args) => {
176 // When the vertical line is dragged, update the
177 // threshold palette and redraw the SciChartSurface
178 THRESHOLD_LOW_LEVEL = thresholdLowAnnotation.y1;
179 boxHighAnnotation.y1 = THRESHOLD_LOW_LEVEL;
180 sciChartSurface.invalidateElement();
181 },
182 });
183 sciChartSurface.annotations.add(thresholdLowAnnotation);
184 // Add title annotation
185 sciChartSurface.annotations.add(
186 new TextAnnotation({
187 text: "Per point colouring in SciChart.js. Can be applied to lines, areas, scatter points and bubbles",
188 fontSize: 16,
189 textColor: appTheme.ForegroundColor,
190 x1: 0,
191 y1: 0,
192 xCoordShift: 10,
193 yCoordShift: 10,
194 opacity: 0.77,
195 horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
196 xCoordinateMode: ECoordinateMode.Relative,
197 yCoordinateMode: ECoordinateMode.Relative,
198 })
199 );
200
201 return { sciChartSurface, wasmContext };
202};
203This example demonstrates how to implement per-point coloring for both line and scatter series using SciChart.js with JavaScript. It highlights dynamic color assignment based on threshold values and interactive annotations for real-time updates, making it ideal for high performance and visually rich charting applications.
The chart is asynchronously initialized using SciChartSurface.create and loading Wasm, ensuring that the WebAssembly context is properly loaded. NumericAxis are configured with options such as maxAutoTicks and growBy as described in the NumericAxis API, while a random walk data series is generated for visual demonstration, which aligns with techniques seen in generating a smooth random trend. Custom implementations of the IStrokePaletteProvider and IPointMarkerPaletteProvider are used to override default coloring on a per-data-point basis. These providers use the PaletteProvider API documentation and Per-Point Colouring of Scatter Charts to determine colors dynamically based on each data point’s y-value.
The example includes interactive annotations, such as draggable horizontal lines that update threshold levels in real-time. This interactivity is implemented to demonstrate how threshold changes can immediately affect the rendering of per-point colors, ensuring that the visualization remains responsive and informative. Performance is optimized by using efficient color conversion through methods like parseColorToUIntArgb and by processing color updates only when necessary.
Being implemented in JavaScript, this example avoids framework-specific constructs such as hooks or the builder API, allowing for easy integration into any HTML page. Developers are encouraged to follow Memory Best Practices to ensure proper resource cleanup, such as deleting the SciChartSurface when it is no longer needed. This straightforward approach provides a solid foundation for incorporating advanced charting capabilities in a lightweight, easy-to-maintain JavaScript project.

Demonstrates how to place Annotations (lines, arrows, markers, text) over a JavaScript Chart using SciChart.js Annotations API

Demonstrates how to place Buy/Sell arrow markers on a JavaScript Stock Chart using SciChart.js - Annotations API

Demonstrates how to add draggable thresholds which change the series color in the chart in SciChart.js

Demonstrates how to edit Annotations (shapes, boxes, lines, text, horizontal and vertical line) over a JavaScript Chart using SciChart.js Annotations API

Demonstrates how to color areas of the chart surface using background Annotations using SciChart.js Annotations API

Demonstrates how layering works a JavaScript Chart using SciChart.js Annotations API

Build Responsive JavaScript HTML Annotations with SciChart. Use the advanced CSS container queries for responsive text layout and custom design. View demo now.

JavaScript HTML Chart Control example demonstrates advanced HTML annotation integration and how to render HTML components within charts. Try the SciChart demo.