Ant Design Charts with Tooltip Proximity

If you've ever wished for tooltips to appear as your cursor approaches a data point, you're in luck. While Ant Design Charts doesn't offer this feature out of the box, fear not! A bit of manual tweaking through mathematical formulas, can bring tooltip proximity to your charts.

Ant Design Charts with Tooltip Proximity

Introduction

Are you an Ant Design Charts user looking to add a touch of interactivity to your graphs? If you've ever wished for tooltips to appear as your cursor approaches a data point, you're in luck. While Ant Design Charts doesn't offer this feature out of the box, fear not! A bit of manual tweaking through mathematical formulas, can bring tooltip proximity to your charts.

Tooltip proximity refers to the dynamic display of tooltips as the mouse cursor nears a data point on a graph. This feature adds a layer of intuitiveness and engagement to data visualization, allowing users to glean insights with ease.

Having tooltips appear as the cursor gets close to a data point can significantly improve user interaction with data visualizations. Static tooltips that appear only when you hover directly over a point can hinder quick information retrieval. Additionally, high data point density or proximity to map edges makes it challenging to activate tooltips effectively. By making tooltips pop up as you near a point, the interaction becomes more intuitive and engaging. This way, users can get insights more easily and accurately, making data exploration smoother and more enjoyable.

Ant Design Charts provides a robust API that offers comprehensive information about the chart, including the coordinates of data points. Leveraging this context, we can implement tooltip proximity effectively.

How to Implement Tooltip Proximity

Here's how you can achieve tooltip proximity on Ant Design Charts:

  1. Create react app.
  2. Install AntD charts dependencies: Install following dependencies
    npm install @ant-design/charts --save
  3. Plot the graph
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
import { Area } from '@ant-design/plots';

const DemoArea = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    asyncFetch();
  }, []);

  const asyncFetch = () => {
    fetch(
      'https://gw.alipayobjects.com/os/bmw-prod/1d565782-dde4-4bb6-8946-ea6a38ccf184.json'
    )
      .then((response) => response.json())
      .then((json) => {
        const newdata = json.filter((x) => x.scales > 2000);
        setData(newdata);
      })
          .catch((error) => {
        console.log('fetch data failed', error);
      });
  };

  const config = {
    data,
    xField: 'Date',
    yField: 'scales',
    annotations: [
      {
        type: 'text',
        position: ['min', 'median'],
        content: 'test',
        offsetY: -4,
        style: {
          textBaseline: 'bottom',
        },
      },
      {
        type: 'line',
        start: ['min', 'median'],
        end: ['max', 'median'],
        content: 'test2',
        style: {
          stroke: 'red',
          lineDash: [2, 2],
        },
      },
    ],
    point: {
      size: 5,
      shape: 'point',
      style: {
        fill: 'white',
        stroke: '#5B8FF9',
        lineWidth: 2,
      },
    }
  };

  return <Area {...config} />;
};
  1. Add interactions to the graph to show tooltips conditionally. Show the tooltip when mouse enters a certain region on the graph and stop showing it when mouse leaves the region. We can add such interaction into graph config.
interactions: [
  {
    type: 'tooltip',
    cfg: {
      start: [
        {
          trigger: 'plot:mousemove',
          isEnable(context) {
            return true;
          },
          action: 'tooltip:show',
        },
      ],

      end: [
        {
          trigger: 'plot:mouseleave',
          action: ['tooltip:hide'],
        },
        {
          trigger: 'plot:mousemove',
          isEnable(context) {
            return false;
          },
          action: 'tooltip:hide',
        },
      ],
    },
  },
]
  1. This tooltip interaction configuration provides a callback called isEnabled which takes graph context as a parameter. This context contains essential information about the chart, including data points coordinates and current position of the cursor.
  2. We could use the callback to check if the position of the cursor is inside the bounding box made by point using the coordinates of point.
function isInBox(obox, point) {
  const box = obox;
  return (
    box.x <= point.x &&
    box.maxX >= point.x &&
    box.y <= point.y &&
    box.maxY > point.y
  );
}

const inProximity = (context, inverse = false) => {
  const pointObject = context.view.geometries.find(
    (geometry) => geometry.type === 'point'
  );
  const elements = pointObject.elements.map((x) => x.shape.cfg.bbox);
  const currentPoint = context.getCurrentPoint();
  const shouldShow =
    elements.filter((x) => x && isInBox(x, currentPoint)).length > 0;
  return inverse === false ? shouldShow : !shouldShow;
};

Change the interaction to use isProximity as a callback to isEnabled . This function takes another parameter called inverse to check if we need to show or hide tooltips.

interactions: [
  {
    type: 'tooltip',
    cfg: {
      start: [
        {
          trigger: 'plot:mousemove',
          isEnable(context) {
            return inProximity(context);
          },
          action: 'tooltip:show',
        },
      ],

      end: [
        {
          trigger: 'plot:mouseleave',
          action: ['tooltip:hide'],
        },
        {
          trigger: 'plot:mousemove',
          isEnable(context) {
            return inProximity(context, true);
          },
          action: 'tooltip:hide',
        },
      ],
    },
  },
],
  1. With bounding box coordinates we could increase the size of the original bounding box by using the following function:
function makeBBoxBigger(box) {
  const factor = 2;
  return {
    x: box.x - box.width * (factor / 2),
    y: box.y - box.height * (factor / 2),
    maxX: box.x + (box.width + box.width * factor),
    maxY: box.y + (box.height + box.height * factor),
  };
}

It takes in the original bounding box and returns a bounding box with increased size over a point. The enlargement factor determines the extent to which the bounding box is increased.

We could use this function in the isInBBox like:

function isInBox(obox, point) {
  const box = makeBBoxBigger(obox);
  return (
    box.x <= point.x &&
    box.maxX >= point.x &&
    box.y <= point.y &&
    box.maxY > point.y
  );
}

By following these steps, you can enhance your Ant Design Charts with tooltip proximity, providing users with a more interactive and insightful data visualization experience.

Note!!!
This implementation might not always work as expected if the data points are too close or are overlapping. For example, if data points are too close on the x-axis then the bounding box for a datapoint that triggers the tooltip might show information from the adjacent datapoint. To overcome this issue we can make this dynamic by setting the proximity settings based on the number of datapoints.

Conclusion

In conclusion, while Ant Design Charts may not natively support tooltip proximity, with a little creativity and manual implementation, you can incorporate this feature seamlessly into your charts. Unlock the power of dynamic tooltips and take your data visualization to the next level!

Happy charting!

If you liked our ideas, click on the subscribe button below to get our latest blogs delivered directly to your email.