mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[Maps] Fix legend icon color for custom categorial palettes (#67141)
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
c8b1fc585b
commit
c9c37f77e6
5 changed files with 281 additions and 70 deletions
|
@ -170,10 +170,10 @@ export enum LAYER_STYLE_TYPE {
|
||||||
TILE = 'TILE',
|
TILE = 'TILE',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const COLOR_MAP_TYPE = {
|
export enum COLOR_MAP_TYPE {
|
||||||
CATEGORICAL: 'CATEGORICAL',
|
CATEGORICAL = 'CATEGORICAL',
|
||||||
ORDINAL: 'ORDINAL',
|
ORDINAL = 'ORDINAL',
|
||||||
};
|
}
|
||||||
|
|
||||||
export const CATEGORICAL_DATA_TYPES = ['string', 'ip', 'boolean'];
|
export const CATEGORICAL_DATA_TYPES = ['string', 'ip', 'boolean'];
|
||||||
export const ORDINAL_DATA_TYPES = ['number', 'date'];
|
export const ORDINAL_DATA_TYPES = ['number', 'date'];
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
/* eslint-disable @typescript-eslint/consistent-type-definitions */
|
/* eslint-disable @typescript-eslint/consistent-type-definitions */
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
COLOR_MAP_TYPE,
|
||||||
FIELD_ORIGIN,
|
FIELD_ORIGIN,
|
||||||
LABEL_BORDER_SIZES,
|
LABEL_BORDER_SIZES,
|
||||||
SYMBOLIZE_AS_TYPES,
|
SYMBOLIZE_AS_TYPES,
|
||||||
|
@ -60,7 +61,7 @@ export type IconStop = {
|
||||||
|
|
||||||
export type ColorDynamicOptions = {
|
export type ColorDynamicOptions = {
|
||||||
// ordinal color properties
|
// ordinal color properties
|
||||||
color: string; // TODO move color category ramps to constants and make ENUM type
|
color?: string; // TODO move color category ramps to constants and make ENUM type
|
||||||
customColorRamp?: OrdinalColorStop[];
|
customColorRamp?: OrdinalColorStop[];
|
||||||
useCustomColorRamp?: boolean;
|
useCustomColorRamp?: boolean;
|
||||||
|
|
||||||
|
@ -71,22 +72,28 @@ export type ColorDynamicOptions = {
|
||||||
|
|
||||||
field?: StylePropertyField;
|
field?: StylePropertyField;
|
||||||
fieldMetaOptions: FieldMetaOptions;
|
fieldMetaOptions: FieldMetaOptions;
|
||||||
|
|
||||||
|
type?: COLOR_MAP_TYPE;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ColorStaticOptions = {
|
export type ColorStaticOptions = {
|
||||||
color: string;
|
color: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ColorStylePropertyDescriptor =
|
export type ColorStaticStylePropertyDescriptor = {
|
||||||
| {
|
|
||||||
type: STYLE_TYPE.STATIC;
|
type: STYLE_TYPE.STATIC;
|
||||||
options: ColorStaticOptions;
|
options: ColorStaticOptions;
|
||||||
}
|
};
|
||||||
| {
|
|
||||||
|
export type ColorDynamicStylePropertyDescriptor = {
|
||||||
type: STYLE_TYPE.DYNAMIC;
|
type: STYLE_TYPE.DYNAMIC;
|
||||||
options: ColorDynamicOptions;
|
options: ColorDynamicOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ColorStylePropertyDescriptor =
|
||||||
|
| ColorStaticStylePropertyDescriptor
|
||||||
|
| ColorDynamicStylePropertyDescriptor;
|
||||||
|
|
||||||
export type IconDynamicOptions = {
|
export type IconDynamicOptions = {
|
||||||
iconPaletteId?: string;
|
iconPaletteId?: string;
|
||||||
customIconStops?: IconStop[];
|
customIconStops?: IconStop[];
|
||||||
|
|
|
@ -1,57 +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;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { getColorRampCenterColor, getColorPalette } from '../../../color_utils';
|
|
||||||
import { COLOR_MAP_TYPE, STYLE_TYPE } from '../../../../../../common/constants';
|
|
||||||
|
|
||||||
export function extractColorFromStyleProperty(colorStyleProperty, defaultColor) {
|
|
||||||
if (!colorStyleProperty) {
|
|
||||||
return defaultColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colorStyleProperty.type === STYLE_TYPE.STATIC) {
|
|
||||||
return colorStyleProperty.options.color;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not use dynamic color unless configuration is complete
|
|
||||||
if (!colorStyleProperty.options.field || !colorStyleProperty.options.field.name) {
|
|
||||||
return defaultColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colorStyleProperty.options.type === COLOR_MAP_TYPE.CATEGORICAL) {
|
|
||||||
if (colorStyleProperty.options.useCustomColorPalette) {
|
|
||||||
return colorStyleProperty.options.customColorPalette &&
|
|
||||||
colorStyleProperty.options.customColorPalette.length
|
|
||||||
? colorStyleProperty.options.customColorPalette[0].colorCategory
|
|
||||||
: defaultColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!colorStyleProperty.options.colorCategory) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const palette = getColorPalette(colorStyleProperty.options.colorCategory);
|
|
||||||
return palette[0];
|
|
||||||
} else {
|
|
||||||
// return middle of gradient for dynamic style property
|
|
||||||
if (colorStyleProperty.options.useCustomColorRamp) {
|
|
||||||
if (
|
|
||||||
!colorStyleProperty.options.customColorRamp ||
|
|
||||||
!colorStyleProperty.options.customColorRamp.length
|
|
||||||
) {
|
|
||||||
return defaultColor;
|
|
||||||
}
|
|
||||||
// favor the lowest color in even arrays
|
|
||||||
const middleIndex = Math.floor((colorStyleProperty.options.customColorRamp.length - 1) / 2);
|
|
||||||
return colorStyleProperty.options.customColorRamp[middleIndex].color;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!colorStyleProperty.options.color) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return getColorRampCenterColor(colorStyleProperty.options.color);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { extractColorFromStyleProperty } from './extract_color_from_style_property';
|
||||||
|
import {
|
||||||
|
ColorDynamicOptions,
|
||||||
|
ColorDynamicStylePropertyDescriptor,
|
||||||
|
ColorStaticOptions,
|
||||||
|
ColorStaticStylePropertyDescriptor,
|
||||||
|
} from '../../../../../../common/descriptor_types';
|
||||||
|
import { COLOR_MAP_TYPE, FIELD_ORIGIN, STYLE_TYPE } from '../../../../../../common/constants';
|
||||||
|
// @ts-ignore
|
||||||
|
import { euiPaletteColorBlind } from '@elastic/eui/lib/services';
|
||||||
|
|
||||||
|
const blue = '#0000ff';
|
||||||
|
const yellow = '#ffff00';
|
||||||
|
const green = '#00FF00';
|
||||||
|
const purple = '#800080';
|
||||||
|
const defaultColor = '#FFFFFF';
|
||||||
|
const fieldMetaOptions = {
|
||||||
|
isEnabled: true,
|
||||||
|
};
|
||||||
|
const field = {
|
||||||
|
name: 'myField',
|
||||||
|
origin: FIELD_ORIGIN.SOURCE,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('static', () => {
|
||||||
|
test('Should return color', () => {
|
||||||
|
const colorStyleProperty = {
|
||||||
|
type: STYLE_TYPE.STATIC,
|
||||||
|
options: {
|
||||||
|
color: blue,
|
||||||
|
} as ColorStaticOptions,
|
||||||
|
} as ColorStaticStylePropertyDescriptor;
|
||||||
|
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe(blue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('dynamic', () => {
|
||||||
|
test('Should return default color when field is not provided', () => {
|
||||||
|
const colorStyleProperty = {
|
||||||
|
type: STYLE_TYPE.DYNAMIC,
|
||||||
|
options: {
|
||||||
|
fieldMetaOptions,
|
||||||
|
} as ColorDynamicOptions,
|
||||||
|
} as ColorDynamicStylePropertyDescriptor;
|
||||||
|
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe(defaultColor);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('categorical', () => {
|
||||||
|
describe('predefined color palette', () => {
|
||||||
|
test('Should return default color when color palette is not specified', () => {
|
||||||
|
const colorStyleProperty = {
|
||||||
|
type: STYLE_TYPE.DYNAMIC,
|
||||||
|
options: {
|
||||||
|
type: COLOR_MAP_TYPE.CATEGORICAL,
|
||||||
|
field,
|
||||||
|
fieldMetaOptions,
|
||||||
|
} as ColorDynamicOptions,
|
||||||
|
} as ColorDynamicStylePropertyDescriptor;
|
||||||
|
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe(defaultColor);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should return first color from color palette', () => {
|
||||||
|
const colorStyleProperty = {
|
||||||
|
type: STYLE_TYPE.DYNAMIC,
|
||||||
|
options: {
|
||||||
|
type: COLOR_MAP_TYPE.CATEGORICAL,
|
||||||
|
colorCategory: 'palette_0',
|
||||||
|
field,
|
||||||
|
fieldMetaOptions,
|
||||||
|
} as ColorDynamicOptions,
|
||||||
|
} as ColorDynamicStylePropertyDescriptor;
|
||||||
|
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe(
|
||||||
|
euiPaletteColorBlind()[0]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('custom color palette', () => {
|
||||||
|
test('Should return default color when custom color palette is not provided', () => {
|
||||||
|
const colorStyleProperty = {
|
||||||
|
type: STYLE_TYPE.DYNAMIC,
|
||||||
|
options: {
|
||||||
|
type: COLOR_MAP_TYPE.CATEGORICAL,
|
||||||
|
colorCategory: 'palette_0',
|
||||||
|
field,
|
||||||
|
fieldMetaOptions,
|
||||||
|
useCustomColorPalette: true,
|
||||||
|
} as ColorDynamicOptions,
|
||||||
|
} as ColorDynamicStylePropertyDescriptor;
|
||||||
|
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe(defaultColor);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should return first color from custom color palette', () => {
|
||||||
|
const colorStyleProperty = {
|
||||||
|
type: STYLE_TYPE.DYNAMIC,
|
||||||
|
options: {
|
||||||
|
type: COLOR_MAP_TYPE.CATEGORICAL,
|
||||||
|
colorCategory: 'palette_0',
|
||||||
|
field,
|
||||||
|
fieldMetaOptions,
|
||||||
|
useCustomColorPalette: true,
|
||||||
|
customColorPalette: [{ stop: 'myCategory1', color: blue }],
|
||||||
|
} as ColorDynamicOptions,
|
||||||
|
} as ColorDynamicStylePropertyDescriptor;
|
||||||
|
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe(blue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ordinal', () => {
|
||||||
|
describe('predefined color ramp', () => {
|
||||||
|
test('Should return default color when color ramp is not specified', () => {
|
||||||
|
const colorStyleProperty = {
|
||||||
|
type: STYLE_TYPE.DYNAMIC,
|
||||||
|
options: {
|
||||||
|
type: COLOR_MAP_TYPE.ORDINAL,
|
||||||
|
field,
|
||||||
|
fieldMetaOptions,
|
||||||
|
} as ColorDynamicOptions,
|
||||||
|
} as ColorDynamicStylePropertyDescriptor;
|
||||||
|
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe(defaultColor);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should return center color from color ramp', () => {
|
||||||
|
const colorStyleProperty = {
|
||||||
|
type: STYLE_TYPE.DYNAMIC,
|
||||||
|
options: {
|
||||||
|
type: COLOR_MAP_TYPE.ORDINAL,
|
||||||
|
color: 'Blues',
|
||||||
|
field,
|
||||||
|
fieldMetaOptions,
|
||||||
|
} as ColorDynamicOptions,
|
||||||
|
} as ColorDynamicStylePropertyDescriptor;
|
||||||
|
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe(
|
||||||
|
'rgb(106,173,213)'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('custom color ramp', () => {
|
||||||
|
test('Should return default color when custom color ramp is not provided', () => {
|
||||||
|
const colorStyleProperty = {
|
||||||
|
type: STYLE_TYPE.DYNAMIC,
|
||||||
|
options: {
|
||||||
|
type: COLOR_MAP_TYPE.ORDINAL,
|
||||||
|
field,
|
||||||
|
fieldMetaOptions,
|
||||||
|
useCustomColorRamp: true,
|
||||||
|
} as ColorDynamicOptions,
|
||||||
|
} as ColorDynamicStylePropertyDescriptor;
|
||||||
|
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe(defaultColor);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should return middle color from custom color ramp (odd # of stops)', () => {
|
||||||
|
const colorStyleProperty = {
|
||||||
|
type: STYLE_TYPE.DYNAMIC,
|
||||||
|
options: {
|
||||||
|
type: COLOR_MAP_TYPE.ORDINAL,
|
||||||
|
field,
|
||||||
|
fieldMetaOptions,
|
||||||
|
useCustomColorRamp: true,
|
||||||
|
customColorRamp: [
|
||||||
|
{ stop: 0, color: blue },
|
||||||
|
{ stop: 5, color: green },
|
||||||
|
{ stop: 10, color: yellow },
|
||||||
|
],
|
||||||
|
} as ColorDynamicOptions,
|
||||||
|
} as ColorDynamicStylePropertyDescriptor;
|
||||||
|
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe(green);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should return middle color from custom color ramp (even # of stops)', () => {
|
||||||
|
const colorStyleProperty = {
|
||||||
|
type: STYLE_TYPE.DYNAMIC,
|
||||||
|
options: {
|
||||||
|
type: COLOR_MAP_TYPE.ORDINAL,
|
||||||
|
field,
|
||||||
|
fieldMetaOptions,
|
||||||
|
useCustomColorRamp: true,
|
||||||
|
customColorRamp: [
|
||||||
|
{ stop: 0, color: blue },
|
||||||
|
{ stop: 3, color: purple },
|
||||||
|
{ stop: 6, color: green },
|
||||||
|
{ stop: 10, color: yellow },
|
||||||
|
],
|
||||||
|
} as ColorDynamicOptions,
|
||||||
|
} as ColorDynamicStylePropertyDescriptor;
|
||||||
|
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe(purple);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { getColorRampCenterColor, getColorPalette } from '../../../color_utils';
|
||||||
|
import { COLOR_MAP_TYPE, STYLE_TYPE } from '../../../../../../common/constants';
|
||||||
|
import {
|
||||||
|
ColorDynamicOptions,
|
||||||
|
ColorStylePropertyDescriptor,
|
||||||
|
} from '../../../../../../common/descriptor_types';
|
||||||
|
|
||||||
|
export function extractColorFromStyleProperty(
|
||||||
|
colorStyleProperty: ColorStylePropertyDescriptor | undefined,
|
||||||
|
defaultColor: string
|
||||||
|
): string {
|
||||||
|
if (!colorStyleProperty) {
|
||||||
|
return defaultColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colorStyleProperty.type === STYLE_TYPE.STATIC) {
|
||||||
|
return colorStyleProperty.options.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dynamicOptions: ColorDynamicOptions = colorStyleProperty.options;
|
||||||
|
|
||||||
|
// Do not use dynamic color unless configuration is complete
|
||||||
|
if (!dynamicOptions.field || !dynamicOptions.field.name) {
|
||||||
|
return defaultColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dynamicOptions.type === COLOR_MAP_TYPE.CATEGORICAL) {
|
||||||
|
if (dynamicOptions.useCustomColorPalette) {
|
||||||
|
return dynamicOptions.customColorPalette && dynamicOptions.customColorPalette.length
|
||||||
|
? dynamicOptions.customColorPalette[0].color
|
||||||
|
: defaultColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dynamicOptions.colorCategory) {
|
||||||
|
return defaultColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
const palette = getColorPalette(dynamicOptions.colorCategory);
|
||||||
|
return palette[0];
|
||||||
|
} else {
|
||||||
|
// return middle of gradient for dynamic style property
|
||||||
|
if (dynamicOptions.useCustomColorRamp) {
|
||||||
|
if (!dynamicOptions.customColorRamp || !dynamicOptions.customColorRamp.length) {
|
||||||
|
return defaultColor;
|
||||||
|
}
|
||||||
|
// favor the lowest color in even arrays
|
||||||
|
const middleIndex = Math.floor((dynamicOptions.customColorRamp.length - 1) / 2);
|
||||||
|
return dynamicOptions.customColorRamp[middleIndex].color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dynamicOptions.color) {
|
||||||
|
return defaultColor;
|
||||||
|
}
|
||||||
|
return getColorRampCenterColor(dynamicOptions.color);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue