From 55e9dc3ee6a37dc9169612d54a20c7edeb2cb1b5 Mon Sep 17 00:00:00 2001 From: Mickael Audel Date: Mon, 29 Jan 2024 17:40:02 +0100 Subject: [PATCH 1/6] feat: added new layer type --- .../map-layer-form-builder.service.ts | 12 ++++++++++-- .../services/map-layer-form-builder/models.ts | 1 + .../main-form-manager/config-map-export-helper.ts | 6 ++++++ .../config-form-control.component.html | 2 +- .../config-form-group/config-form-group.component.ts | 1 + 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/app/modules/map-config/services/map-layer-form-builder/map-layer-form-builder.service.ts b/src/app/modules/map-config/services/map-layer-form-builder/map-layer-form-builder.service.ts index 1bdf3d27..71f969d6 100644 --- a/src/app/modules/map-config/services/map-layer-form-builder/map-layer-form-builder.service.ts +++ b/src/app/modules/map-config/services/map-layer-form-builder/map-layer-form-builder.service.ts @@ -696,8 +696,15 @@ export class MapLayerAllTypesFormGroup extends ConfigFormGroup { ) { super({ geometryStep: new ConfigFormGroup({ - ...geometryFormControls - }).withStepName(marker('Geometry')), + ...geometryFormControls, + }).withStepName(marker('Geometry')) + .withDependsOn(() => [this.geometryType]) + .withOnDependencyChange( + configForm => { + if(this.geometryType.value === GEOMETRY_TYPE.circleHeat) { + configForm.get('aggregatedGeometry').setValue(AGGREGATE_GEOMETRY_TYPE.cell_center); + } + }), styleStep: new ConfigFormGroup({ ...styleFormControls, geometryType: new SelectFormControl( @@ -1438,6 +1445,7 @@ export class MapLayerTypeClusterFormGroup extends MapLayerAllTypesFormGroup { GEOMETRY_TYPE.fill, GEOMETRY_TYPE.circle, GEOMETRY_TYPE.heatmap, + GEOMETRY_TYPE.circleHeat, GEOMETRY_TYPE.label ], propertySelectorFormBuilder, diff --git a/src/app/modules/map-config/services/map-layer-form-builder/models.ts b/src/app/modules/map-config/services/map-layer-form-builder/models.ts index 4f58db89..000ef7b4 100644 --- a/src/app/modules/map-config/services/map-layer-form-builder/models.ts +++ b/src/app/modules/map-config/services/map-layer-form-builder/models.ts @@ -20,6 +20,7 @@ export enum GEOMETRY_TYPE { fill = 'fill', line = 'line', circle = 'circle', + circleHeat = 'circle-heatmap', heatmap = 'heatmap', label = 'label' } diff --git a/src/app/services/main-form-manager/config-map-export-helper.ts b/src/app/services/main-form-manager/config-map-export-helper.ts index 3dd220d8..a302b417 100644 --- a/src/app/services/main-form-manager/config-map-export-helper.ts +++ b/src/app/services/main-form-manager/config-map-export-helper.ts @@ -281,6 +281,12 @@ export class ConfigMapExportHelper { break; } + case GEOMETRY_TYPE.circleHeat: { + paint['circle-opacity'] = opacity; + paint['circle-color'] = color; + paint['circle-radius'] = this.getMapProperty(modeValues.styleStep.radiusFg, mode, colorService, taggableFields); + break; + } } return paint; } diff --git a/src/app/shared/components/config-form-control/config-form-control.component.html b/src/app/shared/components/config-form-control/config-form-control.component.html index c47438e1..308ebb62 100644 --- a/src/app/shared/components/config-form-control/config-form-control.component.html +++ b/src/app/shared/components/config-form-control/config-form-control.component.html @@ -63,7 +63,7 @@
{{opt.value | translate}} {{opt.detail | translate }} diff --git a/src/app/shared/components/config-form-group/config-form-group.component.ts b/src/app/shared/components/config-form-group/config-form-group.component.ts index 2ce72104..7c2e0f56 100644 --- a/src/app/shared/components/config-form-group/config-form-group.component.ts +++ b/src/app/shared/components/config-form-group/config-form-group.component.ts @@ -99,6 +99,7 @@ export class ConfigFormGroupComponent implements OnInit, OnDestroy { * depend on a displayed field, this was not managed. */ if (!this.isSubGroup) { + console.error(this.configFormGroup); ConfigFormGroupComponent.listenToAllControlsOnDependencyChange(this.configFormGroup, this.toUnsubscribe); this.initDependentControls(); this.markChildControls(); From bfcb3e729a62e5884f0de28820e5bf8beba1ca11 Mon Sep 17 00:00:00 2001 From: Mickael Audel Date: Tue, 30 Jan 2024 17:05:34 +0100 Subject: [PATCH 2/6] feat: handle export of circle-heatmap --- .../config-map-export-helper.ts | 59 +++++++++++++++- .../main-form-manager/models-map-config.ts | 4 +- .../config-form-group.component.ts | 1 - .../interfaces/config-map.interfaces.ts | 67 +++++++++++++++++++ .../circle-heat-map-radius-granularity.ts | 60 +++++++++++++++++ 5 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 src/app/shared/interfaces/config-map.interfaces.ts create mode 100644 src/app/shared/models/circle-heat-map-radius-granularity.ts diff --git a/src/app/services/main-form-manager/config-map-export-helper.ts b/src/app/services/main-form-manager/config-map-export-helper.ts index a302b417..3b514030 100644 --- a/src/app/services/main-form-manager/config-map-export-helper.ts +++ b/src/app/services/main-form-manager/config-map-export-helper.ts @@ -35,13 +35,16 @@ import { Layer, Layout, MapConfig, - Paint, + Paint, PaintValue, SELECT_LAYER_PREFIX } from './models-map-config'; +import {InterpolatedProperty, ModesValues} from '@shared/interfaces/config-map.interfaces'; +import {circleHeatMapRadiusGranularity} from '@shared-models/circle-heat-map-radius-granularity'; export enum VISIBILITY { visible = 'visible', none = 'none' } + export const NORMALIZED = 'normalized'; export class ConfigMapExportHelper { @@ -282,9 +285,11 @@ export class ConfigMapExportHelper { break; } case GEOMETRY_TYPE.circleHeat: { + paint['circle-opacity'] = opacity; paint['circle-color'] = color; - paint['circle-radius'] = this.getMapProperty(modeValues.styleStep.radiusFg, mode, colorService, taggableFields); + paint['circle-radius'] = this.getRadPropFromGranularity(modeValues as ModesValues); + paint['circle-blur'] = 1; break; } } @@ -310,6 +315,10 @@ export class ConfigMapExportHelper { layout['symbol-placement'] = modeValues.styleStep.labelPlacementCtrl; break; } + case GEOMETRY_TYPE.circleHeat: { + layout['circle-sort-key'] = this.getCircleHeatMapSortKey(modeValues.styleStep.colorFg); + break; + } } return layout; } @@ -490,6 +499,51 @@ export class ConfigMapExportHelper { } } + /** + * Methode used to construct the key props + */ + public static getCircleHeatMapSortKey(fgValues: any): PaintValue { + switch (fgValues.propertySource) { + case PROPERTY_SELECTOR_SOURCE.fix_color: + return 1; + case PROPERTY_SELECTOR_SOURCE.interpolated: + const interpolatedValues = fgValues.propertyInterpolatedFg as InterpolatedProperty; + const minValue = interpolatedValues.propertyInterpolatedValuesCtrl[0].proportion; + const maxValue = interpolatedValues + .propertyInterpolatedValuesCtrl[interpolatedValues.propertyInterpolatedValuesCtrl.length - 1] + .proportion; + return [ + 'interpolate', + [ + 'linear' + ], + [ + 'get', + 'count_:normalized' + ], + minValue, 0, + maxValue, 8 + ]; + } + } + + /** + * set default Radius according to granularity. WARNING : only for circle-heatMap + */ + public static getRadPropFromGranularity(modeValues: ModesValues): PaintValue { + const granularity = modeValues.geometryStep.granularity?.toLowerCase(); + const radiusSteps = circleHeatMapRadiusGranularity[granularity] || []; + return [ + 'interpolate', + [ + 'linear' + ], + ['zoom'], + ...radiusSteps + ]; + } + + public static getFieldPath(field: string, taggableFields: Set): string { return (taggableFields && taggableFields.has(field)) ? field + '.0' : field; } @@ -563,4 +617,5 @@ export class ConfigMapExportHelper { return value as number + nbPixel; } } + } diff --git a/src/app/services/main-form-manager/models-map-config.ts b/src/app/services/main-form-manager/models-map-config.ts index 17c1a715..5eb16aa4 100644 --- a/src/app/services/main-form-manager/models-map-config.ts +++ b/src/app/services/main-form-manager/models-map-config.ts @@ -56,9 +56,10 @@ export interface Layout { 'text-allow-overlap'?: boolean; 'text-anchor'?: string; 'symbol-placement'?: string; + 'circle-sort-key'?: PaintValue; } -type PaintValue = Array | number> | PaintColor | string | number; +export type PaintValue = Array | number> | PaintColor | string | number; export interface Paint { 'fill-color'?: PaintValue; 'fill-opacity'?: number; @@ -69,6 +70,7 @@ export interface Paint { 'line-width'?: PaintValue; 'line-dasharray'?: PaintValue; 'circle-radius'?: PaintValue; + 'circle-blur'?: number; 'circle-stroke-width'?: PaintValue; 'heatmap-color'?: PaintValue; 'heatmap-radius'?: PaintValue; diff --git a/src/app/shared/components/config-form-group/config-form-group.component.ts b/src/app/shared/components/config-form-group/config-form-group.component.ts index 7c2e0f56..2ce72104 100644 --- a/src/app/shared/components/config-form-group/config-form-group.component.ts +++ b/src/app/shared/components/config-form-group/config-form-group.component.ts @@ -99,7 +99,6 @@ export class ConfigFormGroupComponent implements OnInit, OnDestroy { * depend on a displayed field, this was not managed. */ if (!this.isSubGroup) { - console.error(this.configFormGroup); ConfigFormGroupComponent.listenToAllControlsOnDependencyChange(this.configFormGroup, this.toUnsubscribe); this.initDependentControls(); this.markChildControls(); diff --git a/src/app/shared/interfaces/config-map.interfaces.ts b/src/app/shared/interfaces/config-map.interfaces.ts new file mode 100644 index 00000000..a12201ad --- /dev/null +++ b/src/app/shared/interfaces/config-map.interfaces.ts @@ -0,0 +1,67 @@ +interface InterpolatedValue { + proportion: number; +} + +export interface InterpolatedValueNumber extends InterpolatedValue { + value: number; +} + +export interface InterpolatedValueString extends InterpolatedValue { + value: string; +} + +export interface Propriety { + propertySource: string; + propertyFixColor?: string; + propertyFixSlider?: string; +} + +export interface InterpolatedProperty { + propertyInterpolatedCountOrMetricCtrl?: string; + propertyInterpolatedCountNormalizeCtrl?: boolean; + propertyInterpolatedValuesCtrl?: interpolatedValues[]; + propertyInterpolatedMinValueCtrl?: number; + propertyInterpolatedMaxValueCtrl?: number; + propertyInterpolatedValuesButton?: string; + propertyInterpolatedValuesPreview?: interpolatedValues[]; +} + +export interface VisibilityStep { + visible: boolean; + zoomMin: number; + zoomMax: number; + featuresMin: number; +} + +export interface GeometryStep { + aggGeometry: string; + aggType: string; + granularity: string; + clusterGeometryType: string; + aggregatedGeometry: string; +} + +export interface StylesStep { + geometryType: string; + filter?: []; + opacity?: { + propertySource: string; + propertyInterpolatedFg?: InterpolatedProperty | any; + }; + colorFg?: { + propertySource: string; + propertyInterpolatedFg?: InterpolatedProperty | any; + }; + radiusFg?: Propriety; + strokeColorFg?: Propriety; + strokeWidthFg?: Propriety; + strokeOpacityFg?: Propriety; +} + +type interpolatedValues = InterpolatedValueString | InterpolatedValueNumber; + +export interface ModesValues { + geometryStep: GeometryStep | any; + styleStep: StylesStep | any; + visibilityStep: VisibilityStep; +} diff --git a/src/app/shared/models/circle-heat-map-radius-granularity.ts b/src/app/shared/models/circle-heat-map-radius-granularity.ts new file mode 100644 index 00000000..66bafcb4 --- /dev/null +++ b/src/app/shared/models/circle-heat-map-radius-granularity.ts @@ -0,0 +1,60 @@ +export const circleHeatMapRadiusGranularity = { + 'finest': [ + 0, 9, + 2.9999999999999, 25, + 3, 9, + 4.9999999999999, 12, + 5, 4, + 7.9999999999999, 20, + 8, 10, + 10.9999999999999, 25, + 11, 60, + 13.9999999999999, 200, + 14, 200, + 16.9999999999999, 1000, + 17, 1000, + 19.9999999999999, 1500, + 20, 2000 + ], + 'fine': [ + 0, 10, + 1.999, 30, + 4.999999, 90, + 5, 30, + 7.999999, 120, + 8, 40, + 10.499999, 180, + 10.5, 30, + 13.999999, 210, + 14, 300, + 16.999999, 1000, + 17, 2000 + ], + 'medium': [ + 0, 50, + 2.999999, 110, + 3, 30, + 5.999999, 180, + 6, 40, + 8.999999, 200, + 9, 50, + 11.999999, 360, + 12, 70, + 14.999999, 460, + 15, 600, + 17, 2000 + ], + 'coarse': [ + 0, 30, + 3.999999, 250, + 4, 50, + 6.999999, 320, + 7, 120, + 9.999999, 480, + 10, 120, + 12.999999, 580, + 13, 160, + 14, 600, + 17, 1000 + ], +}; From bdfd9a592629abddeafb9cca67b1d7e8fadc9646 Mon Sep 17 00:00:00 2001 From: Mickael Audel Date: Wed, 31 Jan 2024 12:10:44 +0100 Subject: [PATCH 3/6] feat: handled circle-heatmap color for icons and for input. Saved the layer with the correct type to preserve the compatibility with mapbox. --- .../services/map-import/map-import.service.ts | 14 ++++++++--- .../config-map-export-helper.ts | 25 +++++++++++++++++-- .../circle-heat-map-radius-granularity.ts | 4 +-- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/app/modules/map-config/services/map-import/map-import.service.ts b/src/app/modules/map-config/services/map-import/map-import.service.ts index a995edf6..29610837 100644 --- a/src/app/modules/map-config/services/map-import/map-import.service.ts +++ b/src/app/modules/map-config/services/map-import/map-import.service.ts @@ -242,7 +242,9 @@ export class MapImportService { } else { propertySelectorValues.propertySource = PROPERTY_SELECTOR_SOURCE.interpolated; - const getValue = (inputValues[2] as Array)[1]; + const interpolatedColumn = (inputValues[2] as Array); + // cause interpolated column could contain only one value, ex: [zoom] + const getValue = (interpolatedColumn.length > 1) ? interpolatedColumn[1] : interpolatedColumn[0]; if (getValue.startsWith('count')) { propertySelectorValues.propertyInterpolatedFg = { propertyInterpolatedCountOrMetricCtrl: COUNT_OR_METRIC.COUNT, @@ -536,6 +538,7 @@ export class MapImportService { (manualValues || []).forEach(kc => typeFg.colorFg.addToColorManualValuesCtrl(kc)); + return layerFg; } @@ -550,7 +553,6 @@ export class MapImportService { values.visibilityStep.featuresMax = layerSource.maxfeatures; values.styleStep.geometryType = layer.type === 'symbol' ? 'label' : layer.type; values.styleStep.filter = layer.filter; - } public static importLayerFeaturesMetric( @@ -597,9 +599,13 @@ export class MapImportService { values.geometryStep.rawGeometry = isGeometryTypeRaw ? layerSource.raw_geometry.geometry : null; values.geometryStep.clusterSort = isGeometryTypeRaw ? layerSource.raw_geometry.sort : null; values.visibilityStep.featuresMin = layerSource.minfeatures; - values.styleStep.geometryType = layer.type === 'symbol' ? 'label' : layer.type; + // to display the correct geom type when editing a circle-heat layer + if(layer.metadata.hiddenProps && layer.metadata.hiddenProps.geomType === GEOMETRY_TYPE.circleHeat) { + values.styleStep.geometryType = GEOMETRY_TYPE.circleHeat; + } else { + values.styleStep.geometryType = layer.type === 'symbol' ? 'label' : layer.type; + } values.styleStep.filter = layer.filter; - } public doImport(config: Config, mapConfig: MapConfig) { diff --git a/src/app/services/main-form-manager/config-map-export-helper.ts b/src/app/services/main-form-manager/config-map-export-helper.ts index 3b514030..11298dcb 100644 --- a/src/app/services/main-form-manager/config-map-export-helper.ts +++ b/src/app/services/main-form-manager/config-map-export-helper.ts @@ -53,6 +53,7 @@ export class ConfigMapExportHelper { const fillStrokeLayers = []; const scrollableLayers = []; const labelLayers = []; + console.error('in process config map export'); const layers: Array<[Layer, LAYER_MODE]> = mapConfigLayers.controls.map((layerFg: MapLayerFormGroup) => { const taggableFields = taggableFieldsMap.get(layerFg.customControls.collection.value); const layer = this.getLayer(layerFg, colorService, taggableFields); @@ -169,6 +170,13 @@ export class ConfigMapExportHelper { collection, collectionDisplayName }; + + // with this prop we ll be able to restore the good geomType when we ll reload the layer; + metadata.hiddenProps = {geomType: ''}; + if(modeValues.styleStep.geometryType === GEOMETRY_TYPE.circleHeat) { + metadata.hiddenProps.geomType = GEOMETRY_TYPE.circleHeat; + } + if (modeValues.styleStep.geometryType === GEOMETRY_TYPE.fill.toString()) { const fillStroke: FillStroke = { color: this.getMapProperty(modeValues.styleStep.strokeColorFg, mode, colorService, taggableFields), @@ -192,7 +200,7 @@ export class ConfigMapExportHelper { const layerSource: LayerSourceConfig = ConfigExportHelper.getLayerSourceConfig(layerFg); const layer: Layer = { id: layerFg.value.arlasId, - type: modeValues.styleStep.geometryType === 'label' ? 'symbol' : modeValues.styleStep.geometryType, + type: this.getLayerType(modeValues), source: layerSource.source, minzoom: modeValues.visibilityStep.zoomMin, maxzoom: modeValues.visibilityStep.zoomMax, @@ -234,6 +242,19 @@ export class ConfigMapExportHelper { return layer; } + /** + * set the correct layer type before we save it. + * @param modeValues + */ + public static getLayerType(modeValues: ModesValues): GEOMETRY_TYPE { + /** we change the type of circle heat map to keep the compatibility with mapbox **/ + if(modeValues.styleStep.geometryType === GEOMETRY_TYPE.circleHeat){ + return GEOMETRY_TYPE.circle; + } + + return modeValues.styleStep.geometryType === 'label' ? 'symbol' : modeValues.styleStep.geometryType; + } + public static getLayerPaint(modeValues, mode, colorService: ArlasColorService, taggableFields?: Set) { const paint: Paint = {}; const color = this.getMapProperty(modeValues.styleStep.colorFg, mode, colorService, taggableFields); @@ -285,7 +306,7 @@ export class ConfigMapExportHelper { break; } case GEOMETRY_TYPE.circleHeat: { - + paint['circle-stroke-color'] = color; paint['circle-opacity'] = opacity; paint['circle-color'] = color; paint['circle-radius'] = this.getRadPropFromGranularity(modeValues as ModesValues); diff --git a/src/app/shared/models/circle-heat-map-radius-granularity.ts b/src/app/shared/models/circle-heat-map-radius-granularity.ts index 66bafcb4..e63f69c0 100644 --- a/src/app/shared/models/circle-heat-map-radius-granularity.ts +++ b/src/app/shared/models/circle-heat-map-radius-granularity.ts @@ -33,7 +33,7 @@ export const circleHeatMapRadiusGranularity = { 'medium': [ 0, 50, 2.999999, 110, - 3, 30, + 3, 90, 5.999999, 180, 6, 40, 8.999999, 200, @@ -48,7 +48,7 @@ export const circleHeatMapRadiusGranularity = { 0, 30, 3.999999, 250, 4, 50, - 6.999999, 320, + 6.999999, 300, 7, 120, 9.999999, 480, 10, 120, From 336c461143a3ea0fcb58215263576dec5df0fbf7 Mon Sep 17 00:00:00 2001 From: Mickael Audel Date: Thu, 1 Feb 2024 17:46:55 +0100 Subject: [PATCH 4/6] feat: add better transition related with aggregation type. Fixed a bug related with preview of the color. --- .../services/map-import/map-import.service.ts | 2 +- .../config-map-export-helper.ts | 4 +- .../circle-heat-map-radius-granularity.ts | 124 ++++++++++-------- 3 files changed, 70 insertions(+), 60 deletions(-) diff --git a/src/app/modules/map-config/services/map-import/map-import.service.ts b/src/app/modules/map-config/services/map-import/map-import.service.ts index 29610837..3d4fe2ea 100644 --- a/src/app/modules/map-config/services/map-import/map-import.service.ts +++ b/src/app/modules/map-config/services/map-import/map-import.service.ts @@ -307,7 +307,7 @@ export class MapImportService { } } const min = inputValues[4]; - const max = inputValues.pop(); + const max = inputValues[inputValues.length - 1]; propertySelectorValues.propertyInterpolatedFg.propertyInterpolatedMinValueCtrl = min === 0 ? '0' : min; propertySelectorValues.propertyInterpolatedFg.propertyInterpolatedMaxValueCtrl = max === 0 ? '0' : max; } diff --git a/src/app/services/main-form-manager/config-map-export-helper.ts b/src/app/services/main-form-manager/config-map-export-helper.ts index 11298dcb..50c96499 100644 --- a/src/app/services/main-form-manager/config-map-export-helper.ts +++ b/src/app/services/main-form-manager/config-map-export-helper.ts @@ -306,6 +306,7 @@ export class ConfigMapExportHelper { break; } case GEOMETRY_TYPE.circleHeat: { + paint['circle-stroke-opacity'] = 0; paint['circle-stroke-color'] = color; paint['circle-opacity'] = opacity; paint['circle-color'] = color; @@ -553,7 +554,8 @@ export class ConfigMapExportHelper { */ public static getRadPropFromGranularity(modeValues: ModesValues): PaintValue { const granularity = modeValues.geometryStep.granularity?.toLowerCase(); - const radiusSteps = circleHeatMapRadiusGranularity[granularity] || []; + const aggType = modeValues.geometryStep.aggType?.toLowerCase(); + const radiusSteps = circleHeatMapRadiusGranularity[aggType][granularity] || []; return [ 'interpolate', [ diff --git a/src/app/shared/models/circle-heat-map-radius-granularity.ts b/src/app/shared/models/circle-heat-map-radius-granularity.ts index e63f69c0..33d2aeef 100644 --- a/src/app/shared/models/circle-heat-map-radius-granularity.ts +++ b/src/app/shared/models/circle-heat-map-radius-granularity.ts @@ -1,60 +1,68 @@ export const circleHeatMapRadiusGranularity = { - 'finest': [ - 0, 9, - 2.9999999999999, 25, - 3, 9, - 4.9999999999999, 12, - 5, 4, - 7.9999999999999, 20, - 8, 10, - 10.9999999999999, 25, - 11, 60, - 13.9999999999999, 200, - 14, 200, - 16.9999999999999, 1000, - 17, 1000, - 19.9999999999999, 1500, - 20, 2000 - ], - 'fine': [ - 0, 10, - 1.999, 30, - 4.999999, 90, - 5, 30, - 7.999999, 120, - 8, 40, - 10.499999, 180, - 10.5, 30, - 13.999999, 210, - 14, 300, - 16.999999, 1000, - 17, 2000 - ], - 'medium': [ - 0, 50, - 2.999999, 110, - 3, 90, - 5.999999, 180, - 6, 40, - 8.999999, 200, - 9, 50, - 11.999999, 360, - 12, 70, - 14.999999, 460, - 15, 600, - 17, 2000 - ], - 'coarse': [ - 0, 30, - 3.999999, 250, - 4, 50, - 6.999999, 300, - 7, 120, - 9.999999, 480, - 10, 120, - 12.999999, 580, - 13, 160, - 14, 600, - 17, 1000 - ], + geohash: { + finest: [ + 0, 9, + 2.9999999999999, 25, + 3, 9, + 4.9999999999999, 12, + 5, 4, + 7.9999999999999, 20, + 8, 10, + 10.9999999999999, 25, + 11, 60, + 13.9999999999999, 200, + 14, 200, + 16.9999999999999, 1000, + 17, 1000, + 19.9999999999999, 1500, + 20, 2000 + ], + fine: [ + 0, 10, + 1.999, 20, + 4.999999, 60, + 5, 30, + 7.999999, 120, + 8, 40, + 10.499999, 180, + 10.5, 30, + 13.999999, 210, + 14, 300, + 16.999999, 1000, + 17, 2000 + ], + medium: [ + 0, 10, + 2.999999, 90, + 3, 30, + 5.999999, 130, + 6, 40, + 8.999999, 200, + 9, 50, + 11.999999, 360, + 12, 70, + 14.999999, 460, + 15, 600, + 17, 2000 + ], + coarse: [ + 0, 30, + 3.999999, 250, + 4, 50, + 6.999999, 300, + 7, 120, + 9.999999, 480, + 10, 120, + 12.999999, 580, + 13, 160, + 14, 600, + 17, 1000 + ], + }, + tile: { + finest: [0,9, 23,15], + fine: [0, 35, 23,45], + medium: [0, 50, 23, 100], + coarse: [0, 80, 23,150] + } }; From 5914dbbfbf9a811f65ffae2bc3e8f288b8e74573 Mon Sep 17 00:00:00 2001 From: Mickael Audel Date: Fri, 2 Feb 2024 12:13:09 +0100 Subject: [PATCH 5/6] feat: add more attribute to the interface. refactor the method to build values for a prop. --- .../config-map-export-helper.ts | 107 ++++++++++-------- .../interfaces/config-map.interfaces.ts | 25 ++++ .../circle-heat-map-radius-granularity.ts | 18 +++ 3 files changed, 100 insertions(+), 50 deletions(-) diff --git a/src/app/services/main-form-manager/config-map-export-helper.ts b/src/app/services/main-form-manager/config-map-export-helper.ts index 50c96499..7582d391 100644 --- a/src/app/services/main-form-manager/config-map-export-helper.ts +++ b/src/app/services/main-form-manager/config-map-export-helper.ts @@ -53,7 +53,6 @@ export class ConfigMapExportHelper { const fillStrokeLayers = []; const scrollableLayers = []; const labelLayers = []; - console.error('in process config map export'); const layers: Array<[Layer, LAYER_MODE]> = mapConfigLayers.controls.map((layerFg: MapLayerFormGroup) => { const taggableFields = taggableFieldsMap.get(layerFg.customControls.collection.value); const layer = this.getLayer(layerFg, colorService, taggableFields); @@ -338,7 +337,7 @@ export class ConfigMapExportHelper { break; } case GEOMETRY_TYPE.circleHeat: { - layout['circle-sort-key'] = this.getCircleHeatMapSortKey(modeValues.styleStep.colorFg); + layout['circle-sort-key'] = this.getCircleHeatMapSortKey(modeValues.styleStep.colorFg, mode); break; } } @@ -466,41 +465,9 @@ export class ConfigMapExportHelper { } case PROPERTY_SELECTOR_SOURCE.interpolated: { const interpolatedValues = fgValues.propertyInterpolatedFg; - let interpolatedColor: Array>; - const getField = () => - (interpolatedValues.propertyInterpolatedCountOrMetricCtrl === 'metric') - ? interpolatedValues.propertyInterpolatedFieldCtrl + '_' + - (interpolatedValues.propertyInterpolatedMetricCtrl as string).toLowerCase() + '_' : - interpolatedValues.propertyInterpolatedFieldCtrl; - - if (mode !== LAYER_MODE.features && interpolatedValues.propertyInterpolatedCountOrMetricCtrl === 'count') { - // for types FEATURE-METRIC and CLUSTER, if we interpolate by count - interpolatedColor = [ - 'interpolate', - ['linear'], - ['get', 'count' + (!!interpolatedValues.propertyInterpolatedCountNormalizeCtrl ? `_:${NORMALIZED}` : '')] - ]; - } else if (interpolatedValues.propertyInterpolatedNormalizeCtrl) { - // otherwise if we normalize - interpolatedColor = [ - 'interpolate', - ['linear'], - this.getArray( - getField() - .concat(':' + NORMALIZED) - .concat(interpolatedValues.propertyInterpolatedNormalizeByKeyCtrl ? - ':' + interpolatedValues.propertyInterpolatedNormalizeLocalFieldCtrl : '')) - ]; - } else { - // if we don't normalize - interpolatedColor = [ - 'interpolate', - ['linear'], - this.getArray(getField()) - ]; - } - return interpolatedColor.concat((interpolatedValues.propertyInterpolatedValuesCtrl as Array) - .flatMap(pc => [pc.proportion, pc.value])); + const values = (interpolatedValues.propertyInterpolatedValuesCtrl as Array) + .flatMap(pc => [pc.proportion, pc.value]); + return this.buildPropsValuesFromInterpolatedValues(interpolatedValues, mode, values); } case PROPERTY_SELECTOR_SOURCE.heatmap_density: { const interpolatedValues = fgValues.propertyInterpolatedFg; @@ -521,10 +488,61 @@ export class ConfigMapExportHelper { } } + /** + * build the correct values from interpolated values. + * @param interpolatedValues + * @param mode + * @param valuesToInsert + * @private + */ + private static buildPropsValuesFromInterpolatedValues(interpolatedValues: InterpolatedProperty, + mode: LAYER_MODE, + valuesToInsert?: (string | number)[]){ + let interpolatedColor: Array>; + const getField = () => + (interpolatedValues.propertyInterpolatedCountOrMetricCtrl === 'metric') + ? interpolatedValues.propertyInterpolatedFieldCtrl + '_' + + (interpolatedValues.propertyInterpolatedMetricCtrl as string).toLowerCase() + '_' : + interpolatedValues.propertyInterpolatedFieldCtrl; + + if (mode !== LAYER_MODE.features && interpolatedValues.propertyInterpolatedCountOrMetricCtrl === 'count') { + // for types FEATURE-METRIC and CLUSTER, if we interpolate by count + interpolatedColor = [ + 'interpolate', + ['linear'], + ['get', 'count' + (!!interpolatedValues.propertyInterpolatedCountNormalizeCtrl ? `_:${NORMALIZED}` : '')] + ]; + } else if (interpolatedValues.propertyInterpolatedNormalizeCtrl) { + // otherwise if we normalize + interpolatedColor = [ + 'interpolate', + ['linear'], + this.getArray( + getField() + .concat(':' + NORMALIZED) + .concat(interpolatedValues.propertyInterpolatedNormalizeByKeyCtrl ? + ':' + interpolatedValues.propertyInterpolatedNormalizeLocalFieldCtrl : '')) + ]; + } else { + // if we don't normalize + interpolatedColor = [ + 'interpolate', + ['linear'], + this.getArray(getField()) + ]; + } + + if(valuesToInsert){ + return interpolatedColor.concat(valuesToInsert); + } + + return interpolatedColor; + } + /** * Methode used to construct the key props */ - public static getCircleHeatMapSortKey(fgValues: any): PaintValue { + public static getCircleHeatMapSortKey(fgValues: any, mode: LAYER_MODE): PaintValue { switch (fgValues.propertySource) { case PROPERTY_SELECTOR_SOURCE.fix_color: return 1; @@ -534,18 +552,7 @@ export class ConfigMapExportHelper { const maxValue = interpolatedValues .propertyInterpolatedValuesCtrl[interpolatedValues.propertyInterpolatedValuesCtrl.length - 1] .proportion; - return [ - 'interpolate', - [ - 'linear' - ], - [ - 'get', - 'count_:normalized' - ], - minValue, 0, - maxValue, 8 - ]; + return this.buildPropsValuesFromInterpolatedValues(interpolatedValues, mode, [minValue, 0, maxValue, 8]); } } diff --git a/src/app/shared/interfaces/config-map.interfaces.ts b/src/app/shared/interfaces/config-map.interfaces.ts index a12201ad..38a087fe 100644 --- a/src/app/shared/interfaces/config-map.interfaces.ts +++ b/src/app/shared/interfaces/config-map.interfaces.ts @@ -1,3 +1,21 @@ +/* +Licensed to Gisaïa under one or more contributor +license agreements. See the NOTICE.txt file distributed with +this work for additional information regarding copyright +ownership. Gisaïa licenses this file to you under +the Apache License, Version 2.0 (the "License"); you may +not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ interface InterpolatedValue { proportion: number; } @@ -19,6 +37,13 @@ export interface Propriety { export interface InterpolatedProperty { propertyInterpolatedCountOrMetricCtrl?: string; propertyInterpolatedCountNormalizeCtrl?: boolean; + propertyInterpolatedFieldCtrl?: string; + propertyInterpolatedNormalizeCtrl?: boolean; + propertyInterpolatedNormalizeByKeyCtrl?: string; + propertyInterpolatedNormalizeLocalFieldCtrl?: string; + propertyInterpolatedMinFieldValueCtrl?: number; + propertyInterpolatedMaxFieldValueCtrl?: number; + propertyInterpolatedMetricCtrl?: string; propertyInterpolatedValuesCtrl?: interpolatedValues[]; propertyInterpolatedMinValueCtrl?: number; propertyInterpolatedMaxValueCtrl?: number; diff --git a/src/app/shared/models/circle-heat-map-radius-granularity.ts b/src/app/shared/models/circle-heat-map-radius-granularity.ts index 33d2aeef..73ad7624 100644 --- a/src/app/shared/models/circle-heat-map-radius-granularity.ts +++ b/src/app/shared/models/circle-heat-map-radius-granularity.ts @@ -1,3 +1,21 @@ +/* +Licensed to Gisaïa under one or more contributor +license agreements. See the NOTICE.txt file distributed with +this work for additional information regarding copyright +ownership. Gisaïa licenses this file to you under +the Apache License, Version 2.0 (the "License"); you may +not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ export const circleHeatMapRadiusGranularity = { geohash: { finest: [ From 738032b6658ca9bac42a72f0464fcdb8e1bd42da Mon Sep 17 00:00:00 2001 From: Mickael Audel Date: Fri, 9 Feb 2024 16:33:43 +0100 Subject: [PATCH 6/6] feat: include feedback --- .../config-map-export-helper.ts | 35 +++++++++++-------- .../interfaces/config-map.interfaces.ts | 5 +-- .../circle-heat-map-radius-granularity.ts | 2 +- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/app/services/main-form-manager/config-map-export-helper.ts b/src/app/services/main-form-manager/config-map-export-helper.ts index 7582d391..f2f5bf09 100644 --- a/src/app/services/main-form-manager/config-map-export-helper.ts +++ b/src/app/services/main-form-manager/config-map-export-helper.ts @@ -39,7 +39,7 @@ import { SELECT_LAYER_PREFIX } from './models-map-config'; import {InterpolatedProperty, ModesValues} from '@shared/interfaces/config-map.interfaces'; -import {circleHeatMapRadiusGranularity} from '@shared-models/circle-heat-map-radius-granularity'; +import {CIRCLE_HEATMAP_RADIUS_GRANULARITY} from '@shared-models/circle-heat-map-radius-granularity'; export enum VISIBILITY { visible = 'visible', none = 'none' @@ -171,11 +171,15 @@ export class ConfigMapExportHelper { }; // with this prop we ll be able to restore the good geomType when we ll reload the layer; - metadata.hiddenProps = {geomType: ''}; + if (metadata.hasOwnProperty('hiddenProps')) { + delete metadata['hiddenProps']; + } + if(modeValues.styleStep.geometryType === GEOMETRY_TYPE.circleHeat) { - metadata.hiddenProps.geomType = GEOMETRY_TYPE.circleHeat; + metadata.hiddenProps = {geomType: GEOMETRY_TYPE.circleHeat}; } + if (modeValues.styleStep.geometryType === GEOMETRY_TYPE.fill.toString()) { const fillStroke: FillStroke = { color: this.getMapProperty(modeValues.styleStep.strokeColorFg, mode, colorService, taggableFields), @@ -199,7 +203,7 @@ export class ConfigMapExportHelper { const layerSource: LayerSourceConfig = ConfigExportHelper.getLayerSourceConfig(layerFg); const layer: Layer = { id: layerFg.value.arlasId, - type: this.getLayerType(modeValues), + type: this.getLayerType(modeValues.styleStep.geometryType), source: layerSource.source, minzoom: modeValues.visibilityStep.zoomMin, maxzoom: modeValues.visibilityStep.zoomMax, @@ -243,15 +247,15 @@ export class ConfigMapExportHelper { /** * set the correct layer type before we save it. - * @param modeValues + * @param geometryType */ - public static getLayerType(modeValues: ModesValues): GEOMETRY_TYPE { + public static getLayerType(geometryType: GEOMETRY_TYPE): GEOMETRY_TYPE | string { /** we change the type of circle heat map to keep the compatibility with mapbox **/ - if(modeValues.styleStep.geometryType === GEOMETRY_TYPE.circleHeat){ + if(geometryType === GEOMETRY_TYPE.circleHeat){ return GEOMETRY_TYPE.circle; } - return modeValues.styleStep.geometryType === 'label' ? 'symbol' : modeValues.styleStep.geometryType; + return geometryType === 'label' ? 'symbol' : geometryType; } public static getLayerPaint(modeValues, mode, colorService: ArlasColorService, taggableFields?: Set) { @@ -489,10 +493,11 @@ export class ConfigMapExportHelper { } /** - * build the correct values from interpolated values. - * @param interpolatedValues + * Build the correct array from interpolated values to obtain an array that respects the MapBox expression format + * https://docs.mapbox.com/style-spec/reference/expressions/ + * @param interpolatedValues interpolated properties that determine the type of array we build ( count, normalize ) * @param mode - * @param valuesToInsert + * @param valuesToInsert the value to insert at the end of the array * @private */ private static buildPropsValuesFromInterpolatedValues(interpolatedValues: InterpolatedProperty, @@ -532,7 +537,7 @@ export class ConfigMapExportHelper { ]; } - if(valuesToInsert){ + if (valuesToInsert) { return interpolatedColor.concat(valuesToInsert); } @@ -540,7 +545,8 @@ export class ConfigMapExportHelper { } /** - * Methode used to construct the key props + * Method used to construct the key props. + * based on color props. */ public static getCircleHeatMapSortKey(fgValues: any, mode: LAYER_MODE): PaintValue { switch (fgValues.propertySource) { @@ -552,6 +558,7 @@ export class ConfigMapExportHelper { const maxValue = interpolatedValues .propertyInterpolatedValuesCtrl[interpolatedValues.propertyInterpolatedValuesCtrl.length - 1] .proportion; + // those values ([minValue, 0, maxValue, 8]) don't have a special meaning and made to guarantee the interpolation of the circle sort key return this.buildPropsValuesFromInterpolatedValues(interpolatedValues, mode, [minValue, 0, maxValue, 8]); } } @@ -562,7 +569,7 @@ export class ConfigMapExportHelper { public static getRadPropFromGranularity(modeValues: ModesValues): PaintValue { const granularity = modeValues.geometryStep.granularity?.toLowerCase(); const aggType = modeValues.geometryStep.aggType?.toLowerCase(); - const radiusSteps = circleHeatMapRadiusGranularity[aggType][granularity] || []; + const radiusSteps = CIRCLE_HEATMAP_RADIUS_GRANULARITY[aggType][granularity] || []; return [ 'interpolate', [ diff --git a/src/app/shared/interfaces/config-map.interfaces.ts b/src/app/shared/interfaces/config-map.interfaces.ts index 38a087fe..50df0529 100644 --- a/src/app/shared/interfaces/config-map.interfaces.ts +++ b/src/app/shared/interfaces/config-map.interfaces.ts @@ -66,7 +66,7 @@ export interface GeometryStep { aggregatedGeometry: string; } -export interface StylesStep { +export interface StyleStep { geometryType: string; filter?: []; opacity?: { @@ -85,8 +85,9 @@ export interface StylesStep { type interpolatedValues = InterpolatedValueString | InterpolatedValueNumber; +// TODO: when we ll be sure of the object structure remove the any. export interface ModesValues { geometryStep: GeometryStep | any; - styleStep: StylesStep | any; + styleStep: StyleStep | any; visibilityStep: VisibilityStep; } diff --git a/src/app/shared/models/circle-heat-map-radius-granularity.ts b/src/app/shared/models/circle-heat-map-radius-granularity.ts index 73ad7624..5af8112f 100644 --- a/src/app/shared/models/circle-heat-map-radius-granularity.ts +++ b/src/app/shared/models/circle-heat-map-radius-granularity.ts @@ -16,7 +16,7 @@ KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -export const circleHeatMapRadiusGranularity = { +export const CIRCLE_HEATMAP_RADIUS_GRANULARITY = { geohash: { finest: [ 0, 9,