diff --git a/CHANGELOG.md b/CHANGELOG.md index f86159a251..94201a480b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,32 @@ +## [10.0.1](https://github.com/elastic/elastic-charts/compare/v10.0.0...v10.0.1) (2019-08-21) + + +### Bug Fixes + +* default theme ([#336](https://github.com/elastic/elastic-charts/issues/336)) ([2edadb2](https://github.com/elastic/elastic-charts/commit/2edadb2)) + +# [10.0.0](https://github.com/elastic/elastic-charts/compare/v9.2.1...v10.0.0) (2019-08-21) + + +### Bug Fixes + +* **tooltip:** ie11 flex sizing ([#334](https://github.com/elastic/elastic-charts/issues/334)) ([abaa472](https://github.com/elastic/elastic-charts/commit/abaa472)), closes [#332](https://github.com/elastic/elastic-charts/issues/332) +* decuple brush cursor from chart rendering ([#331](https://github.com/elastic/elastic-charts/issues/331)) ([789f85a](https://github.com/elastic/elastic-charts/commit/789f85a)), closes [elastic/kibana#36517](https://github.com/elastic/kibana/issues/36517) +* remove clippings from chart geometries ([#320](https://github.com/elastic/elastic-charts/issues/320)) ([ed6d0e5](https://github.com/elastic/elastic-charts/commit/ed6d0e5)), closes [#20](https://github.com/elastic/elastic-charts/issues/20) + + +### Features + +* auto legend resize ([#316](https://github.com/elastic/elastic-charts/issues/316)) ([659d27e](https://github.com/elastic/elastic-charts/commit/659d27e)), closes [#268](https://github.com/elastic/elastic-charts/issues/268) +* customize number of axis ticks ([#319](https://github.com/elastic/elastic-charts/issues/319)) ([2b838d7](https://github.com/elastic/elastic-charts/commit/2b838d7)) +* **theme:** base theme prop ([#333](https://github.com/elastic/elastic-charts/issues/333)) ([a9ff5e1](https://github.com/elastic/elastic-charts/commit/a9ff5e1)), closes [#292](https://github.com/elastic/elastic-charts/issues/292) + + +### BREAKING CHANGES + +* **theme:** remove `baseThemeType` prop on `Settings` component and `BaseThemeTypes` type. +* `theme.legend.spacingBuffer` added to `Theme` type. Controls the width buffer between the legend label and value. + ## [9.2.1](https://github.com/elastic/elastic-charts/compare/v9.2.0...v9.2.1) (2019-08-20) diff --git a/package.json b/package.json index 5ad6ddcd52..f64007a848 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@elastic/charts", "description": "Elastic-Charts data visualization library", - "version": "9.2.1", + "version": "10.0.1", "author": "Marco Vettorello ", "license": "Apache-2.0", "main": "dist/index.js", 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..d9217023aa 100644 --- a/src/chart_types/xy_chart/store/chart_state.test.ts +++ b/src/chart_types/xy_chart/store/chart_state.test.ts @@ -20,7 +20,6 @@ import { ChartStore } from './chart_state'; describe('Chart Store', () => { let store = new ChartStore(); - store.chartTheme = LIGHT_THEME; const SPEC_ID = getSpecId('spec_1'); const AXIS_ID = getAxisId('axis_1'); @@ -68,7 +67,6 @@ describe('Chart Store', () => { }; beforeEach(() => { store = new ChartStore(); - store.chartTheme = LIGHT_THEME; store.updateParentDimensions(600, 600, 0, 0); store.computeChart(); }); @@ -902,21 +900,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..d11a9f19a5 100644 --- a/src/chart_types/xy_chart/store/chart_state.ts +++ b/src/chart_types/xy_chart/store/chart_state.ts @@ -92,6 +92,7 @@ import { Transform, updateDeselectedDataSeries, } from './utils'; +import { LIGHT_THEME } from '../../../utils/themes/light_theme'; export interface Point { x: number; @@ -149,10 +150,7 @@ export class ChartStore { chartRotation: Rotation = 0; // updated from jsx chartRendering: Rendering = 'canvas'; // updated from jsx - /** - * Chart theme to be set from Settings.tsx - */ - chartTheme!: Theme; + chartTheme: Theme = LIGHT_THEME; axesSpecs: Map = new Map(); // readed from jsx axesTicksDimensions: Map = new Map(); // computed axesPositions: Map = new Map(); // computed @@ -238,17 +236,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 +463,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 +539,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()} + + ); } diff --git a/src/specs/settings.test.tsx b/src/specs/settings.test.tsx index 0e1f3e7125..2e6e6e3955 100644 --- a/src/specs/settings.test.tsx +++ b/src/specs/settings.test.tsx @@ -6,6 +6,7 @@ import { TooltipType } from '../chart_types/xy_chart/utils/interactions'; import { ChartStore } from '../chart_types/xy_chart/store/chart_state'; import { DEFAULT_TOOLTIP_SNAP, DEFAULT_TOOLTIP_TYPE, SettingsComponent, SettingSpecProps } from './settings'; import { PartialTheme } from '../utils/themes/theme'; +import { LIGHT_THEME } from '../utils/themes/light_theme'; describe('Settings spec component', () => { test('should update store on mount if spec has a chart store', () => { @@ -55,7 +56,7 @@ describe('Settings spec component', () => { test('should set chart properties on chart store', () => { const chartStore = new ChartStore(); - expect(chartStore.chartTheme).toBeUndefined(); + expect(chartStore.chartTheme).toEqual(LIGHT_THEME); expect(chartStore.chartRotation).toBe(0); expect(chartStore.chartRendering).toBe('canvas'); expect(chartStore.animateData).toBe(false); @@ -162,7 +163,7 @@ describe('Settings spec component', () => { }, }; - expect(chartStore.chartTheme).toBeUndefined(); + expect(chartStore.chartTheme).toEqual(LIGHT_THEME); const updatedProps: SettingSpecProps = { theme: partialTheme,