From cb601f12e8aeb785739f399b3f0689c84d54f817 Mon Sep 17 00:00:00 2001 From: Katie McFaul Date: Wed, 6 Sep 2023 10:32:03 -0400 Subject: [PATCH 1/6] feat(charts): add RTL legend support --- .../src/components/Chart/Chart.tsx | 14 ++++++++++++- .../components/ChartBullet/ChartBullet.tsx | 20 ++++++++++++++++++- .../src/components/ChartDonut/ChartDonut.tsx | 8 +++++++- .../ChartDonutUtilization.tsx | 8 +++++++- .../src/components/ChartPie/ChartPie.tsx | 13 +++++++++--- .../src/components/ChartUtils/chart-label.ts | 3 ++- .../src/components/ChartUtils/chart-legend.ts | 12 +++++++++-- 7 files changed, 68 insertions(+), 10 deletions(-) diff --git a/packages/react-charts/src/components/Chart/Chart.tsx b/packages/react-charts/src/components/Chart/Chart.tsx index d7954a92db9..6e5905393a9 100644 --- a/packages/react-charts/src/components/Chart/Chart.tsx +++ b/packages/react-charts/src/components/Chart/Chart.tsx @@ -31,6 +31,8 @@ import { getPaddingForSide } from '../ChartUtils/chart-padding'; import { getPatternDefs, mergePatternData, useDefaultPatternProps } from '../ChartUtils/chart-patterns'; import { getChartTheme } from '../ChartUtils/chart-theme-types'; import { useEffect } from 'react'; +import { ChartLabel } from '../ChartLabel/ChartLabel'; +import { ChartPoint } from '../ChartPoint/ChartPoint'; /** * Chart is a wrapper component that reconciles the domain for all its children, controls the layout of the chart, @@ -283,7 +285,11 @@ export interface ChartProps extends VictoryChartProps { * Note: When adding a legend, padding may need to be adjusted in order to accommodate the extra legend. In some * cases, the legend may not be visible until enough padding is applied. */ - legendPosition?: 'bottom' | 'bottom-left' | 'right'; + legendPosition?: 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'right'; + /** + * Text direction of the legend labels. + */ + legendDirection?: 'ltr' | 'rtl'; /** * The maxDomain prop defines a maximum domain value for a chart. This prop is useful in situations where the maximum * domain of a chart is static, while the minimum value depends on data or other variable information. If the domain @@ -471,6 +477,7 @@ export const Chart: React.FunctionComponent = ({ legendComponent = , legendData, legendPosition = ChartCommonStyles.legend.position, + legendDirection = 'ltr', name, padding, patternScale, @@ -527,6 +534,8 @@ export const Chart: React.FunctionComponent = ({ ...(name && { name: `${name}-${(legendComponent as any).type.displayName}` }), orientation: legendOrientation, theme, + ...(legendDirection === 'rtl' && { dataComponent: }), + ...(legendDirection === 'rtl' && { labelComponent: }), ...legendComponent.props }); @@ -553,6 +562,9 @@ export const Chart: React.FunctionComponent = ({ } else if (legendPosition === 'bottom-left') { dy += xAxisLabelHeight + legendTitleHeight; dx = -10; + } else if (legendPosition === 'bottom-right') { + dy += xAxisLabelHeight + legendTitleHeight; + dx = 10; } // Adjust legend position when axis is hidden diff --git a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx index 72d01043bea..6af8d69320f 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx +++ b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx @@ -29,6 +29,8 @@ import { getBulletDomain } from './utils/chart-bullet-domain'; import { getBulletThemeWithLegendColorScale } from './utils/chart-bullet-theme'; import { getPaddingForSide } from '../ChartUtils/chart-padding'; import { useEffect } from 'react'; +import { ChartPoint } from '../ChartPoint/ChartPoint'; +import { ChartLabel } from '../ChartLabel/ChartLabel'; /** * ChartBullet renders a dataset as a bullet chart. @@ -251,7 +253,11 @@ export interface ChartBulletProps { * Note: When adding a legend, padding may need to be adjusted in order to accommodate the extra legend. In some * cases, the legend may not be visible until enough padding is applied. */ - legendPosition?: 'bottom' | 'bottom-left' | 'right'; + legendPosition?: 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'right'; + /** + * Text direction of the legend labels. + */ + legendDirection?: 'ltr' | 'rtl'; /** * The maxDomain prop defines a maximum domain value for a chart. This prop is useful in situations where the maximum * domain of a chart is static, while the minimum value depends on data or other variable information. If the domain @@ -509,6 +515,7 @@ export const ChartBullet: React.FunctionComponent = ({ legendComponent = , legendItemsPerRow, legendPosition = 'bottom', + legendDirection = 'ltr', maxDomain, minDomain, name, @@ -670,6 +677,8 @@ export const ChartBullet: React.FunctionComponent = ({ orientation: legendOrientation, position: legendPosition, theme, + ...(legendDirection === 'rtl' && { dataComponent: }), + ...(legendDirection === 'rtl' && { labelComponent: }), ...legendComponent.props }); @@ -778,6 +787,15 @@ export const ChartBullet: React.FunctionComponent = ({ dy = -defaultPadding.bottom; } dx = -10; + } else if (legendPosition === 'bottom-right') { + if (horizontal) { + dy = defaultPadding.top * 0.5 + (defaultPadding.bottom * 0.5 - defaultPadding.bottom) - 25; + } else if (title) { + dy = -defaultPadding.bottom + 60; + } else { + dy = -defaultPadding.bottom; + } + dx = 10; } return getComputedLegend({ diff --git a/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx b/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx index 19f323ddc97..e08bf824b49 100644 --- a/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx +++ b/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx @@ -344,7 +344,11 @@ export interface ChartDonutProps extends ChartPieProps { * Note: When adding a legend, padding may need to be adjusted in order to accommodate the extra legend. In some * cases, the legend may not be visible until enough padding is applied. */ - legendPosition?: 'bottom' | 'right'; + legendPosition?: 'bottom' | 'right' | 'left'; + /** + * Text direction of the legend labels. + */ + legendDirection?: 'ltr' | 'rtl'; /** * The name prop is typically used to reference a component instance when defining shared events. However, this * optional prop may also be applied to child elements as an ID prefix. This is a workaround to ensure Victory @@ -573,6 +577,7 @@ export const ChartDonut: React.FunctionComponent = ({ containerComponent = , innerRadius, legendPosition = ChartCommonStyles.legend.position, + legendDirection = 'ltr', name, padAngle, padding, @@ -698,6 +703,7 @@ export const ChartDonut: React.FunctionComponent = ({ innerRadius={chartInnerRadius > 0 ? chartInnerRadius : 0} key="pf-chart-donut-pie" legendPosition={legendPosition} + legendDirection={legendDirection} name={name} padAngle={padAngle !== undefined ? padAngle : getPadAngle} padding={padding} diff --git a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx b/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx index 26892f0e747..3836df2cfdd 100644 --- a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx +++ b/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx @@ -336,7 +336,11 @@ export interface ChartDonutUtilizationProps extends ChartDonutProps { * Note: When adding a legend, padding may need to be adjusted in order to accommodate the extra legend. In some * cases, the legend may not be visible until enough padding is applied. */ - legendPosition?: 'bottom' | 'right'; + legendPosition?: 'bottom' | 'right' | 'left'; + /** + * Text direction of the legend labels. + */ + legendDirection?: 'ltr' | 'rtl'; /** * The labelRadius prop defines the radius of the arc that will be used for positioning each slice label. * If this prop is not set, the label radius will default to the radius of the pie + label padding. @@ -589,6 +593,7 @@ export const ChartDonutUtilization: React.FunctionComponent = ({ legendComponent = , legendData, legendPosition = ChartCommonStyles.legend.position, + legendDirection = 'ltr', name, patternScale, patternUnshiftIndex, - padding, radius, standalone = true, style, themeColor, - // destructure last theme = getTheme(themeColor), labelComponent = allowTooltip ? ( @@ -583,6 +588,8 @@ export const ChartPie: React.FunctionComponent = ({ key: 'pf-chart-pie-legend', orientation: legendOrientation, theme, + ...(legendDirection === 'rtl' && { dataComponent: }), + ...(legendDirection === 'rtl' && { labelComponent: }), ...legendComponent.props }); diff --git a/packages/react-charts/src/components/ChartUtils/chart-label.ts b/packages/react-charts/src/components/ChartUtils/chart-label.ts index 3c94a2c702e..9736600db13 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-label.ts +++ b/packages/react-charts/src/components/ChartUtils/chart-label.ts @@ -20,7 +20,7 @@ interface ChartPieLabelInterface { dy?: number; // Horizontal shift from the y coordinate height: number; // Chart height labelPosition?: 'bottom' | 'center' | 'right'; // Position of label - legendPosition?: 'bottom' | 'right'; // Position of legend + legendPosition?: 'bottom' | 'right' | 'left'; // Position of legend padding: any; // Chart padding width: number; // Chart width } @@ -77,6 +77,7 @@ export const getPieLabelX = ({ return origin.x + ChartCommonStyles.label.margin + dx + radius; case 'right': return origin.x + ChartCommonStyles.label.margin + dx; + case 'left': default: return dx; } diff --git a/packages/react-charts/src/components/ChartUtils/chart-legend.ts b/packages/react-charts/src/components/ChartUtils/chart-legend.ts index 060a683535f..6a9e6a53687 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-legend.ts +++ b/packages/react-charts/src/components/ChartUtils/chart-legend.ts @@ -18,7 +18,7 @@ interface ChartLegendInterface { orientation?: 'horizontal' | 'vertical'; // Orientation of legend padding: PaddingProps; // Chart padding patternScale?: string[]; // Legend symbol patterns - position: 'bottom' | 'bottom-left' | 'right'; // The legend position + position: 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'right'; // The legend position theme: ChartThemeDefinition; // The theme that will be applied to the chart width: number; // Overall width of SVG } @@ -37,7 +37,7 @@ interface ChartLegendPositionInterface { height?: number; // Overall height of SVG legendData: any[]; // The legend data used to determine width legendOrientation: 'horizontal' | 'vertical'; // Orientation of legend - legendPosition: 'bottom' | 'bottom-left' | 'right'; // Position of legend + legendPosition: 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'right'; // Position of legend legendProps: any; // The legend props used to determine width padding?: PaddingProps; // Chart padding theme: ChartThemeDefinition; // The theme that will be applied to the chart @@ -311,6 +311,7 @@ const getBulletLegendY = ({ switch (legendPosition) { case 'bottom': case 'bottom-left': + case 'bottom-right': return chartSize.height + ChartCommonStyles.legend.margin + dy; case 'right': { // Legend height with padding @@ -356,12 +357,15 @@ const getChartLegendX = ({ }); switch (legendPosition) { + case 'bottom-right': + return width - legendDimensions.width - right + dx; case 'bottom': return width > legendDimensions.width ? Math.round((width - legendDimensions.width) / 2) + dx : dx; case 'bottom-left': return left + dx; case 'right': return chartSize.width + ChartCommonStyles.legend.margin + left + dx; + case 'left': default: return dx; } @@ -391,7 +395,9 @@ const getChartLegendY = ({ switch (legendPosition) { case 'bottom': case 'bottom-left': + case 'bottom-right': return chartSize.height + ChartCommonStyles.legend.margin * 2 + top + dy; + case 'left': case 'right': { // Legend height with padding const legendDimensions = getLegendDimensions({ @@ -438,6 +444,7 @@ const getPieLegendX = ({ return width > legendDimensions.width ? Math.round((width - legendDimensions.width) / 2) + dx : dx; case 'right': return origin.x + ChartCommonStyles.label.margin + dx + radius; + case 'left': default: return dx; } @@ -464,6 +471,7 @@ const getPieLegendY = ({ switch (legendPosition) { case 'bottom': return origin.y + ChartCommonStyles.legend.margin + radius + dy; + case 'left': case 'right': { // Legend height with padding const legendDimensions = getLegendDimensions({ From fd66344636f86f2475078b88689d9706a60d975c Mon Sep 17 00:00:00 2001 From: Katie McFaul Date: Thu, 7 Sep 2023 09:44:53 -0400 Subject: [PATCH 2/6] clone data/label components --- .../react-charts/src/components/Chart/Chart.tsx | 16 ++++++++++++++-- .../src/components/ChartBullet/ChartBullet.tsx | 16 ++++++++++++++-- .../src/components/ChartPie/ChartPie.tsx | 16 ++++++++++++++-- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/packages/react-charts/src/components/Chart/Chart.tsx b/packages/react-charts/src/components/Chart/Chart.tsx index 6e5905393a9..bea4780c40d 100644 --- a/packages/react-charts/src/components/Chart/Chart.tsx +++ b/packages/react-charts/src/components/Chart/Chart.tsx @@ -534,8 +534,20 @@ export const Chart: React.FunctionComponent = ({ ...(name && { name: `${name}-${(legendComponent as any).type.displayName}` }), orientation: legendOrientation, theme, - ...(legendDirection === 'rtl' && { dataComponent: }), - ...(legendDirection === 'rtl' && { labelComponent: }), + ...(legendDirection === 'rtl' && { + dataComponent: legendComponent.props.dataComponent ? ( + React.cloneElement(legendComponent.props.dataComponent, { transform: 'translate(40)' }) + ) : ( + + ) + }), + ...(legendDirection === 'rtl' && { + labelComponent: legendComponent.props.labelComponent ? ( + React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: '10' }) + ) : ( + + ) + }), ...legendComponent.props }); diff --git a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx index 6af8d69320f..f9a4f41ba7c 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx +++ b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx @@ -677,8 +677,20 @@ export const ChartBullet: React.FunctionComponent = ({ orientation: legendOrientation, position: legendPosition, theme, - ...(legendDirection === 'rtl' && { dataComponent: }), - ...(legendDirection === 'rtl' && { labelComponent: }), + ...(legendDirection === 'rtl' && { + dataComponent: legendComponent.props.dataComponent ? ( + React.cloneElement(legendComponent.props.dataComponent, { transform: 'translate(40)' }) + ) : ( + + ) + }), + ...(legendDirection === 'rtl' && { + labelComponent: legendComponent.props.labelComponent ? ( + React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: '10' }) + ) : ( + + ) + }), ...legendComponent.props }); diff --git a/packages/react-charts/src/components/ChartPie/ChartPie.tsx b/packages/react-charts/src/components/ChartPie/ChartPie.tsx index dd52f8ca85e..943fb9f9249 100644 --- a/packages/react-charts/src/components/ChartPie/ChartPie.tsx +++ b/packages/react-charts/src/components/ChartPie/ChartPie.tsx @@ -588,8 +588,20 @@ export const ChartPie: React.FunctionComponent = ({ key: 'pf-chart-pie-legend', orientation: legendOrientation, theme, - ...(legendDirection === 'rtl' && { dataComponent: }), - ...(legendDirection === 'rtl' && { labelComponent: }), + ...(legendDirection === 'rtl' && { + dataComponent: legendComponent.props.dataComponent ? ( + React.cloneElement(legendComponent.props.dataComponent, { transform: 'translate(80)' }) + ) : ( + + ) + }), + ...(legendDirection === 'rtl' && { + labelComponent: legendComponent.props.labelComponent ? ( + React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: '50' }) + ) : ( + + ) + }), ...legendComponent.props }); From 794520be3d01e535f12b0fd41da563f1c902965f Mon Sep 17 00:00:00 2001 From: Katie McFaul Date: Tue, 19 Sep 2023 12:05:22 -0400 Subject: [PATCH 3/6] remove legend positions, add beta --- .../react-charts/src/components/Chart/Chart.tsx | 7 ++----- .../src/components/ChartBullet/ChartBullet.tsx | 13 ++----------- .../src/components/ChartDonut/ChartDonut.tsx | 4 ++-- .../ChartDonutUtilization/ChartDonutUtilization.tsx | 4 ++-- .../src/components/ChartPie/ChartPie.tsx | 4 ++-- .../src/components/ChartUtils/chart-legend.ts | 8 -------- 6 files changed, 10 insertions(+), 30 deletions(-) diff --git a/packages/react-charts/src/components/Chart/Chart.tsx b/packages/react-charts/src/components/Chart/Chart.tsx index bea4780c40d..33e388edf7f 100644 --- a/packages/react-charts/src/components/Chart/Chart.tsx +++ b/packages/react-charts/src/components/Chart/Chart.tsx @@ -285,9 +285,9 @@ export interface ChartProps extends VictoryChartProps { * Note: When adding a legend, padding may need to be adjusted in order to accommodate the extra legend. In some * cases, the legend may not be visible until enough padding is applied. */ - legendPosition?: 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'right'; + legendPosition?: 'bottom' | 'bottom-left' | 'right'; /** - * Text direction of the legend labels. + * @beta Text direction of the legend labels. */ legendDirection?: 'ltr' | 'rtl'; /** @@ -574,9 +574,6 @@ export const Chart: React.FunctionComponent = ({ } else if (legendPosition === 'bottom-left') { dy += xAxisLabelHeight + legendTitleHeight; dx = -10; - } else if (legendPosition === 'bottom-right') { - dy += xAxisLabelHeight + legendTitleHeight; - dx = 10; } // Adjust legend position when axis is hidden diff --git a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx index f9a4f41ba7c..275ffe0b8c5 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx +++ b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx @@ -253,9 +253,9 @@ export interface ChartBulletProps { * Note: When adding a legend, padding may need to be adjusted in order to accommodate the extra legend. In some * cases, the legend may not be visible until enough padding is applied. */ - legendPosition?: 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'right'; + legendPosition?: 'bottom' | 'bottom-left' | 'right'; /** - * Text direction of the legend labels. + * @beta Text direction of the legend labels. */ legendDirection?: 'ltr' | 'rtl'; /** @@ -799,15 +799,6 @@ export const ChartBullet: React.FunctionComponent = ({ dy = -defaultPadding.bottom; } dx = -10; - } else if (legendPosition === 'bottom-right') { - if (horizontal) { - dy = defaultPadding.top * 0.5 + (defaultPadding.bottom * 0.5 - defaultPadding.bottom) - 25; - } else if (title) { - dy = -defaultPadding.bottom + 60; - } else { - dy = -defaultPadding.bottom; - } - dx = 10; } return getComputedLegend({ diff --git a/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx b/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx index e08bf824b49..d5b3aa74b27 100644 --- a/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx +++ b/packages/react-charts/src/components/ChartDonut/ChartDonut.tsx @@ -344,9 +344,9 @@ export interface ChartDonutProps extends ChartPieProps { * Note: When adding a legend, padding may need to be adjusted in order to accommodate the extra legend. In some * cases, the legend may not be visible until enough padding is applied. */ - legendPosition?: 'bottom' | 'right' | 'left'; + legendPosition?: 'bottom' | 'right'; /** - * Text direction of the legend labels. + * @beta Text direction of the legend labels. */ legendDirection?: 'ltr' | 'rtl'; /** diff --git a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx b/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx index 3836df2cfdd..90b8cf1ee03 100644 --- a/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx +++ b/packages/react-charts/src/components/ChartDonutUtilization/ChartDonutUtilization.tsx @@ -336,9 +336,9 @@ export interface ChartDonutUtilizationProps extends ChartDonutProps { * Note: When adding a legend, padding may need to be adjusted in order to accommodate the extra legend. In some * cases, the legend may not be visible until enough padding is applied. */ - legendPosition?: 'bottom' | 'right' | 'left'; + legendPosition?: 'bottom' | 'right'; /** - * Text direction of the legend labels. + * @beta Text direction of the legend labels. */ legendDirection?: 'ltr' | 'rtl'; /** diff --git a/packages/react-charts/src/components/ChartPie/ChartPie.tsx b/packages/react-charts/src/components/ChartPie/ChartPie.tsx index 943fb9f9249..dc1e33f04cb 100644 --- a/packages/react-charts/src/components/ChartPie/ChartPie.tsx +++ b/packages/react-charts/src/components/ChartPie/ChartPie.tsx @@ -334,9 +334,9 @@ export interface ChartPieProps extends VictoryPieProps { * Note: When adding a legend, padding may need to be adjusted in order to accommodate the extra legend. In some * cases, the legend may not be visible until enough padding is applied. */ - legendPosition?: 'bottom' | 'right' | 'left'; + legendPosition?: 'bottom' | 'right'; /** - * Text direction of the legend labels. + * @beta Text direction of the legend labels. */ legendDirection?: 'ltr' | 'rtl'; /** diff --git a/packages/react-charts/src/components/ChartUtils/chart-legend.ts b/packages/react-charts/src/components/ChartUtils/chart-legend.ts index 6a9e6a53687..a28540cf2a1 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-legend.ts +++ b/packages/react-charts/src/components/ChartUtils/chart-legend.ts @@ -311,7 +311,6 @@ const getBulletLegendY = ({ switch (legendPosition) { case 'bottom': case 'bottom-left': - case 'bottom-right': return chartSize.height + ChartCommonStyles.legend.margin + dy; case 'right': { // Legend height with padding @@ -357,15 +356,12 @@ const getChartLegendX = ({ }); switch (legendPosition) { - case 'bottom-right': - return width - legendDimensions.width - right + dx; case 'bottom': return width > legendDimensions.width ? Math.round((width - legendDimensions.width) / 2) + dx : dx; case 'bottom-left': return left + dx; case 'right': return chartSize.width + ChartCommonStyles.legend.margin + left + dx; - case 'left': default: return dx; } @@ -395,9 +391,7 @@ const getChartLegendY = ({ switch (legendPosition) { case 'bottom': case 'bottom-left': - case 'bottom-right': return chartSize.height + ChartCommonStyles.legend.margin * 2 + top + dy; - case 'left': case 'right': { // Legend height with padding const legendDimensions = getLegendDimensions({ @@ -444,7 +438,6 @@ const getPieLegendX = ({ return width > legendDimensions.width ? Math.round((width - legendDimensions.width) / 2) + dx : dx; case 'right': return origin.x + ChartCommonStyles.label.margin + dx + radius; - case 'left': default: return dx; } @@ -471,7 +464,6 @@ const getPieLegendY = ({ switch (legendPosition) { case 'bottom': return origin.y + ChartCommonStyles.legend.margin + radius + dy; - case 'left': case 'right': { // Legend height with padding const legendDimensions = getLegendDimensions({ From 62c1ca0bc31d4686425d74ec38715ae7291f144b Mon Sep 17 00:00:00 2001 From: Katie McFaul Date: Tue, 19 Sep 2023 12:10:20 -0400 Subject: [PATCH 4/6] remove last position update --- .../react-charts/src/components/ChartUtils/chart-label.ts | 3 +-- .../react-charts/src/components/ChartUtils/chart-legend.ts | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/react-charts/src/components/ChartUtils/chart-label.ts b/packages/react-charts/src/components/ChartUtils/chart-label.ts index 9736600db13..3c94a2c702e 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-label.ts +++ b/packages/react-charts/src/components/ChartUtils/chart-label.ts @@ -20,7 +20,7 @@ interface ChartPieLabelInterface { dy?: number; // Horizontal shift from the y coordinate height: number; // Chart height labelPosition?: 'bottom' | 'center' | 'right'; // Position of label - legendPosition?: 'bottom' | 'right' | 'left'; // Position of legend + legendPosition?: 'bottom' | 'right'; // Position of legend padding: any; // Chart padding width: number; // Chart width } @@ -77,7 +77,6 @@ export const getPieLabelX = ({ return origin.x + ChartCommonStyles.label.margin + dx + radius; case 'right': return origin.x + ChartCommonStyles.label.margin + dx; - case 'left': default: return dx; } diff --git a/packages/react-charts/src/components/ChartUtils/chart-legend.ts b/packages/react-charts/src/components/ChartUtils/chart-legend.ts index a28540cf2a1..060a683535f 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-legend.ts +++ b/packages/react-charts/src/components/ChartUtils/chart-legend.ts @@ -18,7 +18,7 @@ interface ChartLegendInterface { orientation?: 'horizontal' | 'vertical'; // Orientation of legend padding: PaddingProps; // Chart padding patternScale?: string[]; // Legend symbol patterns - position: 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'right'; // The legend position + position: 'bottom' | 'bottom-left' | 'right'; // The legend position theme: ChartThemeDefinition; // The theme that will be applied to the chart width: number; // Overall width of SVG } @@ -37,7 +37,7 @@ interface ChartLegendPositionInterface { height?: number; // Overall height of SVG legendData: any[]; // The legend data used to determine width legendOrientation: 'horizontal' | 'vertical'; // Orientation of legend - legendPosition: 'bottom' | 'bottom-left' | 'bottom-right' | 'left' | 'right'; // Position of legend + legendPosition: 'bottom' | 'bottom-left' | 'right'; // Position of legend legendProps: any; // The legend props used to determine width padding?: PaddingProps; // Chart padding theme: ChartThemeDefinition; // The theme that will be applied to the chart From a4e0be6a2a1b579df4e2c1291971452dc8fb6546 Mon Sep 17 00:00:00 2001 From: Katie McFaul Date: Thu, 21 Sep 2023 15:44:44 -0400 Subject: [PATCH 5/6] update logic to account for text length --- .../src/components/Chart/Chart.tsx | 11 +++++++--- .../components/ChartBullet/ChartBullet.tsx | 20 ++++++++++++++++--- .../src/components/ChartPie/ChartPie.tsx | 11 +++++++--- .../src/components/ChartUtils/chart-legend.ts | 17 ++++++++++++++++ 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/packages/react-charts/src/components/Chart/Chart.tsx b/packages/react-charts/src/components/Chart/Chart.tsx index 33e388edf7f..3d1560574eb 100644 --- a/packages/react-charts/src/components/Chart/Chart.tsx +++ b/packages/react-charts/src/components/Chart/Chart.tsx @@ -26,7 +26,7 @@ import { ChartCommonStyles } from '../ChartTheme/ChartStyles'; import { ChartThemeDefinition } from '../ChartTheme/ChartTheme'; import { getClassName } from '../ChartUtils/chart-helpers'; import { getLabelTextSize } from '../ChartUtils/chart-label'; -import { getComputedLegend, getLegendItemsExtraHeight } from '../ChartUtils/chart-legend'; +import { getComputedLegend, getLegendItemsExtraHeight, getLegendMaxTextWidth } from '../ChartUtils/chart-legend'; import { getPaddingForSide } from '../ChartUtils/chart-padding'; import { getPatternDefs, mergePatternData, useDefaultPatternProps } from '../ChartUtils/chart-patterns'; import { getChartTheme } from '../ChartUtils/chart-theme-types'; @@ -529,6 +529,11 @@ export const Chart: React.FunctionComponent = ({ ...(labelComponent && { labelComponent }) // Override label component props }); + let legendXOffset = 0; + if (legendDirection === 'rtl') { + legendXOffset = getLegendMaxTextWidth(legendData, theme); + } + const legend = React.cloneElement(legendComponent, { data: legendData, ...(name && { name: `${name}-${(legendComponent as any).type.displayName}` }), @@ -538,14 +543,14 @@ export const Chart: React.FunctionComponent = ({ dataComponent: legendComponent.props.dataComponent ? ( React.cloneElement(legendComponent.props.dataComponent, { transform: 'translate(40)' }) ) : ( - + ) }), ...(legendDirection === 'rtl' && { labelComponent: legendComponent.props.labelComponent ? ( React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: '10' }) ) : ( - + ) }), ...legendComponent.props diff --git a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx index 275ffe0b8c5..12fc4a54b21 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx +++ b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx @@ -17,7 +17,7 @@ import { ChartLegend } from '../ChartLegend/ChartLegend'; import { ChartThemeDefinition } from '../ChartTheme/ChartTheme'; import { ChartTooltip } from '../ChartTooltip/ChartTooltip'; import { ChartBulletStyles } from '../ChartTheme/ChartStyles'; -import { getComputedLegend, getLegendItemsExtraHeight } from '../ChartUtils/chart-legend'; +import { getComputedLegend, getLegendItemsExtraHeight, getLegendMaxTextWidth } from '../ChartUtils/chart-legend'; import { ChartBulletComparativeErrorMeasure } from './ChartBulletComparativeErrorMeasure'; import { ChartBulletComparativeMeasure } from './ChartBulletComparativeMeasure'; import { ChartBulletComparativeWarningMeasure } from './ChartBulletComparativeWarningMeasure'; @@ -663,6 +663,20 @@ export const ChartBullet: React.FunctionComponent = ({ ...comparativeZeroMeasureComponent.props }); + let legendXOffset = 0; + if (legendDirection === 'rtl') { + legendXOffset = getLegendMaxTextWidth( + [ + ...(primaryDotMeasureLegendData ? primaryDotMeasureLegendData : []), + ...(primarySegmentedMeasureLegendData ? primarySegmentedMeasureLegendData : []), + ...(comparativeWarningMeasureLegendData ? comparativeWarningMeasureLegendData : []), + ...(comparativeErrorMeasureLegendData ? comparativeErrorMeasureLegendData : []), + ...(qualitativeRangeLegendData ? qualitativeRangeLegendData : []) + ], + theme + ); + } + // Legend const legend = React.cloneElement(legendComponent, { data: [ @@ -681,14 +695,14 @@ export const ChartBullet: React.FunctionComponent = ({ dataComponent: legendComponent.props.dataComponent ? ( React.cloneElement(legendComponent.props.dataComponent, { transform: 'translate(40)' }) ) : ( - + ) }), ...(legendDirection === 'rtl' && { labelComponent: legendComponent.props.labelComponent ? ( React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: '10' }) ) : ( - + ) }), ...legendComponent.props diff --git a/packages/react-charts/src/components/ChartPie/ChartPie.tsx b/packages/react-charts/src/components/ChartPie/ChartPie.tsx index dc1e33f04cb..65d09fb9dd7 100644 --- a/packages/react-charts/src/components/ChartPie/ChartPie.tsx +++ b/packages/react-charts/src/components/ChartPie/ChartPie.tsx @@ -28,7 +28,7 @@ import { ChartLegend } from '../ChartLegend/ChartLegend'; import { ChartCommonStyles } from '../ChartTheme/ChartStyles'; import { ChartThemeDefinition } from '../ChartTheme/ChartTheme'; import { ChartTooltip } from '../ChartTooltip/ChartTooltip'; -import { getComputedLegend, getLegendItemsExtraHeight } from '../ChartUtils/chart-legend'; +import { getComputedLegend, getLegendItemsExtraHeight, getLegendMaxTextWidth } from '../ChartUtils/chart-legend'; import { getPaddingForSide } from '../ChartUtils/chart-padding'; import { getPatternDefs, useDefaultPatternProps } from '../ChartUtils/chart-patterns'; import { getTheme } from '../ChartUtils/chart-theme'; @@ -581,6 +581,11 @@ export const ChartPie: React.FunctionComponent = ({ /> ); + let legendXOffset = 0; + if (legendDirection === 'rtl') { + legendXOffset = getLegendMaxTextWidth(legendData, theme); + } + const legend = React.cloneElement(legendComponent, { colorScale, data: legendData, @@ -592,14 +597,14 @@ export const ChartPie: React.FunctionComponent = ({ dataComponent: legendComponent.props.dataComponent ? ( React.cloneElement(legendComponent.props.dataComponent, { transform: 'translate(80)' }) ) : ( - + ) }), ...(legendDirection === 'rtl' && { labelComponent: legendComponent.props.labelComponent ? ( React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: '50' }) ) : ( - + ) }), ...legendComponent.props diff --git a/packages/react-charts/src/components/ChartUtils/chart-legend.ts b/packages/react-charts/src/components/ChartUtils/chart-legend.ts index 060a683535f..3bbd51bda43 100644 --- a/packages/react-charts/src/components/ChartUtils/chart-legend.ts +++ b/packages/react-charts/src/components/ChartUtils/chart-legend.ts @@ -4,6 +4,7 @@ import { VictoryLegend } from 'victory-legend'; import { ChartLegendProps } from '../ChartLegend/ChartLegend'; import { ChartCommonStyles } from '../ChartTheme/ChartStyles'; import { ChartThemeDefinition } from '../ChartTheme/ChartTheme'; +import { getLabelTextSize } from '../ChartUtils/chart-label'; import { getPieOrigin } from './chart-origin'; import * as React from 'react'; @@ -49,6 +50,22 @@ interface ChartLegendTextMaxSizeInterface { theme: ChartThemeDefinition; // The theme that will be applied to the chart } +/** + * Returns the max text length in a legend data set to calculate the x offset for right aligned legends. + * @private + */ + +export const getLegendMaxTextWidth = (legendData: any[], theme: ChartThemeDefinition) => { + let legendXOffset = 0; + legendData.map((data: any) => { + const labelWidth = getLabelTextSize({ text: data.name, theme }).width; + if (labelWidth > legendXOffset) { + legendXOffset = labelWidth; + } + }); + return legendXOffset; +}; + /** * Returns a legend which has been positioned per the given chart properties * @private From df4ddfe0c2d23a90b44739af8549c688c6570322 Mon Sep 17 00:00:00 2001 From: Katie McFaul Date: Fri, 22 Sep 2023 09:28:15 -0400 Subject: [PATCH 6/6] update clones --- packages/react-charts/src/components/Chart/Chart.tsx | 4 ++-- .../react-charts/src/components/ChartBullet/ChartBullet.tsx | 4 ++-- packages/react-charts/src/components/ChartPie/ChartPie.tsx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/react-charts/src/components/Chart/Chart.tsx b/packages/react-charts/src/components/Chart/Chart.tsx index 3d1560574eb..10803be4699 100644 --- a/packages/react-charts/src/components/Chart/Chart.tsx +++ b/packages/react-charts/src/components/Chart/Chart.tsx @@ -541,14 +541,14 @@ export const Chart: React.FunctionComponent = ({ theme, ...(legendDirection === 'rtl' && { dataComponent: legendComponent.props.dataComponent ? ( - React.cloneElement(legendComponent.props.dataComponent, { transform: 'translate(40)' }) + React.cloneElement(legendComponent.props.dataComponent, { transform: `translate(${legendXOffset})` }) ) : ( ) }), ...(legendDirection === 'rtl' && { labelComponent: legendComponent.props.labelComponent ? ( - React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: '10' }) + React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: legendXOffset - 30 }) ) : ( ) diff --git a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx index 12fc4a54b21..42ab60edcd5 100644 --- a/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx +++ b/packages/react-charts/src/components/ChartBullet/ChartBullet.tsx @@ -693,14 +693,14 @@ export const ChartBullet: React.FunctionComponent = ({ theme, ...(legendDirection === 'rtl' && { dataComponent: legendComponent.props.dataComponent ? ( - React.cloneElement(legendComponent.props.dataComponent, { transform: 'translate(40)' }) + React.cloneElement(legendComponent.props.dataComponent, { transform: `translate(${legendXOffset})` }) ) : ( ) }), ...(legendDirection === 'rtl' && { labelComponent: legendComponent.props.labelComponent ? ( - React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: '10' }) + React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: legendXOffset - 30 }) ) : ( ) diff --git a/packages/react-charts/src/components/ChartPie/ChartPie.tsx b/packages/react-charts/src/components/ChartPie/ChartPie.tsx index 65d09fb9dd7..899cabe0bd7 100644 --- a/packages/react-charts/src/components/ChartPie/ChartPie.tsx +++ b/packages/react-charts/src/components/ChartPie/ChartPie.tsx @@ -595,14 +595,14 @@ export const ChartPie: React.FunctionComponent = ({ theme, ...(legendDirection === 'rtl' && { dataComponent: legendComponent.props.dataComponent ? ( - React.cloneElement(legendComponent.props.dataComponent, { transform: 'translate(80)' }) + React.cloneElement(legendComponent.props.dataComponent, { transform: `translate(${legendXOffset})` }) ) : ( ) }), ...(legendDirection === 'rtl' && { labelComponent: legendComponent.props.labelComponent ? ( - React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: '50' }) + React.cloneElement(legendComponent.props.labelComponent, { direction: 'rtl', dx: legendXOffset - 30 }) ) : ( )