Reputation: 15
I have to add the tooltip on react d3 v4 bar chart on mouseover.I have tried customized function mentioned below,
onMouseOverHandler(d){
var tooltip = d3Select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
tooltip.transition().duration(200).style("opacity", .9);
tooltip.html(d)
.style("left", d3Select(this).attr("cx") + "px")
.style("top", d3Select(this).attr("cy") + "px");
but it's not working. someone can you help me for this one.
Thanks, Arun S
Upvotes: 1
Views: 10328
Reputation: 117
Here I have described a solution to the same problem.
https://stackoverflow.com/a/56674517/2903711
The result looked this
Upvotes: -1
Reputation: 451
I added a tooltip to the example you linked to in your comment to this fork of the original GitHub repository.
I created a Tooltip
component. Of course, keep in mind that this isn't necessarily the "right" or only way to add a tooltip to a React application that uses D3.
I went through the following steps:
Created state in the Chart
component that tracks the data for which bar, if any, is currently hovered
Created onMouseOver
and onMouseOut
events in the Bars
component to determine which bar has just been hovered or left and pass that up to the Chart
component to set the new state
Passed the state from the Chart
component back down to a Tooltip
component I created
The Tooltip
component looks like this:
export default ({hoveredBar, scales}) => {
const { xScale, yScale } = scales
const styles = {
left: `${xScale(hoveredBar.title) - 30}px`,
top: `${yScale(hoveredBar.value)}px`
}
return (
<div className="Tooltip" style={styles}>
<table>
<thead>
<tr>
<th colSpan="2">{hoveredBar.title}</th>
</tr>
</thead>
<tbody>
<tr>
<td colSpan="1">Bodies</td>
<td colSpan="1">{hoveredBar.value}</td>
</tr>
<tr>
<td colSpan="1">Year</td>
<td colSpan="1">{hoveredBar.year}</td>
</tr>
</tbody>
</table>
</div>
)
}
I used it in the Chart
component, and tracked the currently hovered bar as state:
class Chart extends Component {
constructor(props) {
super(props)
this.xScale = scaleBand()
this.yScale = scaleLinear()
this.state = {
hoveredBar: null
}
}
render() {
const margins = { top: 50, right: 20, bottom: 100, left: 60 }
const svgDimensions = {
width: Math.max(this.props.parentWidth, 300),
height: 500
}
const maxValue = Math.max(...data.map(d => d.value))
const xScale = this.xScale
.padding(0.5)
.domain(data.map(d => d.title))
.range([margins.left, svgDimensions.width - margins.right])
const yScale = this.yScale
.domain([0, maxValue])
.range([svgDimensions.height - margins.bottom, margins.top])
return (
<div className="Chart">
<svg width={svgDimensions.width} height={svgDimensions.height}>
<Axes
scales={{ xScale, yScale }}
margins={margins}
svgDimensions={svgDimensions}
/>
<Bars
scales={{ xScale, yScale }}
margins={margins}
data={data}
maxValue={maxValue}
svgDimensions={svgDimensions}
onMouseOverCallback={datum => this.setState({hoveredBar: datum})}
onMouseOutCallback={datum => this.setState({hoveredBar: null})}
/>
</svg>
{ this.state.hoveredBar ?
<Tooltip
hoveredBar={this.state.hoveredBar}
scales={{ xScale, yScale }}
/> :
null
}
</div>
)
}
}
And I set the onMouseOver
and onMouseOut
events in the Bars
component:
export default class Bars extends Component {
constructor(props) {
super(props)
this.colorScale = scaleLinear()
.domain([0, this.props.maxValue])
.range(['#F3E5F5', '#7B1FA2'])
.interpolate(interpolateLab)
}
render() {
const { scales, margins, data, svgDimensions } = this.props
const { xScale, yScale } = scales
const { height } = svgDimensions
const bars = (
data.map(datum =>
<rect
key={datum.title}
x={xScale(datum.title)}
y={yScale(datum.value)}
height={height - margins.bottom - scales.yScale(datum.value)}
width={xScale.bandwidth()}
fill={this.colorScale(datum.value)}
onMouseOver={() => this.props.onMouseOverCallback(datum)}
onMouseOut={() => this.props.onMouseOutCallback(null)}
/>,
)
)
return (
<g>{bars}</g>
)
}
}
Upvotes: 6