)}
+ snapTooltipToDataX
>
node`, should return the inner tooltip contents on trigger.
-onClick | PropTypes.func | - | `func({ data, datum, event, color [, seriesKey] })`, passed to all child series (or voronoi)
-onMouseMove | PropTypes.func | - | `func({ data, datum, event, color })`, passed to all child series (or voronoi). only needed if you are rolling your own tooltips (see below)
+innerRef | PropTypes.func | - | Callback ref that is set on the inner `svg` element
+margin | PropTypes.shape({ top: PropTypes.number, right: PropTypes.number, bottom: PropTypes.number, left: PropTypes.number }) | { top: 64, right: 64, bottom: 64, left: 64 } | chart margin, leave room for axes and labels! a "complete" margin will be created using the default top/right/bottom/left values meaning that you have to explicitly set each dimension for full control. also note that a value of `0` may clip LineSeries and PointSeries.
+onClick | PropTypes.func | - | `func({ datum, event [, coords [, data, [, color [, series [, seriesKey]]]]] })`, passed to all child series (or voronoi)
+onMouseMove | PropTypes.func | - | `func({ datum, event [, coords [, data, [, color [, series [, seriesKey]]]]] })`, passed to all child series (or voronoi). only needed if you are rolling your own tooltips (see below)
onMouseLeave | PropTypes.func | - | `func()`, passed to all child series (or voronoi). only needed if you are rolling your own tooltips (see below)
-xScale | scaleShape.isRequired | - | scale config, see below.
-yScale | scaleShape.isRequired | - | scale config, see below.
+renderTooltip | PropTypes.func | - | `({ datum, event [, coords [, data, [, color [, series [, seriesKey]]]]] }) => node`, should return the inner tooltip contents on trigger.
showXGrid | PropTypes.bool | false | whether to show vertical gridlines
showYGrid | PropTypes.bool | false | whether to show vertical gridlines
+showVoronoi | PropTypes.bool | false | convenience prop for debugging to view the underlying voronoi if eventTrigger='voronoi'
+snapTooltipToDataX | PropTypes.bool | false | whether to pass coords.x in event callbacks, which has the effect of snapping a tooltip to data x values
+snapTooltipToDataY | PropTypes.bool | false | whether to pass coords.y in event callbacks, which has the effect of snapping a tooltip to data y values
theme | themeShape | false | theme shape, see below
-useVoronoi | PropTypes.bool | false | whether to compute and use a voronoi for all datapoints (with x, y values) / mouse interactions
-showVoronoi | PropTypes.bool | false | convenience prop for debugging to view the underlying voronoi if used
-
+width | PropTypes.number.isRequired | - | Required width of the chart (including margin). Check out `withParentSize` in the examples for responsive charts.
+xScale | scaleShape.isRequired | - | scale config, see below.
+yScale | scaleShape.isRequired | - | scale config, see below.
#### Scale config
X and y-scales are configured using `xScale` and `yScale` config props which essentially configure d3/vx scales:
@@ -83,12 +87,14 @@ X and y-scales are configured using `xScale` and `yScale` config props which ess
const scaleConfigShape = PropTypes.shape({
type: PropTypes.oneOf([
'time',
+ 'timeUtc',
'linear',
'band',
+ 'ordinal',
]).isRequired,
includeZero: PropTypes.bool,
- // these would override any computation done by xyplot, allowing specific ranges or colors
+ // these would override any computation done by XYChart, allowing specific ranges or colors
// see storybook for more examples
range: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.string])),
rangeRound: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.string])),
@@ -96,50 +102,7 @@ const scaleConfigShape = PropTypes.shape({
});
```
-#### Theme
-A theme object with the following shape can be passed to `` to style the chart, axes, and series.
-See `@data-ui/theme` for an example.
-
-```javascript
-export const themeShape = PropTypes.shape({
- gridStyles: PropTypes.shape({
- stroke: PropTypes.string,
- strokeWidth: PropTypes.number,
- }),
- xAxisStyles: PropTypes.shape({
- stroke: PropTypes.string,
- strokeWidth: PropTypes.number,
- label: PropTypes.shape({
- bottom: PropTypes.object,
- top: PropTypes.object,
- }),
- }),
- yAxisStyles: PropTypes.shape({
- stroke: PropTypes.string,
- strokeWidth: PropTypes.number,
- label: PropTypes.shape({
- left: PropTypes.object,
- right: PropTypes.object,
- }),
- })
- xTickStyles: PropTypes.shape({
- stroke: PropTypes.string,
- tickLength: PropTypes.number,
- label: PropTypes.shape({
- bottom: PropTypes.object,
- top: PropTypes.object,
- }),
- }),
- yTickStyles: PropTypes.shape({
- stroke: PropTypes.string,
- tickLength: PropTypes.number,
- label: PropTypes.shape({
- left: PropTypes.object,
- right: PropTypes.object,
- }),
- }),
-});
-```
+Entries in scale objects are shallow checked so new objects don't trigger re-renders.
### `` and ``
@@ -160,26 +123,25 @@ tickValues | PropTypes.arrayOf( PropTypes.oneOfType([ PropTypes.number, PropType
Several types of series types are exported by the package, and can be used in combination. See the storybook source for more proptables for your series of interest. Here is an overview of scale support and data shapes:
-Series | supported x scale type | supported y scale types | data shape | voronoi compatible for tooltips?
------------- | ------------- | ------- | ---- | ----
-`` | time, linear | linear | `{ x, y [, y0, y1, fill, stroke] }`* | yes*
-`` | time, linear, band | linear | `{ x, y [, fill, stroke] }` | no
-`` | time, linear | linear | `{ x, y [, stroke] }` | yes
-`` | time, linear | time, linear | `{ x, y [size, fill, stroke, label] }` | yes
-`` | time, linear | linear | `{ x, y [, [stackKey(s)]] }`* | no
-`` | band | linear | `{ x, y }` (colors controlled with stackFills & stackKeys) | no
-`` | band | linear | `{ x, y }` (colors controlled with groupFills & groupKeys) | no
-`` | time, linear | y is computed | `{ x [, size] }` | no
-`` | time, linear | linear | `{ x0, x1 [, fill, stroke] }` | no
-`` | linear, band | band, linear | `{ x (or y), min, max, median, firstQuartile, thirdQuartile, outliers [, fill, stroke] }` | no
-`` | linear, band | band, linear | `{ x (or y), binData [, fill, stroke] }` | no
+Series | supported x scale type | supported y scale types | data shape | supported `eventTrigger`s | shared tooltip compatible
+------------ | ------------- | ------- | ---- | ---- | ----
+`` | `time`, `linear` | `linear` | `{ x, y [, y0, y1, fill, stroke] }`* | `series`, `container`, `voronoi`* | yes
+`` | `time`, `linear`, `band` | `linear` | `{ x, y [, fill, stroke] }` | `series`, `container` | yes
+`` | `time`, `linear` | `linear` | `{ x, y [, stroke] }` | `series`, `container`, `voronoi` | yes
+`` | `time`, `linear` | `time`, `linear` | `{ x, y [size, fill, stroke, label] }` | `series`, `container` (not best for dense data) `voronoi` | yes
+`` | `time`, `linear` | `linear` | `{ x, y [, [stackKey(s)]] }`* | `series` | data for all stack keys should be in passed `datum`
+`` | `band` | `linear` | `{ x, y }` (colors controlled with stackFills & stackKeys) | `series` | data for all stack keys should be in passed `datum`
+`` | `band` | `linear` | `{ x, y }` (colors controlled with groupFills & groupKeys) | `series` | data for all group keys should be in passed `datum`
+`` | `time`, `linear` | y is computed | `{ x [, size] }` | `series` | no
+`` | `time`, `linear` | `linear` | `{ x0, x1 [, fill, stroke] }` | `series` | no
+`` | `linear`, `band` | `band`, `linear` | `{ x (or y), min, max, median, firstQuartile, thirdQuartile, outliers [, fill, stroke] }` | `series` | no
+`` | `linear`, `band` | `band`, `linear` | `{ x (or y), binData [, fill, stroke] }` | `series` | no
\* The y boundaries of the `` may be specified by either
- defined `y0` and `y1` values or
- a single `y` value, in which case its lower bound is set to 0 (a "closed" area series)
-It is worth noting that voronoi overlays require a defined `y` attribute, so use of voronoi with only `y0` and `y1` values will not work.
#### CirclePackSeries
@@ -192,25 +154,22 @@ This series implements the Circle packing algorithm described by ` with `` yourself, which accepts props for additional customization:
Name | Type | Default | Description
------------ | ------------- | ------- | ----
-children | PropTypes.func or PropTypes.object | - | Child function (to call) or element (to clone) with onMouseMove, onMouseLeave, and tooltipData props/keys
+children | PropTypes.func or PropTypes.object | - | Child function (to call) or element (to clone) with `onMouseMove`, `onMouseLeave`, and `tooltipData` props
className | PropTypes.string | - | Class name to add to the `
` container wrapper
renderTooltip | PropTypes.func.isRequired | - | Renders the _contents_ of the tooltip, signature of `({ event, data, datum, color }) => node`. If this function returns a `falsy` value, a tooltip will not be rendered.
styles | PropTypes.object | {} | Styles to add to the `
` container wrapper
@@ -219,21 +178,9 @@ tooltipProps | PropTypes.object | - | Props that are passed to `TooltipComponent
tooltipTimeout | PropTypes.number | 200 | Timeout in ms for the tooltip to hide upon calling `onMouseLeave`
-#### ``
-
-
-
-
-For series components that have "small" mouse areas, such as `PointSeries` and `LineSeries`, you may opt to use an invisible Voronoi overlay on top of the visualization to increase the target area of interaction sites and improve user experience. To enable this simply set `useVoronoi` to `true` on the `` component and optionally use the convenience prop `showVoronoi` to view or debug it. Note that this will compute a voronoi layout for _all_ data points (with defined `x` and `y` datum values!) across all series.
-
-#### Note ‼️
-Because of the polygonal shapes generated by the voronoi layout, you probably _don't_ want to use this option if you are e.g., only rendering a `BarSeries` because the bar points represent the tops of the bars and thus polygons for one bar may overlap the rect of another bar (again, you may use `showVoronoi` to debug this).
-
-
-
-
+Note that to correctly position a tooltip, the `` `onMouseMove` function minimally requires an `event` or `coords` object of the form `{ x: Number, y: Number }`. If `coords` is specified it takes precedent over any position computed from the event. See function signatures below for more.
-#### ``
+##### ``
The `` component may be used in combination with tooltips for additional visual feedback (see the storybook for many examples!). Simply pass the component as a child of `` and it will automatically position itself upon tooltip trigger. Compared to a tooltip, this component snaps to actual data points for improved precision. It accepts the following props:
Name | Type | Default | Description
@@ -252,6 +199,99 @@ stroke | PropTypes.oneOfType([PropTypes.func, PropTypes.string]) | data-ui/theme
strokeDasharray | PropTypes.oneOfType([PropTypes.func, PropTypes.string]) | `3, 3` | The stroke-dash-array of both horizontal and vertical lines
strokeWidth | PropTypes.oneOfType([PropTypes.func, PropTypes.number]) | 1 | The strokeWidth of both horizontal and vertical lines
+
+#### Mouse Events & Triggers
+`XYChart` has hooks for `mousemove`, `mouseleave`, and `click` events that can be triggered at different levels as specified by the `eventTrigger` prop:
+
+##### eventTrigger='series'
+For the `series` event trigger, `XYChart` will pass along event handlers to its child series unless a series has `disableMouseEvents` set to `true`, and any event handlers defined at the series level will _override_ those defined at the `XYChart` level. Series-level events are triggered by interactions with the series DOM elements themselves.
+
+##### eventTrigger='container'
+For the `container` event trigger, the `XYChart` container will intercept all mouse events and event handlers will be called with all `datum`s nearest the hovered x value. This type of event trigger is useful if you want to implement a shared tooltip. Note that `data` passed to series should be sorted by x-value for this to work correctly.
+
+##### eventTrigger='voronoi'
+
+
+
+
+For series components that have "small" mouse areas, such as `PointSeries` and `LineSeries`, you may opt to use an invisible Voronoi overlay on top of the visualization to increase the target area of interaction sites and improve user experience. To view or debug a voronoi you may set the convenience prop `showVoronoi` to `true`. Note that this will compute a voronoi layout for _all_ data points across _all_ series.
+
+##### Note ‼️
+It is worth noting that voronoi overlays require a defined `y` attribute, so use of voronoi with only `y0` and `y1` values will not work (this is reflected in the compatibility table above).
+
+Additionally, because of the polygonal shapes generated by the voronoi layout, you probably _don't_ want to use this option if you are e.g., only rendering a `BarSeries` because the bar points represent the tops of the bars and thus polygons for one bar may overlap the rect of another bar (again, you may use `showVoronoi` to debug this).
+
+
+
+
+
+#### Functions and Function Signatures
+
+`XYChart` and all series support `onMouseMove`, `onMouseLeave`, and `onClick` event handlers with the following signatures:
+
+```
+onMouseMove({ datum, event [, coords [, data, [, color [, series [, seriesKey]]]]] })
+onClick({ datum, event [, coords [, data, [, color [, series [, seriesKey]]]]] })
+onMouseLeave()
+```
+
+A `seriesKey` is passed when `eventTrigger=series` for ``, ``, or ``. It corresponds to the relevant `stackKey` or `groupKey` that triggered the event.
+
+`series` is passed when `eventTrigger=container` and represents an object of `datum`s across all series components nearest the current mouse `x`. The _closest_ `datum` across all series components is passed as `datum` in the function signature. Within the `series` object, `datum`s are keyed on the `seriesKey` prop set on the series component itself. **similar to React, if `seriesKey` is not set its index as a child of `XYChart` will be used which is more error prone**
+
+`coords` is an object of the form `{ x: Number, y: Number }`. `XYChart` passes `x` and `y` only if `snapTooltipToDataX` or `snapTooltipToDataY` are `true`, respectively.
+
+##### Programmatically triggering tooltips
+`XYChart` exposes hooks to manually trigger any of these handlers with the `eventTriggerRefs` prop. Similar to `React` `ref`s, this prop is a callback function that is called by `XYChart` after mounting. The callback receives an object as input, with keys corresponding to the event type names and respective handlers as values: `eventTriggerRefs({ click, mousemove, mouseleave })`. The ref handlers have the same signatures as defined above.
+
+Note that `snapTooltipToData*` props will still have an effect when events are triggered this way.
+
+
+#### Theme
+A theme object with the following shape can be passed to `` to style the chart, axes, and series.
+See `@data-ui/theme` for an example.
+
+```javascript
+export const themeShape = PropTypes.shape({
+ gridStyles: PropTypes.shape({
+ stroke: PropTypes.string,
+ strokeWidth: PropTypes.number,
+ }),
+ xAxisStyles: PropTypes.shape({
+ stroke: PropTypes.string,
+ strokeWidth: PropTypes.number,
+ label: PropTypes.shape({
+ bottom: PropTypes.object,
+ top: PropTypes.object,
+ }),
+ }),
+ yAxisStyles: PropTypes.shape({
+ stroke: PropTypes.string,
+ strokeWidth: PropTypes.number,
+ label: PropTypes.shape({
+ left: PropTypes.object,
+ right: PropTypes.object,
+ }),
+ })
+ xTickStyles: PropTypes.shape({
+ stroke: PropTypes.string,
+ tickLength: PropTypes.number,
+ label: PropTypes.shape({
+ bottom: PropTypes.object,
+ top: PropTypes.object,
+ }),
+ }),
+ yTickStyles: PropTypes.shape({
+ stroke: PropTypes.string,
+ tickLength: PropTypes.number,
+ label: PropTypes.shape({
+ left: PropTypes.object,
+ right: PropTypes.object,
+ }),
+ }),
+});
+```
+
More on the way.
### Other
diff --git a/packages/xy-chart/src/chart/XYChart.jsx b/packages/xy-chart/src/chart/XYChart.jsx
index 5340f631..5481bc8c 100644
--- a/packages/xy-chart/src/chart/XYChart.jsx
+++ b/packages/xy-chart/src/chart/XYChart.jsx
@@ -5,33 +5,39 @@ import Grid from '@vx/grid/build/grids/Grid';
import Group from '@vx/group/build/Group';
import WithTooltip, { withTooltipPropTypes } from '@data-ui/shared/build/enhancer/WithTooltip';
+import collectVoronoiData from '../utils/collectVoronoiData';
+import findClosestDatums from '../utils/findClosestDatums';
+import shallowCompareObjectEntries from '../utils/shallowCompareObjectEntries';
import Voronoi from './Voronoi';
import {
- collectDataFromChildSeries,
componentName,
isAxis,
- isBarSeries,
- isCirclePackSeries,
isCrossHair,
- isDefined,
isReferenceLine,
isSeries,
getChildWithName,
- getScaleForAccessor,
numTicksForWidth,
numTicksForHeight,
propOrFallback,
} from '../utils/chartUtils';
+import collectScalesFromProps from '../utils/collectScalesFromProps';
+import getChartDimensions from '../utils/getChartDimensions';
import { scaleShape, themeShape } from '../utils/propShapes';
+export const CONTAINER_TRIGGER = 'container';
+export const SERIES_TRIGGER = 'series';
+export const VORONOI_TRIGGER = 'voronoi';
+
export const propTypes = {
...withTooltipPropTypes,
ariaLabel: PropTypes.string.isRequired,
children: PropTypes.node,
- width: PropTypes.number.isRequired,
+ eventTrigger: PropTypes.oneOf([CONTAINER_TRIGGER, SERIES_TRIGGER, VORONOI_TRIGGER]),
+ eventTriggerRefs: PropTypes.func,
height: PropTypes.number.isRequired,
+ innerRef: PropTypes.func,
margin: PropTypes.shape({
top: PropTypes.number,
right: PropTypes.number,
@@ -39,17 +45,23 @@ export const propTypes = {
left: PropTypes.number,
}),
renderTooltip: PropTypes.func,
- xScale: scaleShape.isRequired,
- yScale: scaleShape.isRequired,
showXGrid: PropTypes.bool,
showYGrid: PropTypes.bool,
- theme: themeShape,
- useVoronoi: PropTypes.bool,
showVoronoi: PropTypes.bool,
+ snapTooltipToDataX: PropTypes.bool,
+ snapTooltipToDataY: PropTypes.bool,
+ theme: themeShape,
+ width: PropTypes.number.isRequired,
+ xScale: scaleShape.isRequired,
+ yScale: scaleShape.isRequired,
};
-const defaultProps = {
+export const defaultProps = {
children: null,
+ disableMouseEvents: false,
+ eventTrigger: SERIES_TRIGGER,
+ eventTriggerRefs: null,
+ innerRef: null,
margin: {
top: 64,
right: 64,
@@ -57,92 +69,24 @@ const defaultProps = {
left: 64,
},
renderTooltip: null,
+ showVoronoi: false,
showXGrid: false,
showYGrid: false,
+ snapTooltipToDataX: false,
+ snapTooltipToDataY: false,
+ styles: null,
theme: {},
- // @TODO tooltipProps
- // voronoi
- useVoronoi: false,
- showVoronoi: false,
};
// accessors
-const getX = d => d.x;
-const getY = d => d.y;
-const xString = d => getX(d).toString();
+const getX = d => d && d.x;
+const getY = d => d && d.y;
class XYChart extends React.PureComponent {
- static collectScalesFromProps(props) {
- const { xScale: xScaleObject, yScale: yScaleObject, children } = props;
- const { innerWidth, innerHeight } = XYChart.getDimmensions(props);
- const { allData } = collectDataFromChildSeries(children);
-
- const xScale = getScaleForAccessor({
- allData,
- minAccessor: d => (typeof d.x0 !== 'undefined' ? d.x0 : d.x),
- maxAccessor: d => (typeof d.x1 !== 'undefined' ? d.x1 : d.x),
- range: [0, innerWidth],
- ...xScaleObject,
- });
-
- const yScale = getScaleForAccessor({
- allData,
- minAccessor: d => (typeof d.y0 !== 'undefined' ? d.y0 : d.y),
- maxAccessor: d => (typeof d.y1 !== 'undefined' ? d.y1 : d.y),
- range: [innerHeight, 0],
- ...yScaleObject,
- });
-
- React.Children.forEach(children, (Child) => { // Child-specific scales or adjustments here
- const name = componentName(Child);
- if (isBarSeries(name) && xScaleObject.type !== 'band') {
- const dummyBand = getScaleForAccessor({
- allData,
- minAccessor: xString,
- maxAccessor: xString,
- type: 'band',
- rangeRound: [0, innerWidth],
- paddingOuter: 1,
- });
-
- const offset = dummyBand.bandwidth() / 2;
- xScale.range([offset, innerWidth - offset]);
- xScale.barWidth = dummyBand.bandwidth();
- xScale.offset = offset;
- }
- if (isCirclePackSeries(name)) {
- yScale.domain([-innerHeight / 2, innerHeight / 2]);
- }
- });
-
- return {
- xScale,
- yScale,
- };
- }
-
- static getDimmensions(props) {
- const { margin, width, height } = props;
- const completeMargin = { ...defaultProps.margin, ...margin };
- return {
- margin: completeMargin,
- innerHeight: height - completeMargin.top - completeMargin.bottom,
- innerWidth: width - completeMargin.left - completeMargin.right,
- };
- }
-
static getStateFromProps(props) {
- const { margin, innerWidth, innerHeight } = XYChart.getDimmensions(props);
- const { xScale, yScale } = XYChart.collectScalesFromProps(props);
-
- const voronoiData = React.Children.toArray(props.children).reduce((result, Child) => {
- if (isSeries(componentName(Child)) && !Child.props.disableMouseEvents) {
- return result.concat(
- Child.props.data.filter(d => isDefined(getX(d)) && isDefined(getY(d))),
- );
- }
- return result;
- }, []);
+ const { margin, innerWidth, innerHeight } = getChartDimensions(props);
+ const { xScale, yScale } = collectScalesFromProps(props);
+ const voronoiData = collectVoronoiData({ children: props.children, getX, getY });
return {
innerHeight,
@@ -161,19 +105,41 @@ class XYChart extends React.PureComponent {
// if renderTooltip is passed we return another XYChart wrapped in WithTooltip
// therefore we don't want to compute state if the nested chart will do so
this.state = props.renderTooltip ? {} : XYChart.getStateFromProps(props);
+
+ this.getDatumCoords = this.getDatumCoords.bind(this);
+ this.handleClick = this.handleClick.bind(this);
+ this.handleMouseLeave = this.handleMouseLeave.bind(this);
+ this.handleMouseMove = this.handleMouseMove.bind(this);
+ this.handleContainerEvent = this.handleContainerEvent.bind(this);
+ }
+
+ componentDidMount() {
+ if (!this.props.renderTooltip && this.props.eventTriggerRefs) {
+ this.props.eventTriggerRefs({
+ mousemove: this.handleMouseMove,
+ mouseleave: this.handleMouseLeave,
+ click: this.handleClick,
+ });
+ }
}
componentWillReceiveProps(nextProps) {
- if ([ // recompute scales if any of the following change
+ let shouldComputeScales = false;
+ if ([
+ 'width',
'height',
+ 'children',
+ ].some(prop => this.props[prop] !== nextProps[prop])) {
+ shouldComputeScales = true;
+ }
+ if ([
'margin',
- 'width',
'xScale',
'yScale',
- ].some(prop => this.props[prop] !== nextProps[prop])) {
- // @TODO update only on children updates that require new scales
- this.setState(XYChart.getStateFromProps(nextProps));
+ ].some(prop => !shallowCompareObjectEntries(this.props[prop], nextProps[prop]))) {
+ shouldComputeScales = true;
}
+ if (shouldComputeScales) this.setState(XYChart.getStateFromProps(nextProps));
}
getNumTicks(innerWidth, innerHeight) {
@@ -185,6 +151,63 @@ class XYChart extends React.PureComponent {
};
}
+ getDatumCoords(datum) {
+ const { snapTooltipToDataX, snapTooltipToDataY } = this.props;
+ const { xScale, yScale, margin } = this.state;
+ const coords = {};
+ // tooltip operates in full width/height space so we must account for margins
+ if (datum && snapTooltipToDataX) coords.x = xScale(getX(datum)) + margin.left;
+ if (datum && snapTooltipToDataY) coords.y = yScale(getY(datum)) + margin.top;
+ return coords;
+ }
+
+ handleContainerEvent(event) {
+ const { xScale, yScale } = this.state;
+ const { children } = this.props;
+ const { closestDatum, series } = findClosestDatums({
+ children,
+ event,
+ getX,
+ getY,
+ xScale,
+ yScale,
+ });
+ if (closestDatum || Object.keys(series).length > 0) {
+ event.persist();
+ const args = { event, datum: closestDatum, series };
+ if (event.type === 'mousemove') this.handleMouseMove(args);
+ else if (event.type === 'click') this.handleClick(args);
+ }
+ }
+
+ handleMouseMove(args) {
+ if (this.props.onMouseMove) {
+ this.props.onMouseMove({
+ ...args,
+ coords: {
+ ...this.getDatumCoords(args.datum),
+ ...args.coords,
+ },
+ });
+ }
+ }
+
+ handleMouseLeave(args) {
+ if (this.props.onMouseLeave) this.props.onMouseLeave(args);
+ }
+
+ handleClick(args) {
+ if (this.props.onClick) {
+ this.props.onClick({
+ ...args,
+ coords: {
+ ...this.getDatumCoords(args.datum),
+ ...args.coords,
+ },
+ });
+ }
+ }
+
render() {
if (this.props.renderTooltip) {
return (
@@ -196,18 +219,16 @@ class XYChart extends React.PureComponent {
const {
ariaLabel,
+ eventTrigger,
children,
showXGrid,
showYGrid,
theme,
height,
width,
- onClick,
- onMouseLeave,
- onMouseMove,
+ innerRef,
tooltipData,
showVoronoi,
- useVoronoi,
} = this.props;
const {
@@ -224,13 +245,13 @@ class XYChart extends React.PureComponent {
const { numXTicks, numYTicks } = this.getNumTicks(innerWidth, innerHeight);
const barWidth = xScale.barWidth || (xScale.bandwidth && xScale.bandwidth()) || 0;
const CrossHairs = []; // ensure these are the top-most layer
-
return innerWidth > 0 && innerHeight > 0 && (