diff --git a/e2e/screenshots/all.test.ts-snapshots/baselines/test-cases/resize-debounce-chrome-linux.png b/e2e/screenshots/all.test.ts-snapshots/baselines/test-cases/resize-debounce-chrome-linux.png deleted file mode 100644 index 94eb938d67..0000000000 Binary files a/e2e/screenshots/all.test.ts-snapshots/baselines/test-cases/resize-debounce-chrome-linux.png and /dev/null differ diff --git a/packages/charts/api/charts.api.md b/packages/charts/api/charts.api.md index bb7707c775..53e1a10ca8 100644 --- a/packages/charts/api/charts.api.md +++ b/packages/charts/api/charts.api.md @@ -585,7 +585,7 @@ export class Chart extends React_2.Component { // (undocumented) componentDidMount(): void; // (undocumented) - componentDidUpdate({ title, description }: Readonly): void; + componentDidUpdate({ title, description, size }: Readonly): void; // (undocumented) componentWillUnmount(): void; // (undocumented) @@ -2656,7 +2656,7 @@ export const Settings: (props: SFProps; +export const settingsBuildProps: BuildProps; // @public (undocumented) export type SettingsProps = ComponentProps; @@ -2709,6 +2709,7 @@ export interface SettingsSpec extends Spec, LegendSpec { pointerUpdateTrigger: PointerUpdateTrigger; // (undocumented) rendering: Rendering; + // @deprecated resizeDebounce?: number; // (undocumented) rotation: Rotation; diff --git a/packages/charts/package.json b/packages/charts/package.json index 84162f9164..8255ad62c5 100644 --- a/packages/charts/package.json +++ b/packages/charts/package.json @@ -47,7 +47,6 @@ "react-redux": "^7.1.0", "redux": "^4.0.4", "reselect": "^4.0.0", - "resize-observer-polyfill": "^1.5.1", "ts-debounce": "^4.0.0", "utility-types": "^3.10.0", "uuid": "^9", diff --git a/packages/charts/src/components/__snapshots__/chart.test.tsx.snap b/packages/charts/src/components/__snapshots__/chart.test.tsx.snap index 3084b3130b..060963eb45 100644 --- a/packages/charts/src/components/__snapshots__/chart.test.tsx.snap +++ b/packages/charts/src/components/__snapshots__/chart.test.tsx.snap @@ -17,7 +17,7 @@ exports[`Chart should render the legend name test 1`] = ` - +
diff --git a/packages/charts/src/components/chart.tsx b/packages/charts/src/components/chart.tsx index ef38f131b7..20ee266a8c 100644 --- a/packages/charts/src/components/chart.tsx +++ b/packages/charts/src/components/chart.tsx @@ -23,14 +23,14 @@ import { getElementZIndex } from './portal/utils'; import { Colors } from '../common/colors'; import { LegendPositionConfig, PointerEvent } from '../specs'; import { SpecsParser } from '../specs/specs_parser'; -import { updateChartTitles } from '../state/actions/chart_settings'; +import { updateChartTitles, updateParentDimensions } from '../state/actions/chart_settings'; import { onExternalPointerEvent } from '../state/actions/events'; import { onComputedZIndex } from '../state/actions/z_index'; import { chartStoreReducer, GlobalChartState } from '../state/chart_state'; import { getChartThemeSelector } from '../state/selectors/get_chart_theme'; import { getInternalIsInitializedSelector, InitStatus } from '../state/selectors/get_internal_is_intialized'; import { getLegendConfigSelector } from '../state/selectors/get_legend_config_selector'; -import { ChartSize, getChartSize } from '../utils/chart_size'; +import { ChartSize, getChartSize, getFixedChartSize } from '../utils/chart_size'; import { LayoutDirection } from '../utils/common'; import { LIGHT_THEME } from '../utils/themes/light_theme'; @@ -121,10 +121,16 @@ export class Chart extends React.Component { this.unsubscribeToStore(); } - componentDidUpdate({ title, description }: Readonly) { + componentDidUpdate({ title, description, size }: Readonly) { if (title !== this.props.title || description !== this.props.description) { this.chartStore.dispatch(updateChartTitles(this.props.title, this.props.description)); } + const prevChartSize = getChartSize(size); + const newChartSize = getFixedChartSize(this.props.size); + // if the size is specified in pixels then update directly the store + if (newChartSize && (newChartSize.width !== prevChartSize.width || newChartSize.height !== prevChartSize.height)) { + this.chartStore.dispatch(updateParentDimensions({ ...newChartSize, top: 0, left: 0 })); + } } getPNGSnapshot( diff --git a/packages/charts/src/components/chart_resizer.tsx b/packages/charts/src/components/chart_resizer.tsx index 57b7a2fe4a..926f553d0c 100644 --- a/packages/charts/src/components/chart_resizer.tsx +++ b/packages/charts/src/components/chart_resizer.tsx @@ -9,18 +9,13 @@ import React, { RefObject } from 'react'; import { connect } from 'react-redux'; import { Dispatch, bindActionCreators } from 'redux'; -import ResizeObserver from 'resize-observer-polyfill'; -import { DEFAULT_RESIZE_DEBOUNCE } from '../specs/constants'; import { ResizeListener } from '../specs/settings'; import { updateParentDimensions } from '../state/actions/chart_settings'; import { GlobalChartState } from '../state/chart_state'; import { getSettingsSpecSelector } from '../state/selectors/get_settings_spec'; -import { isFiniteNumber } from '../utils/common'; -import { debounce, DebouncedFunction } from '../utils/debounce'; interface ResizerStateProps { - resizeDebounce: number; onResize?: ResizeListener; } @@ -32,44 +27,26 @@ type ResizerProps = ResizerStateProps & ResizerDispatchProps; type ResizeFn = (entries: ResizeObserverEntry[]) => void; class Resizer extends React.Component { - private initialResizeComplete = false; - private readonly containerRef: RefObject; private ro: ResizeObserver; - private animationFrameID: number; - - private onResizeDebounced?: ResizeFn | DebouncedFunction, ResizeFn>; - constructor(props: ResizerProps) { super(props); this.containerRef = React.createRef(); - this.ro = new ResizeObserver(this.handleResize); - this.animationFrameID = NaN; + this.ro = new ResizeObserver(this.onResize); } componentDidMount() { - this.setupResizeDebounce(); if (this.containerRef.current) { this.ro.observe(this.containerRef.current as Element); } } - componentDidUpdate({ resizeDebounce }: Readonly): void { - if (resizeDebounce !== this.props.resizeDebounce) this.setupResizeDebounce(); - } - componentWillUnmount() { - window.cancelAnimationFrame(this.animationFrameID); this.ro.disconnect(); } - setupResizeDebounce() { - this.onResizeDebounced = - this.props.resizeDebounce > 0 ? debounce(this.onResize, this.props.resizeDebounce) : this.onResize; - } - onResize: ResizeFn = (entries) => { if (!Array.isArray(entries)) { return; @@ -78,19 +55,8 @@ class Resizer extends React.Component { return; } const { width, height } = entries[0].contentRect; - this.animationFrameID = window.requestAnimationFrame(() => { - this.props.updateParentDimensions({ width, height, top: 0, left: 0 }); - this.props.onResize?.(); - }); - }; - - handleResize = (entries: ResizeObserverEntry[]) => { - if (this.initialResizeComplete) { - this.onResizeDebounced?.(entries); - } else { - this.initialResizeComplete = true; - this.onResize(entries); - } + this.props.updateParentDimensions({ width, height, top: 0, left: 0 }); + this.props.onResize?.(); }; render() { @@ -99,19 +65,11 @@ class Resizer extends React.Component { } const mapDispatchToProps = (dispatch: Dispatch): ResizerDispatchProps => - bindActionCreators( - { - updateParentDimensions, - }, - dispatch, - ); + bindActionCreators({ updateParentDimensions }, dispatch); const mapStateToProps = (state: GlobalChartState): ResizerStateProps => { - const { resizeDebounce, onResize } = getSettingsSpecSelector(state); - return { - resizeDebounce: isFiniteNumber(resizeDebounce) ? resizeDebounce : DEFAULT_RESIZE_DEBOUNCE, - onResize, - }; + const { onResize } = getSettingsSpecSelector(state); + return { onResize }; }; /** @internal */ diff --git a/packages/charts/src/specs/constants.ts b/packages/charts/src/specs/constants.ts index 72608e35d0..441745e50d 100644 --- a/packages/charts/src/specs/constants.ts +++ b/packages/charts/src/specs/constants.ts @@ -127,9 +127,6 @@ export const TooltipStickTo = Object.freeze({ /** @public */ export type TooltipStickTo = $Values; -/** @internal */ -export const DEFAULT_RESIZE_DEBOUNCE = 10; - /** * Default legend config * @internal @@ -154,7 +151,6 @@ export const settingsBuildProps = buildSFProps()( rendering: 'canvas' as const, rotation: 0 as const, animateData: true, - resizeDebounce: DEFAULT_RESIZE_DEBOUNCE, debug: false, pointerUpdateTrigger: PointerUpdateTrigger.X, externalPointerEvents: { diff --git a/packages/charts/src/specs/settings.tsx b/packages/charts/src/specs/settings.tsx index 1c106b00fc..e1e305e994 100644 --- a/packages/charts/src/specs/settings.tsx +++ b/packages/charts/src/specs/settings.tsx @@ -540,6 +540,7 @@ export interface SettingsSpec extends Spec, LegendSpec { /** * debounce delay used for resizing chart + * @deprecated currently unused */ resizeDebounce?: number; diff --git a/packages/charts/src/utils/chart_size.ts b/packages/charts/src/utils/chart_size.ts index 1a3ffa6484..5d5baaa080 100644 --- a/packages/charts/src/utils/chart_size.ts +++ b/packages/charts/src/utils/chart_size.ts @@ -18,10 +18,7 @@ export interface ChartSizeObject { export type ChartSize = number | string | ChartSizeArray | ChartSizeObject; /** @internal */ -export function getChartSize(size?: ChartSize): ChartSizeObject { - if (size === undefined) { - return {}; - } +export function getChartSize(size?: ChartSize): Required { if (Array.isArray(size)) { return { width: size[0] === undefined ? '100%' : size[0], @@ -40,3 +37,12 @@ export function getChartSize(size?: ChartSize): ChartSizeObject { height: sameSize, }; } + +/** + * Return the requested size if specified in pixel, null otherwise + * @internal + */ +export function getFixedChartSize(size?: ChartSize): { width: number; height: number } | null { + const { width, height } = getChartSize(size); + return typeof height === 'number' && typeof width === 'number' ? { width, height } : null; +} diff --git a/storybook/stories/test_cases/11_resize_debounce.story.tsx b/storybook/stories/test_cases/11_resize_debounce.story.tsx deleted file mode 100644 index f368f81344..0000000000 --- a/storybook/stories/test_cases/11_resize_debounce.story.tsx +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { action } from '@storybook/addon-actions'; -import { number } from '@storybook/addon-knobs'; -import moment from 'moment'; -import React from 'react'; - -import { Axis, Chart, BarSeries, Position, ScaleType, Settings } from '@elastic/charts'; -import { getRandomNumberGenerator } from '@elastic/charts/src/mocks/utils'; - -import { ChartsStory } from '../../types'; -import { useBaseTheme } from '../../use_base_theme'; - -const rng = getRandomNumberGenerator(); - -const data: { t: number; values: { v: number; cat: string }[] }[] = []; -const end = moment(1699037055867); -const days = 3; -const maxCardinality = 100; -const start = end.clone().subtract(days, 'days'); -const hours = 6; -while (start.isBefore(end)) { - const values = Array.from({ length: maxCardinality }, (_, i) => ({ - v: rng(0, 100), - cat: `Category ${i + 1}`, - })); - data.push({ t: start.add(hours, 'hours').valueOf(), values }); -} - -export const Example: ChartsStory = (_, { title, description }) => { - const resizeDebounce = number('resizeDebounce (ms)', 10, { min: 0, step: 20 }); - const cardinality = number('cardinality', 100, { min: 1, max: maxCardinality }); - return ( - - - - - - values.slice(0, cardinality).map(({ v, cat }) => ({ t, v, cat })))} - /> - - ); -}; - -Example.parameters = { - markdown: `The \`resizeDebounce\` option on the \`Settings\` spec provides control over the eagerness of the chart to re-render upon resize. A value of \`0\` will remove the debounce altogether. -You can play with the cardinality and debounce time to see how the debouncing affects the chart render timing`, - resize: true, -}; diff --git a/storybook/stories/test_cases/test_cases.stories.tsx b/storybook/stories/test_cases/test_cases.stories.tsx index ba47ce1729..6461d6d42e 100644 --- a/storybook/stories/test_cases/test_cases.stories.tsx +++ b/storybook/stories/test_cases/test_cases.stories.tsx @@ -20,5 +20,4 @@ export { Example as rtlText } from './7_rtl_text.story'; export { Example as testPointsOutsideOfDomain } from './8_test_points_outside_of_domain.story'; export { Example as duplicateLabelsInPartitionLegend } from './9_duplicate_labels_in_partition_legend.story'; export { Example as highlighterZIndex } from './10_highlighter_z_index.story'; -export { Example as resizeDebounce } from './11_resize_debounce.story'; export { Example as domainEdges } from './21_domain_edges.story'; diff --git a/yarn.lock b/yarn.lock index 64ec93ea76..00011eaff2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11638,7 +11638,8 @@ eslint-module-utils@^2.8.0: debug "^3.2.7" "eslint-plugin-elastic-charts@link:./packages/eslint-plugin-elastic-charts": - version "1.0.0" + version "0.0.0" + uid "" eslint-plugin-eslint-comments@^3.2.0: version "3.2.0" @@ -20389,11 +20390,6 @@ reselect@^4.0.0: resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7" integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA== -resize-observer-polyfill@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" - integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== - resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"