diff --git a/src/chart_types/xy_chart/store/chart_state.test.ts b/src/chart_types/xy_chart/store/chart_state.test.ts index 3a77008179..f4fa3c0eb4 100644 --- a/src/chart_types/xy_chart/store/chart_state.test.ts +++ b/src/chart_types/xy_chart/store/chart_state.test.ts @@ -902,21 +902,63 @@ describe('Chart Store', () => { store.cursorPosition.x = -1; store.cursorPosition.y = -1; store.onBrushEndListener = brushEndListener; - expect(store.isCrosshairCursorVisible.get()).toBe(false); + expect(store.chartCursor.get()).toBe('default'); }); test('when cursor is within chart bounds and brush enabled', () => { store.cursorPosition.x = 10; store.cursorPosition.y = 10; store.onBrushEndListener = brushEndListener; - expect(store.isCrosshairCursorVisible.get()).toBe(true); + expect(store.chartCursor.get()).toBe('crosshair'); }); test('when cursor is within chart bounds and brush disabled', () => { store.cursorPosition.x = 10; store.cursorPosition.y = 10; store.onBrushEndListener = undefined; - expect(store.isCrosshairCursorVisible.get()).toBe(false); + expect(store.chartCursor.get()).toBe('default'); + }); + test('when cursor is within chart bounds and brush enabled but over one geom', () => { + store.cursorPosition.x = 10; + store.cursorPosition.y = 10; + store.onBrushEndListener = brushEndListener; + const geom1: IndexedGeometry = { + color: 'red', + geometryId: { + specId: getSpecId('specId1'), + seriesKey: [2], + }, + value: { + x: 0, + y: 1, + accessor: 'y1', + }, + x: 0, + y: 0, + width: 0, + height: 0, + seriesStyle: { + rect: { + opacity: 1, + }, + rectBorder: { + strokeWidth: 1, + visible: false, + }, + displayValue: { + fill: 'black', + fontFamily: '', + fontSize: 2, + offsetX: 0, + offsetY: 0, + padding: 2, + }, + }, + }; + store.highlightedGeometries.replace([geom1]); + expect(store.chartCursor.get()).toBe('crosshair'); + store.onElementClickListener = jest.fn(); + expect(store.chartCursor.get()).toBe('pointer'); }); }); test('should set tooltip type to follow when single value x scale', () => { diff --git a/src/chart_types/xy_chart/store/chart_state.ts b/src/chart_types/xy_chart/store/chart_state.ts index 3d9a697cde..7e8bc14e59 100644 --- a/src/chart_types/xy_chart/store/chart_state.ts +++ b/src/chart_types/xy_chart/store/chart_state.ts @@ -238,17 +238,16 @@ export class ChartStore { legendPosition = observable.box(Position.Right); showLegendDisplayValue = observable.box(true); - /** - * determine if crosshair cursor should be visible based on cursor position and brush enablement - */ - isCrosshairCursorVisible = computed(() => { + chartCursor = computed(() => { const { x: xPos, y: yPos } = this.cursorPosition; if (yPos < 0 || xPos < 0) { - return false; + return 'default'; } - - return this.isBrushEnabled(); + if (this.highlightedGeometries.length > 0 && (this.onElementClickListener || this.onElementOverListener)) { + return 'pointer'; + } + return this.isBrushEnabled() ? 'crosshair' : 'default'; }); /** @@ -466,13 +465,6 @@ export class ChartStore { } else { this.tooltipData.replace(tooltipValues); } - - // TODO move this into the renderer - if (oneHighlighted) { - document.body.style.cursor = 'pointer'; - } else { - document.body.style.cursor = 'default'; - } }); legendItemTooltipValues = computed(() => { @@ -549,8 +541,6 @@ export class ChartStore { this.highlightedGeometries.clear(); this.tooltipData.clear(); - document.body.style.cursor = 'default'; - if (this.onCursorUpdateListener && this.isActiveChart.get()) { this.onCursorUpdateListener(); } diff --git a/src/components/_container.scss b/src/components/_container.scss index ad0bad3076..4a01d60487 100644 --- a/src/components/_container.scss +++ b/src/components/_container.scss @@ -11,11 +11,26 @@ display: flex; height: 100%; - &--isBrushEnabled { - cursor: crosshair; - } - &--column { flex-direction: column; } } + +.echChartCursorContainer { + position: absolute; + top: 0; + bottom: 0; + right: 0; + left: 0; + box-sizing: border-box; +} + +.echChartResizer { + z-index: -10000000; + position: absolute; + bottom: 0; + top: 0; + left: 0; + right: 0; + box-sizing: border-box; +} \ No newline at end of file diff --git a/src/components/chart.tsx b/src/components/chart.tsx index 8d58628155..54a428ae64 100644 --- a/src/components/chart.tsx +++ b/src/components/chart.tsx @@ -9,7 +9,7 @@ import { ChartResizer } from './chart_resizer'; import { Crosshair } from './crosshair'; import { Highlighter } from './highlighter'; import { Legend } from './legend/legend'; -import { ReactiveChart as ReactChart } from './react_canvas/reactive_chart'; +import { ChartContainer } from './react_canvas/chart_container'; import { Tooltips } from './tooltips'; import { isHorizontal } from '../chart_types/xy_chart/utils/axis_utils'; import { Position } from '../chart_types/xy_chart/utils/specs'; @@ -94,8 +94,8 @@ export class Chart extends React.Component { {// TODO reenable when SVG rendered is aligned with canvas one - renderer === 'svg' && } - {renderer === 'canvas' && } + renderer === 'svg' && } + {renderer === 'canvas' && } diff --git a/src/components/chart_resizer.tsx b/src/components/chart_resizer.tsx index 1a6ea13b82..10cd605997 100644 --- a/src/components/chart_resizer.tsx +++ b/src/components/chart_resizer.tsx @@ -35,20 +35,7 @@ class Resizer extends React.Component { }; render() { - return ( -
- ); + return
; } private handleResize = (entries: ResizeObserverEntry[]) => { diff --git a/src/components/react_canvas/chart_container.tsx b/src/components/react_canvas/chart_container.tsx new file mode 100644 index 0000000000..744284349e --- /dev/null +++ b/src/components/react_canvas/chart_container.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { inject, observer } from 'mobx-react'; +import { ChartStore } from '../../chart_types/xy_chart/store/chart_state'; +import { ReactiveChart } from './reactive_chart'; +interface ReactiveChartProps { + chartStore?: ChartStore; // FIX until we find a better way on ts mobx +} + +class ChartContainerComponent extends React.Component { + static displayName = 'ChartContainer'; + + render() { + const { chartInitialized } = this.props.chartStore!; + if (!chartInitialized.get()) { + return null; + } + const { setCursorPosition } = this.props.chartStore!; + return ( +
{ + setCursorPosition(offsetX, offsetY); + }} + onMouseLeave={() => { + setCursorPosition(-1, -1); + }} + onMouseUp={() => { + if (this.props.chartStore!.isBrushing.get()) { + return; + } + this.props.chartStore!.handleChartClick(); + }} + > + +
+ ); + } +} + +export const ChartContainer = inject('chartStore')(observer(ChartContainerComponent)); diff --git a/src/components/react_canvas/reactive_chart.tsx b/src/components/react_canvas/reactive_chart.tsx index 3044d6231a..7c62c1f6f2 100644 --- a/src/components/react_canvas/reactive_chart.tsx +++ b/src/components/react_canvas/reactive_chart.tsx @@ -1,4 +1,3 @@ -import classNames from 'classnames'; import { inject, observer } from 'mobx-react'; import React from 'react'; import { Layer, Rect, Stage } from 'react-konva'; @@ -352,7 +351,6 @@ class Chart extends React.Component { chartRotation, chartTransform, debug, - setCursorPosition, isChartEmpty, } = this.props.chartStore!; @@ -373,74 +371,48 @@ class Chart extends React.Component { }; } - const className = classNames({ - 'echChart--isBrushEnabled': this.props.chartStore!.isCrosshairCursorVisible.get(), - }); - return ( -
{ - setCursorPosition(offsetX, offsetY); - }} - onMouseLeave={() => { - setCursorPosition(-1, -1); + width: '100%', + height: '100%', }} - onMouseUp={() => { - if (this.props.chartStore!.isBrushing.get()) { - return; - } - this.props.chartStore!.handleChartClick(); - }} - className={className} + {...brushProps} > - + {this.renderGrids()} + + + {this.renderAxes()} + + + - - {this.renderGrids()} - - - {this.renderAxes()} - - - - {this.sortAndRenderElements()} - + {this.sortAndRenderElements()} + + {debug && ( - {debug && this.renderDebugChartBorders()} + {this.renderDebugChartBorders()} - {isBrushEnabled && ( - - {this.renderBrushTool()} - - )} - + )} + {isBrushEnabled && ( - {this.renderBarValues()} + {this.renderBrushTool()} - -
+ )} + + + {this.renderBarValues()} + + ); }