Skip to content

Commit

Permalink
Moved map model from component to service
Browse files Browse the repository at this point in the history
  • Loading branch information
holgerstolzenberg committed Mar 6, 2024
1 parent 7916f48 commit f56171d
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 65 deletions.
54 changes: 10 additions & 44 deletions src/app/map/map.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { MapService } from './map.service';
import { NGXLogger } from 'ngx-logger';
import { Subject, takeUntil } from 'rxjs';
import { NotificationService } from '../notifications/notification.service';
import { Deck } from '@deck.gl/core/typed';
import { INITIAL_VIEW_STATE, LayerIndices } from './map.constants';
import { DeckMetrics } from '@deck.gl/core/typed/lib/deck';

@Component({
Expand All @@ -13,63 +11,42 @@ import { DeckMetrics } from '@deck.gl/core/typed/lib/deck';
styleUrl: './map.component.scss'
})
export class MapComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('deckGlMap', { static: false }) private mapDiv?: ElementRef<HTMLDivElement>;

showLoader: boolean = false;
showMetrics: boolean = true;
loadedTileId: string = '';

readonly metrics$?: Subject<DeckMetrics> = new Subject<DeckMetrics>();
readonly metrics$: Subject<DeckMetrics> = new Subject<DeckMetrics>();

private readonly onUnsubscribe$: Subject<boolean> = new Subject<boolean>();

@ViewChild('deckGlMap', { static: false }) private mapDiv?: ElementRef<HTMLDivElement>;
private map?: Deck;

constructor(
private log: NGXLogger,
private mapService: MapService,
private notificationService: NotificationService
) {}
) {
this.metrics$.pipe(takeUntil(this.onUnsubscribe$));
}

ngOnInit(): void {
this.initAllSubscriptions();
}

ngAfterViewInit() {
this.initDeckGlMap();
this.mapService.initDeckGlMap(this.mapDiv!, this.metrics$!);
}

ngOnDestroy(): void {
this.unsubscribeAll();
this.disposeMap();
}

initDeckGlMap() {
this.mapService.getLayers().then(layers => {
this.map = new Deck({
parent: this.mapDiv!.nativeElement,
initialViewState: INITIAL_VIEW_STATE,
style: { position: 'relative', top: '0', bottom: '0' },
controller: true,
useDevicePixels: false,
layers: [layers],

onWebGLInitialized: gl => {
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE, gl.ONE_MINUS_DST_ALPHA, gl.ONE);
gl.blendEquation(gl.FUNC_ADD);
},

_onMetrics: metrics => {
this.metrics$!.next(metrics);
}
});
});
}

