Skip to content

Commit

Permalink
Externalise the map interface methods to an angular service
Browse files Browse the repository at this point in the history
  • Loading branch information
MohamedHamouGisaia committed Dec 10, 2024
1 parent c74abf6 commit 34ce9fe
Show file tree
Hide file tree
Showing 19 changed files with 655 additions and 440 deletions.
217 changes: 217 additions & 0 deletions projects/arlas-map/src/lib/arlas-map-logic.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
import { Injectable } from '@angular/core';
import { ArlasMapService } from './map/service/arlas-map.service';
import { FeatureCollection } from '@turf/helpers';
import { AbstractArlasMapGL } from './map/AbstractArlasMapGL';
import { ArlasMapSource } from './map/model/sources';
import { VisualisationSetConfig } from './map/model/visualisationsets';
import { ARLAS_ID, ExternalEvent, FILLSTROKE_LAYER_PREFIX, MapLayers, SCROLLABLE_ARLAS_ID } from './map/model/layers';
import { ElementIdentifier } from 'arlas-web-components';


@Injectable({
providedIn: 'root'
})
export abstract class ArlasMapFunctionalService {
/** IMPORTANT NOTE: All the attributes/params that are typed with "any", will have the right type in the implementation. */
public dataSources: any[] = [];
public abstract layersMap: Map<string, any>;
public visualisationsSets: {
visualisations: Map<string, Set<string>>;
status: Map<string, boolean>;
} = {
visualisations: new Map(),
status: new Map()
};
public constructor(public mapService: ArlasMapService) { }

/** Add to map the sources that will host ARLAS data. */
public declareArlasDataSources(dataSourcesIds: Set<string>, data: FeatureCollection<GeoJSON.Geometry>, map: AbstractArlasMapGL) {
if (dataSourcesIds) {
dataSourcesIds.forEach(sourceId => {
const source = this.mapService.createGeojsonSource(data)

Check failure on line 31 in projects/arlas-map/src/lib/arlas-map-logic.service.ts

View workflow job for this annotation

GitHub Actions / Lint, Build, Test & Documentation

Missing semicolon

Check failure on line 31 in projects/arlas-map/src/lib/arlas-map-logic.service.ts

View workflow job for this annotation

GitHub Actions / Lint, Build, Test & Documentation

Missing semicolon
this.dataSources.push(source);
/** For an implementation that doesn't add a source to map
* --- for instance Openalayers, adds the source to layer ---
* the following line should be reconsidered.
*/
this.mapService.setSource(sourceId, source, map);
});
}
}

public declareLabelSources(labelSourceId: string, data: FeatureCollection<GeoJSON.Geometry>, map: AbstractArlasMapGL) {
if (labelSourceId) {
const source = this.mapService.createGeojsonSource(data)

Check failure on line 44 in projects/arlas-map/src/lib/arlas-map-logic.service.ts

View workflow job for this annotation

GitHub Actions / Lint, Build, Test & Documentation

Missing semicolon

Check failure on line 44 in projects/arlas-map/src/lib/arlas-map-logic.service.ts

View workflow job for this annotation

GitHub Actions / Lint, Build, Test & Documentation

Missing semicolon
this.mapService.setSource(labelSourceId, source, map);
}
}

public updateLabelSources(labelSourceId: string, data: FeatureCollection<GeoJSON.Geometry>, map: AbstractArlasMapGL) {
if (labelSourceId) {
const source = this.mapService.getSource(labelSourceId, map);
this.mapService.setDataToGeojsonSource(labelSourceId, source);
}
}

public declareBasemapSources(basemapSources: Array<ArlasMapSource<any>>, map: AbstractArlasMapGL) {
// Add sources defined as input in mapSources;
const mapSourcesMap = new Map<string, ArlasMapSource<any>>();
if (basemapSources) {
basemapSources.forEach(mapSource => {
mapSourcesMap.set(mapSource.id, mapSource);
});
mapSourcesMap.forEach((mapSource, id) => {
if (typeof (mapSource.source) !== 'string') {
this.mapService.setSource(id, mapSource.source, map);
}
});
}
}

public abstract setLayersMap(mapLayers: MapLayers<any>, layers?: Array<any>);

/**
* Inits a map of visulisation from the configuration.
* @param visualisationSetsConfig Visualisation set configuration.
*/
public initVisualisationSet(visualisationSetsConfig: VisualisationSetConfig[]) {
if (visualisationSetsConfig) {
console.log('_initVisualisationSet');
visualisationSetsConfig.forEach(visu => {
this.visualisationsSets.visualisations.set(visu.name, new Set(visu.layers));
this.visualisationsSets.status.set(visu.name, visu.enabled);
});
}
}

public initMapLayers(mapLayers: MapLayers<any>, map: AbstractArlasMapGL) {
if (mapLayers) {
console.log('init maplayers');
this.setLayersMap(mapLayers as MapLayers<any>);
}
}

public addArlasDataLayers(visualisationSetsConfig: VisualisationSetConfig[], mapLayers: MapLayers<any>, map: AbstractArlasMapGL) {
this.initMapLayers(mapLayers, map);
this.initVisualisationSet(visualisationSetsConfig);
for (let i = visualisationSetsConfig.length - 1; i >= 0; i--) {
const visualisation: VisualisationSetConfig = visualisationSetsConfig[i];
if (!!visualisation.layers) {
for (let j = visualisation.layers.length - 1; j >= 0; j--) {
const l = visualisation.layers[j];
const layer = this.layersMap.get(l);
this.mapService.addArlasDataLayer(map, layer, this.layersMap);
}
}
}
this._addExternalEventLayers(mapLayers, map);
this.visualisationsSets.status.forEach((visible, vs) => {
this.visualisationsSets.visualisations.get(vs).forEach(l => {
this.mapService.setLayerVisibility(l, visible, map);
});
});
this.reorderLayers(visualisationSetsConfig, map);
}

private _addExternalEventLayers(mapLayers: MapLayers<any>, map: AbstractArlasMapGL) {
if (!!mapLayers.externalEventLayers) {
mapLayers.layers
.filter(layer => mapLayers.externalEventLayers.map(e => e.id).indexOf(layer.id) >= 0)
.forEach(l => this.mapService.addLayer(map, l.id));
}
}


public reorderLayers(visualisationSetsConfig: VisualisationSetConfig[], map: AbstractArlasMapGL) {
// parses the visulisation list from bottom in order to put the fist ones first
for (let i = visualisationSetsConfig.length - 1; i >= 0; i--) {
const visualisation: VisualisationSetConfig = visualisationSetsConfig[i];
if (!!visualisation.layers && visualisation.enabled) {
for (let j = visualisation.layers.length - 1; j >= 0; j--) {
const l = visualisation.layers[j];
this.mapService.moveArlasDataLayer(map, l, this.layersMap)

Check failure on line 132 in projects/arlas-map/src/lib/arlas-map-logic.service.ts

View workflow job for this annotation

GitHub Actions / Lint, Build, Test & Documentation

Missing semicolon

Check failure on line 132 in projects/arlas-map/src/lib/arlas-map-logic.service.ts

View workflow job for this annotation

GitHub Actions / Lint, Build, Test & Documentation

Missing semicolon
}
}
}
this.reorderDrawLayers(map);

}

private reorderDrawLayers(map: AbstractArlasMapGL) {
this.mapService.getLayersFromPattern(map, '.cold').forEach(l => this.mapService.moveLayer(map, l.id));
this.mapService.getLayersFromPattern(map, '.hot').forEach(l => this.mapService.moveLayer(map, l.id));
}


public filterLayersOnEvent(mapLayers: MapLayers<any>, map: AbstractArlasMapGL, visibilityCondition: boolean, visibilityFilter: Array<any>, visibilityEvent: ExternalEvent,

Check failure on line 146 in projects/arlas-map/src/lib/arlas-map-logic.service.ts

View workflow job for this annotation

GitHub Actions / Lint, Build, Test & Documentation

This line has a length of 172. Maximum allowed is 146
collection?: string): void {
if (mapLayers && mapLayers.externalEventLayers) {
mapLayers.externalEventLayers.filter(layer => layer.on === visibilityEvent).forEach(layer => {
if (this.mapService.hasLayer(map, layer.id)) {
let originalLayerIsVisible = false;
const fullLayer = this.layersMap.get(layer.id);
const isCollectionCompatible = (!collection || (!!collection && (fullLayer.source as string).includes(collection)));
if (isCollectionCompatible) {
const originalLayerId = layer.id.replace('arlas-' + visibilityEvent.toString() + '-', '');
const originalLayer = this.mapService.getLayer(map, originalLayerId);
if (!!originalLayer) {
originalLayerIsVisible = this.mapService.isLayerVisible(originalLayer);
}
const layerFilter: Array<any> = [];
const externalEventLayer = this.layersMap.get(layer.id);
if (!!externalEventLayer && !!externalEventLayer.filter) {
externalEventLayer.filter.forEach(f => {
layerFilter.push(f);
});
}
if (layerFilter.length === 0) {
layerFilter.push('all');
}
if (visibilityCondition && originalLayerIsVisible) {
layerFilter.push(visibilityFilter);
this.mapService.filterGeojsonData(map, layer.id, layerFilter);
} else {
this.mapService.filterGeojsonData(map, layer.id, (layer as any).filter);
}
this.mapService.setLayerVisibility(layer.id, visibilityCondition && originalLayerIsVisible, map);
}
}
});
}
}


public selectFeatures(mapLayers: MapLayers<any>, map: AbstractArlasMapGL, elementToSelect: Array<ElementIdentifier>) {
if (elementToSelect) {
const ids = elementToSelect.length > 0 ?
elementToSelect.reduce((memo, element) => {
memo.push(element.idValue);
return memo;
}, []) : [];
const numericalIds = ids.filter(id => !isNaN(+id)).map(id => +id);
const visibilityFilter = ids.length > 0 ? ['in', ['get', elementToSelect[0].idFieldName], ['literal', ids.concat(numericalIds)]] : [];
this.filterLayersOnEvent(mapLayers, map, (elementToSelect.length > 0), visibilityFilter, ExternalEvent.select);
}
}

public highlightFeature(mapLayers: MapLayers<any>, map: AbstractArlasMapGL, featureToHightLight: { isleaving: boolean; elementidentifier: ElementIdentifier; }) {

Check failure on line 197 in projects/arlas-map/src/lib/arlas-map-logic.service.ts

View workflow job for this annotation

GitHub Actions / Lint, Build, Test & Documentation

This line has a length of 163. Maximum allowed is 146
if (featureToHightLight && featureToHightLight.elementidentifier) {
const ids: Array<number | string> = [featureToHightLight.elementidentifier.idValue];
if (!isNaN(+featureToHightLight.elementidentifier.idValue)) {
ids.push(+featureToHightLight.elementidentifier.idValue);
}
const visibilityFilter = ['in', ['get', featureToHightLight.elementidentifier.idFieldName],
['literal', ids]];
this.filterLayersOnEvent(mapLayers, map, !featureToHightLight.isleaving, visibilityFilter, ExternalEvent.hover);
}
}

public selectFeaturesByCollection(mapLayers: MapLayers<any>, map: AbstractArlasMapGL, features: Array<ElementIdentifier>, collection: string) {
const ids: Array<number | string> = features.map(f => f.idValue);
const numericalIds = ids.filter(id => !isNaN(+id)).map(id => +id);
const visibilityFilter = ids.length > 0 ? ['in', ['get', features[0].idFieldName], ['literal', ids.concat(numericalIds)]] : [];
this.filterLayersOnEvent(mapLayers, map, (features.length > 0), visibilityFilter, ExternalEvent.select, collection);
}


}

