From c7db4c9e612147da91cce763df529387c4262942 Mon Sep 17 00:00:00 2001 From: Samuel Girard Date: Mon, 5 Feb 2018 14:03:25 +0100 Subject: [PATCH] Take in account layers order --- src/components/layers/layer.component.ts | 36 +++++++++++++++++-- src/components/layers/layergroup.component.ts | 31 +++++++++++++--- src/components/layers/layerimage.component.ts | 5 +-- src/components/layers/layertile.component.ts | 5 +-- .../layers/layervector.component.ts | 5 +-- .../layers/layervectortile.component.ts | 5 +-- src/components/map.component.ts | 19 +++++++++- 7 files changed, 90 insertions(+), 16 deletions(-) diff --git a/src/components/layers/layer.component.ts b/src/components/layers/layer.component.ts index e54955a9..647fa582 100644 --- a/src/components/layers/layer.component.ts +++ b/src/components/layers/layer.component.ts @@ -17,7 +17,7 @@ export abstract class LayerComponent implements OnInit, OnChanges, OnDestroy { @Input() precompose: (evt: ol.events.Event) => void; @Input() postcompose: (evt: ol.events.Event) => void; - constructor(protected host: LayerGroupComponent | MapComponent) { + constructor(public host: LayerGroupComponent | MapComponent) { } ngOnInit() { @@ -27,11 +27,9 @@ export abstract class LayerComponent implements OnInit, OnChanges, OnDestroy { if (this.postcompose !== null && this.postcompose !== undefined) { this.instance.on('postcompose', this.postcompose); } - this.host.instance.getLayers().push(this.instance); } ngOnDestroy() { - this.host.instance.getLayers().remove(this.instance); } ngOnChanges(changes: SimpleChanges) { @@ -56,3 +54,35 @@ export abstract class LayerComponent implements OnInit, OnChanges, OnDestroy { this.instance.setProperties(properties, false); } } + + +export class LayersHelper { + /** + * Update OpenLayers layers (from a Map or a LayerGroup for example) from a given LayerComponent list. + * It helps to keep OpenLayers natural orders after adding, deleting and moving layers + * @param {ol.Collection} olLayers + * @param {LayerComponent[]} viewLayers + */ + static updateLayers(olLayers: ol.Collection, viewLayers: LayerComponent[]) { + viewLayers.forEach((layer, index) => { + let olIndex = olLayers.getArray().indexOf(layer.instance); + if (olIndex < 0) { + // New layer: we add it to the map + olLayers.insertAt(index, layer.instance); + // console.log(`~~ updateLayers: new layer at pos ${index}`, layer.instance); + } else if (index !== olIndex) { + // layer has moved inside the layers list + olLayers.removeAt(olIndex); + olLayers.insertAt(index, layer.instance); + // console.log(`~~ updateLayers: existing layer at pos ${olIndex} moving to pos ${index}`, layer.instance); + } + }); + // Remove the layers that have disapeared from childrenLayers + if (olLayers.getLength() > viewLayers.length) { + for (let i = viewLayers.length; i < olLayers.getLength(); i++) { + olLayers.removeAt(i); + // console.log(`~~ updateLayers: remove layer at pos ${i}`); + } + } + } +} diff --git a/src/components/layers/layergroup.component.ts b/src/components/layers/layergroup.component.ts index 48350d24..80392ae6 100644 --- a/src/components/layers/layergroup.component.ts +++ b/src/components/layers/layergroup.component.ts @@ -1,15 +1,21 @@ -import { Component, OnDestroy, OnInit, SkipSelf, Inject, Optional } from '@angular/core'; +import { + Component, OnDestroy, OnInit, SkipSelf, Inject, Optional, ViewChildren, QueryList, + AfterViewInit, ContentChildren, forwardRef +} from '@angular/core'; import { layer } from 'openlayers'; -import { LayerComponent } from './layer.component'; +import { LayersHelper, LayerComponent } from './layer.component'; import { MapComponent } from '../map.component'; @Component({ selector: 'aol-layer-group', - template: `` + template: ``, + providers: [{provide: LayerComponent, useExisting: forwardRef(() => LayerGroupComponent) }] }) -export class LayerGroupComponent extends LayerComponent implements OnInit, OnDestroy { +export class LayerGroupComponent extends LayerComponent implements AfterViewInit, OnInit, OnDestroy { public instance: ol.layer.Group; + @ContentChildren(LayerComponent, {descendants: true}) childrenLayers: QueryList; + constructor(map: MapComponent, @SkipSelf() @Optional() group?: LayerGroupComponent) { super(group || map); @@ -20,4 +26,21 @@ export class LayerGroupComponent extends LayerComponent implements OnInit, OnDes this.instance = new layer.Group(this); super.ngOnInit(); } + + ngAfterViewInit() { + // console.log('layerGroup.AfterViewInit', this.childrenLayers); + // Update layers when new layers are added/moved/removed + this.childrenLayers.changes.subscribe( + () => LayersHelper.updateLayers( + this.instance.getLayers(), + // Filter is a temporary fix waiting for https://github.com/angular/angular/issues/10098 + this.childrenLayers.filter(l => l.host === this) + ) + ); + // Initialization: add all the children layers + // Filter is a temporary fix waiting for https://github.com/angular/angular/issues/10098 + this.childrenLayers.filter(l => l.host === this).forEach((layer) => { + this.instance.getLayers().push(layer.instance); + }); + } } diff --git a/src/components/layers/layerimage.component.ts b/src/components/layers/layerimage.component.ts index e5e8ff22..5e679841 100644 --- a/src/components/layers/layerimage.component.ts +++ b/src/components/layers/layerimage.component.ts @@ -1,5 +1,5 @@ import { - Component, EventEmitter, Input, OnChanges, OnInit, Optional, + Component, EventEmitter, forwardRef, Input, OnChanges, OnInit, Optional, SimpleChanges } from '@angular/core'; import { Extent, layer, source } from 'openlayers'; @@ -9,7 +9,8 @@ import { LayerGroupComponent } from './layergroup.component'; @Component({ selector: 'aol-layer-image', - template: `` + template: ``, + providers: [{provide: LayerComponent, useExisting: forwardRef(() => LayerImageComponent) }] }) export class LayerImageComponent extends LayerComponent implements OnInit, OnChanges { public source: source.Image; diff --git a/src/components/layers/layertile.component.ts b/src/components/layers/layertile.component.ts index 4f268f39..ec940724 100644 --- a/src/components/layers/layertile.component.ts +++ b/src/components/layers/layertile.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy, OnInit, Input, Optional, OnChanges, - SimpleChanges + SimpleChanges, forwardRef } from '@angular/core'; import { layer, source } from 'openlayers'; import { MapComponent } from '../map.component'; @@ -9,7 +9,8 @@ import { LayerGroupComponent } from './layergroup.component'; @Component({ selector: 'aol-layer-tile', - template: `` + template: ``, + providers: [{provide: LayerComponent, useExisting: forwardRef(() => LayerTileComponent) }] }) export class LayerTileComponent extends LayerComponent implements OnInit, OnDestroy, OnChanges { public source: source.Tile; diff --git a/src/components/layers/layervector.component.ts b/src/components/layers/layervector.component.ts index 8d9b8398..9d62de89 100644 --- a/src/components/layers/layervector.component.ts +++ b/src/components/layers/layervector.component.ts @@ -1,6 +1,6 @@ import { Component, OnDestroy, OnInit, Input, Optional, OnChanges, - SimpleChanges + SimpleChanges, forwardRef } from '@angular/core'; import { layer, source } from 'openlayers'; import { MapComponent } from '../map.component'; @@ -9,7 +9,8 @@ import { LayerGroupComponent } from './layergroup.component'; @Component({ selector: 'aol-layer-vector', - template: `` + template: ``, + providers: [{provide: LayerComponent, useExisting: forwardRef(() => LayerVectorComponent) }] }) export class LayerVectorComponent extends LayerComponent implements OnInit, OnDestroy, OnChanges { public source: source.Vector; diff --git a/src/components/layers/layervectortile.component.ts b/src/components/layers/layervectortile.component.ts index fc9c1bd1..ba4f5fc0 100644 --- a/src/components/layers/layervectortile.component.ts +++ b/src/components/layers/layervectortile.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, Input, Optional, SimpleChanges, OnChanges } from '@angular/core'; +import {Component, OnInit, Input, Optional, SimpleChanges, OnChanges, forwardRef} from '@angular/core'; import { layer, style, StyleFunction } from 'openlayers'; import { MapComponent } from '../map.component'; import { LayerComponent } from './layer.component'; @@ -6,7 +6,8 @@ import { LayerGroupComponent } from './layergroup.component'; @Component({ selector: 'aol-layer-vectortile', - template: `` + template: ``, + providers: [{provide: LayerComponent, useExisting: forwardRef(() => LayerVectorTileComponent) }] }) export class LayerVectorTileComponent extends LayerComponent implements OnInit, OnChanges { diff --git a/src/components/map.component.ts b/src/components/map.component.ts index d7401a03..87a49cf2 100644 --- a/src/components/map.component.ts +++ b/src/components/map.component.ts @@ -1,11 +1,12 @@ import { Component, OnInit, ElementRef, Input, Output, EventEmitter, AfterViewInit, - SimpleChanges, OnChanges + SimpleChanges, OnChanges, QueryList, ContentChildren, forwardRef } from '@angular/core'; import { Map, MapBrowserEvent, MapEvent, render, ObjectEvent, control, interaction } from 'openlayers'; +import { LayerComponent, LayersHelper } from './layers'; @Component({ selector: 'aol-map', @@ -16,6 +17,8 @@ export class MapComponent implements OnInit, AfterViewInit, OnChanges { public instance: Map; public componentType: string = 'map'; + @ContentChildren(LayerComponent, {descendants: true}) childrenLayers: QueryList; + @Input() width: string = '100%'; @Input() height: string = '100%'; @Input() pixelRatio: number; @@ -86,5 +89,19 @@ export class MapComponent implements OnInit, AfterViewInit, OnChanges { ngAfterViewInit() { this.instance.updateSize(); + + // Update layers when new layers are added/moved/removed + this.childrenLayers.changes.subscribe( + () => LayersHelper.updateLayers( + this.instance.getLayers(), + // Filter is a temporary fix waiting for https://github.com/angular/angular/issues/10098 + this.childrenLayers.filter(l => l.host === this) + ) + ); + // Initialization: add all the layers + // Filter is a temporary fix waiting for https://github.com/angular/angular/issues/10098 + this.childrenLayers.filter(l => l.host === this).forEach((layer) => { + this.instance.getLayers().push(layer.instance); + }); } }