private initAllSubscriptions() {
// prettier-ignore
this.mapService.loading$
.pipe(takeUntil(this.onUnsubscribe$))
.subscribe(tileId => this.showHideLoader(tileId));
.pipe(takeUntil(this.onUnsubscribe$))
.subscribe(tileId => this.showHideLoader(tileId));

// TODO deck.gl: this.resetMap();
this.mapService.resetMap$.pipe(takeUntil(this.onUnsubscribe$)).subscribe(() => {
Expand All @@ -80,29 +57,18 @@ export class MapComponent implements OnInit, AfterViewInit, OnDestroy {
this.mapService.toMyLocation$.pipe(takeUntil(this.onUnsubscribe$)).subscribe(() => {
this.notificationService.showWarnLocalized('common.not-implemented');
});

this.mapService.showEuBorders$.pipe(takeUntil(this.onUnsubscribe$)).subscribe(value => {
this.mapService.changeLayerVisibility(this.map!, LayerIndices.EU_LAYER_INDEX, value);
});

this.mapService.showCapitols$.pipe(takeUntil(this.onUnsubscribe$)).subscribe(value => {
this.mapService.changeLayerVisibility(this.map!, LayerIndices.CAPITOLS_LAYER_INDEX, value);
});
}

private showHideLoader(tileId: string) {
this.loadedTileId = tileId;
this.showLoader = true;
setTimeout(() => (this.showLoader = false), 500);
setTimeout(() => (this.showLoader = false), 1000);
}

private unsubscribeAll() {
this.onUnsubscribe$.next(true);
this.onUnsubscribe$.complete();
this.onUnsubscribe$!.unsubscribe();

this.metrics$!.complete();
this.metrics$!.unsubscribe();
}

// TODO deck.gl: dispose deck map
Expand Down
61 changes: 40 additions & 21 deletions src/app/map/map.service.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import { EventEmitter, Injectable } from '@angular/core';
import { ElementRef, EventEmitter, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { NGXLogger } from 'ngx-logger';
import { CAPITOLS_LAYER, CENTER_OF_EUROPE } from './map.constants';
import { CAPITOLS_LAYER, CENTER_OF_EUROPE, INITIAL_VIEW_STATE, LayerIndices } from './map.constants';
import { NotificationService } from '../notifications/notification.service';
import { Deck, Layer } from '@deck.gl/core/typed';
import { BitmapLayer, GeoJsonLayer } from '@deck.gl/layers/typed';
import { firstValueFrom } from 'rxjs';
import { firstValueFrom, Subject } from 'rxjs';
import { TileLayer } from '@deck.gl/geo-layers/typed';
import { environment } from '../../environments/environment';
import { DeckMetrics } from '@deck.gl/core/typed/lib/deck';

@Injectable()
export class MapService {
resetMap$ = new EventEmitter<string>();
toMyLocation$ = new EventEmitter<string>();
showEuBorders$ = new EventEmitter<boolean>();
showCapitols$ = new EventEmitter<boolean>();
loading$ = new EventEmitter<string>();

private readonly mapLayer: Promise<TileLayer>;
private readonly euBordersLayer: Promise<GeoJsonLayer>;
private readonly layers: Promise<Layer[]>;

private map?: Deck;

constructor(
private readonly http: HttpClient,
private readonly log: NGXLogger,
Expand All @@ -31,22 +32,10 @@ export class MapService {
this.layers = this.loadAllLayers();
}

getLayers() {
return this.layers;
}

async loadAllLayers(): Promise<Layer[]> {
return Promise.all([this.getMapLayer(), this.getEuBordersLayer(), this.getCapitolsLayer()]);
}

changeLayerVisibility(map: Deck, layerIndex: number, value: boolean) {
this.layers.then(layers => {
const clonedLayers = layers.slice();
clonedLayers[layerIndex] = layers[layerIndex].clone({ visible: value });
map.setProps({ layers: clonedLayers });
});
}

async resetMapToEuropeanCenter() {
this.log.debug('Reset map');
this.resetMap$.emit();
Expand All @@ -58,13 +47,35 @@ export class MapService {
}

async doShowEuBorders(value: boolean) {
this.log.trace('Show EU borders', value);
this.showEuBorders$.emit(value);
this.changeLayerVisibility(LayerIndices.EU_LAYER_INDEX, value).then(() => this.log.trace('Show EU borders', value));
}

async doShowCapitols(value: boolean) {
this.log.trace('Show capitols', value);
this.showCapitols$.emit(value);
this.changeLayerVisibility(LayerIndices.CAPITOLS_LAYER_INDEX, value).then(() =>
this.log.trace('Show capitols', value)
);
}

initDeckGlMap(mapDiv: ElementRef<HTMLDivElement>, metricsRef: Subject<DeckMetrics>) {
this.layers.then(layers => {
this.map = new Deck({
parent: mapDiv.nativeElement,
initialViewState: INITIAL_VIEW_STATE,
style: { position: 'relative', top: '0', bottom: '0' },
controller: true,
useDevicePixels: false,
layers: [layers],

onWebGLInitialized: gl => {
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE, gl.ONE_MINUS_DST_ALPHA, gl.ONE);
gl.blendEquation(gl.FUNC_ADD);
},

_onMetrics: metrics => {
metricsRef.next(metrics);
}
});
});
}

private async initMapLayer() {
Expand Down Expand Up @@ -121,6 +132,14 @@ export class MapService {
});
}

private async changeLayerVisibility(layerIndex: number, value: boolean) {
this.layers.then(layers => {
const clonedLayers = layers.slice();
clonedLayers[layerIndex] = layers[layerIndex].clone({ visible: value });
this.map!.setProps({ layers: clonedLayers });
});
}

// TODO deck.gl: do not forget this method
private async getCenterOfEurope() {
return CENTER_OF_EUROPE;
Expand Down

0 comments on commit f56171d

Please sign in to comment.