From bea05199df60d06e45b7a1223ff3cc5ff5729bc5 Mon Sep 17 00:00:00 2001 From: Dan Labrecque Date: Thu, 16 Feb 2023 22:23:32 -0500 Subject: [PATCH 1/4] feat(charts) Add legendAllowWrap callback prop Closes https://github.com/patternfly/patternfly-react/issues/8643 --- .../src/components/Chart/Chart.tsx | 34 +++- .../components/ChartBullet/ChartBullet.tsx | 32 +++- .../ChartBullet/examples/ChartBullet.md | 16 +- .../src/components/ChartDonut/ChartDonut.tsx | 15 +- .../ChartDonutUtilization.tsx | 13 +- .../ChartLegend/examples/ChartLegend.md | 72 +++++---- .../src/components/ChartPie/ChartPie.tsx | 38 ++++- .../src/components/ChartUtils/chart-legend.ts | 33 +++- .../components/Patterns/examples/patterms.md | 153 +++++++++++------- .../ResizeObserver/examples/resizeObserver.md | 16 +- 10 files changed, 320 insertions(+), 102 deletions(-) diff --git a/packages/react-charts/src/components/Chart/Chart.tsx b/packages/react-charts/src/components/Chart/Chart.tsx index 9c311c1c840..ae6649765fb 100644 --- a/packages/react-charts/src/components/Chart/Chart.tsx +++ b/packages/react-charts/src/components/Chart/Chart.tsx @@ -31,8 +31,10 @@ import { getPaddingForSide, getPatternDefs, getDefaultData, - useDefaultPatternProps -} from '../ChartUtils'; + getLegendItemsExtraHeight, + useDefaultPatternProps, +} from "../ChartUtils"; +import { useEffect } from "react"; /** * Chart is a wrapper component that reconciles the domain for all its children, controls the layout of the chart, @@ -236,11 +238,22 @@ export interface ChartProps extends VictoryChartProps { innerRadius?: number; /** * Allows legend items to wrap. A value of true allows the legend to wrap onto the next line - * if its container is not wide enough. + * if the chart is not wide enough. + * + * Note that the chart's SVG height and width are 100% by default, so it can be responsive itself. However, if you + * define the height and width of the chart's parent container, you must accommodate for extra legend height due to + * legend items wrapping onto the next line. When the height of the chart's parent container is too small, some legend + * items may not be visible. * * Note: This is overridden by the legendItemsPerRow property */ legendAllowWrap?: boolean; + /** + * If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been + * calculated, based on available width. The value provided can be used to increase the chart's parent container + * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. + */ + legendAllowWrapCallback?: (extraHeight: number) => void; /** * The legend component to render with chart. * @@ -464,6 +477,7 @@ export const Chart: React.FunctionComponent = ({ colorScale, hasPatterns, legendAllowWrap = false, + legendAllowWrapCallback, legendComponent = , legendData, legendPosition = ChartCommonStyles.legend.position as ChartLegendPosition, @@ -594,6 +608,20 @@ export const Chart: React.FunctionComponent = ({ return child; }); + // Callback to compliment legendAllowWrap + useEffect(() => { + if (legendAllowWrap && legendAllowWrapCallback) { + const computedLegend = getLegend(); + const extraHeight = getLegendItemsExtraHeight({ + legendData: computedLegend.props.data, + legendOrientation: computedLegend.props.orientation, + legendProps: computedLegend.props, + theme + }); + legendAllowWrapCallback(extraHeight); + } + }, [width]); + // Note: containerComponent is required for theme return ( string | number | null); /** * Allows legend items to wrap. A value of true allows the legend to wrap onto the next line - * if its container is not wide enough. + * if the chart is not wide enough. + * + * Note that the chart's SVG height and width are 100% by default, so it can be responsive itself. However, if you + * define the height and width of the chart's parent container, you must accommodate for extra legend height due to + * legend items wrapping onto the next line. When the height of the chart's parent container is too small, some legend + * items may not be visible. * * Note: This is overridden by the legendItemsPerRow property */ legendAllowWrap?: boolean; + /** + * If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been + * calculated, based on available width. The value provided can be used to increase the chart's parent container + * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. + */ + legendAllowWrapCallback?: (extraHeight: number) => void; /** * The legend component to render with chart. */ @@ -495,6 +507,7 @@ export const ChartBullet: React.FunctionComponent = ({ invert = false, labels, legendAllowWrap = false, + legendAllowWrapCallback, legendComponent = , legendItemsPerRow, legendPosition = 'bottom' as ChartLegendPosition, @@ -766,6 +779,7 @@ export const ChartBullet: React.FunctionComponent = ({ } dx = -10; } + return getComputedLegend({ allowWrap: legendAllowWrap, chartType: 'bullet', @@ -840,6 +854,20 @@ export const ChartBullet: React.FunctionComponent = ({ ); + // Callback to compliment legendAllowWrap + useEffect(() => { + if (legendAllowWrap && legendAllowWrapCallback) { + const computedLegend = getLegend(); + const extraHeight = getLegendItemsExtraHeight({ + legendData: computedLegend.props.data, + legendOrientation: computedLegend.props.orientation, + legendProps: computedLegend.props, + theme + }); + legendAllowWrapCallback(extraHeight); + } + }, [width]); + return standalone ? ( {bulletChart} diff --git a/packages/react-charts/src/components/ChartBullet/examples/ChartBullet.md b/packages/react-charts/src/components/ChartBullet/examples/ChartBullet.md index 04b9fc3f63a..01d3467e55c 100644 --- a/packages/react-charts/src/components/ChartBullet/examples/ChartBullet.md +++ b/packages/react-charts/src/components/ChartBullet/examples/ChartBullet.md @@ -92,6 +92,7 @@ class BulletChart extends React.Component { this.containerRef = React.createRef(); this.observer = () => {}; this.state = { + extraHeight: 0, width: 0 }; this.handleResize = () => { @@ -99,6 +100,15 @@ class BulletChart extends React.Component { this.setState({ width: this.containerRef.current.clientWidth }); } }; + this.handleLegendAllowWrapCallback = (extraHeight) => { + if (extraHeight !== this.state.extraHeight) { + this.setState({ extraHeight }); + } + } + this.getHeight = (baseHeight) => { + const { extraHeight } = this.state; + return baseHeight + extraHeight; + }; } componentDidMount() { @@ -112,17 +122,19 @@ class BulletChart extends React.Component { render() { const { width } = this.state; + const height = this.getHeight(200); return ( -
+
`${datum.name}: ${datum.y}`} legendAllowWrap + legendAllowWrapCallback={this.handleLegendAllowWrapCallback} legendPosition="bottom-left" maxDomain={{y: 100}} name="chart3" diff --git a/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx b/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx index 309744cfd29..56c7735a221 100644 --- a/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx +++ b/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx @@ -309,11 +309,22 @@ export interface ChartDonutProps extends ChartPieProps { labels?: string[] | number[] | ((data: any) => string | number | null); /** * Allows legend items to wrap. A value of true allows the legend to wrap onto the next line - * if its container is not wide enough. + * if the chart is not wide enough. + * + * Note that the chart's SVG height and width are 100% by default, so it can be responsive itself. However, if you + * define the height and width of the chart's parent container, you must accommodate for extra legend height due to + * legend items wrapping onto the next line. When the height of the chart's parent container is too small, some legend + * items may not be visible. * * Note: This is overridden by the legendItemsPerRow property */ legendAllowWrap?: boolean; + /** + * If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been + * calculated, based on available width. The value provided can be used to increase the chart's parent container + * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. + */ + legendAllowWrapCallback?: (extraHeight: number) => void; /** * The legend component to render with chart. * @@ -580,7 +591,6 @@ export const ChartDonut: React.FunctionComponent = ({ capHeight = 1.1, containerComponent = , innerRadius, - legendAllowWrap, legendPosition = ChartCommonStyles.legend.position as ChartPieLegendPosition, name, padAngle, @@ -706,7 +716,6 @@ export const ChartDonut: React.FunctionComponent = ({ height={height} innerRadius={chartInnerRadius > 0 ? chartInnerRadius : 0} key="pf-chart-donut-pie" - legendAllowWrap={legendAllowWrap} legendPosition={legendPosition} name={name} padAngle={padAngle !== undefined ? padAngle : getPadAngle} diff --git a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx b/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx index 5650c008bd1..31e26a6dca6 100644 --- a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx +++ b/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx @@ -293,11 +293,22 @@ export interface ChartDonutUtilizationProps extends ChartDonutProps { isStatic?: boolean; /** * Allows legend items to wrap. A value of true allows the legend to wrap onto the next line - * if its container is not wide enough. + * if the chart is not wide enough. + * + * Note that the chart's SVG height and width are 100% by default, so it can be responsive itself. However, if you + * define the height and width of the chart's parent container, you must accommodate for extra legend height due to + * legend items wrapping onto the next line. When the height of the chart's parent container is too small, some legend + * items may not be visible. * * Note: This is overridden by the legendItemsPerRow property */ legendAllowWrap?: boolean; + /** + * If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been + * calculated, based on available width. The value provided can be used to increase the chart's parent container + * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. + */ + legendAllowWrapCallback?: (extraHeight: number) => void; /** * The labelComponent prop takes in an entire label component which will be used * to create a label for the area. The new element created from the passed labelComponent diff --git a/packages/react-charts/src/components/ChartLegend/examples/ChartLegend.md b/packages/react-charts/src/components/ChartLegend/examples/ChartLegend.md index 27201b4d578..01c6e077bf9 100644 --- a/packages/react-charts/src/components/ChartLegend/examples/ChartLegend.md +++ b/packages/react-charts/src/components/ChartLegend/examples/ChartLegend.md @@ -131,13 +131,23 @@ class BulletChart extends React.Component { this.containerRef = React.createRef(); this.observer = () => {}; this.state = { + extraHeight: 0, width: 0 }; this.handleResize = () => { - if(this.containerRef.current && this.containerRef.current.clientWidth){ + if (this.containerRef.current && this.containerRef.current.clientWidth) { this.setState({ width: this.containerRef.current.clientWidth }); } }; + this.handleLegendAllowWrapCallback = (extraHeight) => { + if (extraHeight !== this.state.extraHeight) { + this.setState({ extraHeight }); + } + } + this.getHeight = (baseHeight) => { + const { extraHeight } = this.state; + return baseHeight + extraHeight; + }; } componentDidMount() { @@ -151,37 +161,37 @@ class BulletChart extends React.Component { render() { const { width } = this.state; + const height = this.getHeight(200); return ( -
-
- `${datum.name}: ${datum.y}`} - legendAllowWrap - legendPosition="bottom-left" - maxDomain={{y: 100}} - name="chart3" - padding={{ - bottom: 50, - left: 50, - right: 50, - top: 100 // Adjusted to accommodate labels - }} - primarySegmentedMeasureData={[{ name: 'Measure', y: 25 }, { name: 'Measure', y: 60 }]} - primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} - qualitativeRangeData={[{ name: 'Range', y: 50 }, { name: 'Range', y: 75 }]} - qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} - subTitle="Measure details" - title="Text label" - titlePosition="top-left" - width={width} - /> -
+
+ `${datum.name}: ${datum.y}`} + legendAllowWrap + legendAllowWrapCallback={this.handleLegendAllowWrapCallback} + legendPosition="bottom-left" + maxDomain={{y: 100}} + name="chart3" + padding={{ + bottom: 50, + left: 50, + right: 50, + top: 100 // Adjusted to accommodate labels + }} + primarySegmentedMeasureData={[{ name: 'Measure', y: 25 }, { name: 'Measure', y: 60 }]} + primarySegmentedMeasureLegendData={[{ name: 'Measure 1' }, { name: 'Measure 2' }]} + qualitativeRangeData={[{ name: 'Range', y: 50 }, { name: 'Range', y: 75 }]} + qualitativeRangeLegendData={[{ name: 'Range 1' }, { name: 'Range 2' }]} + subTitle="Measure details" + title="Text label" + titlePosition="top-left" + width={width} + />
); } diff --git a/packages/react-charts/src/components/ChartPie/ChartPie.tsx b/packages/react-charts/src/components/ChartPie/ChartPie.tsx index c5818da94c0..081dbf79bf6 100644 --- a/packages/react-charts/src/components/ChartPie/ChartPie.tsx +++ b/packages/react-charts/src/components/ChartPie/ChartPie.tsx @@ -27,7 +27,15 @@ import { ChartContainer } from '../ChartContainer'; import { ChartLegend, ChartLegendOrientation } from '../ChartLegend'; import { ChartCommonStyles, ChartThemeDefinition } from '../ChartTheme'; import { ChartTooltip } from '../ChartTooltip'; -import { getComputedLegend, useDefaultPatternProps, getPaddingForSide, getPatternDefs, getTheme } from '../ChartUtils'; +import { + getComputedLegend, + useDefaultPatternProps, + getPaddingForSide, + getPatternDefs, + getTheme, + getLegendItemsExtraHeight +} from "../ChartUtils"; +import { useEffect } from 'react'; export enum ChartPieLabelPosition { centroid = 'centroid', @@ -294,11 +302,22 @@ export interface ChartPieProps extends VictoryPieProps { labels?: string[] | number[] | ((data: any) => string | number | null); /** * Allows legend items to wrap. A value of true allows the legend to wrap onto the next line - * if its container is not wide enough. + * if the chart is not wide enough. + * + * Note that the chart's SVG height and width are 100% by default, so it can be responsive itself. However, if you + * define the height and width of the chart's parent container, you must accommodate for extra legend height due to + * legend items wrapping onto the next line. When the height of the chart's parent container is too small, some legend + * items may not be visible. * * Note: This is overridden by the legendItemsPerRow property */ legendAllowWrap?: boolean; + /** + * If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been + * calculated, based on available width. The value provided can be used to increase the chart's parent container + * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. + */ + legendAllowWrapCallback?: (extraHeight: number) => void; /** * The legend component to render with chart. * @@ -500,6 +519,7 @@ export const ChartPie: React.FunctionComponent = ({ containerComponent = , hasPatterns, legendAllowWrap = false, + legendAllowWrapCallback, legendComponent = , legendData, legendPosition = ChartCommonStyles.legend.position as ChartPieLegendPosition, @@ -630,6 +650,20 @@ export const ChartPie: React.FunctionComponent = ({ ) : null; + // Callback to compliment legendAllowWrap + useEffect(() => { + if (legendAllowWrap && legendAllowWrapCallback) { + const computedLegend = getLegend(); + const extraHeight = getLegendItemsExtraHeight({ + legendData: computedLegend.props.data, + legendOrientation: computedLegend.props.orientation, + legendProps: computedLegend.props, + theme + }); + legendAllowWrapCallback(extraHeight); + } + }, [width]); + return standalone ? ( {container} ) : ( diff --git a/packages/react-charts/src/components/ChartUtils/chart-legend.ts b/packages/react-charts/src/components/ChartUtils/chart-legend.ts index c4ebd392ea8..28b3bfe9c47 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-legend.ts +++ b/packages/react-charts/src/components/ChartUtils/chart-legend.ts @@ -73,7 +73,6 @@ export const getComputedLegend = ({ const legendItemsProps = legendComponent.props ? legendComponent.props : {}; const legendItemsPerRow = allowWrap ? getLegendItemsPerRow({ - chartType, dx, height, legendData: legendItemsProps.data, @@ -233,6 +232,38 @@ export const getLegendItemsPerRow = ({ return itemsPerRow; }; +/** + * Returns the extra height required to accommodate wrapped legend items + * @private + */ +export const getLegendItemsExtraHeight = ({ + legendData, + legendOrientation, + legendProps, + theme +}: ChartLegendDimensionsInterface) => { + // Get legend dimensions + const legendDimensions = getLegendDimensions({ + legendData, + legendOrientation, + legendProps, + theme + }); + + // Get legend dimensions without any wrapped items + const legendDimensionsNoWrap = getLegendDimensions({ + legendData, + legendOrientation, + legendProps: { + ...legendProps, + itemsPerRow: undefined + }, + theme + }); + + return Math.abs(legendDimensions.height - legendDimensionsNoWrap.height); +}; + /** * Returns x coordinate for legend * @private diff --git a/packages/react-charts/src/components/Patterns/examples/patterms.md b/packages/react-charts/src/components/Patterns/examples/patterms.md index 95942336f3d..f3a0f8e64db 100644 --- a/packages/react-charts/src/components/Patterns/examples/patterms.md +++ b/packages/react-charts/src/components/Patterns/examples/patterms.md @@ -713,62 +713,105 @@ import chart_color_green_300 from '@patternfly/react-tokens/dist/esm/chart_color ```js import React from 'react'; import { ChartPie, ChartThemeColor } from '@patternfly/react-charts'; +import { getResizeObserver } from '@patternfly/react-core'; -
- `${datum.x}: ${datum.y}`} - legendData={[ - { name: 'Cats: 6' }, - { name: 'Dogs: 6' }, - { name: 'Birds: 6' }, - { name: 'Fish: 6' }, - { name: 'Rabbits: 6' }, - { name: 'Squirels: 6' }, - { name: 'Chipmunks: 6' }, - { name: 'Bats: 6' }, - { name: 'Ducks: 6' }, - { name: 'Geese: 6' }, - { name: 'Bobcat: 6' }, - { name: 'Foxes: 6' }, - { name: 'Coyotes: 6' }, - { name: 'Deer: 6' }, - { name: 'Bears: 6' }, - ]} - legendAllowWrap - legendPosition="bottom" - name="chart12" - padding={{ - bottom: 110, - left: 20, - right: 20, - top: 20 - }} - themeColor={ChartThemeColor.multiOrdered} - width={600} - /> -
+class PatternsPie extends React.Component { + constructor(props) { + super(props); + this.containerRef = React.createRef(); + this.observer = () => {}; + this.state = { + extraHeight: 0, + width: 0 + }; + this.handleResize = () => { + if (this.containerRef.current && this.containerRef.current.clientWidth) { + this.setState({ width: this.containerRef.current.clientWidth }); + } + }; + this.handleLegendAllowWrapCallback = (extraHeight) => { + if (extraHeight !== this.state.extraHeight) { + this.setState({ extraHeight }); + } + } + this.getHeight = (baseHeight) => { + const { extraHeight } = this.state; + return baseHeight + extraHeight; + }; + } + + componentDidMount() { + this.observer = getResizeObserver(this.containerRef.current, this.handleResize); + this.handleResize(); + } + + componentWillUnmount() { + this.observer(); + } + + render() { + const { width } = this.state; + const height = this.getHeight(260); + return ( +
+ `${datum.x}: ${datum.y}`} + legendData={[ + { name: 'Cats: 6' }, + { name: 'Dogs: 6' }, + { name: 'Birds: 6' }, + { name: 'Fish: 6' }, + { name: 'Rabbits: 6' }, + { name: 'Squirels: 6' }, + { name: 'Chipmunks: 6' }, + { name: 'Bats: 6' }, + { name: 'Ducks: 6' }, + { name: 'Geese: 6' }, + { name: 'Bobcat: 6' }, + { name: 'Foxes: 6' }, + { name: 'Coyotes: 6' }, + { name: 'Deer: 6' }, + { name: 'Bears: 6' }, + ]} + legendAllowWrap + legendAllowWrapCallback={this.handleLegendAllowWrapCallback} + legendPosition="bottom" + name="chart12" + padding={{ + bottom: this.getHeight(50), // This must be adjusted to maintain the aspec ratio + left: 20, + right: 20, + top: 20 + }} + themeColor={ChartThemeColor.multiOrdered} + width={width} + /> +
+ ); + } +} ``` ## Documentation diff --git a/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md b/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md index 9a3bc0982ef..5f5afd7abc8 100644 --- a/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md +++ b/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md @@ -62,6 +62,7 @@ class BulletChart extends React.Component { this.containerRef = React.createRef(); this.observer = () => {}; this.state = { + extraHeight: 0, width: 0 }; this.handleResize = () => { @@ -69,6 +70,15 @@ class BulletChart extends React.Component { this.setState({ width: this.containerRef.current.clientWidth }); } }; + this.handleLegendAllowWrapCallback = (extraHeight) => { + if (extraHeight !== this.state.extraHeight) { + this.setState({ extraHeight }); + } + } + this.getHeight = (baseHeight) => { + const { extraHeight } = this.state; + return baseHeight + extraHeight; + }; } componentDidMount() { @@ -82,17 +92,19 @@ class BulletChart extends React.Component { render() { const { width } = this.state; + const height = this.getHeight(200); return ( -
+
`${datum.name}: ${datum.y}`} legendAllowWrap + legendAllowWrapCallback={this.handleLegendAllowWrapCallback} legendPosition="bottom-left" maxDomain={{y: 100}} name="chart1" From 4d543287f43a16fb37c4c0d8f61fac68955f2cf7 Mon Sep 17 00:00:00 2001 From: Dan Labrecque Date: Tue, 21 Feb 2023 09:42:07 -0500 Subject: [PATCH 2/4] chore(charts): fix lint warnings --- packages/react-charts/src/components/Chart/Chart.tsx | 6 +++--- .../react-charts/src/components/ChartBullet/ChartBullet.tsx | 6 +++--- packages/react-charts/src/components/ChartPie/ChartPie.tsx | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/react-charts/src/components/Chart/Chart.tsx b/packages/react-charts/src/components/Chart/Chart.tsx index ae6649765fb..4d043813307 100644 --- a/packages/react-charts/src/components/Chart/Chart.tsx +++ b/packages/react-charts/src/components/Chart/Chart.tsx @@ -609,9 +609,9 @@ export const Chart: React.FunctionComponent = ({ }); // Callback to compliment legendAllowWrap + const computedLegend = getLegend(); useEffect(() => { if (legendAllowWrap && legendAllowWrapCallback) { - const computedLegend = getLegend(); const extraHeight = getLegendItemsExtraHeight({ legendData: computedLegend.props.data, legendOrientation: computedLegend.props.orientation, @@ -620,7 +620,7 @@ export const Chart: React.FunctionComponent = ({ }); legendAllowWrapCallback(extraHeight); } - }, [width]); + }, [computedLegend, legendAllowWrap, legendAllowWrapCallback, theme, width]); // Note: containerComponent is required for theme return ( @@ -634,7 +634,7 @@ export const Chart: React.FunctionComponent = ({ {...rest} > {renderChildren()} - {getLegend()} + {computedLegend} {isPatternDefs && getPatternDefs({ patternId, colorScale: defaultColorScale })} ); diff --git a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx index 8cce7ab8eee..b1cd8f9d58c 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx +++ b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx @@ -839,6 +839,7 @@ export const ChartBullet: React.FunctionComponent = ({ ...axisComponent.props }); + const computedLegend = getLegend(); const bulletChart = ( {axis} @@ -850,14 +851,13 @@ export const ChartBullet: React.FunctionComponent = ({ {comparativeErrorMeasure} {comparativeWarningMeasure} {getComparativeZeroMeasure()} - {getLegend()} + {computedLegend} ); // Callback to compliment legendAllowWrap useEffect(() => { if (legendAllowWrap && legendAllowWrapCallback) { - const computedLegend = getLegend(); const extraHeight = getLegendItemsExtraHeight({ legendData: computedLegend.props.data, legendOrientation: computedLegend.props.orientation, @@ -866,7 +866,7 @@ export const ChartBullet: React.FunctionComponent = ({ }); legendAllowWrapCallback(extraHeight); } - }, [width]); + }, [computedLegend, legendAllowWrap, legendAllowWrapCallback, theme, width]); return standalone ? ( diff --git a/packages/react-charts/src/components/ChartPie/ChartPie.tsx b/packages/react-charts/src/components/ChartPie/ChartPie.tsx index 081dbf79bf6..3d02e5044a2 100644 --- a/packages/react-charts/src/components/ChartPie/ChartPie.tsx +++ b/packages/react-charts/src/components/ChartPie/ChartPie.tsx @@ -651,9 +651,9 @@ export const ChartPie: React.FunctionComponent = ({ : null; // Callback to compliment legendAllowWrap + const computedLegend = getLegend(); useEffect(() => { if (legendAllowWrap && legendAllowWrapCallback) { - const computedLegend = getLegend(); const extraHeight = getLegendItemsExtraHeight({ legendData: computedLegend.props.data, legendOrientation: computedLegend.props.orientation, @@ -662,14 +662,14 @@ export const ChartPie: React.FunctionComponent = ({ }); legendAllowWrapCallback(extraHeight); } - }, [width]); + }, [computedLegend, legendAllowWrap, legendAllowWrapCallback, theme, width]); return standalone ? ( {container} ) : ( {chart} - {getLegend()} + {computedLegend} {isPatternDefs && getPatternDefs({ patternId, colorScale: defaultColorScale, patternUnshiftIndex })} ); From 92f743760a0a2ebae39bdc471ab75d76ba489293 Mon Sep 17 00:00:00 2001 From: Dan Labrecque Date: Tue, 21 Feb 2023 10:16:32 -0500 Subject: [PATCH 3/4] chore(charts) added @beta flag to legendAllowWrapCallback props --- packages/react-charts/src/components/Chart/Chart.tsx | 2 +- .../react-charts/src/components/ChartBullet/ChartBullet.tsx | 2 +- packages/react-charts/src/components/ChartDonut/ChartDonut.tsx | 2 +- .../components/ChartDonutUtilization/ChartDonutUtilization.tsx | 2 +- packages/react-charts/src/components/ChartPie/ChartPie.tsx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/react-charts/src/components/Chart/Chart.tsx b/packages/react-charts/src/components/Chart/Chart.tsx index 4d043813307..116b018117c 100644 --- a/packages/react-charts/src/components/Chart/Chart.tsx +++ b/packages/react-charts/src/components/Chart/Chart.tsx @@ -249,7 +249,7 @@ export interface ChartProps extends VictoryChartProps { */ legendAllowWrap?: boolean; /** - * If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been + * @beta If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been * calculated, based on available width. The value provided can be used to increase the chart's parent container * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. */ diff --git a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx index b1cd8f9d58c..7167d2d56de 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx +++ b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx @@ -220,7 +220,7 @@ export interface ChartBulletProps { */ legendAllowWrap?: boolean; /** - * If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been + * @beta If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been * calculated, based on available width. The value provided can be used to increase the chart's parent container * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. */ diff --git a/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx b/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx index 56c7735a221..1bdea101378 100644 --- a/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx +++ b/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx @@ -320,7 +320,7 @@ export interface ChartDonutProps extends ChartPieProps { */ legendAllowWrap?: boolean; /** - * If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been + * @beta If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been * calculated, based on available width. The value provided can be used to increase the chart's parent container * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. */ diff --git a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx b/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx index 31e26a6dca6..cafe072f641 100644 --- a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx +++ b/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx @@ -304,7 +304,7 @@ export interface ChartDonutUtilizationProps extends ChartDonutProps { */ legendAllowWrap?: boolean; /** - * If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been + * @beta If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been * calculated, based on available width. The value provided can be used to increase the chart's parent container * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. */ diff --git a/packages/react-charts/src/components/ChartPie/ChartPie.tsx b/packages/react-charts/src/components/ChartPie/ChartPie.tsx index 3d02e5044a2..96289d876e4 100644 --- a/packages/react-charts/src/components/ChartPie/ChartPie.tsx +++ b/packages/react-charts/src/components/ChartPie/ChartPie.tsx @@ -313,7 +313,7 @@ export interface ChartPieProps extends VictoryPieProps { */ legendAllowWrap?: boolean; /** - * If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been + * @beta If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been * calculated, based on available width. The value provided can be used to increase the chart's parent container * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. */ From de08b2324b2875c76db0c8115c1ff913d8fd01c7 Mon Sep 17 00:00:00 2001 From: Dan Labrecque Date: Mon, 27 Feb 2023 20:43:57 -0500 Subject: [PATCH 4/4] Combined legendAllowWrap and legendAllowWrapCallback per code review comments --- .../src/components/Chart/Chart.tsx | 24 ++++++++----------- .../components/ChartBullet/ChartBullet.tsx | 24 ++++++++----------- .../ChartBullet/examples/ChartBullet.md | 5 ++-- .../src/components/ChartDonut/ChartDonut.tsx | 15 +++++------- .../ChartDonutUtilization.tsx | 15 +++++------- .../ChartLegend/examples/ChartLegend.md | 5 ++-- .../src/components/ChartPie/ChartPie.tsx | 24 ++++++++----------- .../components/Patterns/examples/patterms.md | 5 ++-- .../ResizeObserver/examples/resizeObserver.md | 5 ++-- 9 files changed, 50 insertions(+), 72 deletions(-) diff --git a/packages/react-charts/src/components/Chart/Chart.tsx b/packages/react-charts/src/components/Chart/Chart.tsx index 116b018117c..9375f1ca2c7 100644 --- a/packages/react-charts/src/components/Chart/Chart.tsx +++ b/packages/react-charts/src/components/Chart/Chart.tsx @@ -237,23 +237,20 @@ export interface ChartProps extends VictoryChartProps { */ innerRadius?: number; /** - * Allows legend items to wrap. A value of true allows the legend to wrap onto the next line - * if the chart is not wide enough. + * @beta Allows legend items to wrap onto the next line if the chart is not wide enough. * * Note that the chart's SVG height and width are 100% by default, so it can be responsive itself. However, if you * define the height and width of the chart's parent container, you must accommodate for extra legend height due to * legend items wrapping onto the next line. When the height of the chart's parent container is too small, some legend * items may not be visible. * + * Alternatively, a callback function may be provided, which will be called after the legend's itemsPerRow property + * has been calculated. The value provided can be used to increase the chart's parent container height as legend + * items wrap onto the next line. If no adjustment is necessary, the value will be zero. + * * Note: This is overridden by the legendItemsPerRow property */ - legendAllowWrap?: boolean; - /** - * @beta If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been - * calculated, based on available width. The value provided can be used to increase the chart's parent container - * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. - */ - legendAllowWrapCallback?: (extraHeight: number) => void; + legendAllowWrap?: boolean | ((extraHeight: number) => void); /** * The legend component to render with chart. * @@ -477,7 +474,6 @@ export const Chart: React.FunctionComponent = ({ colorScale, hasPatterns, legendAllowWrap = false, - legendAllowWrapCallback, legendComponent = , legendData, legendPosition = ChartCommonStyles.legend.position as ChartLegendPosition, @@ -571,7 +567,7 @@ export const Chart: React.FunctionComponent = ({ } return getComputedLegend({ - allowWrap: legendAllowWrap, + allowWrap: legendAllowWrap === true || typeof legendAllowWrap === 'function', chartType: 'chart', colorScale, dx, @@ -611,16 +607,16 @@ export const Chart: React.FunctionComponent = ({ // Callback to compliment legendAllowWrap const computedLegend = getLegend(); useEffect(() => { - if (legendAllowWrap && legendAllowWrapCallback) { + if (typeof legendAllowWrap === 'function') { const extraHeight = getLegendItemsExtraHeight({ legendData: computedLegend.props.data, legendOrientation: computedLegend.props.orientation, legendProps: computedLegend.props, theme }); - legendAllowWrapCallback(extraHeight); + legendAllowWrap(extraHeight); } - }, [computedLegend, legendAllowWrap, legendAllowWrapCallback, theme, width]); + }, [computedLegend, legendAllowWrap, theme, width]); // Note: containerComponent is required for theme return ( diff --git a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx index 7167d2d56de..0eff090f10a 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx +++ b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx @@ -208,23 +208,20 @@ export interface ChartBulletProps { */ labels?: string[] | number[] | ((data: any) => string | number | null); /** - * Allows legend items to wrap. A value of true allows the legend to wrap onto the next line - * if the chart is not wide enough. + * @beta Allows legend items to wrap onto the next line if the chart is not wide enough. * * Note that the chart's SVG height and width are 100% by default, so it can be responsive itself. However, if you * define the height and width of the chart's parent container, you must accommodate for extra legend height due to * legend items wrapping onto the next line. When the height of the chart's parent container is too small, some legend * items may not be visible. * + * Alternatively, a callback function may be provided, which will be called after the legend's itemsPerRow property + * has been calculated. The value provided can be used to increase the chart's parent container height as legend + * items wrap onto the next line. If no adjustment is necessary, the value will be zero. + * * Note: This is overridden by the legendItemsPerRow property */ - legendAllowWrap?: boolean; - /** - * @beta If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been - * calculated, based on available width. The value provided can be used to increase the chart's parent container - * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. - */ - legendAllowWrapCallback?: (extraHeight: number) => void; + legendAllowWrap?: boolean | ((extraHeight: number) => void); /** * The legend component to render with chart. */ @@ -507,7 +504,6 @@ export const ChartBullet: React.FunctionComponent = ({ invert = false, labels, legendAllowWrap = false, - legendAllowWrapCallback, legendComponent = , legendItemsPerRow, legendPosition = 'bottom' as ChartLegendPosition, @@ -781,7 +777,7 @@ export const ChartBullet: React.FunctionComponent = ({ } return getComputedLegend({ - allowWrap: legendAllowWrap, + allowWrap: legendAllowWrap === true || typeof legendAllowWrap === 'function', chartType: 'bullet', dx, dy, @@ -857,16 +853,16 @@ export const ChartBullet: React.FunctionComponent = ({ // Callback to compliment legendAllowWrap useEffect(() => { - if (legendAllowWrap && legendAllowWrapCallback) { + if (typeof legendAllowWrap === 'function') { const extraHeight = getLegendItemsExtraHeight({ legendData: computedLegend.props.data, legendOrientation: computedLegend.props.orientation, legendProps: computedLegend.props, theme }); - legendAllowWrapCallback(extraHeight); + legendAllowWrap(extraHeight); } - }, [computedLegend, legendAllowWrap, legendAllowWrapCallback, theme, width]); + }, [computedLegend, legendAllowWrap, theme, width]); return standalone ? ( diff --git a/packages/react-charts/src/components/ChartBullet/examples/ChartBullet.md b/packages/react-charts/src/components/ChartBullet/examples/ChartBullet.md index 01d3467e55c..cbba0f0628a 100644 --- a/packages/react-charts/src/components/ChartBullet/examples/ChartBullet.md +++ b/packages/react-charts/src/components/ChartBullet/examples/ChartBullet.md @@ -100,7 +100,7 @@ class BulletChart extends React.Component { this.setState({ width: this.containerRef.current.clientWidth }); } }; - this.handleLegendAllowWrapCallback = (extraHeight) => { + this.handleLegendAllowWrap = (extraHeight) => { if (extraHeight !== this.state.extraHeight) { this.setState({ extraHeight }); } @@ -133,8 +133,7 @@ class BulletChart extends React.Component { constrainToVisibleArea height={height} labels={({ datum }) => `${datum.name}: ${datum.y}`} - legendAllowWrap - legendAllowWrapCallback={this.handleLegendAllowWrapCallback} + legendAllowWrap={this.handleLegendAllowWrap} legendPosition="bottom-left" maxDomain={{y: 100}} name="chart3" diff --git a/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx b/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx index 1bdea101378..e02b893a11b 100644 --- a/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx +++ b/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx @@ -308,23 +308,20 @@ export interface ChartDonutProps extends ChartPieProps { */ labels?: string[] | number[] | ((data: any) => string | number | null); /** - * Allows legend items to wrap. A value of true allows the legend to wrap onto the next line - * if the chart is not wide enough. + * @beta Allows legend items to wrap onto the next line if the chart is not wide enough. * * Note that the chart's SVG height and width are 100% by default, so it can be responsive itself. However, if you * define the height and width of the chart's parent container, you must accommodate for extra legend height due to * legend items wrapping onto the next line. When the height of the chart's parent container is too small, some legend * items may not be visible. * + * Alternatively, a callback function may be provided, which will be called after the legend's itemsPerRow property + * has been calculated. The value provided can be used to increase the chart's parent container height as legend + * items wrap onto the next line. If no adjustment is necessary, the value will be zero. + * * Note: This is overridden by the legendItemsPerRow property */ - legendAllowWrap?: boolean; - /** - * @beta If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been - * calculated, based on available width. The value provided can be used to increase the chart's parent container - * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. - */ - legendAllowWrapCallback?: (extraHeight: number) => void; + legendAllowWrap?: boolean | ((extraHeight: number) => void); /** * The legend component to render with chart. * diff --git a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx b/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx index cafe072f641..57f21d6f5a1 100644 --- a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx +++ b/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx @@ -292,23 +292,20 @@ export interface ChartDonutUtilizationProps extends ChartDonutProps { */ isStatic?: boolean; /** - * Allows legend items to wrap. A value of true allows the legend to wrap onto the next line - * if the chart is not wide enough. + * @beta Allows legend items to wrap onto the next line if the chart is not wide enough. * * Note that the chart's SVG height and width are 100% by default, so it can be responsive itself. However, if you * define the height and width of the chart's parent container, you must accommodate for extra legend height due to * legend items wrapping onto the next line. When the height of the chart's parent container is too small, some legend * items may not be visible. * + * Alternatively, a callback function may be provided, which will be called after the legend's itemsPerRow property + * has been calculated. The value provided can be used to increase the chart's parent container height as legend + * items wrap onto the next line. If no adjustment is necessary, the value will be zero. + * * Note: This is overridden by the legendItemsPerRow property */ - legendAllowWrap?: boolean; - /** - * @beta If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been - * calculated, based on available width. The value provided can be used to increase the chart's parent container - * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. - */ - legendAllowWrapCallback?: (extraHeight: number) => void; + legendAllowWrap?: boolean | ((extraHeight: number) => void); /** * The labelComponent prop takes in an entire label component which will be used * to create a label for the area. The new element created from the passed labelComponent diff --git a/packages/react-charts/src/components/ChartLegend/examples/ChartLegend.md b/packages/react-charts/src/components/ChartLegend/examples/ChartLegend.md index 01c6e077bf9..21f9b8536aa 100644 --- a/packages/react-charts/src/components/ChartLegend/examples/ChartLegend.md +++ b/packages/react-charts/src/components/ChartLegend/examples/ChartLegend.md @@ -139,7 +139,7 @@ class BulletChart extends React.Component { this.setState({ width: this.containerRef.current.clientWidth }); } }; - this.handleLegendAllowWrapCallback = (extraHeight) => { + this.handleLegendAllowWrap = (extraHeight) => { if (extraHeight !== this.state.extraHeight) { this.setState({ extraHeight }); } @@ -172,8 +172,7 @@ class BulletChart extends React.Component { constrainToVisibleArea height={height} labels={({ datum }) => `${datum.name}: ${datum.y}`} - legendAllowWrap - legendAllowWrapCallback={this.handleLegendAllowWrapCallback} + legendAllowWrap={this.handleLegendAllowWrap} legendPosition="bottom-left" maxDomain={{y: 100}} name="chart3" diff --git a/packages/react-charts/src/components/ChartPie/ChartPie.tsx b/packages/react-charts/src/components/ChartPie/ChartPie.tsx index 96289d876e4..2bbb5e720ea 100644 --- a/packages/react-charts/src/components/ChartPie/ChartPie.tsx +++ b/packages/react-charts/src/components/ChartPie/ChartPie.tsx @@ -301,23 +301,20 @@ export interface ChartPieProps extends VictoryPieProps { */ labels?: string[] | number[] | ((data: any) => string | number | null); /** - * Allows legend items to wrap. A value of true allows the legend to wrap onto the next line - * if the chart is not wide enough. + * @beta Allows legend items to wrap onto the next line if the chart is not wide enough. * * Note that the chart's SVG height and width are 100% by default, so it can be responsive itself. However, if you * define the height and width of the chart's parent container, you must accommodate for extra legend height due to * legend items wrapping onto the next line. When the height of the chart's parent container is too small, some legend * items may not be visible. * + * Alternatively, a callback function may be provided, which will be called after the legend's itemsPerRow property + * has been calculated. The value provided can be used to increase the chart's parent container height as legend + * items wrap onto the next line. If no adjustment is necessary, the value will be zero. + * * Note: This is overridden by the legendItemsPerRow property */ - legendAllowWrap?: boolean; - /** - * @beta If legendAllowWrap is true, this function will be called after the legend's itemsPerRow property has been - * calculated, based on available width. The value provided can be used to increase the chart's parent container - * height as legend items wrap onto the next line. If no adjustment is necessary, the value will be zero. - */ - legendAllowWrapCallback?: (extraHeight: number) => void; + legendAllowWrap?: boolean | ((extraHeight: number) => void); /** * The legend component to render with chart. * @@ -519,7 +516,6 @@ export const ChartPie: React.FunctionComponent = ({ containerComponent = , hasPatterns, legendAllowWrap = false, - legendAllowWrapCallback, legendComponent = , legendData, legendPosition = ChartCommonStyles.legend.position as ChartPieLegendPosition, @@ -618,7 +614,7 @@ export const ChartPie: React.FunctionComponent = ({ return null; } return getComputedLegend({ - allowWrap: legendAllowWrap, + allowWrap: legendAllowWrap === true || typeof legendAllowWrap === 'function', chartType: 'pie', height, legendComponent: legend, @@ -653,16 +649,16 @@ export const ChartPie: React.FunctionComponent = ({ // Callback to compliment legendAllowWrap const computedLegend = getLegend(); useEffect(() => { - if (legendAllowWrap && legendAllowWrapCallback) { + if (typeof legendAllowWrap === 'function') { const extraHeight = getLegendItemsExtraHeight({ legendData: computedLegend.props.data, legendOrientation: computedLegend.props.orientation, legendProps: computedLegend.props, theme }); - legendAllowWrapCallback(extraHeight); + legendAllowWrap(extraHeight); } - }, [computedLegend, legendAllowWrap, legendAllowWrapCallback, theme, width]); + }, [computedLegend, legendAllowWrap, theme, width]); return standalone ? ( {container} diff --git a/packages/react-charts/src/components/Patterns/examples/patterms.md b/packages/react-charts/src/components/Patterns/examples/patterms.md index f3a0f8e64db..5269eb57ff6 100644 --- a/packages/react-charts/src/components/Patterns/examples/patterms.md +++ b/packages/react-charts/src/components/Patterns/examples/patterms.md @@ -729,7 +729,7 @@ class PatternsPie extends React.Component { this.setState({ width: this.containerRef.current.clientWidth }); } }; - this.handleLegendAllowWrapCallback = (extraHeight) => { + this.handleLegendAllowWrap = (extraHeight) => { if (extraHeight !== this.state.extraHeight) { this.setState({ extraHeight }); } @@ -795,8 +795,7 @@ class PatternsPie extends React.Component { { name: 'Deer: 6' }, { name: 'Bears: 6' }, ]} - legendAllowWrap - legendAllowWrapCallback={this.handleLegendAllowWrapCallback} + legendAllowWrap={this.handleLegendAllowWrap} legendPosition="bottom" name="chart12" padding={{ diff --git a/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md b/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md index 5f5afd7abc8..adfe14c99bc 100644 --- a/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md +++ b/packages/react-charts/src/components/ResizeObserver/examples/resizeObserver.md @@ -70,7 +70,7 @@ class BulletChart extends React.Component { this.setState({ width: this.containerRef.current.clientWidth }); } }; - this.handleLegendAllowWrapCallback = (extraHeight) => { + this.handleLegendAllowWrap = (extraHeight) => { if (extraHeight !== this.state.extraHeight) { this.setState({ extraHeight }); } @@ -103,8 +103,7 @@ class BulletChart extends React.Component { constrainToVisibleArea height={height} labels={({ datum }) => `${datum.name}: ${datum.y}`} - legendAllowWrap - legendAllowWrapCallback={this.handleLegendAllowWrapCallback} + legendAllowWrap={this.handleLegendAllowWrap} legendPosition="bottom-left" maxDomain={{y: 100}} name="chart1"