Skip to content

Commit

Permalink
feat(legend): custom legend width (#1467)
Browse files Browse the repository at this point in the history
  • Loading branch information
nickofthyme authored Dec 13, 2021
1 parent 27c5f2a commit 51f50df
Show file tree
Hide file tree
Showing 22 changed files with 97 additions and 10 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions integration/tests/legend_stories.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,27 @@ describe('Legend stories', () => {
);
});
});

describe('Custom width', () => {
// eslint-disable-next-line unicorn/consistent-function-scoping
const getUrl = (position: string, size: number) =>
`http://localhost:9001/?path=/story/legend--${position}&knob-enable legend size=true&knob-legend size=${size}`;

describe.each(['top', 'right', 'bottom', 'left'])('position %s', (position) => {
const isVertical = position === 'left' || position === 'right';
if (isVertical) {
it('should limit width to min of 30% of computed width', async () => {
await common.expectChartAtUrlToMatchScreenshot(getUrl(position, 1));
});
}

it('should limit size to max 70% of chart dimension', async () => {
await common.expectChartAtUrlToMatchScreenshot(getUrl(position, 100000));
});

it('should set exact size of legend within constraints', async () => {
await common.expectChartAtUrlToMatchScreenshot(getUrl(position, isVertical ? 400 : 300));
});
});
});
});
3 changes: 2 additions & 1 deletion packages/charts/api/charts.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ export const DEFAULT_TOOLTIP_SNAP = true;
export const DEFAULT_TOOLTIP_TYPE: "vertical";

// @public (undocumented)
export type DefaultSettingsProps = 'id' | 'chartType' | 'specType' | 'rendering' | 'rotation' | 'resizeDebounce' | 'pointerUpdateDebounce' | 'pointerUpdateTrigger' | 'animateData' | 'debug' | 'tooltip' | 'theme' | 'brushAxis' | 'minBrushDelta' | 'externalPointerEvents' | 'showLegend' | 'showLegendExtra' | 'legendPosition' | 'legendMaxDepth' | 'ariaUseDefaultSummary' | 'ariaLabelHeadingLevel' | 'ariaTableCaption' | 'allowBrushingLastHistogramBin';
export type DefaultSettingsProps = 'id' | 'chartType' | 'specType' | 'rendering' | 'rotation' | 'resizeDebounce' | 'pointerUpdateDebounce' | 'pointerUpdateTrigger' | 'animateData' | 'debug' | 'tooltip' | 'theme' | 'brushAxis' | 'minBrushDelta' | 'externalPointerEvents' | 'showLegend' | 'showLegendExtra' | 'legendPosition' | 'legendMaxDepth' | 'legendSize' | 'ariaUseDefaultSummary' | 'ariaLabelHeadingLevel' | 'ariaTableCaption' | 'allowBrushingLastHistogramBin';