Check failure on line 217 in projects/arlas-map/src/lib/arlas-map-logic.service.ts

View workflow job for this annotation

GitHub Actions / Lint, Build, Test & Documentation

Newline required at end of file but not found
41 changes: 18 additions & 23 deletions projects/arlas-map/src/lib/arlas-map.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { BasemapService } from './basemaps/basemap.service';
import { MatSnackBar } from '@angular/material/snack-bar';
import { TranslateService } from '@ngx-translate/core';
import { ArlasBasemaps } from './basemaps/basemaps.model';
import { ArlasMapService } from './arlas-map.service';
import { ArlasMapService } from './map/service/arlas-map.service';
import * as styles from './draw/themes/default-theme'

Check failure on line 22 in projects/arlas-map/src/lib/arlas-map.component.ts

View workflow job for this annotation

GitHub Actions / Lint, Build, Test & Documentation

Missing semicolon
import limitVertexDirectSelectMode from './draw/modes/LimitVertexDirectSelectMode';
import validGeomDrawPolygonMode from './draw/modes/ValidGeomDrawPolygonMode';
Expand All @@ -35,6 +35,7 @@ import { ARLAS_VSET } from './map/model/layers';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { OnMoveResult } from './map/model/map';
import { MapLayerMouseEvent, MapMouseEvent } from './map/model/events';
import { ArlasMapFunctionalService } from './arlas-map-logic.service';

