Chart Axis Image labels

Demonstrates how to use Images as Labels using SciChart.js, High Performance JavaScript Charts

Fullscreen

Edit

 Edit

Docs

drawExample.ts

angular.ts

theme.ts

Copy to clipboard
Minimise
Fullscreen
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        // required for image labels
60        useNativeText: false,
61    });
62    // We need the data value as plain text
63    xAxis.labelProvider.numericFormat = ENumericFormat.NoFormat;
64
65    // SciChart utility function to create HtmlImage elements from urls
66    const emojies = await createImagesArrayAsync(emojiUrls);
67
68    // Override labelProvider.getLabelTexture() to return animage
69    const getLabelTexture = (labelText: string, textureManager: TextureManager, labelStyle: TTextStyle) => {
70        const index = parseInt(labelText);
71        if (!isNaN(index)) {
72            const emoji = emojies[index];
73            if (emoji) {
74                return textureManager.createTextureFromImage(emoji, 40, 40);
75            }
76        }
77        return textureManager.createTextTexture([labelText], labelStyle);
78    };
79    xAxis.labelProvider.getLabelTexture = getLabelTexture;
80
81    // If using asyncLabels = true, override this as well
82    xAxis.labelProvider.getLabelTextureAsync = (
83        labelText: string,
84        textureManager: TextureManager,
85        labelStyle: TTextStyle
86    ) => Promise.resolve(getLabelTexture(labelText, textureManager, labelStyle));
87
88    // Disable shared cache for this provider, otherwise other axes might pick up the emoji textures
89    xAxis.labelProvider.useSharedCache = false;
90
91    sciChartSurface.xAxes.add(xAxis);
92
93    // Create a Y-Axis with standard properties
94    sciChartSurface.yAxes.add(
95        new NumericAxis(wasmContext, {
96            autoRange: EAutoRange.Always,
97            axisTitle: "Market Share (%)",
98            growBy: new NumberRange(0, 0.1),
99            labelPostfix: " %",
100        })
101    );
102
103    // Add a column series.
104    sciChartSurface.renderableSeries.add(
105        new FastColumnRenderableSeries(wasmContext, {
106            // Name index to xvalue for category axis
107            // Map percentage to yvalue
108            // store the manufacturer name in the metadata (used to generate colors)
109            dataSeries: new XyDataSeries(wasmContext, {
110                xValues: dataset.map((row, index) => index),
111                yValues: dataset.map((row) => row.percent),
112            }),
113            strokeThickness: 0,
114            // // Optional datalabels on series. To enable set a style and position
115            // dataLabels: {
116            //     horizontalTextPosition: EHorizontalTextPosition.Center,
117            //     verticalTextPosition: EVerticalTextPosition.Top,
118            //     style: { fontFamily: "Arial", fontSize: 16, padding: new Thickness(0,0,20,0) },
119            //     color: appTheme.ForegroundColor,
120            // },
121            // each column occupies 50% of available space
122            dataPointWidth: 0.5,
123            // add a gradient fill in X (why not?)
124            paletteProvider: PaletteFactory.createGradient(
125                wasmContext,
126                new GradientParams(new Point(0, 0), new Point(1, 1), [
127                    { offset: 0, color: appTheme.VividPink },
128                    { offset: 0.2, color: appTheme.VividOrange },
129                    { offset: 0.3, color: appTheme.MutedRed },
130                    { offset: 0.5, color: appTheme.VividGreen },
131                    { offset: 0.7, color: appTheme.VividSkyBlue },
132                    { offset: 0.9, color: appTheme.Indigo },
133                    { offset: 1, color: appTheme.DarkIndigo },
134                ]),
135                { enableFill: true, enableStroke: true }
136            ),
137            // Bit more eye candy ;)
138            animation: new WaveAnimation({ duration: 1000 }),
139        })
140    );
141
142    // Add title annotation
143    sciChartSurface.annotations.add(
144        new TextAnnotation({
145            text: "Mobile Phone manufacturer market share (2022)",
146            fontSize: 20,
147            textColor: appTheme.ForegroundColor,
148            x1: 0.5,
149            y1: 0,
150            opacity: 0.77,
151            horizontalAnchorPoint: EHorizontalAnchorPoint.Center,
152            xCoordinateMode: ECoordinateMode.Relative,
153            yCoordinateMode: ECoordinateMode.Relative,
154        })
155    );
156
157    sciChartSurface.zoomExtents();
158    return { sciChartSurface, wasmContext };
159};
160
161export class EmojiPaletteProvider implements IStrokePaletteProvider, IFillPaletteProvider {
162    public readonly strokePaletteMode = EStrokePaletteMode.SOLID;
163    public readonly fillPaletteMode = EFillPaletteMode.SOLID;
164    private readonly pfYellow = parseColorToUIntArgb("FFCC4D");
165    private readonly pfBlue = parseColorToUIntArgb("5DADEC");
166    private readonly pfOrange = parseColorToUIntArgb("F58E01");
167    private readonly pfRed = parseColorToUIntArgb("DE2A43");
168    private readonly pfPink = parseColorToUIntArgb("FE7891");
169
170    // tslint:disable-next-line:no-empty
171    public onAttached(parentSeries: IRenderableSeries): void {}
172
173    // tslint:disable-next-line:no-empty
174    public onDetached(): void {}
175
176    public overrideFillArgb(xValue: number, yValue: number, index: number): number {
177        if (xValue === 0 || xValue === 4 || xValue === 8) {
178            return this.pfYellow;
179        } else if (xValue === 1 || xValue === 7) {
180            return this.pfBlue;
181        } else if (xValue === 2 || xValue === 5) {
182            return this.pfOrange;
183        } else if (xValue === 3 || xValue === 6) {
184            return this.pfRed;
185        } else if (xValue === 9) {
186            return this.pfPink;
187        } else {
188            return undefined;
189        }
190    }
191
192    public overrideStrokeArgb(
193        xValue: number,
194        yValue: number,
195        index: number,
196        opacity?: number,
197        metadata?: IPointMetadata
198    ): number {
199        return undefined;
200    }
201}
202

Image Labels on Axis Example (Angular)

Overview

This example demonstrates how to integrate SciChart.js into an Angular application using the scichart-angular component. The chart displays mobile phone market share data and replaces traditional axis labels with images, such as brand logos, to create a more engaging visualization.

Technical Implementation

The setup uses an Angular standalone component that initializes a SciChartSurface through a custom asynchronous function. This function configures numeric axes and overrides the LabelProvider.getLabelTexture and getLabelTextureAsync methods to load and render images as axis labels. Asynchronous image loading is handled through SciChart.js utilities, ensuring efficient asset management as detailed in the Image Labels documentation. The procedural configuration approach, instead of using a Builder API, allows explicit control over chart properties and performance.

Features and Capabilities

Key features include an animated column series with WaveAnimation and gradient fills, which provide smooth transitions and visual depth. Custom palette providers are used for dynamic color rendering, while asynchronous image loading for axis labels improves both performance and user experience. This design demonstrates how to integrate advanced chart features in a high-performance setting.

Integration and Best Practices

The example leverages Angular’s standalone components and dependency injection to encapsulate all chart initialization logic. Developers can refer to the scichart-angular package for integration details and best practices in managing assets as outlined in the Angular Standalone Components guide. The custom label provider implementation, which transforms numeric labels to image textures, follows the techniques presented in the Axis LabelProviders documentation, ensuring a high-quality, extensible solution.

SciChart Ltd, 16 Beaufort Court, Admirals Way, Docklands, London, E14 9XL.