[Maps] Simplify IDynamicStyle-api (#79217)

This commit is contained in:
Thomas Neirynck 2020-10-02 14:04:31 -04:00 committed by GitHub
parent 85528d0ecd
commit 86cb97adf6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 40 deletions

View file

@ -6,7 +6,8 @@
import _ from 'lodash';
import React from 'react';
import { Feature } from 'geojson';
import { Feature, FeatureCollection } from 'geojson';
import { FeatureIdentifier, Map as MbMap } from 'mapbox-gl';
import { AbstractStyleProperty, IStyleProperty } from './style_property';
import { DEFAULT_SIGMA } from '../vector_style_defaults';
import {
@ -44,20 +45,14 @@ export interface IDynamicStyleProperty<T> extends IStyleProperty<T> {
isOrdinal(): boolean;
supportsFieldMeta(): boolean;
getFieldMetaRequest(): Promise<unknown>;
supportsMbFeatureState(): boolean;
getMbLookupFunction(): MB_LOOKUP_FUNCTION;
pluckOrdinalStyleMetaFromFeatures(features: Feature[]): RangeFieldMeta | null;
pluckCategoricalStyleMetaFromFeatures(features: Feature[]): CategoryFieldMeta | null;
getValueSuggestions(query: string): Promise<string[]>;
// Returns the name that should be used for accessing the data from the mb-style rule
// Depending on
// - whether the field is used for labeling, icon-orientation, or other properties (color, size, ...), `feature-state` and or `get` is used
// - whether the field was run through a field-formatter, a new dynamic field is created with the formatted-value
// The combination of both will inform what field-name (e.g. the "raw" field name from the properties, the "computed field-name" for an on-the-fly created property (e.g. for feature-state or field-formatting).
// todo: There is an existing limitation to .mvt backed sources, where the field-formatters are not applied. Here, the raw-data needs to be accessed.
getMbPropertyName(): string;
getMbPropertyValue(value: RawValue): RawValue;
enrichGeoJsonAndMbFeatureState(
featureCollection: FeatureCollection,
mbMap: MbMap,
mbSourceId: string
): boolean;
}
export class DynamicStyleProperty<T>
@ -356,6 +351,12 @@ export class DynamicStyleProperty<T>
);
}
// Returns the name that should be used for accessing the data from the mb-style rule
// Depending on
// - whether the field is used for labeling, icon-orientation, or other properties (color, size, ...), `feature-state` and or `get` is used
// - whether the field was run through a field-formatter, a new dynamic field is created with the formatted-value
// The combination of both will inform what field-name (e.g. the "raw" field name from the properties, the "computed field-name" for an on-the-fly created property (e.g. for feature-state or field-formatting).
// todo: There is an existing limitation to .mvt backed sources, where the field-formatters are not applied. Here, the raw-data needs to be accessed.
getMbPropertyName() {
if (!this._field) {
return '';
@ -385,6 +386,35 @@ export class DynamicStyleProperty<T>
// Calling `isOrdinal` would be equivalent.
return this.supportsMbFeatureState() ? getNumericalMbFeatureStateValue(rawValue) : rawValue;
}
enrichGeoJsonAndMbFeatureState(
featureCollection: FeatureCollection,
mbMap: MbMap,
mbSourceId: string
): boolean {
const supportsFeatureState = this.supportsMbFeatureState();
const featureIdentifier: FeatureIdentifier = {
source: mbSourceId,
id: undefined,
};
const featureState: Record<string, RawValue> = {};
const targetMbName = this.getMbPropertyName();
for (let i = 0; i < featureCollection.features.length; i++) {
const feature = featureCollection.features[i];
const rawValue = feature.properties ? feature.properties[this.getFieldName()] : undefined;
const targetMbValue = this.getMbPropertyValue(rawValue);
if (supportsFeatureState) {
featureState[targetMbName] = targetMbValue; // the same value will be potentially overridden multiple times, if the name remains identical
featureIdentifier.id = feature.id;
mbMap.setFeatureState(featureIdentifier, featureState);
} else {
if (feature.properties) {
feature.properties[targetMbName] = targetMbValue;
}
}
}
return supportsFeatureState;
}
}
export function getNumericalMbFeatureStateValue(value: RawValue) {

View file

@ -641,7 +641,7 @@ export class VectorStyle implements IVectorStyle {
featureCollection: FeatureCollection,
mbMap: MbMap,
mbSourceId: string
) {
): boolean {
if (!featureCollection) {
return false;
}
@ -651,40 +651,24 @@ export class VectorStyle implements IVectorStyle {
return false;
}
const tmpFeatureIdentifier: FeatureIdentifier = {
source: '',
id: undefined,
};
const tmpFeatureState: any = {};
for (let i = 0; i < featureCollection.features.length; i++) {
const feature = featureCollection.features[i];
for (let j = 0; j < dynamicStyleProps.length; j++) {
const dynamicStyleProp = dynamicStyleProps[j];
const targetMbName = dynamicStyleProp.getMbPropertyName();
const rawValue = feature.properties
? feature.properties[dynamicStyleProp.getFieldName()]
: undefined;
const targetMbValue = dynamicStyleProp.getMbPropertyValue(rawValue);
if (dynamicStyleProp.supportsMbFeatureState()) {
tmpFeatureState[targetMbName] = targetMbValue; // the same value will be potentially overridden multiple times, if the name remains identical
} else {
if (feature.properties) {
feature.properties[targetMbName] = targetMbValue;
}
}
let shouldResetAllData = false;
for (let j = 0; j < dynamicStyleProps.length; j++) {
const dynamicStyleProp = dynamicStyleProps[j];
const usedFeatureState = dynamicStyleProp.enrichGeoJsonAndMbFeatureState(
featureCollection,
mbMap,
mbSourceId
);
if (!usedFeatureState) {
shouldResetAllData = true;
}
tmpFeatureIdentifier.source = mbSourceId;
tmpFeatureIdentifier.id = feature.id;
mbMap.setFeatureState(tmpFeatureIdentifier, tmpFeatureState);
}
// returns boolean indicating if styles do not support feature-state and some values are stored in geojson properties
// this return-value is used in an optimization for style-updates with mapbox-gl.
// `true` indicates the entire data needs to reset on the source (otherwise the style-rules will not be reapplied)
// `false` indicates the data does not need to be reset on the store, because styles are re-evaluated if they use featureState
return dynamicStyleProps.some((dynamicStyleProp) => !dynamicStyleProp.supportsMbFeatureState());
return shouldResetAllData;
}
arePointsSymbolizedAsCircles() {