From bc5ba5c82bc7acedf6546c8c96765bd5f1d0e221 Mon Sep 17 00:00:00 2001 From: Matt Vickers Date: Mon, 1 Apr 2024 13:32:09 -0500 Subject: [PATCH] Limit Donut legend to 50% of chart width --- .../src/components/DonutChart/Chart.tsx | 33 ++++++++---- .../components/LegendValues/LegendValues.scss | 1 + .../components/LegendValues/LegendValues.tsx | 3 ++ .../LegendValueItem/LegendValueItem.scss | 5 +- .../LegendValueItem/LegendValueItem.tsx | 23 +++++---- .../stories/TruncatedLegends.stories.tsx | 50 +++++++++++++++++++ 6 files changed, 93 insertions(+), 22 deletions(-) create mode 100644 packages/polaris-viz/src/components/DonutChart/stories/TruncatedLegends.stories.tsx diff --git a/packages/polaris-viz/src/components/DonutChart/Chart.tsx b/packages/polaris-viz/src/components/DonutChart/Chart.tsx index 8936f62d52..e67bdf6cc9 100644 --- a/packages/polaris-viz/src/components/DonutChart/Chart.tsx +++ b/packages/polaris-viz/src/components/DonutChart/Chart.tsx @@ -7,6 +7,7 @@ import { useUniqueId, ChartState, useChartContext, + estimateStringWidth, } from '@shopify/polaris-viz-core'; import type { DataPoint, @@ -40,7 +41,7 @@ import {InnerValue, LegendValues} from './components'; const ERROR_ANIMATION_PADDING = 40; const FULL_CIRCLE = Math.PI * 2; -const MAX_LEGEND_WIDTH_PERCENTAGE = 0.35; +const MAX_LEGEND_WIDTH_PERCENTAGE = 0.5; const RADIUS_PADDING = 20; export interface ChartProps { @@ -113,13 +114,10 @@ export function Chart({ return previous; }, 0); - const maxLegendWidth = - legendDirection === 'vertical' - ? Math.max( - longestLegendWidth, - dimensions.width * MAX_LEGEND_WIDTH_PERCENTAGE, - ) - : 0; + const maxLegendWidth = Math.min( + longestLegendWidth, + dimensions.width * MAX_LEGEND_WIDTH_PERCENTAGE, + ); const {height, width, legend, setLegendDimensions, isLegendMounted} = useLegend({ @@ -131,6 +129,19 @@ export function Chart({ maxWidth: maxLegendWidth, }); + const longestLegendValueWidth = legend.reduce((previous, current) => { + const estimatedLegendWidth = estimateStringWidth( + `${labelFormatter(`${current.value || ''}`)}`, + characterWidths, + ); + + if (estimatedLegendWidth > previous) { + return estimatedLegendWidth; + } + + return previous; + }, 0); + const shouldUseColorVisionEvents = Boolean( width && height && isLegendMounted, ); @@ -147,7 +158,10 @@ export function Chart({ }, }); - if (!width || !height) return null; + if (!width || !height) { + return null; + } + const diameter = Math.min(height, width); const radius = diameter / 2; @@ -187,6 +201,7 @@ export function Chart({ data={data} activeIndex={activeIndex} labelFormatter={labelFormatter} + longestLegendValueWidth={longestLegendValueWidth} getColorVisionStyles={getColorVisionStyles} getColorVisionEventAttrs={getColorVisionEventAttrs} dimensions={{...dimensions, x: 0, y: 0}} diff --git a/packages/polaris-viz/src/components/DonutChart/components/LegendValues/LegendValues.scss b/packages/polaris-viz/src/components/DonutChart/components/LegendValues/LegendValues.scss index 1768cf3c1c..b435b0c60f 100644 --- a/packages/polaris-viz/src/components/DonutChart/components/LegendValues/LegendValues.scss +++ b/packages/polaris-viz/src/components/DonutChart/components/LegendValues/LegendValues.scss @@ -2,4 +2,5 @@ width: 100%; border-collapse: separate; border-spacing: 0 10px; + table-layout: fixed; } diff --git a/packages/polaris-viz/src/components/DonutChart/components/LegendValues/LegendValues.tsx b/packages/polaris-viz/src/components/DonutChart/components/LegendValues/LegendValues.tsx index 61f1fa0a84..c5c9a9ceb7 100644 --- a/packages/polaris-viz/src/components/DonutChart/components/LegendValues/LegendValues.tsx +++ b/packages/polaris-viz/src/components/DonutChart/components/LegendValues/LegendValues.tsx @@ -24,6 +24,7 @@ interface LegendContentProps { activeIndex: number; dimensions: BoundingRect; labelFormatter: LabelFormatter; + longestLegendValueWidth: number; renderHiddenLegendLabel?: RenderHiddenLegendLabel; getColorVisionStyles: ColorVisionInteractionMethods['getColorVisionStyles']; getColorVisionEventAttrs: ColorVisionInteractionMethods['getColorVisionEventAttrs']; @@ -33,6 +34,7 @@ export function LegendValues({ data: allData, activeIndex, labelFormatter, + longestLegendValueWidth, renderHiddenLegendLabel = (count) => `+${count} more`, getColorVisionStyles, getColorVisionEventAttrs, @@ -90,6 +92,7 @@ export function LegendValues({ value={value} trend={trend} index={index} + longestLegendValueWidth={longestLegendValueWidth} maxTrendIndicatorWidth={maxTrendIndicatorWidth} seriesColors={seriesColors} onDimensionChange={(dimensions) => { diff --git a/packages/polaris-viz/src/components/DonutChart/components/LegendValues/components/LegendValueItem/LegendValueItem.scss b/packages/polaris-viz/src/components/DonutChart/components/LegendValues/components/LegendValueItem/LegendValueItem.scss index 2b4a4aa20d..db17abbe06 100644 --- a/packages/polaris-viz/src/components/DonutChart/components/LegendValues/components/LegendValueItem/LegendValueItem.scss +++ b/packages/polaris-viz/src/components/DonutChart/components/LegendValues/components/LegendValueItem/LegendValueItem.scss @@ -7,10 +7,7 @@ text-wrap: nowrap; text-overflow: ellipsis; padding-left: 4px; -} - -.TableSpacer { - padding-left: 30px; + padding-right: 20px; } .alignLeft { diff --git a/packages/polaris-viz/src/components/DonutChart/components/LegendValues/components/LegendValueItem/LegendValueItem.tsx b/packages/polaris-viz/src/components/DonutChart/components/LegendValues/components/LegendValueItem/LegendValueItem.tsx index bb7420034b..391e08f3ee 100644 --- a/packages/polaris-viz/src/components/DonutChart/components/LegendValues/components/LegendValueItem/LegendValueItem.tsx +++ b/packages/polaris-viz/src/components/DonutChart/components/LegendValues/components/LegendValueItem/LegendValueItem.tsx @@ -21,6 +21,7 @@ interface Props { value?: string; trend?: MetaDataTrendIndicator; labelFormatter: LabelFormatter; + longestLegendValueWidth: number; seriesColors: Color[]; maxTrendIndicatorWidth: number; onDimensionChange: (dimensions: Dimensions) => void; @@ -33,6 +34,7 @@ export function LegendValueItem({ value, index, labelFormatter, + longestLegendValueWidth, trend, seriesColors, maxTrendIndicatorWidth, @@ -73,13 +75,12 @@ export function LegendValueItem({ style={{ color: selectedTheme.legend.labelColor, }} + title={name} > {name} - - - + - - {trend && valueExists && } - + {trend && valueExists && ( + + + + + + )} ); } diff --git a/packages/polaris-viz/src/components/DonutChart/stories/TruncatedLegends.stories.tsx b/packages/polaris-viz/src/components/DonutChart/stories/TruncatedLegends.stories.tsx new file mode 100644 index 0000000000..c8bf402be8 --- /dev/null +++ b/packages/polaris-viz/src/components/DonutChart/stories/TruncatedLegends.stories.tsx @@ -0,0 +1,50 @@ +import type {Story} from '@storybook/react'; + +export {META as default} from './meta'; + +import type {DonutChartProps} from '../../DonutChart'; + +import {DEFAULT_PROPS, Template} from './data'; + +export const TruncatedLegends: Story = Template.bind({}); + +TruncatedLegends.args = { + ...DEFAULT_PROPS, + showLegendValues: true, + legendPosition: 'right', + legendFullWidth: false, + labelFormatter: (value) => `$${value}`, + data: [ + { + name: 'This is a long name that will get truncated', + data: [{key: 'april - march', value: 50000}], + metadata: { + trend: { + value: '5%', + }, + }, + }, + { + name: 'This is another long name that will get truncated', + data: [{key: 'april - march', value: 250000}], + metadata: { + trend: { + value: '50%', + direction: 'downward', + trend: 'negative', + }, + }, + }, + { + name: 'This is the last long name that will get truncated', + data: [{key: 'april - march', value: 10000}], + metadata: { + trend: { + value: '100%', + direction: 'upward', + trend: 'positive', + }, + }, + }, + ], +};