-
Notifications
You must be signed in to change notification settings - Fork 70
/
Copy pathWithTooltip.jsx
146 lines (126 loc) Β· 3.87 KB
/
WithTooltip.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import React from 'react';
import PropTypes from 'prop-types';
import localPoint from '@vx/event/build/localPoint';
import withTooltip from '@vx/tooltip/build/enhancers/withTooltip';
import TooltipWithBounds, {
withTooltipPropTypes as vxTooltipPropTypes,
} from '@vx/tooltip/build/tooltips/TooltipWithBounds';
export { default as Tooltip } from '@vx/tooltip/build/tooltips/Tooltip';
export const withTooltipPropTypes = {
onMouseMove: PropTypes.func, // expects to be called like func({ event, datum })
onMouseLeave: PropTypes.func, // expects to be called like func({ event, datum })
tooltipData: PropTypes.any,
};
export const propTypes = {
...vxTooltipPropTypes,
children: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired,
className: PropTypes.string,
HoverStyles: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
renderTooltip: PropTypes.func,
styles: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
TooltipComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
tooltipProps: PropTypes.object, // eslint-disable-line react/forbid-prop-types
tooltipTimeout: PropTypes.number,
};
const defaultProps = {
className: null,
HoverStyles: () => (
<style type="text/css">
{`
.vx-arc:hover,
.vx-bar:hover,
.vx-glyph-dot:hover {
opacity: 0.7;
}
`}
</style>
),
renderTooltip: null,
styles: { display: 'inline-block', position: 'relative' },
TooltipComponent: TooltipWithBounds,
tooltipProps: null,
tooltipTimeout: 200,
};
class WithTooltip extends React.PureComponent {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleMouseLeave = this.handleMouseLeave.bind(this);
this.tooltipTimeout = null;
}
componentWillUnmount() {
if (this.tooltipTimeout) {
clearTimeout(this.tooltipTimeout);
}
}
handleMouseMove({ event, datum, coords, ...rest }) {
const { showTooltip } = this.props;
if (this.tooltipTimeout) {
clearTimeout(this.tooltipTimeout);
}
let tooltipCoords = { x: 0, y: 0 };
if (event && event.target && event.type !== 'focus' && event.target.ownerSVGElement) {
tooltipCoords = localPoint(event.target.ownerSVGElement, event);
}
tooltipCoords = { ...tooltipCoords, ...coords };
showTooltip({
tooltipLeft: tooltipCoords.x,
tooltipTop: tooltipCoords.y,
tooltipData: {
event,
datum,
...rest,
},
});
}
handleMouseLeave() {
const { tooltipTimeout, hideTooltip } = this.props;
this.tooltipTimeout = setTimeout(() => {
hideTooltip();
}, tooltipTimeout);
}
render() {
const {
children,
className,
HoverStyles,
tooltipData,
tooltipOpen,
tooltipLeft,
tooltipTop,
tooltipProps,
renderTooltip,
styles,
TooltipComponent,
} = this.props;
const childProps = {
onMouseMove: this.handleMouseMove,
onMouseLeave: this.handleMouseLeave,
tooltipData,
};
const tooltipContent =
renderTooltip && tooltipOpen && TooltipComponent && renderTooltip(tooltipData);
return (
<div style={styles} className={className}>
{/* inject props or pass to a function depending on child */}
{typeof children === 'function'
? children(childProps)
: React.cloneElement(React.Children.only(children), childProps)}
{!!tooltipContent && (
<TooltipComponent
key={Math.random()}
top={tooltipTop}
left={tooltipLeft}
{...tooltipProps}
>
{tooltipContent}
</TooltipComponent>
)}
{HoverStyles && <HoverStyles />}
</div>
);
}
}
WithTooltip.propTypes = propTypes;
WithTooltip.defaultProps = defaultProps;
export default withTooltip(WithTooltip);