diff --git a/projects/common-map/src/fm-map/actions/map.actions.ts b/projects/common-map/src/fm-map/actions/map.actions.ts index cb87f3c..e492005 100644 --- a/projects/common-map/src/fm-map/actions/map.actions.ts +++ b/projects/common-map/src/fm-map/actions/map.actions.ts @@ -5,6 +5,7 @@ import { IItemLayer } from '../models/item.layer'; import { IQueryState } from '@farmmaps/common'; import { IItem } from '@farmmaps/common'; import { Feature,Style } from 'ol'; +import { IListItem } from 'dist/common/public-api'; export const SETSTATE = '[Map] SetState'; export const SETMAPSTATE = '[Map] MapState'; @@ -16,6 +17,10 @@ export const STARTSEARCHSUCCESS = '[Map] StartSearchSuccess'; export const SELECTFEATURE = '[Map] SelectFeature'; export const SELECTITEM = '[Map] SelectItem'; export const SELECTITEMSUCCESS = '[Map] SelectItemSuccess'; +export const SELECTTEMPORALITEMSSUCCESS = '[Map] SelectTemporalItemsSuccess'; +export const NEXTTEMPORAL = '[Map] NextTemporal'; +export const PREVIOUSTEMPORAL = '[Map] PreviousTemporal'; +export const SELECTTEMPORAL = '[Map] SelectTemporal'; export const ADDFEATURESUCCESS = '[Map] AddFeatureSuccess'; export const UPDATEFEATURESUCCESS = '[Map] UpdateFeatureSuccess'; export const EXPANDSEARCH = '[Map] ExpandSearch'; @@ -97,6 +102,30 @@ export class SelectItemSuccess implements Action { constructor(public item: IItem) { } } +export class SelectTemporalItemsSuccess implements Action { + readonly type = SELECTTEMPORALITEMSSUCCESS; + + constructor(public temporalItems: IItem[]) { } +} + +export class NextTemporal implements Action { + readonly type = NEXTTEMPORAL; + + constructor() { } +} + +export class PreviousTemporal implements Action { + readonly type = PREVIOUSTEMPORAL; + + constructor() { } +} + +export class SelectTemporal implements Action { + readonly type = SELECTTEMPORAL; + + constructor(item:IItem) { } +} + export class AddFeatureSuccess implements Action { readonly type = ADDFEATURESUCCESS; @@ -224,6 +253,10 @@ export type Actions = SetMapState | SelectFeature | SelectItem | SelectItemSuccess + | SelectTemporalItemsSuccess + | NextTemporal + | PreviousTemporal + | SelectTemporal | AddFeatureSuccess | UpdateFeatureSuccess | ExpandSearch diff --git a/projects/common-map/src/fm-map/common-map.module.ts b/projects/common-map/src/fm-map/common-map.module.ts index aa84e50..2f51d1b 100644 --- a/projects/common-map/src/fm-map/common-map.module.ts +++ b/projects/common-map/src/fm-map/common-map.module.ts @@ -34,6 +34,7 @@ import { AbstractItemListComponent,ItemListComponent} from './components/item-li import { AbstractSelectedItemComponent, SelectedItemComponent } from './components/selected-item/selected-item.component'; import { SelectedItemCropfieldComponent } from './components/selected-item-cropfield/selected-item-cropfield.component'; import { SelectedItemGeotiffComponent } from './components/selected-item-geotiff/selected-item-geotiff.component'; +import { SelectedItemTemporalComponent} from './components/selected-item-temporal/selected-item-temporal.component'; import {SelectedItemShapeComponent } from './components/selected-item-shape/selected-item-shape.component'; import { SelectedItemContainerComponent } from './components/selected-item-container/selected-item-container.component'; import { AbstractFeatureListFeatureComponent, FeatureListFeatureComponent } from './components/feature-list-feature/feature-list-feature.component'; @@ -116,6 +117,7 @@ export { SelectedItemComponent, SelectedItemCropfieldComponent, SelectedItemGeotiffComponent, + SelectedItemTemporalComponent, SelectedItemShapeComponent, ItemListItemComponent, ItemListItemContainerComponent, @@ -182,6 +184,7 @@ export { SelectedItemComponent, SelectedItemCropfieldComponent, SelectedItemGeotiffComponent, + SelectedItemTemporalComponent, SelectedItemShapeComponent, ItemListItemComponent, ItemListItemContainerComponent, @@ -202,6 +205,7 @@ export { SelectedItemComponent, SelectedItemCropfieldComponent, SelectedItemGeotiffComponent, + SelectedItemTemporalComponent, SelectedItemShapeComponent, ItemListComponent, ItemListItemComponent, @@ -222,6 +226,7 @@ export { SelectedItemComponent, SelectedItemCropfieldComponent, SelectedItemGeotiffComponent, + SelectedItemTemporalComponent, SelectedItemShapeComponent, ItemListItemComponent, ItemListItemContainerComponent, @@ -261,6 +266,7 @@ export class AppCommonMapModule { { provide: AbstractSelectedItemComponent, useClass: SelectedItemComponent, multi: true }, { provide: AbstractSelectedItemComponent, useClass: SelectedItemCropfieldComponent, multi: true }, { provide: AbstractSelectedItemComponent, useClass: SelectedItemGeotiffComponent, multi: true }, + { provide: AbstractSelectedItemComponent, useClass: SelectedItemTemporalComponent, multi: true }, { provide: AbstractSelectedItemComponent, useClass: SelectedItemShapeComponent, multi: true }, { provide: AbstractItemListItemComponent, useClass: ItemListItemComponent, multi: true }, { provide: AbstractItemListComponent, useClass: ItemListComponent, multi: true } diff --git a/projects/common-map/src/fm-map/components/aol/item-layers/item-layers.component.ts b/projects/common-map/src/fm-map/components/aol/item-layers/item-layers.component.ts index 2d4f9d2..7fa7117 100644 --- a/projects/common-map/src/fm-map/components/aol/item-layers/item-layers.component.ts +++ b/projects/common-map/src/fm-map/components/aol/item-layers/item-layers.component.ts @@ -3,7 +3,7 @@ import { HttpClient } from "@angular/common/http"; import { LayerVectorComponent, LayerTileComponent, LayerGroupComponent, MapComponent } from 'ngx-openlayers'; import { ItemService } from '@farmmaps/common'; import { AppConfig } from '@farmmaps/common'; -import { IItemLayer} from '../../../models/item.layer'; +import { IItemLayer,ItemLayer, ITemporalItemLayer} from '../../../models/item.layer'; import { ILayerData} from '../../../models/layer.data'; import { IRenderoutputTiles,IRenderoutputImage,IGradientstop,ILayer,IHistogram} from '../../../models/color.map'; import {Extent} from 'ol/extent'; @@ -19,6 +19,7 @@ import VectorTileSource from 'ol/source/VectorTile'; import VectorTileLayer from 'ol/layer/VectorTile'; import {GeoJSON,MVT} from 'ol/format'; import { from } from 'rxjs'; +import { IItem } from 'dist/common/public-api'; @Component({ selector: 'fm-map-item-layers', @@ -86,83 +87,95 @@ export class ItemLayersComponent extends LayerGroupComponent implements OnChange }); } - createLayer(itemLayer: IItemLayer): Layer { - var layer: Layer = null; + createGeotiffLayer(item:IItem,itemLayer:IItemLayer):Layer { var layerIndex = -1; - if (itemLayer.item.itemType == 'vnd.farmmaps.itemtype.geotiff.processed') { - layerIndex = itemLayer.layerIndex != -1 ? itemLayer.layerIndex : itemLayer.item.data.layers[0].index; - let source = new XYZ({ maxZoom: 19, minZoom: 1, url: `${this._apiEndPoint}/api/v1/items/${itemLayer.item.code}/tiles/${layerIndex}/{z}/{x}/{y}.png?v=${itemLayer.item.updated.getTime()}` }); + var layer: Layer = null; + layerIndex = itemLayer.layerIndex != -1 ? itemLayer.layerIndex : item.data.layers[0].index; + let source = new XYZ({ maxZoom: 19, minZoom: 1, url: `${this._apiEndPoint}/api/v1/items/${item.code}/tiles/${layerIndex}/{z}/{x}/{y}.png?v=${item.updated.getTime()}` }); + layer = new Tile({ source: source }); + var data = item.data; + var l = (data && data.layers && data.layers.length > 0) ? data.layers[0] : null; + if (l && l.rendering && l.rendering.renderoutputType == "Tiles") { + var rt = l.rendering as IRenderoutputTiles; + let source = new XYZ({ maxZoom: rt.maxzoom, minZoom: rt.minzoom, url: `${this._apiEndPoint}/api/v1/items/${item.code}/tiles/${layerIndex}/{z}/{x}/{y}.png?v=${item.updated.getTime()}` }); layer = new Tile({ source: source }); - var data = itemLayer.item.data; - var l = (data && data.layers && data.layers.length > 0) ? data.layers[0] : null; - if (l && l.rendering && l.rendering.renderoutputType == "Tiles") { - var rt = l.rendering as IRenderoutputTiles; - let source = new XYZ({ maxZoom: rt.maxzoom, minZoom: rt.minzoom, url: `${this._apiEndPoint}/api/v1/items/${itemLayer.item.code}/tiles/${layerIndex}/{z}/{x}/{y}.png?v=${itemLayer.item.updated.getTime()}` }); - layer = new Tile({ source: source }); - } - if (l && l.rendering && l.rendering.renderoutputType == "Image") { - var ri = l.rendering as IRenderoutputImage; - let projection = new Projection({ - code: 'image', - units: 'pixels', - extent: ri.extent - }); - let source = new ImageStatic({ imageExtent: ri.extent, projection: projection, url: `${this._apiEndPoint}/api/v1/items/${itemLayer.item.code}/mapimage/${layerIndex}?v=${itemLayer.item.updated.getTime()}` }); - layer = new Image({ source: source }); - } - } else if (itemLayer.item.itemType == 'vnd.farmmaps.itemtype.shape.processed') { - var data = itemLayer.item.data; - layerIndex = itemLayer.layerIndex != -1 ? itemLayer.layerIndex : itemLayer.item.data.layers[0].index; - var l = itemLayer.item.data.layers[layerIndex]; - if (l && l.rendering && l.rendering.renderoutputType == "VectorTiles") { - var rt = itemLayer.item.data.layers[layerIndex].rendering as IRenderoutputTiles; - layer = new VectorTileLayer({ - declutter: true, - source: new VectorTileSource({ - maxZoom: rt.maxzoom, - minZoom: rt.minzoom, - format: new MVT(), - url: `${this._apiEndPoint}/api/v1/items/${itemLayer.item.code}/vectortiles/{z}/{x}/{y}.pbf?v=${itemLayer.item.updated.getTime()}` - }), - style: (feature) => { - return this.getColorFromGradient(l, feature); - } + } + if (l && l.rendering && l.rendering.renderoutputType == "Image") { + var ri = l.rendering as IRenderoutputImage; + let projection = new Projection({ + code: 'image', + units: 'pixels', + extent: ri.extent + }); + let source = new ImageStatic({ imageExtent: ri.extent, projection: projection, url: `${this._apiEndPoint}/api/v1/items/${item.code}/mapimage/${layerIndex}?v=${item.updated.getTime()}` }); + layer = new Image({ source: source }); + } + return layer; + } + + createShapeLayer(item:IItem,itemLayer:IItemLayer):Layer { + var layerIndex = -1; + var layer: Layer = null; + layerIndex = itemLayer.layerIndex != -1 ? itemLayer.layerIndex : item.data.layers[0].index; + var data = item.data; + var l = (data && data.layers && data.layers.length > 0) ? data.layers[0] : null; + if (l && l.rendering && l.rendering.renderoutputType == "VectorTiles") { + var rt = item.data.layers[layerIndex].rendering as IRenderoutputTiles; + layer = new VectorTileLayer({ + declutter: true, + source: new VectorTileSource({ + maxZoom: rt.maxzoom, + minZoom: rt.minzoom, + format: new MVT(), + url: `${this._apiEndPoint}/api/v1/items/${item.code}/vectortiles/{z}/{x}/{y}.pbf?v=${item.updated.getTime()}` + }), + style: (feature) => { + return this.getColorFromGradient(l, feature); + } + }) + } else if (l && l.rendering && l.rendering.renderoutputType == "Tiles") { + var rt = l.rendering as IRenderoutputTiles; + layer = new Tile({ + source: new XYZ({ + maxZoom: rt.maxzoom, + minZoom: rt.minzoom, + url: `${this._apiEndPoint}/api/v1/items/${item.code}/vectortiles/image_tiles/${layerIndex}/{z}/{x}/{y}.png?v=${item.updated.getTime()}` }) - } else if (l && l.rendering && l.rendering.renderoutputType == "Tiles") { - var rt = l.rendering as IRenderoutputTiles; - layer = new Tile({ - source: new XYZ({ - maxZoom: rt.maxzoom, - minZoom: rt.minzoom, - url: `${this._apiEndPoint}/api/v1/items/${itemLayer.item.code}/vectortiles/image_tiles/${layerIndex}/{z}/{x}/{y}.png?v=${itemLayer.item.updated.getTime()}` - }) - }); - } else { - let __this = this; - let format = new GeoJSON(); - let source = new VectorSource({ - strategy: loadingstrategy.bbox, - loader: function (extent: Extent, resolution: number, projection: Projection) { - var source = this as VectorSource; - __this.itemService.getItemFeatures(itemLayer.item.code, extent, projection.getCode(), layerIndex).subscribe(function (data) { - var features = format.readFeatures(data); - for (let f of features) { - if (f.get("code")) { - f.setId(f.get("code")); - } + }); + } else { + let __this = this; + let format = new GeoJSON(); + let source = new VectorSource({ + strategy: loadingstrategy.bbox, + loader: function (extent: Extent, resolution: number, projection: Projection) { + var source = this as VectorSource; + __this.itemService.getItemFeatures(item.code, extent, projection.getCode(), layerIndex).subscribe(function (data) { + var features = format.readFeatures(data); + for (let f of features) { + if (f.get("code")) { + f.setId(f.get("code")); } - source.addFeatures(features); - }); - } - }); - layer = new VectorLayer({ - source: source, - style: (feature) => { - var key = feature.get("color"); - if (!this.styleCache[key]) { - var color = feature.get("color"); - this.styleCache[key] = new style.Style( - { + } + source.addFeatures(features); + }); + } + }); + layer = new VectorLayer({ + source: source, + style: (feature) => { + var key = feature.get("color"); + if (!this.styleCache[key]) { + var color = feature.get("color"); + this.styleCache[key] = new style.Style( + { + fill: new style.Fill({ + color: color + }), + stroke: new style.Stroke({ + color: color, + width: 1.25 + }), + image: new style.Circle({ fill: new style.Fill({ color: color }), @@ -170,50 +183,58 @@ export class ItemLayersComponent extends LayerGroupComponent implements OnChange color: color, width: 1.25 }), - image: new style.Circle({ - fill: new style.Fill({ - color: color - }), - stroke: new style.Stroke({ - color: color, - width: 1.25 - }), - radius: 5 - }), - } - ) - } - return this.styleCache[key]; + radius: 5 + }), + } + ) } - }); + return this.styleCache[key]; + } + }); + } + return layer; + } + + createExternalLayer(item:IItem,itemLayer:IItemLayer):Layer { + let data = item.data as ILayerData; + var layer: Layer = null; + switch (data.interfaceType) { + case 'OSM': { + let source = new OSM(); + layer = new Tile({ source: source }); + break; } + case 'BingMaps': { + let source = new BingMaps(data.options); + layer = new Tile({ source: source }); + break; + } + case 'TileWMS': { + let source = new TileWMS(data.options); + layer = new Tile({ source: source }); + break; + } + case 'TileArcGISRest': { + let source = new TileArcGISRest(data.options); + layer = new Tile({ source: source }); + break; + } + default: { + break; + } + } + return layer; + } + + createLayer(itemLayer: IItemLayer): Layer { + var layer: Layer = null; + var layerIndex = -1; + if (itemLayer.item.itemType == 'vnd.farmmaps.itemtype.geotiff.processed') { + layer = this.createGeotiffLayer(itemLayer.item,itemLayer); + } else if (itemLayer.item.itemType == 'vnd.farmmaps.itemtype.shape.processed') { + layer = this.createShapeLayer(itemLayer.item,itemLayer); } else if (itemLayer.item.itemType == 'vnd.farmmaps.itemtype.layer') { - let data = itemLayer.item.data as ILayerData; - switch (data.interfaceType) { - case 'OSM': { - let source = new OSM(); - layer = new Tile({ source: source }); - break; - } - case 'BingMaps': { - let source = new BingMaps(data.options); - layer = new Tile({ source: source }); - break; - } - case 'TileWMS': { - let source = new TileWMS(data.options); - layer = new Tile({ source: source }); - break; - } - case 'TileArcGISRest': { - let source = new TileArcGISRest(data.options); - layer = new Tile({ source: source }); - break; - } - default: { - break; - } - } + layer = this.createExternalLayer(itemLayer.item,itemLayer); } if (layer) { let geometry = new GeoJSON().readGeometry(itemLayer.item.geometry); @@ -229,33 +250,51 @@ export class ItemLayersComponent extends LayerGroupComponent implements OnChange this.updateLayers(this.itemLayers); } - updateLayers(itemLayers: IItemLayer[]) { - if (itemLayers) { - var olLayers = this.instance.getLayers(); - itemLayers.forEach((itemLayer, index) => { + addOrUpdateOlLayer(itemLayer:IItemLayer,index:number):Layer { + if(!itemLayer) return null; + var olLayers = this.instance.getLayers(); + var layer = itemLayer.layer; + let olIndex = olLayers.getArray().indexOf(layer); + if (olIndex < 0) { + // New layer: we add it to the map + layer = this.createLayer(itemLayer); + if (layer) { + olLayers.insertAt(index, layer); + } + } else if (index !== olIndex) { + // layer has moved inside the layers list + olLayers.removeAt(olIndex); + olLayers.insertAt(index, layer); + } + if(layer) { + itemLayer.layer = layer; + layer.setOpacity(itemLayer.opacity); + layer.setVisible(itemLayer.visible); + } + return layer; + } - var layer = itemLayer.layer; - let olIndex = olLayers.getArray().indexOf(layer); - if (olIndex < 0) { - // New layer: we add it to the map - layer = this.createLayer(itemLayer); - if (layer) { - itemLayer.layer = layer; - } - olLayers.insertAt(index, layer); - } else if (index !== olIndex) { - // layer has moved inside the layers list - olLayers.removeAt(olIndex); - olLayers.insertAt(index, layer); + updateLayers(itemLayers: IItemLayer[]) { + let newLayers: IItemLayer[] = []; + if (itemLayers) { + itemLayers.forEach((itemLayer, index) => { + if(itemLayer.item.itemType == 'vnd.farmmaps.itemtype.temporal') { + let il = itemLayer as ITemporalItemLayer; + let previousLayer = this.addOrUpdateOlLayer(il.previousItemLayer,newLayers.length); + if(previousLayer) newLayers.push(previousLayer); + let selectedLayer = this.addOrUpdateOlLayer(il.selectedItemLayer,newLayers.length); + if(selectedLayer) newLayers.push(selectedLayer); + let nextLayer = this.addOrUpdateOlLayer(il.nextItemLayer,newLayers.length); + if(nextLayer) newLayers.push(nextLayer); + } else { + let layer = this.addOrUpdateOlLayer(itemLayer,newLayers.length); + if(layer) newLayers.push(layer); } - layer.setOpacity(itemLayer.opacity); - layer.setVisible(itemLayer.visible); }); // Remove the layers that have disapeared from childrenLayers - if (olLayers.getLength() > itemLayers.length) { - for (let i = itemLayers.length; i < olLayers.getLength(); i++) { - olLayers.removeAt(i); - } + var olLayers = this.instance.getLayers(); + while(olLayers.getLength() > newLayers.length) { + olLayers.removeAt(newLayers.length); } } } diff --git a/projects/common-map/src/fm-map/components/map/map.component.html b/projects/common-map/src/fm-map/components/map/map.component.html index f6ed7ac..9567fe2 100644 --- a/projects/common-map/src/fm-map/components/map/map.component.html +++ b/projects/common-map/src/fm-map/components/map/map.component.html @@ -57,7 +57,7 @@