Skip to content

How to show all highlights on Material UI SparkLineChart with Typescript

Problem

When using Material UI SparkLineChart component, showing all highlights without the user needing to hover over the information can be complicated, especially because there are no properties that can do this for us

Solution

We are going to create a custom component that creates a circle, and we are going to show this component for every piece of data passed to the chart. You can also add conditionals or filters to this new component. That way, you can render the highlights conditionally. For example, we only show highlights if the value is more than 100. Take into consideration, for this example, we also show dates and data on the tooltips of the highlights. You can remove dateData and xAxis if you don't need them

import { SparkLineChart } from "@mui/x-charts";
import {
  unstable_useLineSeries,
  useXScale,
  useYScale,
} from "@mui/x-charts/hooks";
import React from "react";

const Highlights = ({
  data,
  dataIndex,
  color,
}: {
  data: number;
  dataIndex: number;
  color: string;
}) => {
  if (!data) {
    return null;
  }
  const xScale = useXScale();
  const yScale = useYScale();
  const lineSeries = unstable_useLineSeries();

  if (lineSeries) {
    const yData = lineSeries.series[lineSeries.seriesOrder[0]].data;
    const xData = xScale.domain();

    const xValue: any = xData[dataIndex];
    const yValue: any = yData[dataIndex];

    /**
     * You can add logic to filter which highlights to show
     * for example only show if value received is bigger than
     * 200
     */
    if (yValue > 200) {
      return (
        <circle
          cx={xScale(xValue)}
          cy={yScale(yValue)}
          // r controls the size of the dots
          r={3.6}
          // Stroke and fill control de color of the highlights
          stroke={color}
          fill={color}
        />
      );
    }

    return null;
  } else {
    return null;
  }
};

const generateTooltip = (value: number | null): string => {
  // Check if value is null
  if (!value) {
    return "Data not available";
  }

  let tooltip: string = value.toString();
  // Format tooltip with specific format
  return tooltip;
};

// Generate unit name for tooltip:
const generateDateTooltip = (value: any): string => {
  // Check if value is null
  if (!value) {
    return "Data not available";
  }

  const tooltip: string = `${value.toISOString().slice(0, 10)}`;

  return tooltip;
};

export const ChartHighlights = ({
  data,
  dateData,
}: {
  data: number[];
  dateData: Date[];
}) => {
  /**
   * You can remove xAsis property and dateData if you dont want
   * to show the date on the tooltip of the highlights, be sure data and
   * dates have the same length
   */
  return data.length === dateData.length ? (
    <SparkLineChart
      showTooltip
      showHighlight
      area
      valueFormatter={(value) => generateTooltip(value)}
      data={data}
      xAxis={{
        data: dateData,
        valueFormatter: (value) => generateDateTooltip(value),
        fill: "#000000",
        stroke: "#000000",
      }}
    >
      <>
        {data.map((singleData, index) => (
          <Highlights
            data={singleData}
            dataIndex={index}
            // Values must have an unique key
            key={`${data[index]}-${dateData[index]}`}
            // Color used on highlights
            color="#000000"
          />
          // You can pass more components if you need here
        ))}
      </>
    </SparkLineChart>
  ) : null;
};

Example of how to use this component

<div style={{ width: "100%", height: "15rem" }}>
  <ChartHighlights
    data={[450, 293, 328, 100, 114, 275, 215, 300, 218, 400]}
    dateData={[
      new Date("2024-08-01T00:00:00.643Z"),
      new Date("2024-08-02T00:00:00.643Z"),
      new Date("2024-08-03T00:00:00.643Z"),
      new Date("2024-08-04T00:00:00.643Z"),
      new Date("2024-08-05T00:00:00.643Z"),
      new Date("2024-08-06T00:00:00.643Z"),
      new Date("2024-08-07T00:00:00.643Z"),
      new Date("2024-08-08T00:00:00.643Z"),
      new Date("2024-08-09T00:00:00.643Z"),
      new Date("2024-08-10T00:00:00.643Z"),
    ]}
  />
</div>

You can find a CodeSandbox with the implementation on the following link https://codesandbox.io/p/sandbox/hidden-leaf-qrwpnt