@Component({
selector: 'arlas-map',
Expand Down Expand Up @@ -243,7 +244,6 @@ export class ArlasMapComponent implements OnInit {
/** @description Subject of [collection, [field, legendData]] map. The map subscribes to it to keep */
/** the legend updated with the data displayed on the map. */
@Input() public legendUpdater: Subject<Map<string, Map<string, LegendData>>> = new Subject();

/** @description Subject of [layerId, boolean] map. The map subscribes to it to keep */
/** the legend updated with the visibility of the layer.*/
@Input() public visibilityUpdater: Subject<Map<string, boolean>> = new Subject();
Expand All @@ -265,6 +265,9 @@ export class ArlasMapComponent implements OnInit {

/** ANGULAR OUTPUTS */


/** @description Subject of [layerId, boolean] map. The map subscribes to it to keep */
/** the legend updated with the visibility of the layer.*/declareArlasDataSources
/** @description Emits true after the map is loaded and all sources & layers are added. */
@Output() public onMapLoaded: Subject<boolean> = new Subject<boolean>();

Expand Down Expand Up @@ -320,7 +323,8 @@ export class ArlasMapComponent implements OnInit {

public constructor(private http: HttpClient, private drawService: MapboxAoiDrawService,
private basemapService: BasemapService, private _snackBar: MatSnackBar, private translate: TranslateService,
protected mapService: ArlasMapService) {
protected mapService: ArlasMapService,
protected mapFunctionalService: ArlasMapFunctionalService) {
console.log('ummm');
this.aoiEditSubscription = this.drawService.editAoi$.subscribe(ae => this.onAoiEdit.emit(ae));
this.drawBboxSubscription = this.drawService.drawBbox$.subscribe({
Expand Down Expand Up @@ -385,9 +389,7 @@ export class ArlasMapComponent implements OnInit {
this.drawService.addFeatures(this.drawData, /** deleteOld */ true);
}
this.drawSelectionChanged = false;
if (this.map.getSource(this.map.POLYGON_LABEL_SOURCE) !== undefined) {
(this.map.getSource(this.map.POLYGON_LABEL_SOURCE) as any).setData(this.polygonlabeldata);
}
this.mapFunctionalService.updateLabelSources(this.map.POLYGON_LABEL_SOURCE, this.polygonlabeldata, this.map);
}
if (changes['boundsToFit'] !== undefined) {
const newBoundsToFit = changes['boundsToFit'].currentValue;
Expand Down Expand Up @@ -429,7 +431,7 @@ export class ArlasMapComponent implements OnInit {
if (e.features[0].properties.cluster_id !== undefined) {
// TODO: should check the this.index is set with good value
const expansionZoom = this.index.getClusterExpansionZoom(e.features[0].properties.cluster_id);
this.map.flyTo({ center: [e.lngLat.lng, e.lngLat.lat] }, expansionZoom);
this.mapService.flyTo(e.lngLat.lat, e.lngLat.lng, expansionZoom, this.map);
} else {
const zoom = this.map.getZoom();
let newZoom: number;
Expand All @@ -446,11 +448,11 @@ export class ArlasMapComponent implements OnInit {
} else {
newZoom = 12;
}
this.map.flyTo({ center: [e.lngLat.lng, e.lngLat.lat], zoom: newZoom },);
this.mapService.flyTo(e.lngLat.lat, e.lngLat.lng, newZoom, this.map);
}
}

protected queryRender(e, map: AbstractArlasMapGL, ) {
protected queryRender(e, map: AbstractArlasMapGL,) {
const hasCrossOrDrawLayer = map.hasCrossOrDrawLayer(e);
if (!this.isDrawingBbox && !this.isDrawingPolygon && !this.isDrawingCircle && !this.isInSimpleDrawMode && !hasCrossOrDrawLayer) {
map.onEvent(e);
Expand All @@ -465,27 +467,21 @@ export class ArlasMapComponent implements OnInit {
const iconName = icon.path.split('.')[0];
const iconPath = this.ICONS_BASE_PATH + icon.path;
const iconErrorMessage = 'The icon "' + this.ICONS_BASE_PATH + icon.path + '" is not found';
this.mapService.addImage(iconName, iconPath, this.map, iconErrorMessage, { 'sdf': icon.recolorable } );
this.mapService.addImage(iconName, iconPath, this.map, iconErrorMessage, { 'sdf': icon.recolorable });
});
}

public declareMap() {
console.log('declaaaring')
this.initTransformRequest();
console.log('traaans')
const config: MapConfig<unknown> = {
displayCurrentCoordinates: this.displayCurrentCoordinates,
fitBoundsPadding: this.fitBoundsPadding,
margePanForLoad: this.margePanForLoad,
margePanForTest: this.margePanForTest,
visualisationSetsConfig: this.visualisationSetsConfig,
offset: this.offset,
wrapLatLng: this.wrapLatLng,
mapLayers: this.mapLayers,
dataSources: this.dataSources,
icons: this.icons,
maxWidthScale: this.maxWidthScale,
mapSources: this.mapSources,
unitScale: this.unitScale,
mapLayersEventBind: {
zoomOnClick: [{ event: 'click', fn: this.defaultOnZoom }],
Expand Down Expand Up @@ -547,8 +543,6 @@ export class ArlasMapComponent implements OnInit {
};
console.log('declare');
this.map = this.mapService.createMap(config);
console.log(this.map);

this.map.eventEmitter$.subscribe({
next: (e: MapLayerMouseEvent) => {
if (e.type === 'click') {
Expand Down Expand Up @@ -618,6 +612,10 @@ export class ArlasMapComponent implements OnInit {
this.basemapService.declareProtomapProtocol(this.map);
this.basemapService.addProtomapBasemap(this.map);
this.addIcons();
this.mapFunctionalService.declareArlasDataSources(this.dataSources, this.emptyData, this.map);
this.mapFunctionalService.declareBasemapSources(this.mapSources, this.map);
this.mapFunctionalService.declareLabelSources('', this.polygonlabeldata, this.map);
this.mapFunctionalService.addArlasDataLayers(this.visualisationSetsConfig, this.mapLayers, this.map);

});

Expand Down Expand Up @@ -904,14 +902,11 @@ export class ArlasMapComponent implements OnInit {

/** Sets the layers order according to the order of `visualisationSetsConfig` list*/
public reorderLayers() {
this.map.reorderLayers();
this.mapFunctionalService.reorderLayers(this.visualisationSetsConfig, this.map);
}






/** ------------------------------------------------------- VISUAL SEPERATOR - DRAWING ----------------------------------------- */


Expand Down Expand Up @@ -1173,7 +1168,7 @@ export class ArlasMapComponent implements OnInit {
public emitVisualisations(visualisationName: string) {
const layers = this.map.updateLayoutVisibility(visualisationName);
this.visualisations.emit(layers);
this.map.reorderLayers();
this.reorderLayers();
}

// Todo: replace layer any by unique type
Expand Down
2 changes: 1 addition & 1 deletion projects/arlas-map/src/lib/arlas-map.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TestBed } from '@angular/core/testing';

import { ArlasMapService } from './arlas-map.service';
import { ArlasMapService } from './map/service/arlas-map.service';

describe('ArlasMapService', () => {
let service: ArlasMapService;
Expand Down
Loading

0 comments on commit 34ce9fe

Please sign in to comment.