SciChart.js JavaScript 2D Charts API > Axis APIs > Axis Labels > Image Labels
Image Labels

In additional to all the label formatting options by SciChart.js, it is possible to go further and override the LabelProvider.getLabelTexture() function which converts the label text that is produced by LabelProvider.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.

const { sciChartSurface, wasmContext } = await SciChartSurface.create(divElementId, {
  theme: new SciChartJsNavyTheme()
});

const xAxis = new NumericAxis(wasmContext, {
  // Ensure there can be 1 label per item in the dataset.
  maxAutoTicks: 15,
  axisTitle: "Mobile phone manufacturer",
  // We need the data value as plain text
  labelFormat: ENumericFormat.NoFormat
});

// SciChart utility function to create HtmlImage elements from urls
// Note: createImageAsync / createImagesArrayAsync() also accept imported images if using WebPack
const images = await createImagesArrayAsync([
  "https://demo.scichart.com/images/apple.png",
  "https://demo.scichart.com/images/samsung.png",
  "https://demo.scichart.com/images/xiaomi.png",
  "https://demo.scichart.com/images/huawei.png",
  "https://demo.scichart.com/images/oppo.png",
  "https://demo.scichart.com/images/vivo.png",
  "https://demo.scichart.com/images/realme.png",
  "https://demo.scichart.com/images/motorola.png",
  "https://demo.scichart.com/images/question.png",
  "https://demo.scichart.com/images/lg.png",
  "https://demo.scichart.com/images/oneplus.png",
  "https://demo.scichart.com/images/tecno.png",
  "https://demo.scichart.com/images/infinix.png",
  "https://demo.scichart.com/images/google.png",
  "https://demo.scichart.com/images/nokia.png"
]);

// Override labelProvider.getLabelTexture() to return an image
const getLabelTexture = (labelText, textureManager, labelStyle) => {
  const index = parseInt(labelText);
  if (!isNaN(index)) {
    const emoji = images[index];
    if (emoji) {
      return textureManager.createTextureFromImage(emoji, 40, 40);
    }
  }
  return textureManager.createTextTexture([labelText], labelStyle);
};
xAxis.labelProvider.getLabelTexture = getLabelTexture;

// If using asyncLabels = true, override this as well
xAxis.labelProvider.getLabelTextureAsync = (labelText, textureManager, labelStyle) =>
    Promise.resolve(getLabelTexture(labelText, textureManager, labelStyle));

// Disable shared cache for this provider, otherwise other axes might pick up the emoji textures
xAxis.labelProvider.useSharedCache = false;

sciChartSurface.xAxes.add(xAxis);

This results in the following output:

<div id="scichart-root" ></div>
  
body { margin: 0; }
#scichart-root { width: 100%; height: 100vh; }
  
