Tooltips
VictoryTooltip
is a label component with defaultEvents
It renders a customizable flyout container as well as a VictoryLabel
component. VictoryTooltip
can be used with any Victory component by setting the labelComponent
prop like so labelComponent={<VictoryTooltip/>
This guide discusses customization and advanced usage of tooltips in Victory
Simple tooltips
The simplest way to add tooltips to a chart is to use VictoryTooltip
as a labelComponent
as in the example below:
<VictoryChart domain={{ x: [0, 11], y: [-10, 10] }} theme={VictoryTheme.clean} > <VictoryBar labelComponent={<VictoryTooltip />} data={[ { x: 2, y: 5, label: "right-side-up", }, { x: 4, y: -6, label: "upside-down", }, { x: 6, y: 4, label: "tiny" }, { x: 8, y: -5, label: "or a little \n BIGGER", }, { x: 10, y: 7, label: "automatically", }, ]} style={{ data: { width: 20 }, }} /> </VictoryChart>
When tooltips are added to a chart in this way, defaultEvents
on VictoryTooltip
are automatically added to the component using them, in this case VictoryBar
. By default, VictoryTooltip
will adjust its position, orientation, and the width and height of its container to match the corresponding data and labels.
Customizing Tooltips
Tooltips can be customized directly on the VictoryTooltip
component
<VictoryChart domain={{ x: [0, 11], y: [-10, 10] }} theme={VictoryTheme.clean} > <VictoryBar labelComponent={ <VictoryTooltip cornerRadius={({ datum }) => datum.x > 6 ? 0 : 20 } pointerLength={({ datum }) => datum.y > 0 ? 5 : 20 } flyoutStyle={{ stroke: ({ datum }) => datum.x === 10 ? "tomato" : "black", }} /> } data={[ { x: 2, y: 5, label: "right-side-up", }, { x: 4, y: -6, label: "upside-down", }, { x: 6, y: 4, label: "tiny" }, { x: 8, y: -5, label: "or a little \n BIGGER", }, { x: 10, y: 7, label: "automatically", }, ]} style={{ data: { width: 20 }, }} /> </VictoryChart>
VictoryTooltip
is composed of VictoryLabel
and the primitive Flyout
component. Both of these components are highly configurable, but may also be replaced if necessary.
const colors = VictoryTheme.clean.palette.cool; function CustomFlyout(props) { const { x, y, orientation } = props; const newY = orientation === "bottom" ? y - 35 : y + 35; return ( <g> <circle cx={x} cy={newY} r="20" stroke={colors[0]} fill="none" /> <circle cx={x} cy={newY} r="25" stroke={colors[1]} fill="none" /> <circle cx={x} cy={newY} r="30" stroke={colors[2]} fill="none" /> </g> ); } function App() { return ( <VictoryChart domain={{ x: [0, 11], y: [-10, 10], }} theme={VictoryTheme.clean} > <VictoryBar labelComponent={ <VictoryTooltip flyoutComponent={ <CustomFlyout /> } /> } data={[ { x: 2, y: 5, label: "A" }, { x: 4, y: -6, label: "B" }, { x: 6, y: 4, label: "C" }, { x: 8, y: -5, label: "D" }, { x: 10, y: 7, label: "E" }, ]} style={{ data: { width: 20 }, }} /> </VictoryChart> ); } render(<App />);
Tooltips with VictoryVoronoiContainer
Voronoi tooltips are useful for adding tooltips to a line, or adding tooltips to data points that
are too small to hover over effectively. VictoryVoronoiContainer
calculates a voronoi diagram
based on the data of every child component it renders. The voronoi data is used to associate a
mouse position with its nearest data point(s). When VictoryVoronoiContainer
is added as the
containerComponent
of your chart, changes in mouse position will add and remove the active
prop
on appropriate data and label elements.
<VictoryChart domain={{ x: [0, 5], y: [-5, 5] }} containerComponent={ <VictoryVoronoiContainer /> } theme={VictoryTheme.clean} > <VictoryScatter size={({ active }) => active ? 5 : 3 } labels={({ datum }) => datum.y} labelComponent={<VictoryTooltip />} data={[ { x: 1, y: -4 }, { x: 2, y: 4 }, { x: 3, y: 2 }, { x: 4, y: 1 }, ]} /> <VictoryScatter size={(datum, active) => active ? 5 : 3 } labels={({ datum }) => datum.y} labelComponent={<VictoryTooltip />} data={[ { x: 1, y: -3 }, { x: 2, y: 3 }, { x: 3, y: 3 }, { x: 4, y: 0 }, ]} /> <VictoryScatter data={[ { x: 1, y: 4 }, { x: 2, y: -4 }, { x: 3, y: -2 }, { x: 4, y: -3 }, ]} labels={({ datum }) => datum.y} labelComponent={<VictoryTooltip />} size={({ active }) => active ? 5 : 3 } /> </VictoryChart>
Multi-point Tooltips with VictoryVoronoiContainer
VictoryVoronoiContainer
can also be used to create multi-point labels when the labels
prop is
provided. In the example below the voronoiDimension
prop indicates that the voronoi diagram
will only be specific to the x dimension. For a given mouse position, all data matching the
associated x value will be activated regardless of y value. In the following example, this leads to
several tooltips being active at the same time. Provide a labels
and (optionally) a
labelComponent
prop to configure multi-point labels.
<VictoryChart domainPadding={{ y: 10 }} containerComponent={ <VictoryVoronoiContainer voronoiDimension="x" labels={({ datum }) => `y: ${datum.y}` } labelComponent={ <VictoryTooltip cornerRadius={0} flyoutStyle={{ fill: "white", }} /> } /> } theme={VictoryTheme.clean} > <VictoryLine data={[ { x: 1, y: 5, l: "one" }, { x: 1.5, y: 5, l: "one point five", }, { x: 2, y: 4, l: "two" }, { x: 3, y: -2, l: "three" }, ]} style={{ data: { stroke: "tomato", strokeWidth: ({ active }) => active ? 4 : 2, }, labels: { fill: "tomato" }, }} /> <VictoryLine data={[ { x: 1, y: -3, l: "red" }, { x: 2, y: 5, l: "green" }, { x: 3, y: 3, l: "blue" }, ]} style={{ data: { stroke: "blue", strokeWidth: ({ active }) => active ? 4 : 2, }, labels: { fill: "blue" }, }} /> <VictoryLine data={[ { x: 1, y: 5, l: "cat" }, { x: 2, y: -4, l: "dog" }, { x: 3, y: -2, l: "bird" }, ]} style={{ data: { stroke: "black", strokeWidth: ({ active }) => active ? 4 : 2, }, labels: { fill: "black" }, }} /> </VictoryChart>
VictoryVoronoiContainer
also has a mouseFollowTooltips
boolean prop that works with single point and multi-point tooltip labels.
<VictoryChart domain={{ y: [0, 6] }} containerComponent={ <VictoryVoronoiContainer mouseFollowTooltips voronoiDimension="x" labels={({ datum }) => `y: ${datum.y}` } /> } theme={VictoryTheme.clean} > <VictoryScatter style={{ data: { fill: "lightblue" }, labels: { fill: "lightblue" }, }} data={[ { x: 0, y: 2 }, { x: 2, y: 3 }, { x: 4, y: 4 }, { x: 6, y: 5 }, ]} /> <VictoryScatter data={[ { x: 2, y: 2 }, { x: 4, y: 3 }, { x: 6, y: 4 }, { x: 8, y: 5 }, ]} /> </VictoryChart>
Tooltips with Other Events
VictoryTooltip
automatically attaches events to data components. When events of the same type are specified for data components, it is necessary to reconcile events so that tooltips still work. For web, the default tooltip events are:
VictoryTooltip
uses defaultEvents
which are prepended onto any events array provided in props. When events
container onMouseOver
and onMouseOut
events, they will interfere with the defaultEvents
on VictoryTooltip
to correct this, your events prop will need to return the same mutations as defaultEvents
. Read about tooltip events here.
static defaultEvents = [{
target: "data",
eventHandlers: {
onMouseOver: () => ({
target: "labels",
mutation: () => ({ active: true })
}),
onMouseOut: () => ({
target: "labels",
mutation: () => ({ active: undefined })
}),
onFocus: () => ({
target: "labels",
mutation: () => ({ active: true })
}),
onBlur: () => ({
target: "labels",
mutation: () => ({ active: undefined })
})
}
}];
When other onMouseOver
and onMouseOut
events are specified for data, the event returns described above must be added to the events for tooltips to continue to work properly.
<VictoryChart domain={{ x: [0, 11], y: [-10, 10] }} theme={VictoryTheme.clean} > <VictoryBar labelComponent={<VictoryTooltip />} data={[ { x: 2, y: 5, label: "A" }, { x: 4, y: -6, label: "B" }, { x: 6, y: 4, label: "C" }, { x: 8, y: -5, label: "D" }, { x: 10, y: 7, label: "E" }, ]} style={{ data: { width: 20 }, }} events={[ { target: "data", eventHandlers: { onMouseOver: () => { return [ { target: "data", mutation: () => ({ style: { fill: "gold", width: 30, }, }), }, { target: "labels", mutation: () => ({ active: true, }), }, ]; }, onMouseOut: () => { return [ { target: "data", mutation: () => {}, }, { target: "labels", mutation: () => ({ active: false, }), }, ]; }, }, }, ]} /> </VictoryChart>
Custom Tooltips - Victory Label
function CustomLabel(props) { return ( <g> <VictoryLabel {...props} /> <VictoryTooltip {...props} x={226} y={197} orientation="top" pointerLength={0} cornerRadius={50} flyoutWidth={100} flyoutHeight={100} flyoutStyle={{ fill: "#bdbdbd", }} /> </g> ); } CustomLabel.defaultEvents = VictoryTooltip.defaultEvents; function App() { return ( <VictoryPie theme={VictoryTheme.clean} style={{ labels: { fill: "white" }, }} innerRadius={80} labelRadius={100} radius={140} labelComponent={<CustomLabel />} data={[ { x: 1, y: 5, label: "Dogs" }, { x: 2, y: 4, label: "Cats" }, { x: 3, y: 2, label: "Rabbits", }, { x: 4, y: 3, label: "Birds" }, { x: 5, y: 1, label: "Snakes" }, ]} /> ); } render(<App />);
Custom Tooltips - Wrapping
The events that control VictoryTooltip
are stored on the static defaultEvents
property. Wrapped instances of VictoryTooltip
will need to replicate or hoist this property in order to add automatic events to the components that use them.
function CustomTooltip(props) { const { x, y } = props; const rotation = `rotate(45 ${x} ${y})`; return ( <g transform={rotation}> <VictoryTooltip {...props} renderInPortal={false} /> </g> ); } CustomTooltip.defaultEvents = VictoryTooltip.defaultEvents; function App() { return ( <VictoryChart domain={{ x: [0, 11], y: [-10, 10], }} theme={VictoryTheme.clean} > <VictoryBar labelComponent={ <CustomTooltip /> } data={[ { x: 2, y: 5, label: "A" }, { x: 4, y: -6, label: "B" }, { x: 6, y: 4, label: "C" }, { x: 8, y: -5, label: "D" }, { x: 10, y: 7, label: "E" }, ]} /> </VictoryChart> ); } render(<App />);
Victory Native
In Victory Native tooltips are much more reliable when using VictoryVoronoiContainer
. Using VictoryVoronoiContainer
registers all touch events on the container itself, which mitigates interference with other chart elements, which can be a problem on some platforms. Showing the closest data point with VictoryVoronoiContainer
also increases the tap targets for the tooltip, which can otherwise be quite small. Set VictoryVoronoiContainer
as the containerComponent
prop on the outermost Victory component.
<VictoryChart
containerComponent={
<VictoryVoronoiContainer />
}
>
<VictoryScatter
labelComponent={<VictoryTooltip />}
labels={({ datum }) => datum.y}
style={{
data: {
fill: ({ datum }) => datum.fill,
},
}}
data={[
{ x: 1, y: 3 },
{ x: 3, y: 5 },
]}
/>
</VictoryChart>