Skip to content

Commit

Permalink
[maps] convert vector style properties to TS
Browse files Browse the repository at this point in the history
  • Loading branch information
nreese committed Aug 5, 2020
1 parent 47b9aba commit b6226ee
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,6 @@ 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,51 @@ import { shallow } from 'enzyme';
import { DynamicSizeProperty } from './dynamic_size_property';
import { VECTOR_STYLES } from '../../../../../common/constants';
import { IField } from '../../../fields/field';
import { MockMbMap } from './__tests__/test_util';

import { Map as MbMap } from 'mapbox-gl';
import { SizeDynamicOptions } from '../../../../../common/descriptor_types';
import { mockField, MockLayer, MockStyle } from './__tests__/test_util';

const makeProperty = (options: object, mockStyle: MockStyle, field: IField = mockField) => {
export class MockMbMap {
_paintPropertyCalls: unknown[];

constructor() {
this._paintPropertyCalls = [];
}
setPaintProperty(...args: unknown[]) {
this._paintPropertyCalls.push([...args]);
}

getPaintPropertyCalls(): unknown[] {
return this._paintPropertyCalls;
}
}

const makeProperty = (
options: SizeDynamicOptions,
mockStyle: MockStyle,
field: IField = mockField
) => {
return new DynamicSizeProperty(
options,
VECTOR_STYLES.ICON_SIZE,
field,
new MockLayer(mockStyle),
() => {
return (x: string) => x + '_format';
}
},
false
);
};

const defaultLegendParams = {
isPointsOnly: true,
isLinesOnly: false,
};
const fieldMetaOptions = { isEnabled: true };