async function imageLabels(divElementId) {
  // Demonstrates how to configure an axis with rotated labels in scichart.js
  const {
    SciChartSurface,
    SciChartJsNavyTheme,
    NumericAxis,
    ENumericFormat,
    NumberRange,
    createImagesArrayAsync,
    EAutoRange,
    WaveAnimation,
    TextAnnotation,
    ECoordinateMode,
    EHorizontalAnchorPoint,
    PaletteFactory,
    GradientParams,
    Point,
    FastColumnRenderableSeries,
    XyDataSeries
  } = SciChart;

  // Dataset = 'percentage market share of phones, 2022'
  const dataset = [
    {name: "Apple", percent: 28.41},
    {name: "Samsung", percent: 28.21},
    {name: "Xiaomi", percent: 12.73},
    {name: "Huawei", percent: 5.27},
    {name: "Oppo", percent: 5.53},
    {name: "Vivo", percent: 4.31},
    {name: "Realme", percent: 3.16},
    {name: "Motorola", percent: 2.33},
    {name: "Unknown", percent: 2.19},
    {name: "LG", percent: 0.85},
    {name: "OnePlus", percent: 1.11},
    {name: "Tecno", percent: 1.09},
    {name: "Infinix", percent: 0.96},
    {name: "Google", percent: 0.77},
    {name: "Nokia", percent: 0.45},
  ];

  // #region ExampleA
  const { sciChartSurface, wasmContext } = await SciChartSurface.create(divElementId, {
    theme: new SciChartJsNavyTheme()
  });

  const xAxis = new NumericAxis(wasmContext, {
    // Ensure there can be 1 label per item in the dataset.
    maxAutoTicks: 15,
    axisTitle: "Mobile phone manufacturer",
    // We need the data value as plain text
    labelFormat: ENumericFormat.NoFormat
  });

  // SciChart utility function to create HtmlImage elements from urls
  // Note: createImageAsync / createImagesArrayAsync() also accept imported images if using WebPack
  const images = await createImagesArrayAsync([
    "https://demo.scichart.com/images/apple.png",
    "https://demo.scichart.com/images/samsung.png",
    "https://demo.scichart.com/images/xiaomi.png",
    "https://demo.scichart.com/images/huawei.png",
    "https://demo.scichart.com/images/oppo.png",
    "https://demo.scichart.com/images/vivo.png",
    "https://demo.scichart.com/images/realme.png",
    "https://demo.scichart.com/images/motorola.png",
    "https://demo.scichart.com/images/question.png",
    "https://demo.scichart.com/images/lg.png",
    "https://demo.scichart.com/images/oneplus.png",
    "https://demo.scichart.com/images/tecno.png",
    "https://demo.scichart.com/images/infinix.png",
    "https://demo.scichart.com/images/google.png",
    "https://demo.scichart.com/images/nokia.png"
  ]);

  // Override labelProvider.getLabelTexture() to return an image
  const getLabelTexture = (labelText, textureManager, labelStyle) => {
    const index = parseInt(labelText);
    if (!isNaN(index)) {
      const emoji = images[index];
      if (emoji) {
        return textureManager.createTextureFromImage(emoji, 40, 40);
      }
    }
    return textureManager.createTextTexture([labelText], labelStyle);
  };
  xAxis.labelProvider.getLabelTexture = getLabelTexture;

  // If using asyncLabels = true, override this as well
  xAxis.labelProvider.getLabelTextureAsync = (labelText, textureManager, labelStyle) =>
      Promise.resolve(getLabelTexture(labelText, textureManager, labelStyle));

  // Disable shared cache for this provider, otherwise other axes might pick up the emoji textures
  xAxis.labelProvider.useSharedCache = false;

  sciChartSurface.xAxes.add(xAxis);
  // #endregion

  // Create a Y-Axis with standard properties
  sciChartSurface.yAxes.add(new NumericAxis(wasmContext, {
    autoRange: EAutoRange.Always,
    axisTitle: "Market Share (%)",
    growBy: new NumberRange(0, 0.1),
    labelPostfix: " %"
  }));

  // Add a column series.
  sciChartSurface.renderableSeries.add(new FastColumnRenderableSeries(wasmContext, {
    // Name index to xvalue for category axis
    // Map percentage to y-value
    // store the manufacturer name in the metadata (used to generate colors)
    dataSeries: new XyDataSeries(wasmContext, {
      xValues: dataset.map((row, index) => index),
      yValues: dataset.map(row => row.percent),
    }),
    strokeThickness: 0,
    // each column occupies 50% of available space
    dataPointWidth: 0.5,
    // add a gradient fill in X (why not?)
    paletteProvider: PaletteFactory.createGradient(wasmContext, new GradientParams(new Point(0, 0), new Point(1, 1), [
      {offset: 0, color: "#EC0F6C"},
      {offset: 0.2, color: "#F48420"},
      {offset: 0.3, color: "#DC7969"},
      {offset: 0.5, color: "#67BDAF"},
      {offset: 0.7, color: "#50C7E0"},
      {offset: 0.9, color: "#264B93"},
      {offset: 1, color: "#14233C"},
    ]), {enableFill: true, enableStroke: true}),
    // Bit more eye candy ;)
    animation: new WaveAnimation({duration: 1000})
  }));

  // Add title annotation
  sciChartSurface.annotations.add(new TextAnnotation({
    text: "Mobile Phone manufacturer market share (2022)",
    fontSize: 20,
    textColor: "White",
    x1: 0.5,
    y1: 0,
    opacity: 0.77,
    horizontalAnchorPoint: EHorizontalAnchorPoint.Center,
    xCoordinateMode: ECoordinateMode.Relative,
    yCoordinateMode: ECoordinateMode.Relative,
  }));

  sciChartSurface.zoomExtents();
};

imageLabels("scichart-root");



  

Textures created this way are automatically cached for performance, and disposed of (deleted) 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.

For an example of how to do this with TypeScript, React and npm / webpack to import images, see our Image Labels example, part of the SciChart Demo.