* XY Axis, integrate legend color picker with the eui palette * Fix functional test to work with the eui palette * Order eui colors by group * Add unit test for use color picker * Add useMemo to getColorPicker * Remove the grey background from the first focused circle * Fix bug caused by comparing lowercase with uppercase characters * Fix bug on complimentary palette * Fix CI * fix linter * Use uppercase for hex color * Use eui variable instead * Changes on charts.json * Make the color picker accessible * Fix ci and tests * Allow keyboard navigation * Close the popover on mouse click event * Fix ci Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
f88b143e1f
commit
da9e1c313d
|
@ -9,7 +9,7 @@
|
|||
"children": [
|
||||
{
|
||||
"type": "Object",
|
||||
"label": "{ onChange, color: selectedColor, id, label }",
|
||||
"label": "{\n onChange,\n color: selectedColor,\n label,\n useLegacyColors = true,\n colorIsOverwritten = true,\n}",
|
||||
"isRequired": true,
|
||||
"signature": [
|
||||
"ColorPickerProps"
|
||||
|
@ -17,18 +17,18 @@
|
|||
"description": [],
|
||||
"source": {
|
||||
"path": "src/plugins/charts/public/static/components/color_picker.tsx",
|
||||
"lineNumber": 83
|
||||
"lineNumber": 108
|
||||
}
|
||||
}
|
||||
],
|
||||
"signature": [
|
||||
"({ onChange, color: selectedColor, id, label }: ColorPickerProps) => JSX.Element"
|
||||
"({ onChange, color: selectedColor, label, useLegacyColors, colorIsOverwritten, }: ColorPickerProps) => JSX.Element"
|
||||
],
|
||||
"description": [],
|
||||
"label": "ColorPicker",
|
||||
"source": {
|
||||
"path": "src/plugins/charts/public/static/components/color_picker.tsx",
|
||||
"lineNumber": 83
|
||||
"lineNumber": 108
|
||||
},
|
||||
"tags": [],
|
||||
"returnComment": [],
|
||||
|
|
|
@ -4,6 +4,18 @@ $visColorPickerWidth: $euiSizeL * 8; // 8 columns
|
|||
width: $visColorPickerWidth;
|
||||
}
|
||||
|
||||
.visColorPicker__colorBtn {
|
||||
position: relative;
|
||||
|
||||
input[type='radio'] {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
.visColorPicker__valueDot {
|
||||
cursor: pointer;
|
||||
|
||||
|
|
|
@ -9,12 +9,19 @@
|
|||
import classNames from 'classnames';
|
||||
import React, { BaseSyntheticEvent } from 'react';
|
||||
|
||||
import { EuiButtonEmpty, EuiFlexItem, EuiIcon } from '@elastic/eui';
|
||||
import {
|
||||
EuiButtonEmpty,
|
||||
EuiFlexItem,
|
||||
EuiIcon,
|
||||
euiPaletteColorBlind,
|
||||
EuiScreenReaderOnly,
|
||||
EuiFlexGroup,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import './color_picker.scss';
|
||||
|
||||
export const legendColors: string[] = [
|
||||
export const legacyColors: string[] = [
|
||||
'#3F6833',
|
||||
'#967302',
|
||||
'#2F575E',
|
||||
|
@ -74,54 +81,91 @@ export const legendColors: string[] = [
|
|||
];
|
||||
|
||||
interface ColorPickerProps {
|
||||
id?: string;
|
||||
/**
|
||||
* Label that characterizes the color that is going to change
|
||||
*/
|
||||
label: string | number | null;
|
||||
/**
|
||||
* Callback on the color change
|
||||
*/
|
||||
onChange: (color: string | null, event: BaseSyntheticEvent) => void;
|
||||
/**
|
||||
* Initial color.
|
||||
*/
|
||||
color: string;
|
||||
/**
|
||||
* Defines if the compatibility (legacy) or eui palette is going to be used. Defauls to true.
|
||||
*/
|
||||
useLegacyColors?: boolean;
|
||||
/**
|
||||
* Defines if the default color is overwritten. Defaults to true.
|
||||
*/
|
||||
colorIsOverwritten?: boolean;
|
||||
/**
|
||||
* Callback for onKeyPress event
|
||||
*/
|
||||
onKeyDown?: (e: React.KeyboardEvent<HTMLElement>) => void;
|
||||
}
|
||||
const euiColors = euiPaletteColorBlind({ rotations: 4, order: 'group' });
|
||||
|
||||
export const ColorPicker = ({ onChange, color: selectedColor, id, label }: ColorPickerProps) => (
|
||||
<div className="visColorPicker">
|
||||
<span id={`${id}ColorPickerDesc`} className="euiScreenReaderOnly">
|
||||
<FormattedMessage
|
||||
id="charts.colorPicker.setColor.screenReaderDescription"
|
||||
defaultMessage="Set color for value {legendDataLabel}"
|
||||
values={{ legendDataLabel: label }}
|
||||
/>
|
||||
</span>
|
||||
<div className="visColorPicker__value" role="listbox">
|
||||
{legendColors.map((color) => (
|
||||
<EuiIcon
|
||||
role="option"
|
||||
tabIndex={0}
|
||||
type="dot"
|
||||
size="l"
|
||||
color={selectedColor}
|
||||
key={color}
|
||||
aria-label={color}
|
||||
aria-describedby={`${id}ColorPickerDesc`}
|
||||
aria-selected={color === selectedColor}
|
||||
onClick={(e) => onChange(color, e)}
|
||||
onKeyPress={(e) => onChange(color, e)}
|
||||
className={classNames('visColorPicker__valueDot', {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
'visColorPicker__valueDot-isSelected': color === selectedColor,
|
||||
})}
|
||||
style={{ color }}
|
||||
data-test-subj={`visColorPickerColor-${color}`}
|
||||
/>
|
||||
))}
|
||||
export const ColorPicker = ({
|
||||
onChange,
|
||||
color: selectedColor,
|
||||
label,
|
||||
useLegacyColors = true,
|
||||
colorIsOverwritten = true,
|
||||
onKeyDown,
|
||||
}: ColorPickerProps) => {
|
||||
const legendColors = useLegacyColors ? legacyColors : euiColors;
|
||||
|
||||
return (
|
||||
<div className="visColorPicker">
|
||||
<fieldset>
|
||||
<EuiScreenReaderOnly>
|
||||
<legend>
|
||||
<FormattedMessage
|
||||
id="charts.colorPicker.setColor.screenReaderDescription"
|
||||
defaultMessage="Set color for value {legendDataLabel}"
|
||||
values={{ legendDataLabel: label }}
|
||||
/>
|
||||
</legend>
|
||||
</EuiScreenReaderOnly>
|
||||
<EuiFlexGroup wrap={true} gutterSize="none" className="visColorPicker__value">
|
||||
{legendColors.map((color) => (
|
||||
<label key={color} className="visColorPicker__colorBtn">
|
||||
<input
|
||||
type="radio"
|
||||
onChange={(e) => onChange(color, e)}
|
||||
value={selectedColor}
|
||||
name="visColorPicker__radio"
|
||||
checked={color === selectedColor}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
<EuiIcon
|
||||
type="dot"
|
||||
size="l"
|
||||
color={selectedColor}
|
||||
className={classNames('visColorPicker__valueDot', {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
'visColorPicker__valueDot-isSelected': color === selectedColor,
|
||||
})}
|
||||
style={{ color }}
|
||||
data-test-subj={`visColorPickerColor-${color}`}
|
||||
/>
|
||||
<EuiScreenReaderOnly>
|
||||
<span>{color}</span>
|
||||
</EuiScreenReaderOnly>
|
||||
</label>
|
||||
))}
|
||||
</EuiFlexGroup>
|
||||
</fieldset>
|
||||
{legendColors.some((c) => c === selectedColor) && colorIsOverwritten && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty size="s" onClick={(e: any) => onChange(null, e)}>
|
||||
<FormattedMessage id="charts.colorPicker.clearColor" defaultMessage="Reset color" />
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</div>
|
||||
{legendColors.some((c) => c === selectedColor) && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty
|
||||
size="s"
|
||||
onClick={(e: any) => onChange(null, e)}
|
||||
onKeyPress={(e: any) => onChange(null, e)}
|
||||
>
|
||||
<FormattedMessage id="charts.colorPicker.clearColor" defaultMessage="Clear color" />
|
||||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
|
|
@ -246,8 +246,8 @@ describe('VisLegend Component', () => {
|
|||
first.simulate('click');
|
||||
|
||||
const popover = wrapper.find('.visColorPicker').first();
|
||||
const firstColor = popover.find('.visColorPicker__valueDot').first();
|
||||
firstColor.simulate('click');
|
||||
const firstColor = popover.find('.visColorPicker__colorBtn input').first();
|
||||
firstColor.simulate('change');
|
||||
|
||||
const colors = mockState.get('vis.colors');
|
||||
|
||||
|
|
|
@ -233,7 +233,6 @@ export class VisLegend extends PureComponent<VisLegendProps, VisLegendState> {
|
|||
canFilter={this.state.filterableLabels.has(item.label)}
|
||||
onFilter={this.filter}
|
||||
onSelect={this.toggleDetails}
|
||||
legendId={this.legendId}
|
||||
setColor={this.setColor}
|
||||
getColor={this.getColor}
|
||||
onHighlight={this.highlight}
|
||||
|
|
|
@ -25,7 +25,6 @@ import { ColorPicker } from '../../../../../charts/public';
|
|||
|
||||
interface Props {
|
||||
item: LegendItem;
|
||||
legendId: string;
|
||||
selected: boolean;
|
||||
canFilter: boolean;
|
||||
anchorPosition: EuiPopoverProps['anchorPosition'];
|
||||
|
@ -39,7 +38,6 @@ interface Props {
|
|||
|
||||
const VisLegendItemComponent = ({
|
||||
item,
|
||||
legendId,
|
||||
selected,
|
||||
canFilter,
|
||||
anchorPosition,
|
||||
|
@ -150,7 +148,6 @@ const VisLegendItemComponent = ({
|
|||
{canFilter && renderFilterBar()}
|
||||
|
||||
<ColorPicker
|
||||
id={legendId}
|
||||
label={item.label}
|
||||
color={getColor(item.label)}
|
||||
onChange={(c, e) => setColor(item.label, c, e)}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
import { LegendColorPickerProps, XYChartSeriesIdentifier } from '@elastic/charts';
|
||||
import { EuiPopover } from '@elastic/eui';
|
||||
import { mountWithIntl } from '@kbn/test/jest';
|
||||
import { ComponentType, ReactWrapper } from 'enzyme';
|
||||
import { getColorPicker } from './get_color_picker';
|
||||
import { ColorPicker } from '../../../charts/public';
|
||||
import type { PersistedState } from '../../../visualizations/public';
|
||||
|
||||
jest.mock('@elastic/charts', () => {
|
||||
const original = jest.requireActual('@elastic/charts');
|
||||
|
||||
return {
|
||||
...original,
|
||||
getSpecId: jest.fn(() => {}),
|
||||
};
|
||||
});
|
||||
|
||||
describe('getColorPicker', function () {
|
||||
const mockState = new Map();
|
||||
const uiState = ({
|
||||
get: jest
|
||||
.fn()
|
||||
.mockImplementation((key, fallback) => (mockState.has(key) ? mockState.get(key) : fallback)),
|
||||
set: jest.fn().mockImplementation((key, value) => mockState.set(key, value)),
|
||||
emit: jest.fn(),
|
||||
setSilent: jest.fn(),
|
||||
} as unknown) as PersistedState;
|
||||
|
||||
let wrapperProps: LegendColorPickerProps;
|
||||
const Component: ComponentType<LegendColorPickerProps> = getColorPicker(
|
||||
'left',
|
||||
jest.fn(),
|
||||
jest.fn().mockImplementation((seriesIdentifier) => seriesIdentifier.seriesKeys[0]),
|
||||
'default',
|
||||
uiState
|
||||
);
|
||||
let wrapper: ReactWrapper<LegendColorPickerProps>;
|
||||
|
||||
beforeAll(() => {
|
||||
wrapperProps = {
|
||||
color: 'rgb(109, 204, 177)',
|
||||
onClose: jest.fn(),
|
||||
onChange: jest.fn(),
|
||||
anchor: document.createElement('div'),
|
||||
seriesIdentifiers: [
|
||||
{
|
||||
yAccessor: 'col-2-1',
|
||||
splitAccessors: {},
|
||||
seriesKeys: ['Logstash Airways', 'col-2-1'],
|
||||
specId: 'histogram-col-2-1',
|
||||
key:
|
||||
'groupId{__pseudo_stacked_group-ValueAxis-1__}spec{histogram-col-2-1}yAccessor{col-2-1}splitAccessors{col-1-3-Logstash Airways}',
|
||||
} as XYChartSeriesIdentifier,
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
it('renders the color picker', () => {
|
||||
wrapper = mountWithIntl(<Component {...wrapperProps} />);
|
||||
expect(wrapper.find(ColorPicker).length).toBe(1);
|
||||
});
|
||||
|
||||
it('renders the color picker with the colorIsOverwritten prop set to false if color is not overwritten for the specific series', () => {
|
||||
wrapper = mountWithIntl(<Component {...wrapperProps} />);
|
||||
expect(wrapper.find(ColorPicker).prop('colorIsOverwritten')).toBe(false);
|
||||
});
|
||||
|
||||
it('renders the color picker with the colorIsOverwritten prop set to true if color is overwritten for the specific series', () => {
|
||||
uiState.set('vis.colors', { 'Logstash Airways': '#6092c0' });
|
||||
wrapper = mountWithIntl(<Component {...wrapperProps} />);
|
||||
expect(wrapper.find(ColorPicker).prop('colorIsOverwritten')).toBe(true);
|
||||
});
|
||||
|
||||
it('renders the picker on the correct position', () => {
|
||||
wrapper = mountWithIntl(<Component {...wrapperProps} />);
|
||||
expect(wrapper.find(EuiPopover).prop('anchorPosition')).toEqual('rightCenter');
|
||||
});
|
||||
|
||||
it('renders the picker for kibana palette with useLegacyColors set to true', () => {
|
||||
const LegacyPaletteComponent: ComponentType<LegendColorPickerProps> = getColorPicker(
|
||||
'left',
|
||||
jest.fn(),
|
||||
jest.fn(),
|
||||
'kibana_palette',
|
||||
uiState
|
||||
);
|
||||
wrapper = mountWithIntl(<LegacyPaletteComponent {...wrapperProps} />);
|
||||
expect(wrapper.find(ColorPicker).prop('useLegacyColors')).toBe(true);
|
||||
});
|
||||
});
|
96
src/plugins/vis_type_xy/public/utils/get_color_picker.tsx
Normal file
96
src/plugins/vis_type_xy/public/utils/get_color_picker.tsx
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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 React, { useCallback } from 'react';
|
||||
|
||||
import { LegendColorPicker, Position, XYChartSeriesIdentifier, SeriesName } from '@elastic/charts';
|
||||
import { PopoverAnchorPosition, EuiWrappingPopover, EuiOutsideClickDetector } from '@elastic/eui';
|
||||
import type { PersistedState } from '../../../visualizations/public';
|
||||
import { ColorPicker } from '../../../charts/public';
|
||||
|
||||
function getAnchorPosition(legendPosition: Position): PopoverAnchorPosition {
|
||||
switch (legendPosition) {
|
||||
case Position.Bottom:
|
||||
return 'upCenter';
|
||||
case Position.Top:
|
||||
return 'downCenter';
|
||||
case Position.Left:
|
||||
return 'rightCenter';
|
||||
default:
|
||||
return 'leftCenter';
|
||||
}
|
||||
}
|
||||
|
||||
const KEY_CODE_ENTER = 13;
|
||||
|
||||
export const getColorPicker = (
|
||||
legendPosition: Position,
|
||||
setColor: (newColor: string | null, seriesKey: string | number) => void,
|
||||
getSeriesName: (series: XYChartSeriesIdentifier) => SeriesName,
|
||||
paletteName: string,
|
||||
uiState: PersistedState
|
||||
): LegendColorPicker => ({
|
||||
anchor,
|
||||
color,
|
||||
onClose,
|
||||
onChange,
|
||||
seriesIdentifiers: [seriesIdentifier],
|
||||
}) => {
|
||||
const seriesName = getSeriesName(seriesIdentifier as XYChartSeriesIdentifier);
|
||||
const overwriteColors: Record<string, string> = uiState?.get('vis.colors', {});
|
||||
const colorIsOverwritten = Object.keys(overwriteColors).includes(seriesName as string);
|
||||
let keyDownEventOn = false;
|
||||
|
||||
const handleChange = (newColor: string | null) => {
|
||||
if (!seriesName) {
|
||||
return;
|
||||
}
|
||||
if (newColor) {
|
||||
onChange(newColor);
|
||||
}
|
||||
setColor(newColor, seriesName);
|
||||
// close the popover if no color is applied or the user has clicked a color
|
||||
if (!newColor || !keyDownEventOn) {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
const onKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
|
||||
if (e.keyCode === KEY_CODE_ENTER) {
|
||||
onClose?.();
|
||||
}
|
||||
keyDownEventOn = true;
|
||||
};
|
||||
|
||||
const handleOutsideClick = useCallback(() => {
|
||||
onClose?.();
|
||||
}, [onClose]);
|
||||
|
||||
return (
|
||||
<EuiOutsideClickDetector onOutsideClick={handleOutsideClick}>
|
||||
<EuiWrappingPopover
|
||||
isOpen
|
||||
ownFocus
|
||||
display="block"
|
||||
button={anchor}
|
||||
anchorPosition={getAnchorPosition(legendPosition)}
|
||||
closePopover={onClose}
|
||||
panelPaddingSize="s"
|
||||
>
|
||||
<ColorPicker
|
||||
color={paletteName === 'kibana_palette' ? color : color.toLowerCase()}
|
||||
onChange={handleChange}
|
||||
label={seriesName}
|
||||
useLegacyColors={paletteName === 'kibana_palette'}
|
||||
colorIsOverwritten={colorIsOverwritten}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
</EuiWrappingPopover>
|
||||
</EuiOutsideClickDetector>
|
||||
);
|
||||
};
|
|
@ -11,6 +11,6 @@ export { getTimeZone } from './get_time_zone';
|
|||
export { getLegendActions } from './get_legend_actions';
|
||||
export { getSeriesNameFn } from './get_series_name_fn';
|
||||
export { getXDomain, getAdjustedDomain } from './domain';
|
||||
export { useColorPicker } from './use_color_picker';
|
||||
export { getColorPicker } from './get_color_picker';
|
||||
export { getXAccessor } from './accessors';
|
||||
export { getAllSeries } from './get_all_series';
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* 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 React, { BaseSyntheticEvent, useCallback, useMemo } from 'react';
|
||||
|
||||
import { LegendColorPicker, Position, XYChartSeriesIdentifier, SeriesName } from '@elastic/charts';
|
||||
import { PopoverAnchorPosition, EuiWrappingPopover, EuiOutsideClickDetector } from '@elastic/eui';
|
||||
|
||||
import { ColorPicker } from '../../../charts/public';
|
||||
|
||||
function getAnchorPosition(legendPosition: Position): PopoverAnchorPosition {
|
||||
switch (legendPosition) {
|
||||
case Position.Bottom:
|
||||
return 'upCenter';
|
||||
case Position.Top:
|
||||
return 'downCenter';
|
||||
case Position.Left:
|
||||
return 'rightCenter';
|
||||
default:
|
||||
return 'leftCenter';
|
||||
}
|
||||
}
|
||||
|
||||
export const useColorPicker = (
|
||||
legendPosition: Position,
|
||||
setColor: (
|
||||
newColor: string | null,
|
||||
seriesKey: string | number,
|
||||
event: BaseSyntheticEvent
|
||||
) => void,
|
||||
getSeriesName: (series: XYChartSeriesIdentifier) => SeriesName
|
||||
): LegendColorPicker =>
|
||||
useMemo(
|
||||
() => ({ anchor, color, onClose, onChange, seriesIdentifiers: [seriesIdentifier] }) => {
|
||||
const seriesName = getSeriesName(seriesIdentifier as XYChartSeriesIdentifier);
|
||||
const handlChange = (newColor: string | null, event: BaseSyntheticEvent) => {
|
||||
if (!seriesName) {
|
||||
return;
|
||||
}
|
||||
if (newColor) {
|
||||
onChange(newColor);
|
||||
}
|
||||
setColor(newColor, seriesName, event);
|
||||
// must be called after onChange
|
||||
onClose();
|
||||
};
|
||||
|
||||
// rule doesn't know this is inside a functional component
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const handleOutsideClick = useCallback(() => {
|
||||
onClose?.();
|
||||
}, [onClose]);
|
||||
|
||||
return (
|
||||
<EuiOutsideClickDetector onOutsideClick={handleOutsideClick}>
|
||||
<EuiWrappingPopover
|
||||
isOpen
|
||||
ownFocus
|
||||
display="block"
|
||||
button={anchor}
|
||||
anchorPosition={getAnchorPosition(legendPosition)}
|
||||
closePopover={onClose}
|
||||
panelPaddingSize="s"
|
||||
>
|
||||
<ColorPicker color={color} onChange={handlChange} label={seriesName} />
|
||||
</EuiWrappingPopover>
|
||||
</EuiOutsideClickDetector>
|
||||
);
|
||||
},
|
||||
[getSeriesName, legendPosition, setColor]
|
||||
);
|
|
@ -6,15 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, {
|
||||
BaseSyntheticEvent,
|
||||
KeyboardEvent,
|
||||
memo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import {
|
||||
Chart,
|
||||
|
@ -28,7 +20,6 @@ import {
|
|||
AccessorFn,
|
||||
Accessor,
|
||||
} from '@elastic/charts';
|
||||
import { keys } from '@elastic/eui';
|
||||
|
||||
import { compact } from 'lodash';
|
||||
import {
|
||||
|
@ -50,7 +41,7 @@ import {
|
|||
renderAllSeries,
|
||||
getSeriesNameFn,
|
||||
getLegendActions,
|
||||
useColorPicker,
|
||||
getColorPicker,
|
||||
getXAccessor,
|
||||
getAllSeries,
|
||||
} from './utils';
|
||||
|
@ -86,16 +77,6 @@ const VisComponent = (props: VisComponentProps) => {
|
|||
return props.uiState?.get('vis.legendOpen', bwcLegendStateDefault) as boolean;
|
||||
});
|
||||
const [palettesRegistry, setPalettesRegistry] = useState<PaletteRegistry | null>(null);
|
||||
useEffect(() => {
|
||||
const fn = () => {
|
||||
props?.uiState?.emit?.('reload');
|
||||
};
|
||||
props?.uiState?.on?.('change', fn);
|
||||
|
||||
return () => {
|
||||
props?.uiState?.off?.('change', fn);
|
||||
};
|
||||
}, [props?.uiState]);
|
||||
|
||||
const onRenderChange = useCallback<RenderChangeListener>(
|
||||
(isRendered) => {
|
||||
|
@ -203,11 +184,7 @@ const VisComponent = (props: VisComponentProps) => {
|
|||
}, [props.uiState]);
|
||||
|
||||
const setColor = useCallback(
|
||||
(newColor: string | null, seriesLabel: string | number, event: BaseSyntheticEvent) => {
|
||||
if ((event as KeyboardEvent).key && (event as KeyboardEvent).key !== keys.ENTER) {
|
||||
return;
|
||||
}
|
||||
|
||||
(newColor: string | null, seriesLabel: string | number) => {
|
||||
const colors = props.uiState?.get('vis.colors') || {};
|
||||
if (colors[seriesLabel] === newColor || !newColor) {
|
||||
delete colors[seriesLabel];
|
||||
|
@ -337,6 +314,18 @@ const VisComponent = (props: VisComponentProps) => {
|
|||
xAccessor,
|
||||
]
|
||||
);
|
||||
|
||||
const legendColorPicker = useMemo(
|
||||
() =>
|
||||
getColorPicker(
|
||||
legendPosition,
|
||||
setColor,
|
||||
getSeriesName,
|
||||
visParams.palette.name,
|
||||
props.uiState
|
||||
),
|
||||
[getSeriesName, legendPosition, props.uiState, setColor, visParams.palette.name]
|
||||
);
|
||||
return (
|
||||
<div className="xyChart__container" data-test-subj="visTypeXyChart">
|
||||
<LegendToggle
|
||||
|
@ -355,7 +344,7 @@ const VisComponent = (props: VisComponentProps) => {
|
|||
legendPosition={legendPosition}
|
||||
xDomain={xDomain}
|
||||
adjustedXDomain={adjustedXDomain}
|
||||
legendColorPicker={useColorPicker(legendPosition, setColor, getSeriesName)}
|
||||
legendColorPicker={legendColorPicker}
|
||||
onElementClick={handleFilterClick(
|
||||
visData,
|
||||
xAccessor,
|
||||
|
|
|
@ -76,7 +76,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await queryBar.clickQuerySubmitButton();
|
||||
|
||||
await PageObjects.visChart.openLegendOptionColors('Count', `[data-title="${visName}"]`);
|
||||
await PageObjects.visChart.selectNewLegendColorChoice('#EA6460');
|
||||
const overwriteColor = isNewChartsLibraryEnabled ? '#d36086' : '#EA6460';
|
||||
await PageObjects.visChart.selectNewLegendColorChoice(overwriteColor);
|
||||
|
||||
await PageObjects.dashboard.saveDashboard(dashboarName);
|
||||
|
||||
|
@ -89,7 +90,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
}
|
||||
|
||||
const colorChoiceRetained = await PageObjects.visChart.doesSelectedLegendColorExist(
|
||||
'#EA6460'
|
||||
overwriteColor
|
||||
);
|
||||
|
||||
expect(colorChoiceRetained).to.be(true);
|
||||
|
|
|
@ -408,7 +408,8 @@ export function VisualizeChartPageProvider({ getService, getPageObjects }: FtrPr
|
|||
|
||||
await this.waitForVisualizationRenderingStabilized();
|
||||
// arbitrary color chosen, any available would do
|
||||
const isOpen = await this.doesLegendColorChoiceExist('#EF843C');
|
||||
const arbitraryColor = (await this.isVisTypeXYChart()) ? '#d36086' : '#EF843C';
|
||||
const isOpen = await this.doesLegendColorChoiceExist(arbitraryColor);
|
||||
if (!isOpen) {
|
||||
throw new Error('legend color selector not open');
|
||||
}
|
||||
|
|
|
@ -262,7 +262,6 @@
|
|||
"charts.colormaps.greysText": "グレー",
|
||||
"charts.colormaps.redsText": "赤",
|
||||
"charts.colormaps.yellowToRedText": "黄色から赤",
|
||||
"charts.colorPicker.clearColor": "色のクリア",
|
||||
"charts.colorPicker.setColor.screenReaderDescription": "値 {legendDataLabel} の色を設定",
|
||||
"charts.countText": "カウント",
|
||||
"charts.functions.palette.args.colorHelpText": "パレットの色です。{html} カラー名、{hex}、{hsl}、{hsla}、{rgb}、または {rgba} を使用できます。",
|
||||
|
|
|
@ -265,7 +265,6 @@
|
|||
"charts.colormaps.greysText": "灰色",
|
||||
"charts.colormaps.redsText": "红色",
|
||||
"charts.colormaps.yellowToRedText": "黄到红",
|
||||
"charts.colorPicker.clearColor": "清除颜色",
|
||||
"charts.colorPicker.setColor.screenReaderDescription": "为值 {legendDataLabel} 设置颜色",
|
||||
"charts.countText": "计数",
|
||||
"charts.functions.palette.args.colorHelpText": "调色板颜色。接受 {html} 颜色名称 {hex}、{hsl}、{hsla}、{rgb} 或 {rgba}。",
|
||||
|
|
Loading…
Reference in a new issue