[Maps] use EuiColorPalettePicker (#69190)

* [Maps] use EuiColorPalettePicker and Eui palettes

* use new ramps to create mb style

* update ColorMapSelect to use EuiColorPalettePicker

* move color_utils test to color_palettes

* clean up heatmap constants

* tslint

* fix test expects

* fix merge mistake

* update jest expects

* remove .chromium folder

* another jest expect update

* remove charts from kibana.json

* remove unneeded jest.mock

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2020-07-13 12:53:00 -06:00 committed by GitHub
parent 3031ff7447
commit f95ab33cbe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 446 additions and 520 deletions

View file

@ -21,7 +21,6 @@
"server": true,
"extraPublicDirs": ["common/constants"],
"requiredBundles": [
"charts",
"kibanaReact",
"kibanaUtils",
"savedObjects"

View file

@ -28,7 +28,7 @@ import {
VECTOR_STYLES,
STYLE_TYPE,
} from '../../../../common/constants';
import { COLOR_GRADIENTS } from '../../styles/color_utils';
import { NUMERICAL_COLOR_PALETTES } from '../../styles/color_palettes';
export const clustersLayerWizardConfig: LayerWizard = {
categories: [LAYER_WIZARD_CATEGORY.ELASTICSEARCH],
@ -57,7 +57,7 @@ export const clustersLayerWizardConfig: LayerWizard = {
name: COUNT_PROP_NAME,
origin: FIELD_ORIGIN.SOURCE,
},
color: COLOR_GRADIENTS[0].value,
color: NUMERICAL_COLOR_PALETTES[0].value,
type: COLOR_MAP_TYPE.ORDINAL,
},
},

View file

@ -18,7 +18,7 @@ import {
VECTOR_STYLES,
STYLE_TYPE,
} from '../../../../common/constants';
import { COLOR_GRADIENTS } from '../../styles/color_utils';
import { NUMERICAL_COLOR_PALETTES } from '../../styles/color_palettes';
// @ts-ignore
import { CreateSourceEditor } from './create_source_editor';
import { LayerWizard, RenderWizardArguments } from '../../layers/layer_wizard_registry';
@ -50,7 +50,7 @@ export const point2PointLayerWizardConfig: LayerWizard = {
name: COUNT_PROP_NAME,
origin: FIELD_ORIGIN.SOURCE,
},
color: COLOR_GRADIENTS[0].value,
color: NUMERICAL_COLOR_PALETTES[0].value,
},
},
[VECTOR_STYLES.LINE_WIDTH]: {

View file

@ -1,4 +1,4 @@
@import 'components/color_gradient';
@import 'heatmap/components/legend/color_gradient';
@import 'vector/components/style_prop_editor';
@import 'vector/components/color/color_stops';
@import 'vector/components/symbol/icon_select';

View file

@ -0,0 +1,58 @@
/*
* 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,
getOrdinalMbColorRampStops,
getColorPalette,
} from './color_palettes';
describe('getColorPalette', () => {
it('Should create RGB color ramp', () => {
expect(getColorPalette('Blues')).toEqual([
'#ecf1f7',
'#d9e3ef',
'#c5d5e7',
'#b2c7df',
'#9eb9d8',
'#8bacd0',
'#769fc8',
'#6092c0',
]);
});
});
describe('getColorRampCenterColor', () => {
it('Should get center color from color ramp', () => {
expect(getColorRampCenterColor('Blues')).toBe('#9eb9d8');
});
});
describe('getOrdinalMbColorRampStops', () => {
it('Should create color stops for custom range', () => {
expect(getOrdinalMbColorRampStops('Blues', 0, 1000)).toEqual([
0,
'#ecf1f7',
125,
'#d9e3ef',
250,
'#c5d5e7',
375,
'#b2c7df',
500,
'#9eb9d8',
625,
'#8bacd0',
750,
'#769fc8',
875,
'#6092c0',
]);
});
it('Should snap to end of color stops for identical range', () => {
expect(getOrdinalMbColorRampStops('Blues', 23, 23)).toEqual([23, '#6092c0']);
});
});

View file

@ -0,0 +1,172 @@
/*
* 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 tinycolor from 'tinycolor2';
import {
// @ts-ignore
euiPaletteForStatus,
// @ts-ignore
euiPaletteForTemperature,
// @ts-ignore
euiPaletteCool,
// @ts-ignore
euiPaletteWarm,
// @ts-ignore
euiPaletteNegative,
// @ts-ignore
euiPalettePositive,
// @ts-ignore
euiPaletteGray,
// @ts-ignore
euiPaletteColorBlind,
} from '@elastic/eui/lib/services';
import { EuiColorPalettePickerPaletteProps } from '@elastic/eui';
export const DEFAULT_HEATMAP_COLOR_RAMP_NAME = 'theclassic';
export const DEFAULT_FILL_COLORS: string[] = euiPaletteColorBlind();
export const DEFAULT_LINE_COLORS: string[] = [
...DEFAULT_FILL_COLORS.map((color: string) => tinycolor(color).darken().toHexString()),
// Explicitly add black & white as border color options
'#000',
'#FFF',
];
const COLOR_PALETTES: EuiColorPalettePickerPaletteProps[] = [
{
value: 'Blues',
palette: euiPaletteCool(8),
type: 'gradient',
},
{
value: 'Greens',
palette: euiPalettePositive(8),
type: 'gradient',
},
{
value: 'Greys',
palette: euiPaletteGray(8),
type: 'gradient',
},
{
value: 'Reds',
palette: euiPaletteNegative(8),
type: 'gradient',
},
{
value: 'Yellow to Red',
palette: euiPaletteWarm(8),
type: 'gradient',
},
{
value: 'Green to Red',
palette: euiPaletteForStatus(8),
type: 'gradient',
},
{
value: 'Blue to Red',
palette: euiPaletteForTemperature(8),
type: 'gradient',
},
{
value: DEFAULT_HEATMAP_COLOR_RAMP_NAME,
palette: [
'rgb(65, 105, 225)', // royalblue
'rgb(0, 256, 256)', // cyan
'rgb(0, 256, 0)', // lime
'rgb(256, 256, 0)', // yellow
'rgb(256, 0, 0)', // red
],
type: 'gradient',
},
{
value: 'palette_0',
palette: euiPaletteColorBlind(),
type: 'fixed',
},
{
value: 'palette_20',
palette: euiPaletteColorBlind({ rotations: 2 }),
type: 'fixed',
},
{
value: 'palette_30',
palette: euiPaletteColorBlind({ rotations: 3 }),
type: 'fixed',
},
];
export const NUMERICAL_COLOR_PALETTES = COLOR_PALETTES.filter(
(palette: EuiColorPalettePickerPaletteProps) => {
return palette.type === 'gradient';
}
);
export const CATEGORICAL_COLOR_PALETTES = COLOR_PALETTES.filter(
(palette: EuiColorPalettePickerPaletteProps) => {
return palette.type === 'fixed';
}
);
export function getColorPalette(colorPaletteId: string): string[] {
const colorPalette = COLOR_PALETTES.find(({ value }: EuiColorPalettePickerPaletteProps) => {
return value === colorPaletteId;
});
return colorPalette ? (colorPalette.palette as string[]) : [];
}
export function getColorRampCenterColor(colorPaletteId: string): string | null {
if (!colorPaletteId) {
return null;
}
const palette = getColorPalette(colorPaletteId);
return palette.length === 0 ? null : palette[Math.floor(palette.length / 2)];
}
// Returns an array of color stops
// [ stop_input_1: number, stop_output_1: color, stop_input_n: number, stop_output_n: color ]
export function getOrdinalMbColorRampStops(
colorPaletteId: string,
min: number,
max: number
): Array<number | string> | null {
if (!colorPaletteId) {
return null;
}
if (min > max) {
return null;
}
const palette = getColorPalette(colorPaletteId);
if (palette.length === 0) {
return null;
}
if (max === min) {
// just return single stop value
return [max, palette[palette.length - 1]];
}
const delta = max - min;
return palette.reduce(
(accu: Array<number | string>, stopColor: string, idx: number, srcArr: string[]) => {
const stopNumber = min + (delta * idx) / srcArr.length;
return [...accu, stopNumber, stopColor];
},
[]
);
}
export function getLinearGradient(colorStrings: string[]): string {
const intervals = colorStrings.length;
let linearGradient = `linear-gradient(to right, ${colorStrings[0]} 0%,`;
for (let i = 1; i < intervals - 1; i++) {
linearGradient = `${linearGradient} ${colorStrings[i]} \
${Math.floor((100 * i) / (intervals - 1))}%,`;
}
return `${linearGradient} ${colorStrings[colorStrings.length - 1]} 100%)`;
}

View file

@ -1,104 +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 {
COLOR_GRADIENTS,
getColorRampCenterColor,
getOrdinalMbColorRampStops,
getHexColorRangeStrings,
getLinearGradient,
getRGBColorRangeStrings,
} from './color_utils';
jest.mock('ui/new_platform');
describe('COLOR_GRADIENTS', () => {
it('Should contain EuiSuperSelect options list of color ramps', () => {
expect(COLOR_GRADIENTS.length).toBe(6);
const colorGradientOption = COLOR_GRADIENTS[0];
expect(colorGradientOption.value).toBe('Blues');
});
});
describe('getRGBColorRangeStrings', () => {
it('Should create RGB color ramp', () => {
expect(getRGBColorRangeStrings('Blues', 8)).toEqual([
'rgb(247,250,255)',
'rgb(221,234,247)',
'rgb(197,218,238)',
'rgb(157,201,224)',
'rgb(106,173,213)',
'rgb(65,145,197)',
'rgb(32,112,180)',
'rgb(7,47,107)',
]);
});
});
describe('getHexColorRangeStrings', () => {
it('Should create HEX color ramp', () => {
expect(getHexColorRangeStrings('Blues')).toEqual([
'#f7faff',
'#ddeaf7',
'#c5daee',
'#9dc9e0',
'#6aadd5',
'#4191c5',
'#2070b4',
'#072f6b',
]);
});
});
describe('getColorRampCenterColor', () => {
it('Should get center color from color ramp', () => {
expect(getColorRampCenterColor('Blues')).toBe('rgb(106,173,213)');
});
});
describe('getColorRampStops', () => {
it('Should create color stops for custom range', () => {
expect(getOrdinalMbColorRampStops('Blues', 0, 1000, 8)).toEqual([
0,
'#f7faff',
125,
'#ddeaf7',
250,
'#c5daee',
375,
'#9dc9e0',
500,
'#6aadd5',
625,
'#4191c5',
750,
'#2070b4',
875,
'#072f6b',
]);
});
it('Should snap to end of color stops for identical range', () => {
expect(getOrdinalMbColorRampStops('Blues', 23, 23, 8)).toEqual([23, '#072f6b']);
});
});
describe('getLinearGradient', () => {
it('Should create linear gradient from color ramp', () => {
const colorRamp = [
'rgb(247,250,255)',
'rgb(221,234,247)',
'rgb(197,218,238)',
'rgb(157,201,224)',
'rgb(106,173,213)',
'rgb(65,145,197)',
'rgb(32,112,180)',
'rgb(7,47,107)',
];
expect(getLinearGradient(colorRamp)).toBe(
'linear-gradient(to right, rgb(247,250,255) 0%, rgb(221,234,247) 14%, rgb(197,218,238) 28%, rgb(157,201,224) 42%, rgb(106,173,213) 57%, rgb(65,145,197) 71%, rgb(32,112,180) 85%, rgb(7,47,107) 100%)'
);
});
});

View file

@ -1,174 +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 React from 'react';
import tinycolor from 'tinycolor2';
import chroma from 'chroma-js';
// @ts-ignore
import { euiPaletteColorBlind } from '@elastic/eui/lib/services';
import { ColorGradient } from './components/color_gradient';
import { RawColorSchema, vislibColorMaps } from '../../../../../../src/plugins/charts/public';
export const GRADIENT_INTERVALS = 8;
export const DEFAULT_FILL_COLORS: string[] = euiPaletteColorBlind();
export const DEFAULT_LINE_COLORS: string[] = [
...DEFAULT_FILL_COLORS.map((color: string) => tinycolor(color).darken().toHexString()),
// Explicitly add black & white as border color options
'#000',
'#FFF',
];
function getRGBColors(colorRamp: Array<[number, number[]]>, numLegendColors: number = 4): string[] {
const colors = [];
colors[0] = getRGBColor(colorRamp, 0);
for (let i = 1; i < numLegendColors - 1; i++) {
colors[i] = getRGBColor(colorRamp, Math.floor((colorRamp.length * i) / numLegendColors));
}
colors[numLegendColors - 1] = getRGBColor(colorRamp, colorRamp.length - 1);
return colors;
}
function getRGBColor(colorRamp: Array<[number, number[]]>, i: number): string {
const rgbArray = colorRamp[i][1];
const red = Math.floor(rgbArray[0] * 255);
const green = Math.floor(rgbArray[1] * 255);
const blue = Math.floor(rgbArray[2] * 255);
return `rgb(${red},${green},${blue})`;
}
function getColorSchema(colorRampName: string): RawColorSchema {
const colorSchema = vislibColorMaps[colorRampName];
if (!colorSchema) {
throw new Error(
`${colorRampName} not found. Expected one of following values: ${Object.keys(
vislibColorMaps
)}`
);
}
return colorSchema;
}
export function getRGBColorRangeStrings(
colorRampName: string,
numberColors: number = GRADIENT_INTERVALS
): string[] {
const colorSchema = getColorSchema(colorRampName);
return getRGBColors(colorSchema.value, numberColors);
}
export function getHexColorRangeStrings(
colorRampName: string,
numberColors: number = GRADIENT_INTERVALS
): string[] {
return getRGBColorRangeStrings(colorRampName, numberColors).map((rgbColor) =>
chroma(rgbColor).hex()
);
}
export function getColorRampCenterColor(colorRampName: string): string | null {
if (!colorRampName) {
return null;
}
const colorSchema = getColorSchema(colorRampName);
const centerIndex = Math.floor(colorSchema.value.length / 2);
return getRGBColor(colorSchema.value, centerIndex);
}
// Returns an array of color stops
// [ stop_input_1: number, stop_output_1: color, stop_input_n: number, stop_output_n: color ]
export function getOrdinalMbColorRampStops(
colorRampName: string,
min: number,
max: number,
numberColors: number
): Array<number | string> | null {
if (!colorRampName) {
return null;
}
if (min > max) {
return null;
}
const hexColors = getHexColorRangeStrings(colorRampName, numberColors);
if (max === min) {
// just return single stop value
return [max, hexColors[hexColors.length - 1]];
}
const delta = max - min;
return hexColors.reduce(
(accu: Array<number | string>, stopColor: string, idx: number, srcArr: string[]) => {
const stopNumber = min + (delta * idx) / srcArr.length;
return [...accu, stopNumber, stopColor];
},
[]
);
}
export const COLOR_GRADIENTS = Object.keys(vislibColorMaps).map((colorRampName) => ({
value: colorRampName,
inputDisplay: <ColorGradient colorRampName={colorRampName} />,
}));
export const COLOR_RAMP_NAMES = Object.keys(vislibColorMaps);
export function getLinearGradient(colorStrings: string[]): string {
const intervals = colorStrings.length;
let linearGradient = `linear-gradient(to right, ${colorStrings[0]} 0%,`;
for (let i = 1; i < intervals - 1; i++) {
linearGradient = `${linearGradient} ${colorStrings[i]} \
${Math.floor((100 * i) / (intervals - 1))}%,`;
}
return `${linearGradient} ${colorStrings[colorStrings.length - 1]} 100%)`;
}
export interface ColorPalette {
id: string;
colors: string[];
}
const COLOR_PALETTES_CONFIGS: ColorPalette[] = [
{
id: 'palette_0',
colors: euiPaletteColorBlind(),
},
{
id: 'palette_20',
colors: euiPaletteColorBlind({ rotations: 2 }),
},
{
id: 'palette_30',
colors: euiPaletteColorBlind({ rotations: 3 }),
},
];
export function getColorPalette(paletteId: string): string[] | null {
const palette = COLOR_PALETTES_CONFIGS.find(({ id }: ColorPalette) => id === paletteId);
return palette ? palette.colors : null;
}
export const COLOR_PALETTES = COLOR_PALETTES_CONFIGS.map((palette) => {
const paletteDisplay = palette.colors.map((color) => {
const style: React.CSSProperties = {
backgroundColor: color,
width: `${100 / palette.colors.length}%`,
position: 'relative',
height: '100%',
display: 'inline-block',
};
return (
<div style={style} key={color}>
&nbsp;
</div>
);
});
return {
value: palette.id,
inputDisplay: <div className={'mapColorGradient'}>{paletteDisplay}</div>,
};
});

View file

@ -1,30 +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 React from 'react';
import {
COLOR_RAMP_NAMES,
GRADIENT_INTERVALS,
getRGBColorRangeStrings,
getLinearGradient,
} from '../color_utils';
interface Props {
colorRamp?: string[];
colorRampName?: string;
}
export const ColorGradient = ({ colorRamp, colorRampName }: Props) => {
if (!colorRamp && (!colorRampName || !COLOR_RAMP_NAMES.includes(colorRampName))) {
return null;
}
const rgbColorStrings = colorRampName
? getRGBColorRangeStrings(colorRampName, GRADIENT_INTERVALS)
: colorRamp!;
const background = getLinearGradient(rgbColorStrings);
return <div className="mapColorGradient" style={{ background }} />;
};

View file

@ -10,66 +10,120 @@ exports[`HeatmapStyleEditor is rendered 1`] = `
label="Color range"
labelType="label"
>
<EuiSuperSelect
<EuiColorPalettePicker
compressed={true}
fullWidth={false}
hasDividers={true}
isInvalid={false}
isLoading={false}
onChange={[Function]}
options={
palettes={
Array [
Object {
"inputDisplay": <ColorGradient
colorRamp={
Array [
"rgb(65, 105, 225)",
"rgb(0, 256, 256)",
"rgb(0, 256, 0)",
"rgb(256, 256, 0)",
"rgb(256, 0, 0)",
]
}
/>,
"text": "theclassic",
"value": "theclassic",
},
Object {
"inputDisplay": <ColorGradient
colorRampName="Blues"
/>,
"palette": Array [
"#ecf1f7",
"#d9e3ef",
"#c5d5e7",
"#b2c7df",
"#9eb9d8",
"#8bacd0",
"#769fc8",
"#6092c0",
],
"type": "gradient",
"value": "Blues",
},
Object {
"inputDisplay": <ColorGradient
colorRampName="Greens"
/>,
"palette": Array [
"#e6f1ee",
"#cce4de",
"#b3d6cd",
"#9ac8bd",
"#80bbae",
"#65ad9e",
"#47a08f",
"#209280",
],
"type": "gradient",
"value": "Greens",
},
Object {
"inputDisplay": <ColorGradient
colorRampName="Greys"
/>,
"palette": Array [
"#e0e4eb",
"#c2c9d5",
"#a6afbf",
"#8c95a5",
"#757c8b",
"#5e6471",
"#494d58",
"#343741",
],
"type": "gradient",
"value": "Greys",
},
Object {
"inputDisplay": <ColorGradient
colorRampName="Reds"
/>,
"palette": Array [
"#fdeae5",
"#f9d5cc",
"#f4c0b4",
"#eeab9c",
"#e79685",
"#df816e",
"#d66c58",
"#cc5642",
],
"type": "gradient",
"value": "Reds",
},
Object {
"inputDisplay": <ColorGradient
colorRampName="Yellow to Red"
/>,
"palette": Array [
"#f9eac5",
"#f6d9af",
"#f3c89a",
"#efb785",
"#eba672",
"#e89361",
"#e58053",
"#e7664c",
],
"type": "gradient",
"value": "Yellow to Red",
},
Object {
"inputDisplay": <ColorGradient
colorRampName="Green to Red"
/>,
"palette": Array [
"#209280",
"#3aa38d",
"#54b399",
"#95b978",
"#df9352",
"#e7664c",
"#da5e47",
"#cc5642",
],
"type": "gradient",
"value": "Green to Red",
},
Object {
"palette": Array [
"#6092c0",
"#84a9cd",
"#a8bfda",
"#cad7e8",
"#f0d3b0",
"#ecb385",
"#ea8d69",
"#e7664c",
],
"type": "gradient",
"value": "Blue to Red",
},
Object {
"palette": Array [
"rgb(65, 105, 225)",
"rgb(0, 256, 256)",
"rgb(0, 256, 0)",
"rgb(256, 256, 0)",
"rgb(256, 0, 0)",
],
"type": "gradient",
"value": "theclassic",
},
]
}
valueOfSelected="Blues"

View file

@ -6,17 +6,6 @@
import { i18n } from '@kbn/i18n';
// Color stops from default Mapbox heatmap-color
export const DEFAULT_RGB_HEATMAP_COLOR_RAMP = [
'rgb(65, 105, 225)', // royalblue
'rgb(0, 256, 256)', // cyan
'rgb(0, 256, 0)', // lime
'rgb(256, 256, 0)', // yellow
'rgb(256, 0, 0)', // red
];
export const DEFAULT_HEATMAP_COLOR_RAMP_NAME = 'theclassic';
export const HEATMAP_COLOR_RAMP_LABEL = i18n.translate('xpack.maps.heatmap.colorRampLabel', {
defaultMessage: 'Color range',
});

View file

@ -6,14 +6,9 @@
import React from 'react';
import { EuiFormRow, EuiSuperSelect } from '@elastic/eui';
import { COLOR_GRADIENTS } from '../../color_utils';
import { ColorGradient } from '../../components/color_gradient';
import {
DEFAULT_RGB_HEATMAP_COLOR_RAMP,
DEFAULT_HEATMAP_COLOR_RAMP_NAME,
HEATMAP_COLOR_RAMP_LABEL,
} from './heatmap_constants';
import { EuiFormRow, EuiColorPalettePicker } from '@elastic/eui';
import { NUMERICAL_COLOR_PALETTES } from '../../color_palettes';
import { HEATMAP_COLOR_RAMP_LABEL } from './heatmap_constants';
interface Props {
colorRampName: string;
@ -21,28 +16,18 @@ interface Props {
}
export function HeatmapStyleEditor({ colorRampName, onHeatmapColorChange }: Props) {
const onColorRampChange = (selectedColorRampName: string) => {
const onColorRampChange = (selectedPaletteId: string) => {
onHeatmapColorChange({
colorRampName: selectedColorRampName,
colorRampName: selectedPaletteId,
});
};
const colorRampOptions = [
{
value: DEFAULT_HEATMAP_COLOR_RAMP_NAME,
text: DEFAULT_HEATMAP_COLOR_RAMP_NAME,
inputDisplay: <ColorGradient colorRamp={DEFAULT_RGB_HEATMAP_COLOR_RAMP} />,
},
...COLOR_GRADIENTS,
];
return (
<EuiFormRow label={HEATMAP_COLOR_RAMP_LABEL} display="rowCompressed">
<EuiSuperSelect
options={colorRampOptions}
<EuiColorPalettePicker
palettes={NUMERICAL_COLOR_PALETTES}
onChange={onColorRampChange}
valueOfSelected={colorRampName}
hasDividers={true}
compressed
/>
</EuiFormRow>

View file

@ -0,0 +1,19 @@
/*
* 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 React from 'react';
import { getColorPalette, getLinearGradient } from '../../../color_palettes';
interface Props {
colorPaletteId: string;
}
export const ColorGradient = ({ colorPaletteId }: Props) => {
const palette = getColorPalette(colorPaletteId);
return palette.length ? (
<div className="mapColorGradient" style={{ background: getLinearGradient(palette) }} />
) : null;
};

View file

@ -7,13 +7,9 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
import { ColorGradient } from '../../../components/color_gradient';
import { ColorGradient } from './color_gradient';
import { RangedStyleLegendRow } from '../../../components/ranged_style_legend_row';
import {
DEFAULT_RGB_HEATMAP_COLOR_RAMP,
DEFAULT_HEATMAP_COLOR_RAMP_NAME,
HEATMAP_COLOR_RAMP_LABEL,
} from '../heatmap_constants';
import { HEATMAP_COLOR_RAMP_LABEL } from '../heatmap_constants';
export class HeatmapLegend extends React.Component {
constructor() {
@ -41,17 +37,9 @@ export class HeatmapLegend extends React.Component {
}
render() {
const colorRampName = this.props.colorRampName;
const header =
colorRampName === DEFAULT_HEATMAP_COLOR_RAMP_NAME ? (
<ColorGradient colorRamp={DEFAULT_RGB_HEATMAP_COLOR_RAMP} />
) : (
<ColorGradient colorRampName={colorRampName} />
);
return (
<RangedStyleLegendRow
header={header}
header={<ColorGradient colorPaletteId={this.props.colorRampName} />}
minLabel={i18n.translate('xpack.maps.heatmapLegend.coldLabel', {
defaultMessage: 'cold',
})}

View file

@ -8,15 +8,15 @@ import React from 'react';
import { AbstractStyle } from '../style';
import { HeatmapStyleEditor } from './components/heatmap_style_editor';
import { HeatmapLegend } from './components/legend/heatmap_legend';
import { DEFAULT_HEATMAP_COLOR_RAMP_NAME } from './components/heatmap_constants';
import { DEFAULT_HEATMAP_COLOR_RAMP_NAME, getOrdinalMbColorRampStops } from '../color_palettes';
import { LAYER_STYLE_TYPE, GRID_RESOLUTION } from '../../../../common/constants';
import { getOrdinalMbColorRampStops, GRADIENT_INTERVALS } from '../color_utils';
import { i18n } from '@kbn/i18n';
import { EuiIcon } from '@elastic/eui';
//The heatmap range chosen hear runs from 0 to 1. It is arbitrary.
//Weighting is on the raw count/sum values.
const MIN_RANGE = 0;
const MIN_RANGE = 0.1; // 0 to 0.1 is displayed as transparent color stop
const MAX_RANGE = 1;
export class HeatmapStyle extends AbstractStyle {
@ -83,40 +83,19 @@ export class HeatmapStyle extends AbstractStyle {
property: propertyName,
});
const { colorRampName } = this._descriptor;
if (colorRampName && colorRampName !== DEFAULT_HEATMAP_COLOR_RAMP_NAME) {
const colorStops = getOrdinalMbColorRampStops(
colorRampName,
MIN_RANGE,
MAX_RANGE,
GRADIENT_INTERVALS
);
// TODO handle null
const colorStops = getOrdinalMbColorRampStops(
this._descriptor.colorRampName,
MIN_RANGE,
MAX_RANGE
);
if (colorStops) {
mbMap.setPaintProperty(layerId, 'heatmap-color', [
'interpolate',
['linear'],
['heatmap-density'],
0,
'rgba(0, 0, 255, 0)',
...colorStops.slice(2), // remove first stop from colorStops to avoid conflict with transparent stop at zero
]);
} else {
mbMap.setPaintProperty(layerId, 'heatmap-color', [
'interpolate',
['linear'],
['heatmap-density'],
0,
'rgba(0, 0, 255, 0)',
0.1,
'royalblue',
0.3,
'cyan',
0.5,
'lime',
0.7,
'yellow',
1,
'red',
...colorStops,
]);
}
}

View file

@ -6,10 +6,17 @@
import React, { Component, Fragment } from 'react';
import { EuiSpacer, EuiSelect, EuiSuperSelect, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import {
EuiSpacer,
EuiSelect,
EuiColorPalettePicker,
EuiFlexGroup,
EuiFlexItem,
} from '@elastic/eui';
import { ColorStopsOrdinal } from './color_stops_ordinal';
import { COLOR_MAP_TYPE } from '../../../../../../common/constants';
import { ColorStopsCategorical } from './color_stops_categorical';
import { CATEGORICAL_COLOR_PALETTES, NUMERICAL_COLOR_PALETTES } from '../../../color_palettes';
import { i18n } from '@kbn/i18n';
const CUSTOM_COLOR_MAP = 'CUSTOM_COLOR_MAP';
@ -65,10 +72,10 @@ export class ColorMapSelect extends Component {
);
}
_onColorMapSelect = (selectedValue) => {
const useCustomColorMap = selectedValue === CUSTOM_COLOR_MAP;
_onColorPaletteSelect = (selectedPaletteId) => {
const useCustomColorMap = selectedPaletteId === CUSTOM_COLOR_MAP;
this.props.onChange({
color: useCustomColorMap ? null : selectedValue,
color: useCustomColorMap ? null : selectedPaletteId,
useCustomColorMap,
type: this.props.colorMapType,
});
@ -126,26 +133,28 @@ export class ColorMapSelect extends Component {
return null;
}
const colorMapOptionsWithCustom = [
const palettes =
this.props.colorMapType === COLOR_MAP_TYPE.ORDINAL
? NUMERICAL_COLOR_PALETTES
: CATEGORICAL_COLOR_PALETTES;
const palettesWithCustom = [
{
value: CUSTOM_COLOR_MAP,
inputDisplay: this.props.customOptionLabel,
title:
this.props.colorMapType === COLOR_MAP_TYPE.ORDINAL
? i18n.translate('xpack.maps.style.customColorRampLabel', {
defaultMessage: 'Custom color ramp',
})
: i18n.translate('xpack.maps.style.customColorPaletteLabel', {
defaultMessage: 'Custom color palette',
}),
type: 'text',
'data-test-subj': `colorMapSelectOption_${CUSTOM_COLOR_MAP}`,
},
...this.props.colorMapOptions,
...palettes,
];
let valueOfSelected;
if (this.props.useCustomColorMap) {
valueOfSelected = CUSTOM_COLOR_MAP;
} else {
valueOfSelected = this.props.colorMapOptions.find(
(option) => option.value === this.props.color
)
? this.props.color
: '';
}
const toggle = this.props.showColorMapTypeToggle ? (
<EuiFlexItem grow={false}>{this._renderColorMapToggle()}</EuiFlexItem>
) : null;
@ -155,12 +164,13 @@ export class ColorMapSelect extends Component {
<EuiFlexGroup gutterSize={'none'}>
{toggle}
<EuiFlexItem>
<EuiSuperSelect
<EuiColorPalettePicker
palettes={palettesWithCustom}
onChange={this._onColorPaletteSelect}
valueOfSelected={
this.props.useCustomColorMap ? CUSTOM_COLOR_MAP : this.props.colorPaletteId
}
compressed
options={colorMapOptionsWithCustom}
onChange={this._onColorMapSelect}
valueOfSelected={valueOfSelected}
hasDividers={true}
data-test-subj={`colorMapSelect_${this.props.styleProperty.getStyleName()}`}
/>
</EuiFlexItem>

View file

@ -10,8 +10,6 @@ import { FieldSelect } from '../field_select';
import { ColorMapSelect } from './color_map_select';
import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import { CATEGORICAL_DATA_TYPES, COLOR_MAP_TYPE } from '../../../../../../common/constants';
import { COLOR_GRADIENTS, COLOR_PALETTES } from '../../../color_utils';
import { i18n } from '@kbn/i18n';
export function DynamicColorForm({
fields,
@ -91,14 +89,10 @@ export function DynamicColorForm({
return (
<ColorMapSelect
isCustomOnly={!field.supportsAutoDomain}
colorMapOptions={COLOR_GRADIENTS}
customOptionLabel={i18n.translate('xpack.maps.style.customColorRampLabel', {
defaultMessage: 'Custom color ramp',
})}
onChange={onColorMapSelect}
onColorMapTypeChange={onColorMapTypeChange}
colorMapType={COLOR_MAP_TYPE.ORDINAL}
color={styleOptions.color}
colorPaletteId={styleOptions.color}
customColorMap={styleOptions.customColorRamp}
useCustomColorMap={_.get(styleOptions, 'useCustomColorRamp', false)}
styleProperty={styleProperty}
@ -110,14 +104,10 @@ export function DynamicColorForm({
return (
<ColorMapSelect
isCustomOnly={!field.supportsAutoDomain}
colorMapOptions={COLOR_PALETTES}
customOptionLabel={i18n.translate('xpack.maps.style.customColorPaletteLabel', {
defaultMessage: 'Custom color palette',
})}
onColorMapTypeChange={onColorMapTypeChange}
onChange={onColorMapSelect}
colorMapType={COLOR_MAP_TYPE.CATEGORICAL}
color={styleOptions.colorCategory}
colorPaletteId={styleOptions.colorCategory}
customColorMap={styleOptions.customColorPalette}
useCustomColorMap={_.get(styleOptions, 'useCustomColorPalette', false)}
styleProperty={styleProperty}

View file

@ -137,9 +137,7 @@ describe('dynamic', () => {
fieldMetaOptions,
} as ColorDynamicOptions,
} as ColorDynamicStylePropertyDescriptor;
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe(
'rgb(106,173,213)'
);
expect(extractColorFromStyleProperty(colorStyleProperty, defaultColor)).toBe('#9eb9d8');
});
});

View file

@ -4,8 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
// @ts-ignore
import { getColorRampCenterColor, getColorPalette } from '../../../color_utils';
import { getColorRampCenterColor, getColorPalette } from '../../../color_palettes';
import { COLOR_MAP_TYPE, STYLE_TYPE } from '../../../../../../common/constants';
import {
ColorDynamicOptions,

View file

@ -15,7 +15,7 @@ import { VectorStyleLabelEditor } from './label/vector_style_label_editor';
import { VectorStyleLabelBorderSizeEditor } from './label/vector_style_label_border_size_editor';
import { OrientationEditor } from './orientation/orientation_editor';
import { getDefaultDynamicProperties, getDefaultStaticProperties } from '../vector_style_defaults';
import { DEFAULT_FILL_COLORS, DEFAULT_LINE_COLORS } from '../../color_utils';
import { DEFAULT_FILL_COLORS, DEFAULT_LINE_COLORS } from '../../color_palettes';
import { i18n } from '@kbn/i18n';
import { EuiSpacer, EuiButtonGroup, EuiFormRow, EuiSwitch } from '@elastic/eui';

View file

@ -175,7 +175,7 @@ exports[`ordinal Should render only single band of last color when delta is 0 1`
key="0"
>
<Category
color="#072f6b"
color="#6092c0"
isLinesOnly={false}
isPointsOnly={true}
label="100_format"
@ -227,7 +227,7 @@ exports[`ordinal Should render ordinal legend as bands 1`] = `
key="0"
>
<Category
color="#ddeaf7"
color="#d9e3ef"
isLinesOnly={false}
isPointsOnly={true}
label="13_format"
@ -238,7 +238,7 @@ exports[`ordinal Should render ordinal legend as bands 1`] = `
key="1"
>
<Category
color="#c5daee"
color="#c5d5e7"
isLinesOnly={false}
isPointsOnly={true}
label="25_format"
@ -249,7 +249,7 @@ exports[`ordinal Should render ordinal legend as bands 1`] = `
key="2"
>
<Category
color="#9dc9e0"
color="#b2c7df"
isLinesOnly={false}
isPointsOnly={true}
label="38_format"
@ -260,7 +260,7 @@ exports[`ordinal Should render ordinal legend as bands 1`] = `
key="3"
>
<Category
color="#6aadd5"
color="#9eb9d8"
isLinesOnly={false}
isPointsOnly={true}
label="50_format"
@ -271,7 +271,7 @@ exports[`ordinal Should render ordinal legend as bands 1`] = `
key="4"
>
<Category
color="#4191c5"
color="#8bacd0"
isLinesOnly={false}
isPointsOnly={true}
label="63_format"
@ -282,7 +282,7 @@ exports[`ordinal Should render ordinal legend as bands 1`] = `
key="5"
>
<Category
color="#2070b4"
color="#769fc8"
isLinesOnly={false}
isPointsOnly={true}
label="75_format"
@ -293,7 +293,7 @@ exports[`ordinal Should render ordinal legend as bands 1`] = `
key="6"
>
<Category
color="#072f6b"
color="#6092c0"
isLinesOnly={false}
isPointsOnly={true}
label="88_format"

View file

@ -6,12 +6,7 @@
import { DynamicStyleProperty } from './dynamic_style_property';
import { makeMbClampedNumberExpression, dynamicRound } from '../style_util';
import {
getOrdinalMbColorRampStops,
getColorPalette,
getHexColorRangeStrings,
GRADIENT_INTERVALS,
} from '../../color_utils';
import { getOrdinalMbColorRampStops, getColorPalette } from '../../color_palettes';
import React from 'react';
import { COLOR_MAP_TYPE, MB_LOOKUP_FUNCTION } from '../../../../../common/constants';
import {
@ -138,8 +133,7 @@ export class DynamicColorProperty extends DynamicStyleProperty {
const colorStops = getOrdinalMbColorRampStops(
this._options.color,
rangeFieldMeta.min,
rangeFieldMeta.max,
GRADIENT_INTERVALS
rangeFieldMeta.max
);
if (!colorStops) {
return null;
@ -253,7 +247,7 @@ export class DynamicColorProperty extends DynamicStyleProperty {
return [];
}
const colors = getHexColorRangeStrings(this._options.color, GRADIENT_INTERVALS);
const colors = getColorPalette(this._options.color);
if (rangeFieldMeta.delta === 0) {
//map to last color.
@ -266,7 +260,7 @@ export class DynamicColorProperty extends DynamicStyleProperty {
}
return colors.map((color, index) => {
const rawStopValue = rangeFieldMeta.min + rangeFieldMeta.delta * (index / GRADIENT_INTERVALS);
const rawStopValue = rangeFieldMeta.min + rangeFieldMeta.delta * (index / colors.length);
return {
color,
stop: dynamicRound(rawStopValue),

View file

@ -323,21 +323,21 @@ describe('get mapbox color expression (via internal _getMbColor)', () => {
-1,
'rgba(0,0,0,0)',
0,
'#f7faff',
'#ecf1f7',
12.5,
'#ddeaf7',
'#d9e3ef',
25,
'#c5daee',
'#c5d5e7',
37.5,
'#9dc9e0',
'#b2c7df',
50,
'#6aadd5',
'#9eb9d8',
62.5,
'#4191c5',
'#8bacd0',
75,
'#2070b4',
'#769fc8',
87.5,
'#072f6b',
'#6092c0',
]);
});
});

View file

@ -12,11 +12,11 @@ import {
STYLE_TYPE,
} from '../../../../common/constants';
import {
COLOR_GRADIENTS,
COLOR_PALETTES,
DEFAULT_FILL_COLORS,
DEFAULT_LINE_COLORS,
} from '../color_utils';
NUMERICAL_COLOR_PALETTES,
CATEGORICAL_COLOR_PALETTES,
} from '../color_palettes';
import { VectorStylePropertiesDescriptor } from '../../../../common/descriptor_types';
// @ts-ignore
import { getUiSettings } from '../../../kibana_services';
@ -28,8 +28,8 @@ export const DEFAULT_MAX_SIZE = 32;
export const DEFAULT_SIGMA = 3;
export const DEFAULT_LABEL_SIZE = 14;
export const DEFAULT_ICON_SIZE = 6;
export const DEFAULT_COLOR_RAMP = COLOR_GRADIENTS[0].value;
export const DEFAULT_COLOR_PALETTE = COLOR_PALETTES[0].value;
export const DEFAULT_COLOR_RAMP = NUMERICAL_COLOR_PALETTES[0].value;
export const DEFAULT_COLOR_PALETTE = CATEGORICAL_COLOR_PALETTES[0].value;
export const LINE_STYLES = [VECTOR_STYLES.LINE_COLOR, VECTOR_STYLES.LINE_WIDTH];
export const POLYGON_STYLES = [

View file

@ -52,21 +52,21 @@ export const MAPBOX_STYLES = {
2,
'rgba(0,0,0,0)',
3,
'#f7faff',
'#ecf1f7',
4.125,
'#ddeaf7',
'#d9e3ef',
5.25,
'#c5daee',
'#c5d5e7',
6.375,
'#9dc9e0',
'#b2c7df',
7.5,
'#6aadd5',
'#9eb9d8',
8.625,
'#4191c5',
'#8bacd0',
9.75,
'#2070b4',
'#769fc8',
10.875,
'#072f6b',
'#6092c0',
],
'circle-opacity': 0.75,
'circle-stroke-color': '#41937c',
@ -122,21 +122,21 @@ export const MAPBOX_STYLES = {
2,
'rgba(0,0,0,0)',
3,
'#f7faff',
'#ecf1f7',
4.125,
'#ddeaf7',
'#d9e3ef',
5.25,
'#c5daee',
'#c5d5e7',
6.375,
'#9dc9e0',
'#b2c7df',
7.5,
'#6aadd5',
'#9eb9d8',
8.625,
'#4191c5',
'#8bacd0',
9.75,
'#2070b4',
'#769fc8',
10.875,
'#072f6b',
'#6092c0',
],
'fill-opacity': 0.75,
},