describe('renderLegendDetailRow', () => {
test('Should render as range', async () => {
const sizeProp = makeProperty({}, new MockStyle({ min: 0, max: 100 }));
const legendRow = sizeProp.renderLegendDetailRow(defaultLegendParams);
const sizeProp = makeProperty(
{ minSize: 0, maxSize: 10, fieldMetaOptions },
new MockStyle({ min: 0, max: 100 })
);
const legendRow = sizeProp.renderLegendDetailRow();
const component = shallow(legendRow);

// Ensure all promises resolve
Expand All @@ -55,8 +75,11 @@ describe('renderLegendDetailRow', () => {

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();
const sizeProp = makeProperty(
{ minSize: 8, maxSize: 32, fieldMetaOptions },
new MockStyle({ min: 0, max: 100 })
);
const mockMbMap = (new MockMbMap() as unknown) as MbMap & { getPaintPropertyCalls };

sizeProp.syncCircleRadiusWithMb('foobar', mockMbMap);

Expand Down Expand Up @@ -88,10 +111,10 @@ describe('syncSize', () => {

test('Should truncate interpolate expression to max when no delta', async () => {
const sizeProp = makeProperty(
{ minSize: 8, maxSize: 32 },
{ minSize: 8, maxSize: 32, fieldMetaOptions },
new MockStyle({ min: 100, max: 100 })
);
const mockMbMap = new MockMbMap();
const mockMbMap = (new MockMbMap() as unknown) as MbMap & { getPaintPropertyCalls };

sizeProp.syncCircleRadiusWithMb('foobar', mockMbMap);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,34 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { DynamicStyleProperty } from './dynamic_style_property';
import _ from 'lodash';
import React from 'react';
import { Map as MbMap } from 'mapbox-gl';
import { DynamicStyleProperty, FieldFormatter } from './dynamic_style_property';
import { OrdinalLegend } from '../components/legend/ordinal_legend';
import { makeMbClampedNumberExpression } from '../style_util';
import {
HALF_LARGE_MAKI_ICON_SIZE,
LARGE_MAKI_ICON_SIZE,
SMALL_MAKI_ICON_SIZE,
// @ts-expect-error
} from '../symbol_utils';
import { MB_LOOKUP_FUNCTION, VECTOR_STYLES } from '../../../../../common/constants';
import _ from 'lodash';
import React from 'react';

export class DynamicSizeProperty extends DynamicStyleProperty {
constructor(options, styleName, field, vectorLayer, getFieldFormatter, isSymbolizedAsIcon) {
import { SizeDynamicOptions } from '../../../../../common/descriptor_types';
import { IField } from '../../../fields/field';
import { IVectorLayer } from '../../../layers/vector_layer/vector_layer';

export class DynamicSizeProperty extends DynamicStyleProperty<SizeDynamicOptions> {
private readonly _isSymbolizedAsIcon: boolean;

constructor(
options: SizeDynamicOptions,
styleName: VECTOR_STYLES,
field: IField | null,
vectorLayer: IVectorLayer,
getFieldFormatter: (fieldName: string) => null | FieldFormatter,
isSymbolizedAsIcon: boolean
) {
super(options, styleName, field, vectorLayer, getFieldFormatter);
this._isSymbolizedAsIcon = isSymbolizedAsIcon;
}
Expand All @@ -36,7 +50,7 @@ export class DynamicSizeProperty extends DynamicStyleProperty {
return super.supportsMbFeatureState();
}

syncHaloWidthWithMb(mbLayerId, mbMap) {
syncHaloWidthWithMb(mbLayerId: string, mbMap: MbMap) {
const haloWidth = this.getMbSizeExpression();
mbMap.setPaintProperty(mbLayerId, 'icon-halo-width', haloWidth);
}
Expand All @@ -47,9 +61,9 @@ export class DynamicSizeProperty extends DynamicStyleProperty {
: SMALL_MAKI_ICON_SIZE;
}

syncIconSizeWithMb(symbolLayerId, mbMap) {
syncIconSizeWithMb(symbolLayerId: string, mbMap: MbMap) {
const rangeFieldMeta = this.getRangeFieldMeta();
if (this._isSizeDynamicConfigComplete(this._options) && rangeFieldMeta) {
if (this._isSizeDynamicConfigComplete() && rangeFieldMeta) {
const halfIconPixels = this.getIconPixelSize() / 2;
const targetName = this.getFieldName();
// Using property state instead of feature-state because layout properties do not support feature-state
Expand All @@ -73,29 +87,29 @@ export class DynamicSizeProperty extends DynamicStyleProperty {
}
}

syncCircleStrokeWidthWithMb(mbLayerId, mbMap) {
syncCircleStrokeWidthWithMb(mbLayerId: string, mbMap: MbMap) {
const lineWidth = this.getMbSizeExpression();
mbMap.setPaintProperty(mbLayerId, 'circle-stroke-width', lineWidth);
}

syncCircleRadiusWithMb(mbLayerId, mbMap) {
syncCircleRadiusWithMb(mbLayerId: string, mbMap: MbMap) {
const circleRadius = this.getMbSizeExpression();
mbMap.setPaintProperty(mbLayerId, 'circle-radius', circleRadius);
}

syncLineWidthWithMb(mbLayerId, mbMap) {
syncLineWidthWithMb(mbLayerId: string, mbMap: MbMap) {
const lineWidth = this.getMbSizeExpression();
mbMap.setPaintProperty(mbLayerId, 'line-width', lineWidth);
}

syncLabelSizeWithMb(mbLayerId, mbMap) {
syncLabelSizeWithMb(mbLayerId: string, mbMap: MbMap) {
const lineWidth = this.getMbSizeExpression();
mbMap.setLayoutProperty(mbLayerId, 'text-size', lineWidth);
}

getMbSizeExpression() {
const rangeFieldMeta = this.getRangeFieldMeta();
if (!this._isSizeDynamicConfigComplete(this._options) || !rangeFieldMeta) {
if (!this._isSizeDynamicConfigComplete() || !rangeFieldMeta) {
return null;
}

Expand All @@ -108,7 +122,19 @@ export class DynamicSizeProperty extends DynamicStyleProperty {
});
}

_getMbDataDrivenSize({ targetName, minSize, maxSize, minValue, maxValue }) {
_getMbDataDrivenSize({
targetName,
minSize,
maxSize,
minValue,
maxValue,
}: {
targetName: string;
minSize: number;
maxSize: number;
minValue: number;
maxValue: number;
}) {
const stops =
minValue === maxValue ? [maxValue, maxSize] : [minValue, minSize, maxValue, maxSize];
return [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export interface IDynamicStyleProperty<T> extends IStyleProperty<T> {
getValueSuggestions(query: string): Promise<string[]>;
}

type FieldFormatter = (value: string | number | undefined) => string | number;
export type FieldFormatter = (value: string | number | undefined) => string | number;

export class DynamicStyleProperty<T> extends AbstractStyleProperty<T>
implements IDynamicStyleProperty<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@
*/

import _ from 'lodash';
import { Map as MbMap } from 'mapbox-gl';
import { AbstractStyleProperty } from './style_property';
import { DEFAULT_LABEL_SIZE } from '../vector_style_defaults';
import { LABEL_BORDER_SIZES } from '../../../../../common/constants';
import { LabelBorderSizeOptions } from '../../../../../common/descriptor_types';
import { VECTOR_STYLES } from '../../../../../common/constants';
import { StaticSizeProperty } from './static_size_property';
import { DynamicSizeProperty } from './dynamic_size_property';

const SMALL_SIZE = 1 / 16;
const MEDIUM_SIZE = 1 / 8;
const LARGE_SIZE = 1 / 5; // halo of 1/4 is just a square. Use smaller ratio to preserve contour on letters

function getWidthRatio(size) {
function getWidthRatio(size: LABEL_BORDER_SIZES) {
switch (size) {
case LABEL_BORDER_SIZES.LARGE:
return LARGE_SIZE;
Expand All @@ -24,13 +29,19 @@ function getWidthRatio(size) {
}
}

export class LabelBorderSizeProperty extends AbstractStyleProperty {
constructor(options, styleName, labelSizeProperty) {
export class LabelBorderSizeProperty extends AbstractStyleProperty<LabelBorderSizeOptions> {
private readonly _labelSizeProperty: StaticSizeProperty | DynamicSizeProperty;

constructor(
options: LabelBorderSizeOptions,
styleName: VECTOR_STYLES,
labelSizeProperty: StaticSizeProperty | DynamicSizeProperty
) {
super(options, styleName);
this._labelSizeProperty = labelSizeProperty;
}

syncLabelBorderSizeWithMb(mbLayerId, mbMap) {
syncLabelBorderSizeWithMb(mbLayerId: string, mbMap: MbMap) {
if (this.getOptions().size === LABEL_BORDER_SIZES.NONE) {
mbMap.setPaintProperty(mbLayerId, 'text-halo-width', 0);
return;
Expand All @@ -39,7 +50,8 @@ export class LabelBorderSizeProperty extends AbstractStyleProperty {
const widthRatio = getWidthRatio(this.getOptions().size);

if (this._labelSizeProperty.isDynamic() && this._labelSizeProperty.isComplete()) {
const labelSizeExpression = this._labelSizeProperty.getMbSizeExpression();
const labelSizeExpression = (this
._labelSizeProperty as DynamicSizeProperty).getMbSizeExpression();
if (labelSizeExpression) {
mbMap.setPaintProperty(mbLayerId, 'text-halo-width', [
'max',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,45 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { Map as MbMap } from 'mapbox-gl';
import { StaticStyleProperty } from './static_style_property';
import { ColorStaticOptions } from '../../../../../common/descriptor_types';

export class StaticColorProperty extends StaticStyleProperty {
syncCircleColorWithMb(mbLayerId, mbMap, alpha) {
export class StaticColorProperty extends StaticStyleProperty<ColorStaticOptions> {
syncCircleColorWithMb(mbLayerId: string, mbMap: MbMap, alpha: number) {
mbMap.setPaintProperty(mbLayerId, 'circle-color', this._options.color);
mbMap.setPaintProperty(mbLayerId, 'circle-opacity', alpha);
}

syncFillColorWithMb(mbLayerId, mbMap, alpha) {
syncFillColorWithMb(mbLayerId: string, mbMap: MbMap, alpha: number) {
mbMap.setPaintProperty(mbLayerId, 'fill-color', this._options.color);
mbMap.setPaintProperty(mbLayerId, 'fill-opacity', alpha);
}

syncIconColorWithMb(mbLayerId, mbMap) {
syncIconColorWithMb(mbLayerId: string, mbMap: MbMap) {
mbMap.setPaintProperty(mbLayerId, 'icon-color', this._options.color);
}

syncHaloBorderColorWithMb(mbLayerId, mbMap) {
syncHaloBorderColorWithMb(mbLayerId: string, mbMap: MbMap) {
mbMap.setPaintProperty(mbLayerId, 'icon-halo-color', this._options.color);
}

syncLineColorWithMb(mbLayerId, mbMap, alpha) {
syncLineColorWithMb(mbLayerId: string, mbMap: MbMap, alpha: number) {
mbMap.setPaintProperty(mbLayerId, 'line-color', this._options.color);
mbMap.setPaintProperty(mbLayerId, 'line-opacity', alpha);
}

syncCircleStrokeWithMb(mbLayerId, mbMap, alpha) {
syncCircleStrokeWithMb(mbLayerId: string, mbMap: MbMap, alpha: number) {
mbMap.setPaintProperty(mbLayerId, 'circle-stroke-color', this._options.color);
mbMap.setPaintProperty(mbLayerId, 'circle-stroke-opacity', alpha);
}

syncLabelColorWithMb(mbLayerId, mbMap, alpha) {
syncLabelColorWithMb(mbLayerId: string, mbMap: MbMap, alpha: number) {
mbMap.setPaintProperty(mbLayerId, 'text-color', this._options.color);
mbMap.setPaintProperty(mbLayerId, 'text-opacity', alpha);
}

syncLabelBorderColorWithMb(mbLayerId, mbMap) {
syncLabelBorderColorWithMb(mbLayerId: string, mbMap: MbMap) {
mbMap.setPaintProperty(mbLayerId, 'text-halo-color', this._options.color);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { Map as MbMap } from 'mapbox-gl';
import { StaticStyleProperty } from './static_style_property';
// @ts-expect-error
import { getMakiSymbolAnchor, getMakiIconId } from '../symbol_utils';
import { IconStaticOptions } from '../../../../../common/descriptor_types';

export class StaticIconProperty extends StaticStyleProperty {
syncIconWithMb(symbolLayerId, mbMap, iconPixelSize) {
export class StaticIconProperty extends StaticStyleProperty<IconStaticOptions> {
syncIconWithMb(symbolLayerId: string, mbMap: MbMap, iconPixelSize: number) {
const symbolId = this._options.value;
mbMap.setLayoutProperty(symbolLayerId, 'icon-anchor', getMakiSymbolAnchor(symbolId));
mbMap.setLayoutProperty(symbolLayerId, 'icon-image', getMakiIconId(symbolId, iconPixelSize));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { Map as MbMap } from 'mapbox-gl';
import { StaticStyleProperty } from './static_style_property';
import { VECTOR_STYLES } from '../../../../../common/constants';
import { OrientationStaticOptions } from '../../../../../common/descriptor_types';

export class StaticOrientationProperty extends StaticStyleProperty {
constructor(options, styleName) {
export class StaticOrientationProperty extends StaticStyleProperty<OrientationStaticOptions> {
constructor(options: OrientationStaticOptions, styleName: VECTOR_STYLES) {
if (typeof options.orientation !== 'number') {
super({ orientation: 0 }, styleName);
} else {
super(options, styleName);
}
}

syncIconRotationWithMb(symbolLayerId, mbMap) {
syncIconRotationWithMb(symbolLayerId: string, mbMap: MbMap) {
mbMap.setLayoutProperty(symbolLayerId, 'icon-rotate', this._options.orientation);
}
}
Loading

0 comments on commit b6226ee

Please sign in to comment.