SciChart.js JavaScript 2D Charts API > Axis APIs > Axis Label Formatting - Custom LabelProviders
Axis Label Formatting - Custom LabelProviders

Creating your Own LabelProviders

There are two ways to create a custom LabelProvider in SciChart.js. One is by inheriting LabelProvider as a TypeScript class and implementing your own Custom LabelProvider.


The second is to simply set a custom function on formatLabel or formatCursorLabel.

Let's look at both methods below.

Worked Example: Applying a LabelProvider function to format labels

This method is the easiest, and the most 'JavaScript'. Thanks to the object-based paradigm of JavaScript where every object is effectively collection of properties, you can override the label provider like this:

Example Title
Copy Code
import {SciChartSurface} from "scichart/Charting/Visuals/SciChartSurface";
import {NumericAxis} from "scichart/Charting/Visuals/Axis/NumericAxis";
import {NumberRange} from "scichart/Core/NumberRange";
export async function labelProviderFunction(divId) {
    const { sciChartSurface, wasmContext } = await SciChartSurface.create(divId);
    const minDate = 1609459200; // Unix datestamp for 1st Jan 2021
    const maxDate = 1612137600; // Unid datestamp for 1st Feb 2021
    // Create an XAxis
    const xAxis = new NumericAxis(wasmContext, {
        visibleRange: new NumberRange(minDate, maxDate)
    });
    sciChartSurface.xAxes.add(xAxis);
    // Create a YAxis
    const yAxis = new NumericAxis(wasmContext);
    sciChartSurface.yAxes.add(yAxis);
    // Override X Axis label formatting to format as date strings
    xAxis.labelProvider.formatLabel = (dataValue, format) => {
        const unixDateStamp = dataValue;
        return new Date(unixDateStamp * 1000).toLocaleDateString("en-GB", {
            month: "numeric",
            year: "numeric",
            day: "numeric"
        });
    };
    // Override Y Axis label formatting to format as 4-decimal places
    yAxis.labelProvider.formatLabel = (dataValue, format) => {
        return dataValue.toFixed(4);
    };
}

This can work great in the majority of cases, but if you want finer-grained control over labels, say depending on zoom level or other requirements, then it may be better to create a custom LabelProvider class.

Worked Example: Creating a Custom LabelProvider Class

If you are using TypeScript, to create a custom label provider for the NumericAxis, we simply create a class that inherits LabelProvider, and override formatLabel() and optionally, formatCursorLabel()

There are also some additional functions called when the LabelProvider is attached to an axis, and when an axis draw pass begins. Use these to reset state or one-time setup if you have complex rules in the formatLabel function.

Example Title
Copy Code
import {SciChartSurface} from "scichart/Charting/Visuals/SciChartSurface";
import {NumericAxis} from "scichart/Charting/Visuals/Axis/NumericAxis";
import {AxisCore} from "scichart/Charting/Visuals/Axis/AxisCore";
import {ELabelProviderType} from "scichart/types/LabelProviderType";
import {ENumericFormat} from "scichart/types/NumericFormat";
import {LabelProviderBase2D} from "scichart/Charting/Visuals/Axis/LabelProvider/LabelProviderBase2D";
/**
 * A CustomLabelProvider to format Axis Labels and Cursor / Tooltips for NumericAxis types
 */
export class CustomLabelProvider extends LabelProviderBase2D {
    constructor() {
        super();
    }
    public readonly type: ELabelProviderType.Numeric;
    /**
     * Called when the LabelProvider is attached to an Axis
     */
    public attachedToAxis(axis: AxisCore) {
        super.attachedToAxis(axis);
    }
    /**
     * Called once when an axis drawing pass begins. Use this method to do one-time setup
     */
    public onBeginAxisDraw(): void {
        // TODO: one-time setup at the beginning of a draw pass
    }
    /**
     * Formats a data-value into a string for display on a cursor or tooltip
     */
    public formatCursorLabel(dataValue: number): string {
        return dataValue.toFixed(4);
    }
    /**
     * Formats a data-value into a string for display on the axis labels
     */
    public formatLabel(dataValue: number, format?: ENumericFormat): string {
        return dataValue.toFixed(4);
    }
}
// Apply a label provider to an axis
export async function labelProviderClassExampleTs(divId: string) {
    const { sciChartSurface, wasmContext } = await SciChartSurface.create(divId);
    // Create an XAxis
    const xAxis = new NumericAxis(wasmContext);
    sciChartSurface.xAxes.add(xAxis);
    // Create a YAxis
    const yAxis = new NumericAxis(wasmContext);
    sciChartSurface.yAxes.add(yAxis);
    xAxis.labelProvider = new CustomLabelProvider();
}

Using Images as Labels

It is possible to go further and override the getLabelTexture function which converts the label text that is produced by formatLabel into a texture that can be drawn by WebGL.  This gives you total control over the appearance of your labels so that you can use images, complex text, or a combination.

The code below is taken from our online Image Labels example. The key part is to pass an HtmlImageElement to textureManager.createTextureFromImage. Everything else here is about mapping the data to the images.

Images as Labels
Copy Code
// import the image sources
import emojiUrl1 from "./emojies/e1-face-with-tears-of-joy.png";
import emojiUrl10 from "./emojies/e10-smiling-face-with-smiling-eyes.png";
import emojiUrl2 from "./emojies/e2-loudly-crying-face.png";
import emojiUrl3 from "./emojies/e3-pleading-face.png";
import emojiUrl4 from "./emojies/e4-red-heart_2764.png";
import emojiUrl5 from "./emojies/e5-rolling-on-the-floor-laughing.png";
import emojiUrl6 from "./emojies/e6-sparkles.png";
import emojiUrl7 from "./emojies/e7-smiling-face-with-heart-eyes.png";
import emojiUrl8 from "./emojies/e8-folded-hands.png";
import emojiUrl9 from "./emojies/e9-smiling-face-with-hearts.png";
const xAxis = new CategoryAxis(wasmContext);
// We need the data value as plain text
xAxis.labelProvider.numericFormat = ENumericFormat.NoFormat;
// create an array of images
// SciChart utility function to create HtmlImageElements from urls
const emojies = await createImagesArrayAsync([
    emojiUrl1,
    emojiUrl2,
    emojiUrl3,
    emojiUrl4,
    emojiUrl5,
    emojiUrl6,
    emojiUrl7,
    emojiUrl8,
    emojiUrl9,
    emojiUrl10
    ]);
// Use the data value to index into the image array.
// The size of the texture will be used for layout, so we don't need to do anything else
xAxis.labelProvider.getLabelTexture = (
    labelText: string,
    textureManager: TextureManager,
    labelStyle: TTextStyle
): TTextureObject => {
    const index = parseInt(labelText);
    if (!isNaN(index)) {
        const emoji = emojies[index];
        if (emoji) {
            // This function takes an HtmlImageElement and returns a texture that SciChart can draw using WebGL
            return textureManager.createTextureFromImage(emoji, 40, 40);
        }
    }
    // Fall back to standard text
    return textureManager.createTextTexture([labelText], labelStyle);
};
// X data is just array indexes
const dataSeries = new XyDataSeries(wasmContext);
dataSeries.appendRange([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [220, 170, 105, 85, 80, 75, 60, 50, 45, 45]);

Textures created this way are automatically cached for performance, and disposed of when the chart is deleted.

Normally, the size of the texture returned is used as the width and height for layout purposes.  Depending on the shape of your images, you may also want to override the getLabelWidth and getLabelHeight methods on LabelProviderBase2D.

 

See Also