From 1c92b33a152808d0e71bbf0b2894b000d3e903f6 Mon Sep 17 00:00:00 2001 From: lee00678 Date: Mon, 23 Sep 2024 09:59:35 -0700 Subject: [PATCH 1/4] Core | Percy Test: Add wait time to 1s --- packages/dev/cypress/e2e/unovis.cy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dev/cypress/e2e/unovis.cy.ts b/packages/dev/cypress/e2e/unovis.cy.ts index f87ed10e..69bc5f43 100644 --- a/packages/dev/cypress/e2e/unovis.cy.ts +++ b/packages/dev/cypress/e2e/unovis.cy.ts @@ -14,7 +14,7 @@ describe('Unovis Test', () => { duration: test.duration, }, }) - cy.wait(test.duration > 100 ? test.duration : 100) + cy.wait(test.duration > 1000 ? test.duration : 1000) cy.percySnapshot(test.title, { scope: scopeSelector }) }) }) From 26030031fae8b4c1a955fa8b57037d3fa9963329 Mon Sep 17 00:00:00 2001 From: Nikita Rokotyan Date: Fri, 11 Oct 2024 15:14:27 -0700 Subject: [PATCH 2/4] Core | Container: Improve ResizeObserver handling - Use requestAnimationFrame to avoid multiple resize events when scrollbars appear/disappear - Cancel previous animation frame IDs before scheduling new ones - Renamed `_requestedAnimationFrame` to `_renderAnimationFrameId` Fixes #455 --- .../src/containers/single-container/index.ts | 4 +-- packages/ts/src/core/container/index.ts | 36 +++++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/packages/ts/src/containers/single-container/index.ts b/packages/ts/src/containers/single-container/index.ts index 11aba2ba..3752f9a9 100644 --- a/packages/ts/src/containers/single-container/index.ts +++ b/packages/ts/src/containers/single-container/index.ts @@ -147,8 +147,8 @@ export class SingleContainer extends ContainerCore { if (!this._resizeObserver) this._setUpResizeObserver() // Schedule the actual rendering in the next frame - cancelAnimationFrame(this._requestedAnimationFrame) - this._requestedAnimationFrame = requestAnimationFrame(() => { + cancelAnimationFrame(this._renderAnimationFrameId) + this._renderAnimationFrameId = requestAnimationFrame(() => { this._preRender() this._render(duration) }) diff --git a/packages/ts/src/core/container/index.ts b/packages/ts/src/core/container/index.ts index 7c4c7834..9e828cc0 100644 --- a/packages/ts/src/core/container/index.ts +++ b/packages/ts/src/core/container/index.ts @@ -18,9 +18,10 @@ export class ContainerCore { protected _defaultConfig: ContainerConfigInterface = ContainerDefaultConfig protected _container: HTMLElement - protected _requestedAnimationFrame: number + protected _renderAnimationFrameId: number protected _isFirstRender = true protected _resizeObserver: ResizeObserver | undefined + protected _resizeObserverAnimationFrameId: number protected _svgDefs: Selection protected _svgDefsExternal: Selection private _containerSize: { width: number; height: number } @@ -29,7 +30,7 @@ export class ContainerCore { static DEFAULT_CONTAINER_HEIGHT = 300 constructor (element: HTMLElement) { - this._requestedAnimationFrame = null + this._renderAnimationFrameId = null this._container = element // Setting `role` attribute to `image` to make the container accessible @@ -96,8 +97,8 @@ export class ContainerCore { if (!this._resizeObserver) this._setUpResizeObserver() // Schedule the actual rendering in the next frame - cancelAnimationFrame(this._requestedAnimationFrame) - this._requestedAnimationFrame = requestAnimationFrame(() => { + cancelAnimationFrame(this._renderAnimationFrameId) + this._renderAnimationFrameId = requestAnimationFrame(() => { this._preRender() this._render(duration) }) @@ -137,25 +138,32 @@ export class ContainerCore { protected _setUpResizeObserver (): void { if (this._resizeObserver) return + const containerRect = this._container.getBoundingClientRect() this._containerSize = { width: containerRect.width, height: containerRect.height } this._resizeObserver = new ResizeObserver((entries, observer) => { - const resizedContainerRect = this._container.getBoundingClientRect() - const resizedContainerSize = { width: resizedContainerRect.width, height: resizedContainerRect.height } - const hasSizeChanged = !isEqual(this._containerSize, resizedContainerSize) - // Do resize only if element is attached to the DOM - // will come in useful when some ancestor of container becomes detached - if (hasSizeChanged && resizedContainerSize.width && resizedContainerSize.height) { - this._containerSize = resizedContainerSize - this._onResize() - } + // Using request animation frame to avoid multiple resize events when scrollbars appear/disappear + // See more: https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors + cancelAnimationFrame(this._resizeObserverAnimationFrameId) + this._resizeObserverAnimationFrameId = requestAnimationFrame(() => { + const resizedContainerRect = this._container.getBoundingClientRect() + const resizedContainerSize = { width: resizedContainerRect.width, height: resizedContainerRect.height } + const hasSizeChanged = !isEqual(this._containerSize, resizedContainerSize) + // Do resize only if element is attached to the DOM + // will come in useful when some ancestor of container becomes detached + if (hasSizeChanged && resizedContainerSize.width && resizedContainerSize.height) { + this._containerSize = resizedContainerSize + this._onResize() + } + }) }) this._resizeObserver.observe(this._container) } public destroy (): void { - cancelAnimationFrame(this._requestedAnimationFrame) + cancelAnimationFrame(this._renderAnimationFrameId) + cancelAnimationFrame(this._resizeObserverAnimationFrameId) this._resizeObserver?.disconnect() this.svg.remove() } From 42b5f28f71dd42efcf28b92bc147be0051f1d6f2 Mon Sep 17 00:00:00 2001 From: Nikita Rokotyan Date: Mon, 21 Oct 2024 11:45:36 -0700 Subject: [PATCH 3/4] Dev | Examples | Donut: Add full height donut example - Adds a new example for a full height donut chart - Tests the resize behavior of the donut chart component #455 --- .../misc/donut/donut-full-height/index.tsx | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 packages/dev/src/examples/misc/donut/donut-full-height/index.tsx diff --git a/packages/dev/src/examples/misc/donut/donut-full-height/index.tsx b/packages/dev/src/examples/misc/donut/donut-full-height/index.tsx new file mode 100644 index 00000000..b984204b --- /dev/null +++ b/packages/dev/src/examples/misc/donut/donut-full-height/index.tsx @@ -0,0 +1,22 @@ +import React from 'react' +import { VisSingleContainer, VisDonut } from '@unovis/react' +import { ExampleViewerDurationProps } from '@src/components/ExampleViewer/index' + +export const title = 'Donut: Full Height' +export const subTitle = 'Testing the resize behavior' + +export const component = (props: ExampleViewerDurationProps): JSX.Element => { + const data = [3, 2, 5, 4, 0, 1] + return ( + + d} + data={data} + padAngle={0.02} + duration={props.duration} + arcWidth={80} + /> + + ) +} + From 58dd27a64a3d51b6c36123e10f03291d5c61b86a Mon Sep 17 00:00:00 2001 From: Nikita Rokotyan Date: Fri, 11 Oct 2024 15:27:17 -0700 Subject: [PATCH 4/4] Core | Container: Updating jsdoc for `width` and `height` Removing the part saying that the container automatically fits to the size of the parent element because it's only true for the TypeScript version of the library. Since the majority of Unovis users are using UI frameworks, they may be get confused by this. --- .../single-container/single-container.component.ts | 12 ++++++++++-- .../xy-container/xy-container.component.ts | 12 ++++++++++-- packages/ts/src/core/container/config.ts | 6 ++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/packages/angular/src/containers/single-container/single-container.component.ts b/packages/angular/src/containers/single-container/single-container.component.ts index c9154c9f..3623ee6c 100644 --- a/packages/angular/src/containers/single-container/single-container.component.ts +++ b/packages/angular/src/containers/single-container/single-container.component.ts @@ -19,9 +19,17 @@ export class VisSingleContainerComponent implements AfterViewInit, AfterConte @ContentChild(VisTooltipComponent) tooltipComponent: VisTooltipComponent @ContentChild(VisAnnotationsComponent) annotationsComponent: VisAnnotationsComponent - /** Width in pixels. By default, Container automatically fits to the size of the parent element. Default: `undefined`. */ + /** Width in pixels or in CSS units. + * Percentage units `"%"` are not supported here. If you want to set `width` as a percentage, do it via `style` or `class` + * of the corresponding DOM element. + * Default: `undefined` + */ @Input() width?: number - /** Height in pixels. By default, Container automatically fits to the size of the parent element. Default: `undefined`. */ + /** Height in pixels or in CSS units. + * Percentage units `"%"` are not supported here. If you want to set `height` as a percentage, do it via `style` or `class` + * of the corresponding DOM element. + * Default: `undefined` + */ @Input() height?: number /** Scale for X dimension, e.g. Scale.scaleLinear(). Default: `Scale.scaleLinear()` */ diff --git a/packages/ts/src/core/container/config.ts b/packages/ts/src/core/container/config.ts index 12201ede..37eb93f1 100644 --- a/packages/ts/src/core/container/config.ts +++ b/packages/ts/src/core/container/config.ts @@ -14,16 +14,14 @@ export interface ContainerConfigInterface { /** Defines whether components should fit into the container or the container should expand to fit to the component's size. Default: `Sizing.Fit` */ sizing?: Sizing | string; /** Width in pixels or in CSS units. - * Percentage units `"%"` are not supported here. If you want to set `width` as a percentage, do it via `style` + * Percentage units `"%"` are not supported here. If you want to set `width` as a percentage, do it via `style` or `class` * of the corresponding DOM element. - * By default, Container automatically fits to the size of the parent element. * Default: `undefined` */ width?: number | string; /** Height in pixels or in CSS units. - * Percentage units `"%"` are not supported here. If you want to set `height` as a percentage, do it via `style` + * Percentage units `"%"` are not supported here. If you want to set `height` as a percentage, do it via `style` or `class` * of the corresponding DOM element. - * By default, Container automatically fits to the size of the parent element. * Default: `undefined` */ height?: number | string;