Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion x-pack/legacy/plugins/maps/public/layers/heatmap_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class HeatmapLayer extends VectorLayer {
const propertyKey = this._getPropKeyOfSelectedMetric();
const dataBoundToMap = AbstractLayer.getBoundDataForSource(mbMap, this.getId());
if (featureCollection !== dataBoundToMap) {
let max = 0;
let max = 1; //max will be at least one, since counts or sums will be at least one.
for (let i = 0; i < featureCollection.features.length; i++) {
max = Math.max(featureCollection.features[i].properties[propertyKey], max);
}
Expand Down
25 changes: 17 additions & 8 deletions x-pack/legacy/plugins/maps/public/layers/styles/color_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,26 @@ export function getColorRampCenterColor(colorRampName) {

// Returns an array of color stops
// [ stop_input_1: number, stop_output_1: color, stop_input_n: number, stop_output_n: color ]
export function getOrdinalColorRampStops(colorRampName, numberColors = GRADIENT_INTERVALS) {
export function getOrdinalColorRampStops(colorRampName, min, max) {
if (!colorRampName) {
return null;
}
return getHexColorRangeStrings(colorRampName, numberColors).reduce(
(accu, stopColor, idx, srcArr) => {
const stopNumber = idx / srcArr.length; // number between 0 and 1, increasing as index increases
return [...accu, stopNumber, stopColor];
},
[]
);

if (min > max) {
return null;
}

const hexColors = getHexColorRangeStrings(colorRampName, GRADIENT_INTERVALS);
if (max === min) {
//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];
}, []);
}

export const COLOR_GRADIENTS = Object.keys(vislibColorMaps).map(colorRampName => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,26 +60,30 @@ describe('getColorRampCenterColor', () => {
});

describe('getColorRampStops', () => {
it('Should create color stops for color ramp', () => {
expect(getOrdinalColorRampStops('Blues')).toEqual([
it('Should create color stops for custom range', () => {
expect(getOrdinalColorRampStops('Blues', 0, 1000)).toEqual([
0,
'#f7faff',
0.125,
125,
'#ddeaf7',
0.25,
250,
'#c5daee',
0.375,
375,
'#9dc9e0',
0.5,
500,
'#6aadd5',
0.625,
625,
'#4191c5',
0.75,
750,
'#2070b4',
0.875,
875,
'#072f6b',
]);
});

it('Should snap to end of color stops for identical range', () => {
expect(getOrdinalColorRampStops('Blues', 23, 23)).toEqual([23, '#072f6b']);
});
});

describe('getLinearGradient', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ import { getOrdinalColorRampStops } 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 MAX_RANGE = 1;

export class HeatmapStyle extends AbstractStyle {
static type = LAYER_STYLE_TYPE.HEATMAP;

Expand Down Expand Up @@ -80,7 +85,7 @@ export class HeatmapStyle extends AbstractStyle {

const { colorRampName } = this._descriptor;
if (colorRampName && colorRampName !== DEFAULT_HEATMAP_COLOR_RAMP_NAME) {
const colorStops = getOrdinalColorRampStops(colorRampName);
const colorStops = getOrdinalColorRampStops(colorRampName, MIN_RANGE, MAX_RANGE);
mbMap.setPaintProperty(layerId, 'heatmap-color', [
'interpolate',
['linear'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
*/

import { DynamicStyleProperty } from './dynamic_style_property';
import _ from 'lodash';
import { getComputedFieldName, getOtherCategoryLabel } from '../style_util';
import { getOtherCategoryLabel, makeMbClampedNumberExpression } from '../style_util';
import { getOrdinalColorRampStops, getColorPalette } from '../../color_utils';
import { ColorGradient } from '../../components/color_gradient';
import React from 'react';
Expand All @@ -23,6 +22,7 @@ import { COLOR_MAP_TYPE } from '../../../../../common/constants';
import { isCategoricalStopsInvalid } from '../components/color/color_stops_utils';

const EMPTY_STOPS = { stops: [], defaultColor: null };
const RGBA_0000 = 'rgba(0,0,0,0)';

export class DynamicColorProperty extends DynamicStyleProperty {
syncCircleColorWithMb(mbLayerId, mbMap, alpha) {
Expand Down Expand Up @@ -70,6 +70,17 @@ export class DynamicColorProperty extends DynamicStyleProperty {
mbMap.setPaintProperty(mbLayerId, 'text-halo-color', color);
}

supportsFieldMeta() {
if (!this.isComplete() || !this._field.supportsFieldMeta()) {
return false;
}

return (
(this.isCategorical() && !this._options.useCustomColorPalette) ||
(this.isOrdinal() && !this._options.useCustomColorRamp)
);
}

isOrdinal() {
return (
typeof this._options.type === 'undefined' || this._options.type === COLOR_MAP_TYPE.ORDINAL
Expand All @@ -80,28 +91,20 @@ export class DynamicColorProperty extends DynamicStyleProperty {
return this._options.type === COLOR_MAP_TYPE.CATEGORICAL;
}

isCustomOrdinalColorRamp() {
return this._options.useCustomColorRamp;
}

supportsMbFeatureState() {
return true;
}

isOrdinalScaled() {
return this.isOrdinal() && !this.isCustomOrdinalColorRamp();
}

isOrdinalRanged() {
return this.isOrdinal() && !this.isCustomOrdinalColorRamp();
return this.isOrdinal() && !this._options.useCustomColorRamp;
}

hasOrdinalBreaks() {
return (this.isOrdinal() && this.isCustomOrdinalColorRamp()) || this.isCategorical();
return (this.isOrdinal() && this._options.useCustomColorRamp) || this.isCategorical();
}

_getMbColor() {
if (!_.get(this._options, 'field.name')) {
if (!this._field || !this._field.getName()) {
return null;
}

Expand All @@ -111,7 +114,7 @@ export class DynamicColorProperty extends DynamicStyleProperty {
}

_getOrdinalColorMbExpression() {
const targetName = getComputedFieldName(this._styleName, this._options.field.name);
const targetName = this._field.getName();
if (this._options.useCustomColorRamp) {
if (!this._options.customColorRamp || !this._options.customColorRamp.length) {
// custom color ramp config is not complete
Expand All @@ -122,27 +125,44 @@ export class DynamicColorProperty extends DynamicStyleProperty {
return [...accumulatedStops, nextStop.stop, nextStop.color];
}, []);
const firstStopValue = colorStops[0];
const lessThenFirstStopValue = firstStopValue - 1;
const lessThanFirstStopValue = firstStopValue - 1;
return [
'step',
['coalesce', ['feature-state', targetName], lessThenFirstStopValue],
'rgba(0,0,0,0)', // MB will assign the base value to any features that is below the first stop value
['coalesce', ['feature-state', targetName], lessThanFirstStopValue],
RGBA_0000, // MB will assign the base value to any features that is below the first stop value
...colorStops,
];
}
} else {
const rangeFieldMeta = this.getRangeFieldMeta();
if (!rangeFieldMeta) {
return null;
}

const colorStops = getOrdinalColorRampStops(this._options.color);
if (!colorStops) {
return null;
const colorStops = getOrdinalColorRampStops(
this._options.color,
rangeFieldMeta.min,
rangeFieldMeta.max
);
if (!colorStops) {
return null;
}

const lessThanFirstStopValue = rangeFieldMeta.min - 1;
return [
'interpolate',
['linear'],
makeMbClampedNumberExpression({
minValue: rangeFieldMeta.min,
maxValue: rangeFieldMeta.max,
lookupFunction: 'feature-state',
fallback: lessThanFirstStopValue,
fieldName: targetName,
}),
lessThanFirstStopValue,
RGBA_0000,
...colorStops,
];
}
return [
'interpolate',
['linear'],
['coalesce', ['feature-state', targetName], -1],
-1,
'rgba(0,0,0,0)',
...colorStops,
];
}

_getColorPaletteStops() {
Expand Down Expand Up @@ -220,7 +240,7 @@ export class DynamicColorProperty extends DynamicStyleProperty {
}

mbStops.push(defaultColor); //last color is default color
return ['match', ['to-string', ['get', this._options.field.name]], ...mbStops];
return ['match', ['to-string', ['get', this._field.getName()]], ...mbStops];
}

renderRangeLegendHeader() {
Expand Down
Loading