// @public (undocumented)
export const DEPTH_KEY = "depth";
Expand Down Expand Up @@ -1373,6 +1373,7 @@ export interface LegendSpec {
legendColorPicker?: LegendColorPicker;
legendMaxDepth: number;
legendPosition: Position | LegendPositionConfig;
legendSize: number;
legendStrategy?: LegendStrategy;
// (undocumented)
onLegendItemClick?: LegendItemListener;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ exports[`Chart should render the legend name test 1`] = `
<Connect(SpecsParserComponent)>
<SpecsParserComponent specParsed={[Function (anonymous)]} specUnmounted={[Function (anonymous)]}>
<Connect(SpecInstance) debug={true} rendering=\\"svg\\" showLegend={true}>
<SpecInstance debug={true} rendering=\\"svg\\" showLegend={true} upsertSpec={[Function (anonymous)]} removeSpec={[Function (anonymous)]} id=\\"__global__settings___\\" chartType=\\"global\\" specType=\\"settings\\" rotation={0} animateData={true} resizeDebounce={10} tooltip={{...}} pointerUpdateTrigger=\\"x\\" externalPointerEvents={{...}} baseTheme={{...}} brushAxis=\\"x\\" minBrushDelta={2} ariaUseDefaultSummary={true} ariaLabelHeadingLevel=\\"p\\" allowBrushingLastHistogramBin={true} showLegendExtra={false} legendMaxDepth={Infinity} legendPosition=\\"right\\" />
<SpecInstance debug={true} rendering=\\"svg\\" showLegend={true} upsertSpec={[Function (anonymous)]} removeSpec={[Function (anonymous)]} id=\\"__global__settings___\\" chartType=\\"global\\" specType=\\"settings\\" rotation={0} animateData={true} resizeDebounce={10} tooltip={{...}} pointerUpdateTrigger=\\"x\\" externalPointerEvents={{...}} baseTheme={{...}} brushAxis=\\"x\\" minBrushDelta={2} ariaUseDefaultSummary={true} ariaLabelHeadingLevel=\\"p\\" allowBrushingLastHistogramBin={true} legendSize={NaN} showLegendExtra={false} legendMaxDepth={Infinity} legendPosition=\\"right\\" />
</Connect(SpecInstance)>
<Connect(SpecInstance) id=\\"test\\" data={{...}}>
<SpecInstance id=\\"test\\" data={{...}} upsertSpec={[Function (anonymous)]} removeSpec={[Function (anonymous)]} chartType=\\"xy_axis\\" specType=\\"series\\" seriesType=\\"bar\\" groupId=\\"__global__\\" xScaleType=\\"ordinal\\" yScaleType=\\"linear\\" xAccessor=\\"x\\" yAccessors={{...}} hideInLegend={false} enableHistogramMode={false} />
Expand Down
1 change: 1 addition & 0 deletions packages/charts/src/specs/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ export const DEFAULT_TOOLTIP_SNAP = true;
*/
export const DEFAULT_LEGEND_CONFIG = {
showLegend: false,
legendSize: NaN,
showLegendExtra: false,
legendMaxDepth: Infinity,
legendPosition: Position.Right,
Expand Down
8 changes: 8 additions & 0 deletions packages/charts/src/specs/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,13 @@ export interface LegendSpec {
* Limit the legend to the specified maximal depth when showing a hierarchical legend
*/
legendMaxDepth: number;
/**
* Sets the exact legend width (vertical) or height (horizontal)
*
* Limited to max of 70% of the chart container dimension
* Vertical legends limited to min of 30% of computed width
*/
legendSize: number;
/**
* Display the legend as a flat list. If true, legendStrategy is always `LegendStrategy.Key`.
*/
Expand Down Expand Up @@ -692,6 +699,7 @@ export type DefaultSettingsProps =
| 'showLegendExtra'
| 'legendPosition'
| 'legendMaxDepth'
| 'legendSize'
| 'ariaUseDefaultSummary'
| 'ariaLabelHeadingLevel'
| 'ariaTableCaption'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const getLegendConfigSelector = createCustomCachedSelector(
legendAction,
legendColorPicker,
legendMaxDepth,
legendSize,
legendPosition,
legendStrategy,
onLegendItemClick,
Expand All @@ -33,6 +34,7 @@ export const getLegendConfigSelector = createCustomCachedSelector(
legendAction,
legendColorPicker,
legendMaxDepth,
legendSize,
legendPosition: getLegendPositionConfig(legendPosition),
legendStrategy,
onLegendItemClick,
Expand Down
17 changes: 13 additions & 4 deletions packages/charts/src/state/selectors/get_legend_size.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,28 @@ export const getLegendSizeSelector = createCustomCachedSelector(
const legendItemHeight = bbox.height + VERTICAL_PADDING * 2;
const legendHeight = legendItemHeight * labels.length + TOP_MARGIN;
const scrollBarDimension = legendHeight > parentDimensions.height ? SCROLL_BAR_WIDTH : 0;
const staticWidth = spacingBuffer + actionDimension + scrollBarDimension;

const width = Number.isFinite(legendConfig.legendSize)
? Math.min(Math.max(legendConfig.legendSize, legendItemWidth * 0.3 + staticWidth), parentDimensions.width * 0.7)
: Math.floor(Math.min(legendItemWidth + staticWidth, verticalWidth));

return {
width: Math.floor(
Math.min(legendItemWidth + spacingBuffer + actionDimension + scrollBarDimension, verticalWidth),
),
width,
height: legendHeight,
margin,
position: legendPosition,
};
}
const isSingleLine = (parentDimensions.width - 20) / 200 > labels.length;
const height = Number.isFinite(legendConfig.legendSize)
? Math.min(legendConfig.legendSize, parentDimensions.height * 0.7)
: isSingleLine
? bbox.height + 16
: bbox.height * 2 + 24;

return {
height: isSingleLine ? bbox.height + 16 : bbox.height * 2 + 24,
height,
width: Math.floor(Math.min(legendItemWidth + spacingBuffer + actionDimension, verticalWidth)),
margin,
position: legendPosition,
Expand Down
9 changes: 8 additions & 1 deletion storybook/stories/legend/1_legend_right.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,21 @@ import { Axis, BarSeries, Chart, Position, ScaleType, Settings } from '@elastic/
import * as TestDatasets from '@elastic/charts/src/utils/data_samples/test_dataset';

import { useBaseTheme } from '../../use_base_theme';
import { getLegendSizeKnob } from './legend_size_knob';

export const Example = () => {
const yAccessors = ['y1', 'y2'];
const splitSeriesAccessors = ['g1', 'g2'];

return (
<Chart>
<Settings showLegend showLegendExtra legendPosition={Position.Right} baseTheme={useBaseTheme()} />
<Settings
showLegend
showLegendExtra
legendPosition={Position.Right}
legendSize={getLegendSizeKnob()}
baseTheme={useBaseTheme()}
/>
<Axis id="bottom" position={Position.Bottom} title="Bottom axis" showOverlappingTicks />
<Axis id="left2" title="Left axis" position={Position.Left} tickFormat={(d) => Number(d).toFixed(2)} />

Expand Down
9 changes: 8 additions & 1 deletion storybook/stories/legend/2_legend_bottom.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@ import { Axis, BarSeries, Chart, Position, ScaleType, Settings } from '@elastic/
import * as TestDatasets from '@elastic/charts/src/utils/data_samples/test_dataset';

import { useBaseTheme } from '../../use_base_theme';
import { getLegendSizeKnob } from './legend_size_knob';

export const Example = () => (
<Chart>
<Settings showLegend showLegendExtra legendPosition={Position.Bottom} baseTheme={useBaseTheme()} />
<Settings
showLegend
showLegendExtra
legendPosition={Position.Bottom}
legendSize={getLegendSizeKnob()}
baseTheme={useBaseTheme()}
/>
<Axis id="bottom" position={Position.Bottom} title="Bottom axis" showOverlappingTicks />
<Axis id="left2" title="Left axis" position={Position.Left} tickFormat={(d) => Number(d).toFixed(2)} />

Expand Down
9 changes: 8 additions & 1 deletion storybook/stories/legend/3_legend_left.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@ import { Axis, BarSeries, Chart, Position, ScaleType, Settings } from '@elastic/
import * as TestDatasets from '@elastic/charts/src/utils/data_samples/test_dataset';

import { useBaseTheme } from '../../use_base_theme';
import { getLegendSizeKnob } from './legend_size_knob';

export const Example = () => (
<Chart>
<Settings showLegend showLegendExtra legendPosition={Position.Left} baseTheme={useBaseTheme()} />
<Settings
showLegend
showLegendExtra
legendPosition={Position.Left}
legendSize={getLegendSizeKnob()}
baseTheme={useBaseTheme()}
/>
<Axis id="bottom" position={Position.Bottom} title="Bottom axis" showOverlappingTicks />
<Axis id="left2" title="Left axis" position={Position.Left} tickFormat={(d) => Number(d).toFixed(2)} />

Expand Down
9 changes: 8 additions & 1 deletion storybook/stories/legend/4_legend_top.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@ import { Axis, BarSeries, Chart, Position, ScaleType, Settings } from '@elastic/
import * as TestDatasets from '@elastic/charts/src/utils/data_samples/test_dataset';

import { useBaseTheme } from '../../use_base_theme';
import { getLegendSizeKnob } from './legend_size_knob';

export const Example = () => (
<Chart>
<Settings showLegend showLegendExtra legendPosition={Position.Top} baseTheme={useBaseTheme()} />
<Settings
showLegend
showLegendExtra
legendPosition={Position.Top}
legendSize={getLegendSizeKnob()}
baseTheme={useBaseTheme()}
/>
<Axis id="bottom" position={Position.Bottom} title="Bottom axis" showOverlappingTicks />
<Axis id="left2" title="Left axis" position={Position.Left} tickFormat={(d) => Number(d).toFixed(2)} />

Expand Down
15 changes: 15 additions & 0 deletions storybook/stories/legend/legend_size_knob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { boolean, number } from '@storybook/addon-knobs';

export const getLegendSizeKnob = (group?: string) => {
const enabled = boolean('enable legend size', false, group);
const size = enabled ? number('legend size', 200, { min: 0, step: 1 }, group) : NaN;
return size;
};

0 comments on commit 51f50df

Please sign in to comment.