Adding Tooltip to React-Native Charts

Mohit Kaushik
Level Up Coding
Published in
5 min readJul 31, 2020

--

Adding a tooltip to a chart sounds like a small task, and indeed it is, but with some workarounds as even the most popular chart libraries in react-native don't directly mention it in their documentation.

Requirements

In this article, I am going to use react-native-chart-kit and I will show you how we can add tooltip to its LineChart.

First, install the libraries that we are going to need for your react-native project.

npm install react-native-chart-kit --save
npm install react-native-svg --save

Library versions used in this article (so that if a future update makes some breaking changes you can switch to this combination).

"react": "16.13.1",
"react-native": "0.63.2",
"react-native-chart-kit": "^6.4.1",
"react-native-svg": "^12.1.0"

Implementing a Line Chart

Lets first create a LineChart without a tooltip. The code is very simple as the LineChart props contain either the data to render or some styles for our chart.

Since I have generated a random dataset using Math.random(), the output that you will see is going to be different from the below chart.

Adding tooltip

If we go to the GitHub page of react-native-chart-kit and if we scroll a little bit down in the documentation, we will find a list of properties available for the LineChart, we will see there isn’t any tooltip mentioned. There is one prop named decorator that mentions something about adding additional markup.

LineChart props with their explanation

Simplifying this for our usecase that extra element is our tooltip, which will show some extra information about the datapoint. Now, here is the confusing part, which is not mentioned is what type of element we should use?

One common guess is a core react-native component like View but this alone will not work. The correct answer to the above question is a core react-native element wrapping a react-native-svg element. The reason being is react-native-chart-kit itself uses react-native-svg elements for rendering its chart elements and we will also use the SVG elements to render our tooltip.

Let's see one example of it given below.

decorator={() => {     return <View>     <Svg>         <Rect x={80} y={110} width="40" height="30" fill="black" />         <TextSVG             x={100}             y={130}             fill="white"             fontSize="16"             fontWeight="bold"             textAnchor="middle">             0.0         </TextSVG>     </Svg>  </View>}}

By seeing the tooltip below you can tell I haven’t invested much time in designing it. The react-native-svg library provides lots of shapes for e.g Circle, Rect, Polygon, etc. I have chosen the Rect for drawing the tooltip.

But you can learn to design your own, just visit react-native-svg.

Chart with hardcoded tooltip

Add the above decorator prop to the LineChart and you will be able to see the tooltip on the chart now, but its position and value are hardcoded as x and y are some constant values. We obviously want this tooltip to be positioned dynamically and show value according to the data points rendered on the chart.

Adding Dynamic Tooltip

Before starting the implementation, lets set some expectations. First, we will show tooltip only when the user clicks on the datapoint. Second, we will position the tooltip near to its datapoint. Third and the last is hiding tooltip when the user clicks the same datapoint for the second time.

Let's initialize a state for our tooltip which we can manipulate for positioning and controlling its visibility.

let [tooltipPos,setTooltipPos] = useState(
{ x:0, y:0, visible:false, value:0 })

We will use x and y for positioning and for controlling visibility we will use the visible key.

We will also use a LineChart property onDataPointClick. The onDataPointClick property takes a callback that is called whenever a user clicks a datapoint on the chart. It receives an argument that provides some data and an example of the data it receives is shown below.

{"dataset": {"data": [100, 110, 90, 130, 80, 103]}, "getColor": [Function getColor], "index": 3, "value": 130, "x": 237.7142857142857, "y": 16}

All keys are self-explanatory, x and y define the position of the datapoint clicked, value is the value of the datapoint it is representing from the dataset, index is the index of the value in the dataset, dataset is obviously the dataset used in the line chart. We can ignore getColor as it will only be useful if are dealing with multiple lines, which is not our case.

Implementation for tooltip features

Now let's write some logic for the expected features of our tooltip that we have defined above in this section.

onDataPointClick={  (data) => {
// check if we have clicked on the same point again
let isSamePoint = (tooltipPos.x === data.x
&& tooltipPos.y === data.y)

// if clicked on the same point again toggle visibility
// else,render tooltip to new position and update its value
isSamePoint ? setTooltipPos((previousState)=> {
return {
...previousState,
value: data.value,
visible: !previousState.visible}
})
:
setTooltipPos({x: data.x,
value: data.value, y: data.y,
visible: true
});
} // end function
}

Making some changes in our <Rect> element to align the tooltip, so that it won’t overlap with the datapoint on the chart.

decorator={() => {   return tooltipPos.visible ? <View>    <Svg>       <Rect x={tooltipPos.x -15} y={tooltipPos.y + 10} width="40"  
height="30" fill="black" />
<TextSVG x={tooltipPos.x + 5} y={tooltipPos.y + 30} fill="white" fontSize="16" fontWeight="bold" textAnchor="middle"> {tooltipPos.value} </TextSVG> </Svg></View> : null}}
Tooltip rendered on datapoint click
Tooltip for another datapoint

Combining all changes

Congratulations! We have successfully added a tooltip to our chart. Let’s put all the changes together in one file.

References

--

--