diff --git a/x-pack/plugins/maps/public/layers/styles/vector/properties/__tests__/test_util.ts b/x-pack/plugins/maps/public/layers/styles/vector/properties/__tests__/test_util.ts index 1c478bb85ccc7e..f4ef9bdbe5b6d6 100644 --- a/x-pack/plugins/maps/public/layers/styles/vector/properties/__tests__/test_util.ts +++ b/x-pack/plugins/maps/public/layers/styles/vector/properties/__tests__/test_util.ts @@ -14,6 +14,7 @@ import { StyleMetaDescriptor, } from '../../../../../../common/descriptor_types'; import { AbstractField, IField } from '../../../../fields/field'; +import { IStyle, AbstractStyle } from '../../../style'; class MockField extends AbstractField { async getLabel(): Promise { @@ -24,19 +25,47 @@ class MockField extends AbstractField { } } +export class MockMbMap { + _paintPropertyCalls: unknown[]; + + constructor() { + this._paintPropertyCalls = []; + } + setPaintProperty(...args: unknown[]) { + this._paintPropertyCalls.push([...args]); + } + + getPaintPropertyCalls(): unknown[] { + return this._paintPropertyCalls; + } +} + export const mockField: IField = new MockField({ fieldName: 'foobar', origin: FIELD_ORIGIN.SOURCE, }); -class MockStyle { +export class MockStyle extends AbstractStyle implements IStyle { + private readonly _min: number; + private readonly _max: number; + + constructor({ min = 0, max = 100 } = {}) { + super(null); + this._min = min; + this._max = max; + } + getStyleMeta(): StyleMeta { const geomTypes: GeometryTypes = { isPointsOnly: false, isLinesOnly: false, isPolygonsOnly: false, }; - const rangeFieldMeta: RangeFieldMeta = { min: 0, max: 100, delta: 100 }; + const rangeFieldMeta: RangeFieldMeta = { + min: this._min, + max: this._max, + delta: this._max - this._min, + }; const catFieldMeta: CategoryFieldMeta = { categories: [ { @@ -65,8 +94,12 @@ class MockStyle { } export class MockLayer { + private readonly _style: IStyle; + constructor(style = new MockStyle()) { + this._style = style; + } getStyle() { - return new MockStyle(); + return this._style; } getDataRequest() { diff --git a/x-pack/plugins/maps/public/layers/styles/vector/properties/dynamic_size_property.js b/x-pack/plugins/maps/public/layers/styles/vector/properties/dynamic_size_property.js index 71ac25f0c6e619..7833eae4f26dfe 100644 --- a/x-pack/plugins/maps/public/layers/styles/vector/properties/dynamic_size_property.js +++ b/x-pack/plugins/maps/public/layers/styles/vector/properties/dynamic_size_property.js @@ -140,6 +140,9 @@ export class DynamicSizeProperty extends DynamicStyleProperty { _getMbDataDrivenSize({ targetName, minSize, maxSize, minValue, maxValue }) { const lookup = this.supportsMbFeatureState() ? 'feature-state' : 'get'; + + const stops = + minValue === maxValue ? [maxValue, maxSize] : [minValue, minSize, maxValue, maxSize]; return [ 'interpolate', ['linear'], @@ -150,10 +153,7 @@ export class DynamicSizeProperty extends DynamicStyleProperty { fieldName: targetName, fallback: 0, }), - minValue, - minSize, - maxValue, - maxSize, + ...stops, ]; } diff --git a/x-pack/plugins/maps/public/layers/styles/vector/properties/dynamic_size_property.test.tsx b/x-pack/plugins/maps/public/layers/styles/vector/properties/dynamic_size_property.test.tsx new file mode 100644 index 00000000000000..eb140df1934088 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/styles/vector/properties/dynamic_size_property.test.tsx @@ -0,0 +1,101 @@ +/* + * 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('ui/new_platform'); +jest.mock('../components/vector_style_editor', () => ({ + VectorStyleEditor: () => { + return
mockVectorStyleEditor
; + }, +})); + +import React from 'react'; + +// @ts-ignore +import { DynamicSizeProperty } from './dynamic_size_property'; +import { VECTOR_STYLES } from '../../../../../common/constants'; +import { IField } from '../../../fields/field'; +import { MockMbMap } from './__tests__/test_util'; + +import { mockField, MockLayer, MockStyle } from './__tests__/test_util'; + +const makeProperty = (options: object, mockStyle: MockStyle, field: IField = mockField) => { + return new DynamicSizeProperty( + options, + VECTOR_STYLES.ICON_SIZE, + field, + new MockLayer(mockStyle), + () => { + return (x: string) => x + '_format'; + } + ); +}; + +describe('syncSize', () => { + test('Should sync with circle-radius prop', async () => { + const sizeProp = makeProperty({ minSize: 8, maxSize: 32 }, new MockStyle({ min: 0, max: 100 })); + const mockMbMap = new MockMbMap(); + + sizeProp.syncCircleRadiusWithMb('foobar', mockMbMap); + + expect(mockMbMap.getPaintPropertyCalls()).toEqual([ + [ + 'foobar', + 'circle-radius', + [ + 'interpolate', + ['linear'], + [ + 'coalesce', + [ + 'case', + ['==', ['feature-state', 'foobar'], null], + -1, + ['max', ['min', ['to-number', ['feature-state', 'foobar']], 100], 0], + ], + 0, + ], + 0, + 8, + 100, + 32, + ], + ], + ]); + }); + + test('Should truncate interpolate expression to max when no delta', async () => { + const sizeProp = makeProperty( + { minSize: 8, maxSize: 32 }, + new MockStyle({ min: 100, max: 100 }) + ); + const mockMbMap = new MockMbMap(); + + sizeProp.syncCircleRadiusWithMb('foobar', mockMbMap); + + expect(mockMbMap.getPaintPropertyCalls()).toEqual([ + [ + 'foobar', + 'circle-radius', + [ + 'interpolate', + ['linear'], + [ + 'coalesce', + [ + 'case', + ['==', ['feature-state', 'foobar'], null], + 99, + ['max', ['min', ['to-number', ['feature-state', 'foobar']], 100], 100], + ], + 0, + ], + 100, + 32, + ], + ], + ]); + }); +});