Demonstrates how to use Images as Labels using SciChart.js, High Performance JavaScript Charts
drawExample.ts
index.tsx
theme.ts
1import {
2 XyDataSeries,
3 TTextStyle,
4 NumericAxis,
5 FastColumnRenderableSeries,
6 SciChartSurface,
7 TextureManager,
8 EAutoRange,
9 ENumericFormat,
10 createImagesArrayAsync,
11 EFillPaletteMode,
12 EStrokePaletteMode,
13 IFillPaletteProvider,
14 IStrokePaletteProvider,
15 parseColorToUIntArgb,
16 IRenderableSeries,
17 IPointMetadata,
18 PaletteFactory,
19 GradientParams,
20 Point,
21 WaveAnimation,
22 NumberRange,
23 TextAnnotation,
24 EHorizontalAnchorPoint,
25 ECoordinateMode,
26} from "scichart";
27import { appTheme } from "../../../theme";
28
29export const drawExample = (emojiUrls: string[]) => async (rootElement: string | HTMLDivElement) => {
30 // Dataset = 'percentage market share of phones, 2022'
31 const dataset = [
32 { name: "Apple", percent: 28.41 },
33 { name: "Samsung", percent: 28.21 },
34 { name: "Xiaomi", percent: 12.73 },
35 { name: "Huawei", percent: 5.27 },
36 { name: "Oppo", percent: 5.53 },
37 { name: "Vivo", percent: 4.31 },
38 { name: "Realme", percent: 3.16 },
39 { name: "Motorola", percent: 2.33 },
40 { name: "Unknown", percent: 2.19 },
41 { name: "LG", percent: 0.85 },
42 { name: "OnePlus", percent: 1.11 },
43 { name: "Tecno", percent: 1.09 },
44 { name: "Infinix", percent: 0.96 },
45 { name: "Google", percent: 0.77 },
46 { name: "Nokia", percent: 0.45 },
47 ];
48 // Create the SciChartSurface with theme
49 const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
50 theme: appTheme.SciChartJsTheme,
51 });
52
53 const xAxis = new NumericAxis(wasmContext, {
54 // Ensure there can be 1 label per item in the dataset.
55 // Also see major/minor delta in the docs
56 maxAutoTicks: 15,
57 axisTitle: "Mobile phone manufacturer",
58 growBy: new NumberRange(0.02, 0.02),
59 });
60 // We need the data value as plain text
61 xAxis.labelProvider.numericFormat = ENumericFormat.NoFormat;
62
63 // SciChart utility function to create HtmlImage elements from urls
64 const emojies = await createImagesArrayAsync(emojiUrls);
65
66 // Override labelProvider.getLabelTexture() to return animage
67 const getLabelTexture = (labelText: string, textureManager: TextureManager, labelStyle: TTextStyle) => {
68 const index = parseInt(labelText);
69 if (!isNaN(index)) {
70 const emoji = emojies[index];
71 if (emoji) {
72 return textureManager.createTextureFromImage(emoji, 40, 40);
73 }
74 }
75 return textureManager.createTextTexture([labelText], labelStyle);
76 };
77 xAxis.labelProvider.getLabelTexture = getLabelTexture;
78
79 // If using asyncLabels = true, override this as well
80 xAxis.labelProvider.getLabelTextureAsync = (
81 labelText: string,
82 textureManager: TextureManager,
83 labelStyle: TTextStyle
84 ) => Promise.resolve(getLabelTexture(labelText, textureManager, labelStyle));
85
86 // Disable shared cache for this provider, otherwise other axes might pick up the emoji textures
87 xAxis.labelProvider.useSharedCache = false;
88
89 sciChartSurface.xAxes.add(xAxis);
90
91 // Create a Y-Axis with standard properties
92 sciChartSurface.yAxes.add(
93 new NumericAxis(wasmContext, {
94 autoRange: EAutoRange.Always,
95 axisTitle: "Market Share (%)",
96 growBy: new NumberRange(0, 0.1),
97 labelPostfix: " %",
98 })
99 );
100
101 // Add a column series.
102 sciChartSurface.renderableSeries.add(
103 new FastColumnRenderableSeries(wasmContext, {
104 // Name index to xvalue for category axis
105 // Map percentage to yvalue
106 // store the manufacturer name in the metadata (used to generate colors)
107 dataSeries: new XyDataSeries(wasmContext, {
108 xValues: dataset.map((row, index) => index),
109 yValues: dataset.map((row) => row.percent),
110 }),
111 strokeThickness: 0,
112 // // Optional datalabels on series. To enable set a style and position
113 // dataLabels: {
114 // horizontalTextPosition: EHorizontalTextPosition.Center,
115 // verticalTextPosition: EVerticalTextPosition.Top,
116 // style: { fontFamily: "Arial", fontSize: 16, padding: new Thickness(0,0,20,0) },
117 // color: appTheme.ForegroundColor,
118 // },
119 // each column occupies 50% of available space
120 dataPointWidth: 0.5,
121 // add a gradient fill in X (why not?)
122 paletteProvider: PaletteFactory.createGradient(
123 wasmContext,
124 new GradientParams(new Point(0, 0), new Point(1, 1), [
125 { offset: 0, color: appTheme.VividPink },
126 { offset: 0.2, color: appTheme.VividOrange },
127 { offset: 0.3, color: appTheme.MutedRed },
128 { offset: 0.5, color: appTheme.VividGreen },
129 { offset: 0.7, color: appTheme.VividSkyBlue },
130 { offset: 0.9, color: appTheme.Indigo },
131 { offset: 1, color: appTheme.DarkIndigo },
132 ]),
133 { enableFill: true, enableStroke: true }
134 ),
135 // Bit more eye candy ;)
136 animation: new WaveAnimation({ duration: 1000 }),
137 })
138 );
139
140 // Add title annotation
141 sciChartSurface.annotations.add(
142 new TextAnnotation({
143 text: "Mobile Phone manufacturer market share (2022)",
144 fontSize: 20,
145 textColor: appTheme.ForegroundColor,
146 x1: 0.5,
147 y1: 0,
148 opacity: 0.77,
149 horizontalAnchorPoint: EHorizontalAnchorPoint.Center,
150 xCoordinateMode: ECoordinateMode.Relative,
151 yCoordinateMode: ECoordinateMode.Relative,
152 })
153 );
154
155 sciChartSurface.zoomExtents();
156 return { sciChartSurface, wasmContext };
157};
158
159export class EmojiPaletteProvider implements IStrokePaletteProvider, IFillPaletteProvider {
160 public readonly strokePaletteMode = EStrokePaletteMode.SOLID;
161 public readonly fillPaletteMode = EFillPaletteMode.SOLID;
162 private readonly pfYellow = parseColorToUIntArgb("FFCC4D");
163 private readonly pfBlue = parseColorToUIntArgb("5DADEC");
164 private readonly pfOrange = parseColorToUIntArgb("F58E01");
165 private readonly pfRed = parseColorToUIntArgb("DE2A43");
166 private readonly pfPink = parseColorToUIntArgb("FE7891");
167
168 // tslint:disable-next-line:no-empty
169 public onAttached(parentSeries: IRenderableSeries): void {}
170
171 // tslint:disable-next-line:no-empty
172 public onDetached(): void {}
173
174 public overrideFillArgb(xValue: number, yValue: number, index: number): number {
175 if (xValue === 0 || xValue === 4 || xValue === 8) {
176 return this.pfYellow;
177 } else if (xValue === 1 || xValue === 7) {
178 return this.pfBlue;
179 } else if (xValue === 2 || xValue === 5) {
180 return this.pfOrange;
181 } else if (xValue === 3 || xValue === 6) {
182 return this.pfRed;
183 } else if (xValue === 9) {
184 return this.pfPink;
185 } else {
186 return undefined;
187 }
188 }
189
190 public overrideStrokeArgb(
191 xValue: number,
192 yValue: number,
193 index: number,
194 opacity?: number,
195 metadata?: IPointMetadata
196 ): number {
197 return undefined;
198 }
199}
200
Demonstrates how to use arbitrary text for axis labels, rather than formatted data values, using the new TextLabelProvider
Rotate to create vertical axis labels and fit more on an axis