From 0bcb930c761e71dfcb1ff543e9511f22047d713c Mon Sep 17 00:00:00 2001 From: krkshitij <110246001+krkshitij@users.noreply.github.com> Date: Fri, 24 Jan 2025 11:20:36 +0000 Subject: [PATCH 1/8] make cartesian charts responsive --- .../react-charting/etc/react-charting.api.md | 18 +++ .../react-charting/src/ResponsiveContainer.ts | 1 + .../ResponsiveContainer.styles.ts | 22 +++ .../ResponsiveContainer.tsx | 64 +++++++++ .../ResponsiveContainer.types.ts | 31 ++++ .../components/ResponsiveContainer/index.ts | 2 + packages/charts/react-charting/src/index.ts | 2 + .../VerticalBarChart.Responsive.Example.tsx | 132 ++++++++++++++++++ .../VerticalBarChart/VerticalBarChart.doc.tsx | 8 ++ .../VerticalBarChart/VerticalBarChartPage.tsx | 6 + .../VerticalBarChart/index.stories.tsx | 3 + 11 files changed, 289 insertions(+) create mode 100644 packages/charts/react-charting/src/ResponsiveContainer.ts create mode 100644 packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.styles.ts create mode 100644 packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.tsx create mode 100644 packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.types.ts create mode 100644 packages/charts/react-charting/src/components/ResponsiveContainer/index.ts create mode 100644 packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Responsive.Example.tsx diff --git a/packages/charts/react-charting/etc/react-charting.api.md b/packages/charts/react-charting/etc/react-charting.api.md index 3d1c49be07983f..98f8df1416fa8e 100644 --- a/packages/charts/react-charting/etc/react-charting.api.md +++ b/packages/charts/react-charting/etc/react-charting.api.md @@ -1212,6 +1212,21 @@ export interface IRefArrayData { refElement?: SVGGElement; } +// @public (undocumented) +export interface IResponsiveContainerProps { + // (undocumented) + children: React_2.ReactElement<{ + width?: number; + height?: number; + }>; + // (undocumented) + height?: number | string; + // (undocumented) + onResize?: (width: number, height: number) => void; + // (undocumented) + width?: number | string; +} + // @public export interface ISankeyChartAccessibilityProps { emptyAriaLabel?: string; @@ -1637,6 +1652,9 @@ export enum NodesComposition { // @public export const PieChart: React_2.FunctionComponent; +// @public (undocumented) +export const ResponsiveContainer: React_2.FC; + // @public export const SankeyChart: React_2.FunctionComponent; diff --git a/packages/charts/react-charting/src/ResponsiveContainer.ts b/packages/charts/react-charting/src/ResponsiveContainer.ts new file mode 100644 index 00000000000000..1cda6e6c89ed93 --- /dev/null +++ b/packages/charts/react-charting/src/ResponsiveContainer.ts @@ -0,0 +1 @@ +export * from './components/ResponsiveContainer/index'; diff --git a/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.styles.ts b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.styles.ts new file mode 100644 index 00000000000000..e53f420e68dd9f --- /dev/null +++ b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.styles.ts @@ -0,0 +1,22 @@ +import { IResponsiveContainerStyles } from './ResponsiveContainer.types'; + +export const getStyles = (): IResponsiveContainerStyles => { + return { + root: { + width: '100%', + height: '100%', + + '& [class^="chartWrapper-"]': { + width: '100%', // optional + // To prevent chart height from collapsing while resizing + height: '100%', // optional + + '> svg': { + // This overrides the pixel width and height of svg allowing it to resize properly within flexbox + width: '100%', + height: '100%', + }, + }, + }, + }; +}; diff --git a/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.tsx b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.tsx new file mode 100644 index 00000000000000..3da87a678f6b3d --- /dev/null +++ b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.tsx @@ -0,0 +1,64 @@ +import * as React from 'react'; +import { classNamesFunction, getWindow } from '@fluentui/react'; +import { IResponsiveContainerProps, IResponsiveContainerStyles } from './ResponsiveContainer.types'; +import { getStyles } from './ResponsiveContainer.styles'; + +const getClassNames = classNamesFunction<{}, IResponsiveContainerStyles>(); + +export const ResponsiveContainer: React.FC = props => { + const containerRef = React.useRef(null); + const onResizeRef = React.useRef(); + const classNames = React.useMemo(() => getClassNames(getStyles()), []); + + const [size, setSize] = React.useState<{ containerWidth?: number; containerHeight?: number }>({}); + + onResizeRef.current = props.onResize; + + React.useEffect(() => { + const _window = getWindow(containerRef.current) as (Window & typeof globalThis) | undefined; + let animationFrameId: number | undefined; + let resizeObserver: ResizeObserver | undefined; + + const resizeCallback = (entries: ResizeObserverEntry[]) => { + const { width: containerWidth, height: containerHeight } = entries[0].contentRect; + // rAF is an alternative to the throttle function. For more info, see: + // https://css-tricks.com/debouncing-throttling-explained-examples/#aa-requestanimationframe-raf + animationFrameId = _window?.requestAnimationFrame(() => { + setSize(prevSize => { + const roundedWidth = Math.floor(containerWidth); + const roundedHeight = Math.floor(containerHeight); + if (prevSize.containerWidth === roundedWidth && prevSize.containerHeight === roundedHeight) { + return prevSize; + } + + return { containerWidth: roundedWidth, containerHeight: roundedHeight }; + }); + }); + onResizeRef.current?.(containerWidth, containerHeight); + }; + + if (_window && _window.ResizeObserver) { + resizeObserver = new _window.ResizeObserver(resizeCallback); + if (containerRef.current) { + resizeObserver.observe(containerRef.current); + } + } + + return () => { + if (animationFrameId) { + _window?.cancelAnimationFrame(animationFrameId); + } + + resizeObserver?.disconnect(); + }; + }, []); + + return ( +
+ {React.cloneElement(props.children, { + width: size.containerWidth, + height: size.containerHeight, + })} +
+ ); +}; diff --git a/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.types.ts b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.types.ts new file mode 100644 index 00000000000000..c7bed7d1e36324 --- /dev/null +++ b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.types.ts @@ -0,0 +1,31 @@ +import * as React from 'react'; +import { IStyle } from '@fluentui/react/lib/Styling'; + +export interface IResponsiveContainerProps { + /** + * + */ + width?: number | string; + + /** + * + */ + height?: number | string; + + /** + * + */ + onResize?: (width: number, height: number) => void; + + /** + * + */ + children: React.ReactElement<{ width?: number; height?: number }>; +} + +export interface IResponsiveContainerStyles { + /** + * + */ + root: IStyle; +} diff --git a/packages/charts/react-charting/src/components/ResponsiveContainer/index.ts b/packages/charts/react-charting/src/components/ResponsiveContainer/index.ts new file mode 100644 index 00000000000000..feabfdb830def2 --- /dev/null +++ b/packages/charts/react-charting/src/components/ResponsiveContainer/index.ts @@ -0,0 +1,2 @@ +export * from './ResponsiveContainer'; +export * from './ResponsiveContainer.types'; diff --git a/packages/charts/react-charting/src/index.ts b/packages/charts/react-charting/src/index.ts index 2ae3660ac7f75a..561374349d8735 100644 --- a/packages/charts/react-charting/src/index.ts +++ b/packages/charts/react-charting/src/index.ts @@ -138,5 +138,7 @@ export type { IGaugeChartProps, IGaugeChartSegment, IGaugeChartStyleProps, IGaug export { GaugeChart, GaugeChartVariant, GaugeValueFormat } from './GaugeChart'; export type { DeclarativeChartProps, Schema, IDeclarativeChart, IImageExportOptions } from './DeclarativeChart'; export { DeclarativeChart } from './DeclarativeChart'; +export type { IResponsiveContainerProps } from './ResponsiveContainer'; +export { ResponsiveContainer } from './ResponsiveContainer'; import './version'; diff --git a/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Responsive.Example.tsx b/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Responsive.Example.tsx new file mode 100644 index 00000000000000..77273bcfda8258 --- /dev/null +++ b/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Responsive.Example.tsx @@ -0,0 +1,132 @@ +import * as React from 'react'; +import { + VerticalBarChart, + IVerticalBarChartDataPoint, + DataVizPalette, + getColorFromToken, + ILineChartLineOptions, + ResponsiveContainer, +} from '@fluentui/react-charting'; +import { classNamesFunction, DefaultPalette, IStyle } from '@fluentui/react'; + +interface IVBCResponsiveExampleStyles { + resizableArea: IStyle; +} + +const getStyles = (): IVBCResponsiveExampleStyles => { + return { + resizableArea: { + display: 'flex', + flexWrap: 'nowrap', + overflow: 'hidden', + + minWidth: '200px', + maxWidth: '800px', + border: `2px solid ${DefaultPalette.blue}`, + padding: '20px 10px 10px 10px', + position: 'relative', + resize: 'horizontal', + '::after': { + content: `'Resizable Area'`, + position: 'absolute', + padding: '1px 4px 1px', + top: '-2px', + left: '-2px', + fontFamily: 'monospace', + fontSize: '15px', + fontWeight: 900, + letterSpacing: '1px', + color: DefaultPalette.white, + backgroundColor: DefaultPalette.blue, + }, + }, + }; +}; +const points: IVerticalBarChartDataPoint[] = [ + { + x: 0, + y: 10000, + legend: 'Oranges', + color: DefaultPalette.accent, + lineData: { + y: 7000, + }, + }, + { + x: 10000, + y: 50000, + legend: 'Dogs', + color: DefaultPalette.blueDark, + lineData: { + y: 30000, + }, + }, + { + x: 25000, + y: 30000, + legend: 'Apples', + color: DefaultPalette.blueMid, + lineData: { + y: 3000, + }, + }, + { + x: 40000, + y: 13000, + legend: 'Bananas', + color: getColorFromToken(DataVizPalette.color6), + }, + { + x: 52000, + y: 43000, + legend: 'Giraffes', + color: getColorFromToken(DataVizPalette.color11), + lineData: { + y: 30000, + }, + }, + { + x: 68000, + y: 30000, + legend: 'Cats', + color: DefaultPalette.blueDark, + lineData: { + y: 5000, + }, + }, + { + x: 80000, + y: 20000, + legend: 'Elephants', + color: getColorFromToken(DataVizPalette.color11), + lineData: { + y: 16000, + }, + }, + { + x: 92000, + y: 45000, + legend: 'Monkeys', + color: getColorFromToken(DataVizPalette.color6), + lineData: { + y: 40000, + }, + }, +]; +const lineOptions: ILineChartLineOptions = { lineBorderWidth: '2' }; + +const getClassNames = classNamesFunction<{}, IVBCResponsiveExampleStyles>(); + +export class VerticalBarChartResponsiveExample extends React.Component { + private _classNames = getClassNames(getStyles()); + + public render(): JSX.Element { + return ( +
+ + + +
+ ); + } +} diff --git a/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.doc.tsx b/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.doc.tsx index a9ee43726ddb2e..745892763b6bc9 100644 --- a/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.doc.tsx +++ b/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.doc.tsx @@ -11,6 +11,7 @@ import { VerticalBarChartRotatedLabelExample } from './VerticalBarChart.RotateLa import { VerticalBarChartDateAxisExample } from './VerticalBarChart.DateAxis.Example'; import { VerticalBarChartNegativeExample } from './VerticalBarChart.Negative.Example'; import { VerticalBarChartAllNegativeExample } from './VerticalBarChart.AllNegative.Example'; +import { VerticalBarChartResponsiveExample } from './VerticalBarChart.Responsive.Example'; const VerticalBarChartBasicExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Basic.Example.tsx') as string; @@ -30,6 +31,8 @@ const VerticalBarChartNegativeExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Negative.Example.tsx') as string; const VerticalBarChartAllNegativeExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.AllNegative.Example.tsx') as string; +const VerticalBarChartResponsiveExampleCode = + require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Responsive.Example.tsx') as string; export const VerticalBarChartPageProps: IDocPageProps = { title: 'VerticalBarChart', @@ -82,6 +85,11 @@ export const VerticalBarChartPageProps: IDocPageProps = { code: VerticalBarChartAllNegativeExampleCode, view: , }, + { + title: 'VerticalBarChart responsive', + code: VerticalBarChartResponsiveExampleCode, + view: , + }, ], overview: require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/VerticalBarChart/docs/VerticalBarChartOverview.md'), bestPractices: require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/VerticalBarChart/docs/VerticalBarChartBestPractices.md'), diff --git a/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChartPage.tsx b/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChartPage.tsx index b6c47bfcca4d73..f63a32d596cf03 100644 --- a/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChartPage.tsx +++ b/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChartPage.tsx @@ -17,6 +17,7 @@ import { VerticalBarChartRotatedLabelExample } from './VerticalBarChart.RotateLa import { VerticalBarChartDateAxisExample } from './VerticalBarChart.DateAxis.Example'; import { VerticalBarChartNegativeExample } from './VerticalBarChart.Negative.Example'; import { VerticalBarChartAllNegativeExample } from './VerticalBarChart.AllNegative.Example'; +import { VerticalBarChartResponsiveExample } from './VerticalBarChart.Responsive.Example'; const VerticalBarChartBasicExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Basic.Example.tsx') as string; @@ -36,6 +37,8 @@ const VerticalBarChartNegativeExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Negative.Example.tsx') as string; const VerticalBarChartAllNegativeExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.AllNegative.Example.tsx') as string; +const VerticalBarChartResponsiveExampleCode = + require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Responsive.Example.tsx') as string; export class VerticalBarChartPage extends React.Component { public render(): JSX.Element { @@ -75,6 +78,9 @@ export class VerticalBarChartPage extends React.Component + + + } propertiesTables={ diff --git a/packages/react-examples/src/react-charting/VerticalBarChart/index.stories.tsx b/packages/react-examples/src/react-charting/VerticalBarChart/index.stories.tsx index 0bfb602a6ec6da..5da2ff1f470792 100644 --- a/packages/react-examples/src/react-charting/VerticalBarChart/index.stories.tsx +++ b/packages/react-examples/src/react-charting/VerticalBarChart/index.stories.tsx @@ -9,6 +9,7 @@ import { VerticalBarChartRotatedLabelExample } from './VerticalBarChart.RotateLa import { VerticalBarChartStyledExample } from './VerticalBarChart.Styled.Example'; import { VerticalBarChartNegativeExample } from './VerticalBarChart.Negative.Example'; import { VerticalBarChartAllNegativeExample } from './VerticalBarChart.AllNegative.Example'; +import { VerticalBarChartResponsiveExample } from './VerticalBarChart.Responsive.Example'; export const Basic = () => ; @@ -28,6 +29,8 @@ export const Negative = () => ; export const AllNegative = () => ; +export const Responsive = () => ; + export default { title: 'Components/VerticalBarChart', }; From bdf306bcdb679b06a1ae3ac8db1458a324ccfa71 Mon Sep 17 00:00:00 2001 From: krkshitij <110246001+krkshitij@users.noreply.github.com> Date: Fri, 24 Jan 2025 11:25:38 +0000 Subject: [PATCH 2/8] add change file --- ...eact-charting-54da258a-d516-4f4d-a974-d05d46893ca6.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@fluentui-react-charting-54da258a-d516-4f4d-a974-d05d46893ca6.json diff --git a/change/@fluentui-react-charting-54da258a-d516-4f4d-a974-d05d46893ca6.json b/change/@fluentui-react-charting-54da258a-d516-4f4d-a974-d05d46893ca6.json new file mode 100644 index 00000000000000..8dbafd8b0a59f4 --- /dev/null +++ b/change/@fluentui-react-charting-54da258a-d516-4f4d-a974-d05d46893ca6.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "feat: make charts responsive", + "packageName": "@fluentui/react-charting", + "email": "110246001+krkshitij@users.noreply.github.com", + "dependentChangeType": "patch" +} From 340db7a6afc4b5be5d2c76db577a23f972eb7a0d Mon Sep 17 00:00:00 2001 From: krkshitij <110246001+krkshitij@users.noreply.github.com> Date: Mon, 27 Jan 2025 07:26:34 +0000 Subject: [PATCH 3/8] make non-cartesian charts responsive --- .../components/DonutChart/DonutChart.base.tsx | 64 ++++---- .../components/GaugeChart/GaugeChart.base.tsx | 2 +- .../ResponsiveContainer.styles.ts | 2 +- .../ResponsiveContainer.tsx | 9 +- .../ResponsiveContainer.types.ts | 11 +- .../DonutChart.Responsive.Example.tsx | 140 ++++++++++++++++++ .../DonutChart/DonutChart.doc.tsx | 8 + .../DonutChart/DonutChartPage.tsx | 6 + .../DonutChart/index.stories.tsx | 3 + .../GaugeChart.Responsive.Example.tsx | 83 +++++++++++ .../GaugeChart/GaugeChart.doc.tsx | 8 + .../GaugeChart/GaugeChartPage.tsx | 6 + .../GaugeChart/index.stories.tsx | 3 + .../SankeyChart.Responsive.Example.tsx | 139 +++++++++++++++++ .../SankeyChart/SankeyChart.doc.tsx | 8 + .../SankeyChart/SankeyChartPage.tsx | 6 + .../SankeyChart/index.stories.tsx | 3 + .../VerticalBarChart.Responsive.Example.tsx | 12 +- 18 files changed, 471 insertions(+), 42 deletions(-) create mode 100644 packages/react-examples/src/react-charting/DonutChart/DonutChart.Responsive.Example.tsx create mode 100644 packages/react-examples/src/react-charting/GaugeChart/GaugeChart.Responsive.Example.tsx create mode 100644 packages/react-examples/src/react-charting/SankeyChart/SankeyChart.Responsive.Example.tsx diff --git a/packages/charts/react-charting/src/components/DonutChart/DonutChart.base.tsx b/packages/charts/react-charting/src/components/DonutChart/DonutChart.base.tsx index 79c4414e3307ab..e154f02c1e28c6 100644 --- a/packages/charts/react-charting/src/components/DonutChart/DonutChart.base.tsx +++ b/packages/charts/react-charting/src/components/DonutChart/DonutChart.base.tsx @@ -137,37 +137,39 @@ export class DonutChartBase extends React.Component (this._rootElem = rootElem)} onMouseLeave={this._handleChartMouseLeave} > - -
- this._setViewBox(node)} - > - - -
+ + this._setViewBox(node)} + > + + (this._rootElem = el)}> - + { width: '100%', height: '100%', - '& [class^="chartWrapper-"]': { + '& [class^="chartWrapper"]': { width: '100%', // optional // To prevent chart height from collapsing while resizing height: '100%', // optional diff --git a/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.tsx b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.tsx index 3da87a678f6b3d..67191b7d61496b 100644 --- a/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.tsx +++ b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.tsx @@ -1,6 +1,10 @@ import * as React from 'react'; import { classNamesFunction, getWindow } from '@fluentui/react'; -import { IResponsiveContainerProps, IResponsiveContainerStyles } from './ResponsiveContainer.types'; +import { + IResponsiveChildProps, + IResponsiveContainerProps, + IResponsiveContainerStyles, +} from './ResponsiveContainer.types'; import { getStyles } from './ResponsiveContainer.styles'; const getClassNames = classNamesFunction<{}, IResponsiveContainerStyles>(); @@ -55,9 +59,10 @@ export const ResponsiveContainer: React.FC = props => return (
- {React.cloneElement(props.children, { + {React.cloneElement(props.children, { width: size.containerWidth, height: size.containerHeight, + shouldResize: (size.containerWidth ?? 0) + (size.containerHeight ?? 0), })}
); diff --git a/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.types.ts b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.types.ts index c7bed7d1e36324..869a953b700d07 100644 --- a/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.types.ts +++ b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.types.ts @@ -1,6 +1,12 @@ import * as React from 'react'; import { IStyle } from '@fluentui/react/lib/Styling'; +export interface IResponsiveChildProps { + width?: number; + height?: number; + shouldResize?: number; +} + export interface IResponsiveContainerProps { /** * @@ -20,12 +26,9 @@ export interface IResponsiveContainerProps { /** * */ - children: React.ReactElement<{ width?: number; height?: number }>; + children: React.ReactElement; } export interface IResponsiveContainerStyles { - /** - * - */ root: IStyle; } diff --git a/packages/react-examples/src/react-charting/DonutChart/DonutChart.Responsive.Example.tsx b/packages/react-examples/src/react-charting/DonutChart/DonutChart.Responsive.Example.tsx new file mode 100644 index 00000000000000..15a87056f265b4 --- /dev/null +++ b/packages/react-examples/src/react-charting/DonutChart/DonutChart.Responsive.Example.tsx @@ -0,0 +1,140 @@ +import * as React from 'react'; +import { + DonutChart, + IChartProps, + IChartDataPoint, + DataVizPalette, + getColorFromToken, + getGradientFromToken, + DataVizGradientPalette, + ResponsiveContainer, +} from '@fluentui/react-charting'; +import { classNamesFunction, DefaultPalette, IStyle } from '@fluentui/react'; + +interface IExampleStyles { + resizableArea: IStyle; +} + +const getStyles = (): IExampleStyles => { + return { + resizableArea: { + display: 'flex', + flexWrap: 'nowrap', + overflow: 'hidden', + + minWidth: '100px', + maxWidth: '800px', + border: `2px solid ${DefaultPalette.blue}`, + padding: '20px 10px 10px 10px', + position: 'relative', + resize: 'horizontal', + '::after': { + content: `'Resizable Area'`, + position: 'absolute', + padding: '1px 4px 1px', + top: '-2px', + left: '-2px', + fontFamily: 'monospace', + fontSize: '15px', + fontWeight: 900, + letterSpacing: '1px', + color: DefaultPalette.white, + backgroundColor: DefaultPalette.blue, + }, + }, + }; +}; + +const points: IChartDataPoint[] = [ + { + legend: 'first', + data: 20000, + color: getColorFromToken(DataVizPalette.color1), + gradient: getGradientFromToken(DataVizGradientPalette.gradient1), + xAxisCalloutData: '2020/04/30', + }, + { + legend: 'second', + data: 39000, + color: getColorFromToken(DataVizPalette.color2), + gradient: getGradientFromToken(DataVizGradientPalette.gradient2), + xAxisCalloutData: '2020/04/20', + }, + { + legend: 'third', + data: 12000, + color: getColorFromToken(DataVizPalette.color3), + gradient: getGradientFromToken(DataVizGradientPalette.gradient2), + xAxisCalloutData: '2020/04/20', + }, + { + legend: 'fourth', + data: 2000, + color: getColorFromToken(DataVizPalette.color4), + gradient: getGradientFromToken(DataVizGradientPalette.gradient2), + xAxisCalloutData: '2020/04/20', + }, + { + legend: 'fifth', + data: 5000, + color: getColorFromToken(DataVizPalette.color5), + gradient: getGradientFromToken(DataVizGradientPalette.gradient2), + xAxisCalloutData: '2020/04/20', + }, + { + legend: 'sixth', + data: 6000, + color: getColorFromToken(DataVizPalette.color6), + gradient: getGradientFromToken(DataVizGradientPalette.gradient2), + xAxisCalloutData: '2020/04/20', + }, + { + legend: 'seventh', + data: 7000, + color: getColorFromToken(DataVizPalette.color7), + gradient: getGradientFromToken(DataVizGradientPalette.gradient2), + xAxisCalloutData: '2020/04/20', + }, + { + legend: 'eighth', + data: 8000, + color: getColorFromToken(DataVizPalette.color8), + gradient: getGradientFromToken(DataVizGradientPalette.gradient2), + xAxisCalloutData: '2020/04/20', + }, + { + legend: 'ninth', + data: 9000, + color: getColorFromToken(DataVizPalette.color9), + gradient: getGradientFromToken(DataVizGradientPalette.gradient2), + xAxisCalloutData: '2020/04/20', + }, + { + legend: 'tenth', + data: 10000, + color: getColorFromToken(DataVizPalette.color10), + gradient: getGradientFromToken(DataVizGradientPalette.gradient2), + xAxisCalloutData: '2020/04/20', + }, +]; + +const data: IChartProps = { + chartTitle: 'Donut chart basic example', + chartData: points, +}; + +const getClassNames = classNamesFunction<{}, IExampleStyles>(); + +export class DonutChartResponsiveExample extends React.Component { + private _classNames = getClassNames(getStyles()); + + public render(): JSX.Element { + return ( +
+ + + +
+ ); + } +} diff --git a/packages/react-examples/src/react-charting/DonutChart/DonutChart.doc.tsx b/packages/react-examples/src/react-charting/DonutChart/DonutChart.doc.tsx index 6c49316833cf88..cc397335776f8b 100644 --- a/packages/react-examples/src/react-charting/DonutChart/DonutChart.doc.tsx +++ b/packages/react-examples/src/react-charting/DonutChart/DonutChart.doc.tsx @@ -6,6 +6,7 @@ import { DonutChartBasicExample } from './DonutChart.Basic.Example'; import { DonutChartDynamicExample } from './DonutChart.Dynamic.Example'; import { DonutChartCustomCalloutExample } from './DonutChart.CustomCallout.Example'; import { DonutChartCustomAccessibilityExample } from './DonutChart.CustomAccessibility.Example'; +import { DonutChartResponsiveExample } from './DonutChart.Responsive.Example'; const DonutChartBasicExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/DonutChart/DonutChart.Basic.Example.tsx') as string; @@ -15,6 +16,8 @@ const DonutChartCustomCalloutExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/DonutChart/DonutChart.CustomCallout.Example.tsx') as string; const DonutChartCustomAccessibilityExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/DonutChart/DonutChart.CustomAccessibility.Example.tsx') as string; +const DonutChartResponsiveExampleCode = + require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/DonutChart/DonutChart.Responsive.Example.tsx') as string; export const DonutChartPageProps: IDocPageProps = { title: 'DonutChart', @@ -42,6 +45,11 @@ export const DonutChartPageProps: IDocPageProps = { code: DonutChartCustomAccessibilityExampleCode, view: , }, + { + title: 'DonutChart Responsive', + code: DonutChartResponsiveExampleCode, + view: , + }, ], overview: require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/DonutChart/docs/DonutChartOverview.md'), bestPractices: require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/DonutChart/docs/DonutChartBestPractices.md'), diff --git a/packages/react-examples/src/react-charting/DonutChart/DonutChartPage.tsx b/packages/react-examples/src/react-charting/DonutChart/DonutChartPage.tsx index 10d3a75feeb855..994d64fb69cb7f 100644 --- a/packages/react-examples/src/react-charting/DonutChart/DonutChartPage.tsx +++ b/packages/react-examples/src/react-charting/DonutChart/DonutChartPage.tsx @@ -12,6 +12,7 @@ import { DonutChartBasicExample } from './DonutChart.Basic.Example'; import { DonutChartDynamicExample } from './DonutChart.Dynamic.Example'; import { DonutChartCustomCalloutExample } from './DonutChart.CustomCallout.Example'; import { DonutChartCustomAccessibilityExample } from './DonutChart.CustomAccessibility.Example'; +import { DonutChartResponsiveExample } from './DonutChart.Responsive.Example'; const DonutChartBasicExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/DonutChart/DonutChart.Basic.Example.tsx') as string; @@ -21,6 +22,8 @@ const DonutChartCustomCalloutExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/DonutChart/DonutChart.CustomCallout.Example.tsx') as string; const DonutChartCustomAccessibilityExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/DonutChart/DonutChart.CustomAccessibility.Example.tsx') as string; +const DonutChartResponsiveExampleCode = + require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/DonutChart/DonutChart.Responsive.Example.tsx') as string; export class DonutChartPage extends React.Component { public render(): JSX.Element { @@ -42,6 +45,9 @@ export class DonutChartPage extends React.Component + + + } propertiesTables={ diff --git a/packages/react-examples/src/react-charting/DonutChart/index.stories.tsx b/packages/react-examples/src/react-charting/DonutChart/index.stories.tsx index 94732d49f5959b..cdca304f84dbc0 100644 --- a/packages/react-examples/src/react-charting/DonutChart/index.stories.tsx +++ b/packages/react-examples/src/react-charting/DonutChart/index.stories.tsx @@ -4,6 +4,7 @@ import { DonutChartBasicExample } from './DonutChart.Basic.Example'; import { DonutChartCustomAccessibilityExample } from './DonutChart.CustomAccessibility.Example'; import { DonutChartCustomCalloutExample } from './DonutChart.CustomCallout.Example'; import { DonutChartDynamicExample } from './DonutChart.Dynamic.Example'; +import { DonutChartResponsiveExample } from './DonutChart.Responsive.Example'; export const Basic = () => ; @@ -13,6 +14,8 @@ export const CustomCallout = () => ; export const Dynamic = () => ; +export const Responsive = () => ; + export default { title: 'Components/DonutChart', }; diff --git a/packages/react-examples/src/react-charting/GaugeChart/GaugeChart.Responsive.Example.tsx b/packages/react-examples/src/react-charting/GaugeChart/GaugeChart.Responsive.Example.tsx new file mode 100644 index 00000000000000..972c8dd442ab8b --- /dev/null +++ b/packages/react-examples/src/react-charting/GaugeChart/GaugeChart.Responsive.Example.tsx @@ -0,0 +1,83 @@ +import * as React from 'react'; +import { + DataVizPalette, + GaugeChart, + GaugeChartVariant, + getGradientFromToken, + DataVizGradientPalette, + ResponsiveContainer, +} from '@fluentui/react-charting'; +import { IStyle, DefaultPalette, classNamesFunction } from '@fluentui/react'; + +interface IExampleStyles { + resizableArea: IStyle; +} + +const getStyles = (): IExampleStyles => { + return { + resizableArea: { + display: 'flex', + flexWrap: 'nowrap', + overflow: 'hidden', + + minWidth: '200px', + maxWidth: '800px', + border: `2px solid ${DefaultPalette.blue}`, + padding: '20px 10px 10px 10px', + position: 'relative', + resize: 'horizontal', + '::after': { + content: `'Resizable Area'`, + position: 'absolute', + padding: '1px 4px 1px', + top: '-2px', + left: '-2px', + fontFamily: 'monospace', + fontSize: '15px', + fontWeight: 900, + letterSpacing: '1px', + color: DefaultPalette.white, + backgroundColor: DefaultPalette.blue, + }, + }, + }; +}; + +const getClassNames = classNamesFunction<{}, IExampleStyles>(); + +export class GaugeChartResponsiveExample extends React.Component { + private _classNames = getClassNames(getStyles()); + + public render(): React.ReactNode { + return ( +
+ + + +
+ ); + } +} diff --git a/packages/react-examples/src/react-charting/GaugeChart/GaugeChart.doc.tsx b/packages/react-examples/src/react-charting/GaugeChart/GaugeChart.doc.tsx index 638ffa1a16ae80..a3a6cdd8d8f7f9 100644 --- a/packages/react-examples/src/react-charting/GaugeChart/GaugeChart.doc.tsx +++ b/packages/react-examples/src/react-charting/GaugeChart/GaugeChart.doc.tsx @@ -4,11 +4,14 @@ import { IDocPageProps } from '@fluentui/react/lib/common/DocPage.types'; import { GaugeChartBasicExample } from './GaugeChart.Basic.Example'; import { GaugeChartSingleSegmentExample } from './GaugeChart.SingleSegment.Example'; +import { GaugeChartResponsiveExample } from './GaugeChart.Responsive.Example'; const GaugeChartBasicExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/GaugeChart/GaugeChart.Basic.Example.tsx') as string; const GaugeChartSingleSegmentExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/GaugeChart/GaugeChart.SingleSegment.Example.tsx') as string; +const GaugeChartResponsiveExampleCode = + require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/GaugeChart/GaugeChart.Responsive.Example.tsx') as string; export const GaugeChartPageProps: IDocPageProps = { title: 'GaugeChart', @@ -26,6 +29,11 @@ export const GaugeChartPageProps: IDocPageProps = { code: GaugeChartSingleSegmentExampleCode, view: , }, + { + title: 'GaugeChart responsive', + code: GaugeChartResponsiveExampleCode, + view: , + }, ], overview: require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/GaugeChart/docs/GaugeChartOverview.md'), bestPractices: require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/GaugeChart/docs/GaugeChartBestPractices.md'), diff --git a/packages/react-examples/src/react-charting/GaugeChart/GaugeChartPage.tsx b/packages/react-examples/src/react-charting/GaugeChart/GaugeChartPage.tsx index 1dae10b82fe164..7ab3637381e49d 100644 --- a/packages/react-examples/src/react-charting/GaugeChart/GaugeChartPage.tsx +++ b/packages/react-examples/src/react-charting/GaugeChart/GaugeChartPage.tsx @@ -10,11 +10,14 @@ import { import { GaugeChartBasicExample } from './GaugeChart.Basic.Example'; import { GaugeChartSingleSegmentExample } from './GaugeChart.SingleSegment.Example'; +import { GaugeChartResponsiveExample } from './GaugeChart.Responsive.Example'; const GaugeChartBasicExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/GaugeChart/GaugeChart.Basic.Example.tsx') as string; const GaugeChartSingleSegmentExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/GaugeChart/GaugeChart.SingleSegment.Example.tsx') as string; +const GaugeChartResponsiveExampleCode = + require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/GaugeChart/GaugeChart.Responsive.Example.tsx') as string; export class GaugeChartPage extends React.Component { public render(): JSX.Element { @@ -30,6 +33,9 @@ export class GaugeChartPage extends React.Component + + + } propertiesTables={ diff --git a/packages/react-examples/src/react-charting/GaugeChart/index.stories.tsx b/packages/react-examples/src/react-charting/GaugeChart/index.stories.tsx index 0b69cfb9866a19..d9d17ccb78878e 100644 --- a/packages/react-examples/src/react-charting/GaugeChart/index.stories.tsx +++ b/packages/react-examples/src/react-charting/GaugeChart/index.stories.tsx @@ -2,11 +2,14 @@ import * as React from 'react'; import { GaugeChartBasicExample } from './GaugeChart.Basic.Example'; import { GaugeChartSingleSegmentExample } from './GaugeChart.SingleSegment.Example'; +import { GaugeChartResponsiveExample } from './GaugeChart.Responsive.Example'; export const Basic = () => ; export const SingleSegment = () => ; +export const Responsive = () => ; + export default { title: 'Components/GaugeChart', }; diff --git a/packages/react-examples/src/react-charting/SankeyChart/SankeyChart.Responsive.Example.tsx b/packages/react-examples/src/react-charting/SankeyChart/SankeyChart.Responsive.Example.tsx new file mode 100644 index 00000000000000..5b61a800266609 --- /dev/null +++ b/packages/react-examples/src/react-charting/SankeyChart/SankeyChart.Responsive.Example.tsx @@ -0,0 +1,139 @@ +import * as React from 'react'; +import { IChartProps, ResponsiveContainer, SankeyChart } from '@fluentui/react-charting'; +import { classNamesFunction, DefaultPalette, IStyle } from '@fluentui/react'; + +interface IExampleStyles { + resizableArea: IStyle; +} + +const getStyles = (): IExampleStyles => { + return { + resizableArea: { + display: 'flex', + flexWrap: 'nowrap', + overflow: 'hidden', + + minWidth: '200px', + maxWidth: '800px', + border: `2px solid ${DefaultPalette.blue}`, + padding: '20px 10px 10px 10px', + position: 'relative', + resize: 'horizontal', + '::after': { + content: `'Resizable Area'`, + position: 'absolute', + padding: '1px 4px 1px', + top: '-2px', + left: '-2px', + fontFamily: 'monospace', + fontSize: '15px', + fontWeight: 900, + letterSpacing: '1px', + color: DefaultPalette.white, + backgroundColor: DefaultPalette.blue, + }, + }, + }; +}; + +const data: IChartProps = { + chartTitle: 'Sankey Chart', + SankeyChartData: { + nodes: [ + { + nodeId: 0, + name: 'node0', + color: '#00758F', + borderColor: '#002E39', + }, + { + nodeId: 1, + name: 'node1', + color: '#77004D', + borderColor: '#43002C', + }, + { + nodeId: 2, + name: 'node2', + color: '#4F6BED', + borderColor: '#3B52B4', + }, + { + nodeId: 3, + name: 'node3', + color: '#937600', + borderColor: '#6D5700', + }, + { + nodeId: 4, + name: 'node4', + color: '#286EA8', + borderColor: '#00457E', + }, + { + nodeId: 5, + name: 'node5', + color: '#A43FB1', + borderColor: '#7C158A', + }, + ], + links: [ + { + source: 0, + target: 2, + value: 2, + }, + { + source: 1, + target: 2, + value: 2, + }, + { + source: 1, + target: 3, + value: 2, + }, + { + source: 0, + target: 4, + value: 2, + }, + { + source: 2, + target: 3, + value: 2, + }, + { + source: 2, + target: 4, + value: 2, + }, + { + source: 3, + target: 4, + value: 4, + }, + { + source: 3, + target: 5, + value: 4, + }, + ], + }, +}; + +const getClassNames = classNamesFunction<{}, IExampleStyles>(); + +export class SankeyChartResponsiveExample extends React.Component { + private _classNames = getClassNames(getStyles()); + + public render(): JSX.Element { + return ( +
+ + + +
+ ); + } +} diff --git a/packages/react-examples/src/react-charting/SankeyChart/SankeyChart.doc.tsx b/packages/react-examples/src/react-charting/SankeyChart/SankeyChart.doc.tsx index f6e067b8e12c4e..a25ccd89b1c4a6 100644 --- a/packages/react-examples/src/react-charting/SankeyChart/SankeyChart.doc.tsx +++ b/packages/react-examples/src/react-charting/SankeyChart/SankeyChart.doc.tsx @@ -4,11 +4,14 @@ import { IDocPageProps } from '@fluentui/react/lib/common/DocPage.types'; import { SankeyChartBasicExample } from './SankeyChart.Basic.Example'; import { SankeyChartInboxExample } from './SankeyChart.Inbox.Example'; +import { SankeyChartResponsiveExample } from './SankeyChart.Responsive.Example'; const SankeyChartBasicExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/SankeyChart/SankeyChart.Basic.Example.tsx') as string; const SankeyChartInboxExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/SankeyChart/SankeyChart.Inbox.Example.tsx') as string; +const SankeyChartResponsiveExampleCode = + require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/SankeyChart/SankeyChart.Responsive.Example.tsx') as string; export const SankeyChartPageProps: IDocPageProps = { title: 'SankeyChart', @@ -26,6 +29,11 @@ export const SankeyChartPageProps: IDocPageProps = { code: SankeyChartInboxExampleCode, view: , }, + { + title: 'SankeyChart responsive', + code: SankeyChartResponsiveExampleCode, + view: , + }, ], overview: require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/SankeyChart/docs/SankeyChartOverview.md'), bestPractices: require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/SankeyChart/docs/SankeyChartBestPractices.md'), diff --git a/packages/react-examples/src/react-charting/SankeyChart/SankeyChartPage.tsx b/packages/react-examples/src/react-charting/SankeyChart/SankeyChartPage.tsx index defbaa447db0af..0dc3a56859193c 100644 --- a/packages/react-examples/src/react-charting/SankeyChart/SankeyChartPage.tsx +++ b/packages/react-examples/src/react-charting/SankeyChart/SankeyChartPage.tsx @@ -12,6 +12,7 @@ import { SankeyChartBasicExample } from './SankeyChart.Basic.Example'; import { SankeyChartInboxExample } from './SankeyChart.Inbox.Example'; import { SankeyChartRebalanceExample } from './SankeyChart.Rebalance.Example'; import { SankeyChartReflowExample } from './SankeyChart.Reflow.Example'; +import { SankeyChartResponsiveExample } from './SankeyChart.Responsive.Example'; const SankeyChartBasicExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/SankeyChart/SankeyChart.Basic.Example.tsx') as string; @@ -21,6 +22,8 @@ const SankeyChartRebalanceExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/SankeyChart/SankeyChart.Rebalance.Example.tsx') as string; const SankeyChartReflowExampleCode = require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/SankeyChart/SankeyChart.Reflow.Example.tsx') as string; +const SankeyChartResponsiveExampleCode = + require('!raw-loader?esModule=false!@fluentui/react-examples/src/react-charting/SankeyChart/SankeyChart.Responsive.Example.tsx') as string; export class SankeyChartPage extends React.Component { public render(): JSX.Element { @@ -42,6 +45,9 @@ export class SankeyChartPage extends React.Component + + + } propertiesTables={ diff --git a/packages/react-examples/src/react-charting/SankeyChart/index.stories.tsx b/packages/react-examples/src/react-charting/SankeyChart/index.stories.tsx index 2d2f11d82c2e2b..1d8278c12579dc 100644 --- a/packages/react-examples/src/react-charting/SankeyChart/index.stories.tsx +++ b/packages/react-examples/src/react-charting/SankeyChart/index.stories.tsx @@ -3,6 +3,7 @@ import * as React from 'react'; import { SankeyChartBasicExample } from './SankeyChart.Basic.Example'; import { SankeyChartInboxExample } from './SankeyChart.Inbox.Example'; import { SankeyChartRebalanceExample } from './SankeyChart.Rebalance.Example'; +import { SankeyChartResponsiveExample } from './SankeyChart.Responsive.Example'; export const Basic = () => ; @@ -10,6 +11,8 @@ export const Inbox = () => ; export const Rebalance = () => ; +export const Responsive = () => ; + export default { title: 'Components/SankeyChart', }; diff --git a/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Responsive.Example.tsx b/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Responsive.Example.tsx index 77273bcfda8258..e7ae5f99691b71 100644 --- a/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Responsive.Example.tsx +++ b/packages/react-examples/src/react-charting/VerticalBarChart/VerticalBarChart.Responsive.Example.tsx @@ -122,9 +122,15 @@ export class VerticalBarChartResponsiveExample extends React.Component { public render(): JSX.Element { return ( -
- - +
+ +
); From bf8d0baac3cc1a716720ba17b0542e85cf592d3e Mon Sep 17 00:00:00 2001 From: krkshitij <110246001+krkshitij@users.noreply.github.com> Date: Mon, 27 Jan 2025 10:13:09 +0000 Subject: [PATCH 4/8] add comments + update api --- .../react-charting/etc/react-charting.api.md | 21 +++++++++++-------- .../ResponsiveContainer.tsx | 4 ++++ .../ResponsiveContainer.types.ts | 16 ++++++++++---- packages/charts/react-charting/src/index.ts | 2 +- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/packages/charts/react-charting/etc/react-charting.api.md b/packages/charts/react-charting/etc/react-charting.api.md index 98f8df1416fa8e..96c52f527ac177 100644 --- a/packages/charts/react-charting/etc/react-charting.api.md +++ b/packages/charts/react-charting/etc/react-charting.api.md @@ -1212,18 +1212,21 @@ export interface IRefArrayData { refElement?: SVGGElement; } -// @public (undocumented) -export interface IResponsiveContainerProps { +// @public +export interface IResponsiveChildProps { // (undocumented) - children: React_2.ReactElement<{ - width?: number; - height?: number; - }>; + height?: number; // (undocumented) - height?: number | string; + shouldResize?: number; // (undocumented) + width?: number; +} + +// @public +export interface IResponsiveContainerProps { + children: React_2.ReactElement; + height?: number | string; onResize?: (width: number, height: number) => void; - // (undocumented) width?: number | string; } @@ -1652,7 +1655,7 @@ export enum NodesComposition { // @public export const PieChart: React_2.FunctionComponent; -// @public (undocumented) +// @public export const ResponsiveContainer: React_2.FC; // @public diff --git a/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.tsx b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.tsx index 67191b7d61496b..e6858ddaaf06dc 100644 --- a/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.tsx +++ b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.tsx @@ -9,6 +9,10 @@ import { getStyles } from './ResponsiveContainer.styles'; const getClassNames = classNamesFunction<{}, IResponsiveContainerStyles>(); +/** + * Responsive Container component + * {@docCategory ResponsiveContainer} + */ export const ResponsiveContainer: React.FC = props => { const containerRef = React.useRef(null); const onResizeRef = React.useRef(); diff --git a/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.types.ts b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.types.ts index 869a953b700d07..5841c8e0f9c63c 100644 --- a/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.types.ts +++ b/packages/charts/react-charting/src/components/ResponsiveContainer/ResponsiveContainer.types.ts @@ -1,30 +1,38 @@ import * as React from 'react'; import { IStyle } from '@fluentui/react/lib/Styling'; +/** + * Responsive Child props + * {@docCategory ResponsiveContainer} + */ export interface IResponsiveChildProps { width?: number; height?: number; shouldResize?: number; } +/** + * Responsive Container props + * {@docCategory ResponsiveContainer} + */ export interface IResponsiveContainerProps { /** - * + * Width of the container */ width?: number | string; /** - * + * Height of the container */ height?: number | string; /** - * + * Callback providing the updated chart width and height values when the container is resized */ onResize?: (width: number, height: number) => void; /** - * + * Child component to be rendered within the container */ children: React.ReactElement; } diff --git a/packages/charts/react-charting/src/index.ts b/packages/charts/react-charting/src/index.ts index 561374349d8735..abc55ffcaf7293 100644 --- a/packages/charts/react-charting/src/index.ts +++ b/packages/charts/react-charting/src/index.ts @@ -138,7 +138,7 @@ export type { IGaugeChartProps, IGaugeChartSegment, IGaugeChartStyleProps, IGaug export { GaugeChart, GaugeChartVariant, GaugeValueFormat } from './GaugeChart'; export type { DeclarativeChartProps, Schema, IDeclarativeChart, IImageExportOptions } from './DeclarativeChart'; export { DeclarativeChart } from './DeclarativeChart'; -export type { IResponsiveContainerProps } from './ResponsiveContainer'; +export type { IResponsiveContainerProps, IResponsiveChildProps } from './ResponsiveContainer'; export { ResponsiveContainer } from './ResponsiveContainer'; import './version'; From 6dece1da76fe140dffdfcb198c302e2186629316 Mon Sep 17 00:00:00 2001 From: krkshitij <110246001+krkshitij@users.noreply.github.com> Date: Mon, 27 Jan 2025 11:18:42 +0000 Subject: [PATCH 5/8] update snapshots --- .../DeclarativeChartRTL.test.tsx.snap | 1327 ++++---- .../__snapshots__/DonutChart.test.tsx.snap | 2713 ++++++++--------- .../__snapshots__/DonutChartRTL.test.tsx.snap | 326 +- .../__snapshots__/GaugeChart.test.tsx.snap | 11 + 4 files changed, 2186 insertions(+), 2191 deletions(-) diff --git a/packages/charts/react-charting/src/components/DeclarativeChart/__snapshots__/DeclarativeChartRTL.test.tsx.snap b/packages/charts/react-charting/src/components/DeclarativeChart/__snapshots__/DeclarativeChartRTL.test.tsx.snap index cf92ce1f59e5a4..2545983a162786 100644 --- a/packages/charts/react-charting/src/components/DeclarativeChart/__snapshots__/DeclarativeChartRTL.test.tsx.snap +++ b/packages/charts/react-charting/src/components/DeclarativeChart/__snapshots__/DeclarativeChartRTL.test.tsx.snap @@ -1215,542 +1215,541 @@ exports[`DeclarativeChart Should render donutchart in DeclarativeChart 1`] = `
-
- + - - - - - - + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - + + + + + + - - 1 - - - - -
+ 1 + + + +
-
- + - - - + - + - - - + 4.5k + + + + - + - - - + 2.5k + + + + - + - - - + 1.1k + + + + - + - - + { + fill: #323130; + font-size: 12px; + font-weight: 600; + } + dominant-baseline="auto" + text-anchor="end" + x="-13.690880285443459" + y="-70.68634802428016" + > + 500 + - -
+ + +
-
- + - - - + - - - + + + - - - + + + - + { + cursor: default; + fill: #DADADA; + opacity: 1; + outline: transparent; + stroke: #ffffff; + } + &::-moz-focus-inner { + border: 0; + } + d="M-23.402,49.773A55,55,0,0,1,-0.585,-54.997L-0.585,19.991Z" + data-is-focusable={true} + id="_Pie_1third45000" + onBlur={[Function]} + onFocus={[Function]} + onMouseLeave={[Function]} + onMouseMove={[Function]} + onMouseOver={[Function]} + role="img" + /> - -
+ +
-
- + - - - + - - - + + + - - - + + + - + { + cursor: default; + fill: #DADADA; + opacity: 1; + outline: transparent; + stroke: #ffffff; + } + &::-moz-focus-inner { + border: 0; + } + d="M-23.402,49.773A55,55,0,0,1,-0.585,-54.997L-0.585,19.991Z" + data-is-focusable={true} + id="_Pie_1third45000" + onBlur={[Function]} + onFocus={[Function]} + onMouseLeave={[Function]} + onMouseMove={[Function]} + onMouseOver={[Function]} + role="img" + /> - -
+ +
-
- + - - - + - - - + + + - - - + + + - - + { + cursor: default; + fill: #DADADA; + opacity: 1; + outline: transparent; + stroke: #ffffff; + } + &::-moz-focus-inner { + border: 0; + } + d="M-42.492,90.523A100,100,0,0,1,-1,-99.995L0,0Z" + data-is-focusable={true} + id="_Pie_1third45000" + onBlur={[Function]} + onFocus={[Function]} + onMouseLeave={[Function]} + onMouseMove={[Function]} + onMouseOver={[Function]} + role="img" + /> - -
+ + +
-
- + - - - + - + - 20.0k - - - - + 20.0k + + + + - + - 39.0k - - - - + 39.0k + + + + - + - 45.0k - - - + { + fill: #323130; + font-size: 12px; + font-weight: 600; + } + dominantBaseline="auto" + textAnchor="end" + x={-60.58001193073337} + y={-13.19326170710649} + > + 45.0k + - -
+ + + -
- + - - - + - + - 19% - - - - + 19% + + + + - + - 38% - - - - + 38% + + + + - + - 43% - - - + { + fill: #323130; + font-size: 12px; + font-weight: 600; + } + dominantBaseline="auto" + textAnchor="end" + x={-60.58001193073337} + y={-13.19326170710649} + > + 43% + - -
+ + + -
- + - - + + + + + + -
- + - - - + - - - + + + - - - + + + - - + { + cursor: default; + fill: #DADADA; + opacity: 1; + outline: transparent; + stroke: #ffffff; + } + &::-moz-focus-inner { + border: 0; + } + d="M-42.492,90.523A100,100,0,0,1,-1,-99.995L0,0Z" + data-is-focusable={true} + id="_Pie_1third45000" + onBlur={[Function]} + onFocus={[Function]} + onMouseLeave={[Function]} + onMouseMove={[Function]} + onMouseOver={[Function]} + role="img" + /> - -
+ + + -
- + - - - + - - - + + + - - - + + + - - + { + cursor: default; + fill: #DADADA; + opacity: 1; + outline: transparent; + stroke: #ffffff; + } + &::-moz-focus-inner { + border: 0; + } + d="M-42.492,90.523A100,100,0,0,1,-1,-99.995L0,0Z" + data-is-focusable={true} + id="_Pie_1third45000" + onBlur={[Function]} + onFocus={[Function]} + onMouseLeave={[Function]} + onMouseMove={[Function]} + onMouseOver={[Function]} + role="img" + /> - -
+ + + -
- + - - - + - - - + + + - - - + + + - - + { + cursor: default; + fill: #DADADA; + opacity: 1; + outline: transparent; + stroke: #ffffff; + } + &::-moz-focus-inner { + border: 0; + } + d="M-42.492,90.523A100,100,0,0,1,-1,-99.995L0,0Z" + data-is-focusable={true} + id="_Pie_1third45000" + onBlur={[Function]} + onFocus={[Function]} + onMouseLeave={[Function]} + onMouseMove={[Function]} + onMouseOver={[Function]} + role="img" + /> - -
+ + + -
- + - - - + - - - + + + - - - + + + - + { + cursor: default; + fill: #DADADA; + opacity: 1; + outline: transparent; + stroke: #ffffff; + } + &::-moz-focus-inner { + border: 0; + } + d="M-23.402,49.773A55,55,0,0,1,-0.585,-54.997L-0.585,19.991Z" + data-is-focusable="true" + id="_Pie_1third45000" + role="img" + tabindex="-1" + /> - -
+ +
-
- + - - - + - - - + + + - - - + + + - + { + cursor: default; + fill: #DADADA; + opacity: 1; + outline: transparent; + stroke: #1b1a19; + } + &::-moz-focus-inner { + border: 0; + } + d="M-23.402,49.773A55,55,0,0,1,-0.585,-54.997L-0.585,19.991Z" + data-is-focusable="true" + id="_Pie_4third45000" + role="img" + tabindex="-1" + /> - -
+ +
Date: Wed, 29 Jan 2025 18:24:06 +0000 Subject: [PATCH 6/8] use responsive container in declarative chart --- .../react-charting/etc/react-charting.api.md | 3 + .../DeclarativeChart/DeclarativeChart.tsx | 56 +- .../DeclarativeChart/PlotlySchemaAdapter.ts | 36 +- .../DeclarativeChartRTL.test.tsx.snap | 51270 ++++++++-------- .../PlotlySchemaAdapterUT.test.tsx.snap | 23 +- .../components/ResponsiveContainer/index.ts | 1 + .../withResponsiveContainer.tsx | 22 + packages/charts/react-charting/src/index.ts | 2 +- 8 files changed, 25801 insertions(+), 25612 deletions(-) create mode 100644 packages/charts/react-charting/src/components/ResponsiveContainer/withResponsiveContainer.tsx diff --git a/packages/charts/react-charting/etc/react-charting.api.md b/packages/charts/react-charting/etc/react-charting.api.md index c8e63ec29d1acc..9112d077a89a7a 100644 --- a/packages/charts/react-charting/etc/react-charting.api.md +++ b/packages/charts/react-charting/etc/react-charting.api.md @@ -1706,6 +1706,9 @@ export const VerticalBarChart: React_2.FunctionComponent // @public export const VerticalStackedBarChart: React_2.FunctionComponent; +// @public +export function withResponsiveContainer>(WrappedComponent: React_2.ComponentType): React_2.FC; + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/charts/react-charting/src/components/DeclarativeChart/DeclarativeChart.tsx b/packages/charts/react-charting/src/components/DeclarativeChart/DeclarativeChart.tsx index fc6dcf1dbd4050..1bc81bc7de36a2 100644 --- a/packages/charts/react-charting/src/components/DeclarativeChart/DeclarativeChart.tsx +++ b/packages/charts/react-charting/src/components/DeclarativeChart/DeclarativeChart.tsx @@ -33,6 +33,18 @@ import { GroupedVerticalBarChart } from '../GroupedVerticalBarChart/index'; import { VerticalBarChart } from '../VerticalBarChart/index'; import { IImageExportOptions, toImage } from './imageExporter'; import { IChart } from '../../types/index'; +import { withResponsiveContainer } from '../ResponsiveContainer/withResponsiveContainer'; + +const ResponsiveDonutChart = withResponsiveContainer(DonutChart); +const ResponsiveVerticalStackedBarChart = withResponsiveContainer(VerticalStackedBarChart); +const ResponsiveLineChart = withResponsiveContainer(LineChart); +const ResponsiveHorizontalBarChartWithAxis = withResponsiveContainer(HorizontalBarChartWithAxis); +const ResponsiveAreaChart = withResponsiveContainer(AreaChart); +const ResponsiveHeatMapChart = withResponsiveContainer(HeatMapChart); +const ResponsiveSankeyChart = withResponsiveContainer(SankeyChart); +const ResponsiveGaugeChart = withResponsiveContainer(GaugeChart); +const ResponsiveGroupedVerticalBarChart = withResponsiveContainer(GroupedVerticalBarChart); +const ResponsiveVerticalBarChart = withResponsiveContainer(VerticalBarChart); /** * DeclarativeChart schema. @@ -167,7 +179,7 @@ export const DeclarativeChart: React.FunctionComponent = // Unsupported schema, render as VerticalStackedBarChart fallbackVSBC = true; return ( - @@ -195,12 +207,17 @@ export const DeclarativeChart: React.FunctionComponent = switch (plotlyInput.data[0].type) { case 'pie': - return ; + return ( + + ); case 'bar': const orientation = plotlyInput.data[0].orientation; if (orientation === 'h') { return ( - @@ -211,14 +228,14 @@ export const DeclarativeChart: React.FunctionComponent = ); if (['group', 'overlay'].includes(plotlySchema?.layout?.barmode) && !containsLines) { return ( - ); } return ( - @@ -233,34 +250,49 @@ export const DeclarativeChart: React.FunctionComponent = ); const renderChartJsx = (chartProps: ILineChartProps | IAreaChartProps) => { if (isAreaChart) { - return ; + return ; } - return ; + return ; }; return checkAndRenderChart(renderChartJsx, isAreaChart); case 'heatmap': - return ; + return ( + + ); case 'sankey': return ( - + ); case 'indicator': if (plotlyInput.data?.[0]?.mode?.includes('gauge')) { return ( - + ); } throw new Error(`Unsupported chart - type: ${plotlyInput.data[0]?.type}, mode: ${plotlyInput.data[0]?.mode}`); case 'histogram': return ( - + ); default: const xValues = (plotlyInput.data[0] as PlotData).x; const yValues = (plotlyInput.data[0] as PlotData).y; if (xValues && yValues && xValues.length > 0 && yValues.length > 0) { const renderLineChartJsx = (chartProps: ILineChartProps) => { - return ; + return ; }; return checkAndRenderChart(renderLineChartJsx); } diff --git a/packages/charts/react-charting/src/components/DeclarativeChart/PlotlySchemaAdapter.ts b/packages/charts/react-charting/src/components/DeclarativeChart/PlotlySchemaAdapter.ts index b0ee50789c429a..e4929a1685e314 100644 --- a/packages/charts/react-charting/src/components/DeclarativeChart/PlotlySchemaAdapter.ts +++ b/packages/charts/react-charting/src/components/DeclarativeChart/PlotlySchemaAdapter.ts @@ -339,8 +339,8 @@ export const transformPlotlyJsonToVSBCProps = ( return { data: Object.values(mapXToDataPoints), - // width: layout?.width, - // height: layout?.height, + width: input.layout?.width, + height: input.layout?.height ?? 350, barWidth: 'auto', yMaxValue, chartTitle, @@ -390,8 +390,8 @@ export const transformPlotlyJsonToGVBCProps = ( return { data: Object.values(mapXToDataPoints), - // width: layout?.width, - // height: layout?.height, + width: input.layout?.width, + height: input.layout?.height ?? 350, barwidth: 'auto', chartTitle, xAxisTitle, @@ -483,8 +483,8 @@ export const transformPlotlyJsonToVBCProps = ( return { data: vbcData, - // width: layout?.width, - // height: layout?.height, + width: input.layout?.width, + height: input.layout?.height ?? 350, supportNegativeData: true, chartTitle, xAxisTitle, @@ -541,6 +541,8 @@ export const transformPlotlyJsonToScatterChartProps = ( secondaryYAxistitle: secondaryYAxisValues.secondaryYAxistitle, secondaryYScaleOptions: secondaryYAxisValues.secondaryYScaleOptions, mode, + width: input.layout?.width, + height: input.layout?.height ?? 350, } as IAreaChartProps; } else { return { @@ -550,6 +552,8 @@ export const transformPlotlyJsonToScatterChartProps = ( yAxisTitle, secondaryYAxistitle: secondaryYAxisValues.secondaryYAxistitle, secondaryYScaleOptions: secondaryYAxisValues.secondaryYScaleOptions, + width: input.layout?.width, + height: input.layout?.height ?? 350, } as ILineChartProps; } }; @@ -599,12 +603,8 @@ export const transformPlotlyJsonToHorizontalBarWithAxisProps = ( : input.layout?.yaxis2?.title?.text || '', barHeight, showYAxisLables: true, - styles: { - root: { - height: chartHeight, - width: input.layout?.width ?? 600, - }, - }, + height: chartHeight, + width: input.layout?.width, }; }; @@ -662,6 +662,8 @@ export const transformPlotlyJsonToHeatmapProps = (input: PlotlySchema): IHeatMap xAxisTitle, yAxisTitle, sortOrder: 'none', + width: input.layout?.width, + height: input.layout?.height ?? 350, }; }; @@ -698,14 +700,11 @@ export const transformPlotlyJsonToSankeyProps = ( }), } as ISankeyChartData; - const width: number = input.layout?.width ?? 440; - const height: number = input.layout?.height ?? 220; const styles: ISankeyChartProps['styles'] = { root: { ...(input.layout?.font?.size ? { fontSize: input.layout.font?.size } : {}), }, }; - const shouldResize: number = width + height; const { chartTitle } = getTitles(input.layout); @@ -714,10 +713,9 @@ export const transformPlotlyJsonToSankeyProps = ( chartTitle, SankeyChartData: sankeyChartData, }, - width, - height, + width: input.layout?.width, + height: input.layout?.height ?? 468, styles, - shouldResize, enableReflow: true, }; }; @@ -784,7 +782,7 @@ export const transformPlotlyJsonToGaugeProps = ( minValue: typeof firstData.gauge?.axis?.range?.[0] === 'number' ? firstData.gauge?.axis?.range?.[0] : undefined, maxValue: typeof firstData.gauge?.axis?.range?.[1] === 'number' ? firstData.gauge?.axis?.range?.[1] : undefined, chartValueFormat: () => firstData.value?.toString() ?? '', - width: input.layout?.width ?? 440, + width: input.layout?.width, height: input.layout?.height ?? 220, styles, variant: firstData.gauge?.steps?.length ? GaugeChartVariant.MultipleSegments : GaugeChartVariant.SingleSegment, diff --git a/packages/charts/react-charting/src/components/DeclarativeChart/__snapshots__/DeclarativeChartRTL.test.tsx.snap b/packages/charts/react-charting/src/components/DeclarativeChart/__snapshots__/DeclarativeChartRTL.test.tsx.snap index 2545983a162786..4d79985aeaa9e7 100644 --- a/packages/charts/react-charting/src/components/DeclarativeChart/__snapshots__/DeclarativeChartRTL.test.tsx.snap +++ b/packages/charts/react-charting/src/components/DeclarativeChart/__snapshots__/DeclarativeChartRTL.test.tsx.snap @@ -6,1182 +6,1200 @@ exports[`DeclarativeChart Should render areachart in DeclarativeChart 1`] = ` class= { - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - display: flex; - flex-direction: column; - font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif; - font-size: 14px; - font-weight: 400; height: 100%; - overflow: hidden; width: 100%; } - id="chart_6" + & [class^="chartWrapper"] { + height: 100%; + width: 100%; + } + & [class^="chartWrapper"] > svg { + height: 100%; + width: 100%; + } + style="height: 350px;" > -
- +
- - + - - - - - - - - - - - - - - - - - - - - + + - + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
+ +
-
-
+
+