[Maps] convert HeatmapLayer dependencies to TS (#66823)

* [Maps] convert HeatmapLayer and dependencies to TS

* heatmap_style_editor snapshots

* eslint

* fix merge problems

* eslint cleanup

* revert rename of getOrdinalMbColorRampStops

* eslint

* tslint

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2020-05-28 08:54:44 -06:00 committed by GitHub
parent 17573f1a0b
commit 57345e092e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 117 additions and 51 deletions

View file

@ -27,7 +27,6 @@ import {
VECTOR_STYLES,
STYLE_TYPE,
} from '../../../../common/constants';
// @ts-ignore
import { COLOR_GRADIENTS } from '../../styles/color_utils';
export const clustersLayerWizardConfig: LayerWizard = {

View file

@ -17,7 +17,6 @@ import {
VECTOR_STYLES,
STYLE_TYPE,
} from '../../../../common/constants';
// @ts-ignore
import { COLOR_GRADIENTS } from '../../styles/color_utils';
// @ts-ignore
import { CreateSourceEditor } from './create_source_editor';

View file

@ -7,73 +7,85 @@
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 { vislibColorMaps } from '../../../../../../src/plugins/charts/public';
import { RawColorSchema, vislibColorMaps } from '../../../../../../src/plugins/charts/public';
export const GRADIENT_INTERVALS = 8;
export const DEFAULT_FILL_COLORS = euiPaletteColorBlind();
export const DEFAULT_LINE_COLORS = [
...DEFAULT_FILL_COLORS.map((color) => tinycolor(color).darken().toHexString()),
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 getLegendColors(colorRamp, numLegendColors = 4) {
function getRGBColors(colorRamp: Array<[number, number[]]>, numLegendColors: number = 4): string[] {
const colors = [];
colors[0] = getColor(colorRamp, 0);
colors[0] = getRGBColor(colorRamp, 0);
for (let i = 1; i < numLegendColors - 1; i++) {
colors[i] = getColor(colorRamp, Math.floor((colorRamp.length * i) / numLegendColors));
colors[i] = getRGBColor(colorRamp, Math.floor((colorRamp.length * i) / numLegendColors));
}
colors[numLegendColors - 1] = getColor(colorRamp, colorRamp.length - 1);
colors[numLegendColors - 1] = getRGBColor(colorRamp, colorRamp.length - 1);
return colors;
}
function getColor(colorRamp, i) {
const color = colorRamp[i][1];
const red = Math.floor(color[0] * 255);
const green = Math.floor(color[1] * 255);
const blue = Math.floor(color[2] * 255);
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 getColorRamp(colorRampName) {
const colorRamp = vislibColorMaps[colorRampName];
if (!colorRamp) {
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 colorRamp;
return colorSchema;
}
export function getRGBColorRangeStrings(colorRampName, numberColors = GRADIENT_INTERVALS) {
const colorRamp = getColorRamp(colorRampName);
return getLegendColors(colorRamp.value, numberColors);
export function getRGBColorRangeStrings(
colorRampName: string,
numberColors: number = GRADIENT_INTERVALS
): string[] {
const colorSchema = getColorSchema(colorRampName);
return getRGBColors(colorSchema.value, numberColors);
}
export function getHexColorRangeStrings(colorRampName, numberColors = GRADIENT_INTERVALS) {
export function getHexColorRangeStrings(
colorRampName: string,
numberColors: number = GRADIENT_INTERVALS
): string[] {
return getRGBColorRangeStrings(colorRampName, numberColors).map((rgbColor) =>
chroma(rgbColor).hex()
);
}
export function getColorRampCenterColor(colorRampName) {
export function getColorRampCenterColor(colorRampName: string): string | null {
if (!colorRampName) {
return null;
}
const colorRamp = getColorRamp(colorRampName);
const centerIndex = Math.floor(colorRamp.value.length / 2);
return getColor(colorRamp.value, centerIndex);
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, min, max, numberColors) {
export function getOrdinalMbColorRampStops(
colorRampName: string,
min: number,
max: number,
numberColors: number
): Array<number | string> | null {
if (!colorRampName) {
return null;
}
@ -84,15 +96,18 @@ export function getOrdinalMbColorRampStops(colorRampName, min, max, numberColors
const hexColors = getHexColorRangeStrings(colorRampName, numberColors);
if (max === min) {
//just return single stop value
// just return single stop value
return [max, hexColors[hexColors.length - 1]];
}
const delta = max - min;
return hexColors.reduce((accu, stopColor, idx, srcArr) => {
const stopNumber = min + (delta * idx) / srcArr.length;
return [...accu, stopNumber, stopColor];
}, []);
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) => ({
@ -102,7 +117,7 @@ export const COLOR_GRADIENTS = Object.keys(vislibColorMaps).map((colorRampName)
export const COLOR_RAMP_NAMES = Object.keys(vislibColorMaps);
export function getLinearGradient(colorStrings) {
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++) {
@ -112,7 +127,12 @@ export function getLinearGradient(colorStrings) {
return `${linearGradient} ${colorStrings[colorStrings.length - 1]} 100%)`;
}
const COLOR_PALETTES_CONFIGS = [
export interface ColorPalette {
id: string;
colors: string[];
}
const COLOR_PALETTES_CONFIGS: ColorPalette[] = [
{
id: 'palette_0',
colors: euiPaletteColorBlind(),
@ -127,14 +147,14 @@ const COLOR_PALETTES_CONFIGS = [
},
];
export function getColorPalette(paletteId) {
const palette = COLOR_PALETTES_CONFIGS.find((palette) => palette.id === paletteId);
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 = {
const style: React.CSSProperties = {
backgroundColor: color,
width: `${100 / palette.colors.length}%`,
position: 'relative',

View file

@ -11,17 +11,20 @@ import {
getRGBColorRangeStrings,
getLinearGradient,
} from '../color_utils';
import classNames from 'classnames';
export const ColorGradient = ({ colorRamp, colorRampName, className }) => {
interface Props {
colorRamp?: string[];
colorRampName?: string;
}
export const ColorGradient = ({ colorRamp, colorRampName }: Props) => {
if (!colorRamp && (!colorRampName || !COLOR_RAMP_NAMES.includes(colorRampName))) {
return null;
}
const classes = classNames('mapColorGradient', className);
const rgbColorStrings = colorRampName
? getRGBColorRangeStrings(colorRampName, GRADIENT_INTERVALS)
: colorRamp;
: colorRamp!;
const background = getLinearGradient(rgbColorStrings);
return <div className={classes} style={{ background }} />;
return <div className="mapColorGradient" style={{ background }} />;
};

View file

@ -15,8 +15,13 @@ import {
HEATMAP_COLOR_RAMP_LABEL,
} from './heatmap_constants';
export function HeatmapStyleEditor({ colorRampName, onHeatmapColorChange }) {
const onColorRampChange = (selectedColorRampName) => {
interface Props {
colorRampName: string;
onHeatmapColorChange: ({ colorRampName }: { colorRampName: string }) => void;
}
export function HeatmapStyleEditor({ colorRampName, onHeatmapColorChange }: Props) {
const onColorRampChange = (selectedColorRampName: string) => {
onHeatmapColorChange({
colorRampName: selectedColorRampName,
});

View file

@ -91,6 +91,7 @@ export class HeatmapStyle extends AbstractStyle {
MAX_RANGE,
GRADIENT_INTERVALS
);
// TODO handle null
mbMap.setPaintProperty(layerId, 'heatmap-color', [
'interpolate',
['linear'],

View file

@ -43,7 +43,7 @@ export function extractColorFromStyleProperty(
}
const palette = getColorPalette(dynamicOptions.colorCategory);
return palette[0];
return palette ? palette[0] : defaultColor;
} else {
// return middle of gradient for dynamic style property
if (dynamicOptions.useCustomColorRamp) {
@ -58,6 +58,7 @@ export function extractColorFromStyleProperty(
if (!dynamicOptions.color) {
return defaultColor;
}
return getColorRampCenterColor(dynamicOptions.color);
const centerColor = getColorRampCenterColor(dynamicOptions.color);
return centerColor ? centerColor : defaultColor;
}
}

View file

@ -0,0 +1,35 @@
/*
* 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.
*/
jest.mock('../../../kibana_services', () => {
const mockUiSettings = {
get: () => {
return undefined;
},
};
return {
getUiSettings: () => {
return mockUiSettings;
},
};
});
import { VECTOR_STYLES } from '../../../../common/constants';
import { getDefaultStaticProperties } from './vector_style_defaults';
describe('getDefaultStaticProperties', () => {
test('Should use first color in DEFAULT_*_COLORS when no colors are used on the map', () => {
const styleProperties = getDefaultStaticProperties([]);
expect(styleProperties[VECTOR_STYLES.FILL_COLOR]!.options.color).toBe('#54B399');
expect(styleProperties[VECTOR_STYLES.LINE_COLOR]!.options.color).toBe('#41937c');
});
test('Should next color in DEFAULT_*_COLORS when colors are used on the map', () => {
const styleProperties = getDefaultStaticProperties(['#54B399']);
expect(styleProperties[VECTOR_STYLES.FILL_COLOR]!.options.color).toBe('#6092C0');
expect(styleProperties[VECTOR_STYLES.LINE_COLOR]!.options.color).toBe('#4379aa');
});
});

View file

@ -16,7 +16,6 @@ import {
COLOR_PALETTES,
DEFAULT_FILL_COLORS,
DEFAULT_LINE_COLORS,
// @ts-ignore
} from '../color_utils';
import { VectorStylePropertiesDescriptor } from '../../../../common/descriptor_types';
// @ts-ignore
@ -58,9 +57,13 @@ export function getDefaultProperties(mapColors: string[] = []): VectorStylePrope
export function getDefaultStaticProperties(
mapColors: string[] = []
): VectorStylePropertiesDescriptor {
// Colors must be state-aware to reduce unnecessary incrementation
const lastColor = mapColors.pop();
const nextColorIndex = (DEFAULT_FILL_COLORS.indexOf(lastColor) + 1) % DEFAULT_FILL_COLORS.length;
let nextColorIndex = 0;
if (mapColors.length) {
const lastColor = mapColors[mapColors.length - 1];
if (DEFAULT_FILL_COLORS.includes(lastColor)) {
nextColorIndex = (DEFAULT_FILL_COLORS.indexOf(lastColor) + 1) % DEFAULT_FILL_COLORS.length;
}
}
const nextFillColor = DEFAULT_FILL_COLORS[nextColorIndex];
const nextLineColor = DEFAULT_LINE_COLORS[nextColorIndex];