import { tassign } from 'tassign'; import { IItem,Item } from '@farmmaps/common'; import { IItemLayer,ItemLayer,ITemporalItemLayer,TemporalItemLayer} from '../models/item.layer'; import { IMapState} from '../models/map.state'; import { IQueryState} from '@farmmaps/common'; import { IPeriodState } from '../models/period.state'; import { IStyles} from '../models/style.cache'; import { ILayervalue } from '../models/layer.value'; import * as mapActions from '../actions/map.actions'; import {commonActions} from '@farmmaps/common'; import { createSelector, createFeatureSelector } from '@ngrx/store'; import {Feature} from 'ol'; import {Geometry} from 'ol/geom'; import { ROUTER_NAVIGATION, RouterNavigationAction } from '@ngrx/router-store'; import { MODULE_NAME } from '../module-name'; const startDate:Date = new Date(new Date(Date.now()).getFullYear(), new Date(Date.now()).getMonth() - 3, 1); const endDate:Date = new Date(Date.now()); export const initialQueryState: IQueryState = { itemCode: null, parentCode: null, level: 1, itemType: null, bboxFilter: false, query: null, tags: null, endDate: null, startDate: null, bbox: [] }; export interface IQuery { querystate: IQueryState, replace: boolean } export interface State { period:IPeriodState, mapState: IMapState, viewExtent: number[], queryState: IQueryState, query:IQuery, parentCode: string, features: Array>, panelVisible: boolean, panelCollapsed: boolean, selectedFeature: Feature, selectedItem:IItem, parentItem:IItem, clearEnabled: boolean, searchCollapsed: boolean, searchMinified: boolean, extent: number[], baseLayers: Array overlayLayers: Array, selectedItemLayer: IItemLayer, projection: string, selectedBaseLayer: IItemLayer, selectedOverlayLayer: IItemLayer, styles:IStyles, showLayerSwitcher:boolean, inSearch:boolean, inZoom:boolean, replaceUrl:boolean, layerValuesX:number, layerValuesY:number, layerValuesEnabled:boolean, layerValues: Array showDataLayerSlide:boolean, } export const initialState: State = { period: { startDate: startDate, endDate: endDate }, mapState: { zoom: 8, rotation: 0, xCenter: 5.377554, yCenter: 52.162422, baseLayerCode: "" }, viewExtent:[], queryState: tassign(initialQueryState), query: null, parentCode: null, features: [], panelVisible: false, panelCollapsed: false, selectedFeature: null, selectedItem: null, parentItem: null, clearEnabled: false, searchCollapsed: true, searchMinified:false, extent: null, baseLayers: [], overlayLayers: [], projection: "EPSG:3857", selectedBaseLayer: null, selectedOverlayLayer: null, selectedItemLayer: null, styles: {}, showLayerSwitcher: false, inSearch:false, inZoom:false, replaceUrl:true, layerValuesX:0, layerValuesY:0, layerValuesEnabled:false, layerValues:[], showDataLayerSlide:false } export function reducer(state = initialState, action: mapActions.Actions | commonActions.Actions | RouterNavigationAction): State { switch (action.type) { case ROUTER_NAVIGATION: { let a = action as RouterNavigationAction; return tassign(state); } case mapActions.SETMAPSTATE: { let a = action as mapActions.SetMapState; return tassign(state, { mapState: a.mapState }); } case mapActions.SETQUERYSTATE: { let a = action as mapActions.SetQueryState; return tassign(state, { queryState: tassign(a.queryState ),replaceUrl:a.replaceUrl}); } case mapActions.SETSTATE: { let a = action as mapActions.SetState; return tassign(state, { mapState: tassign(a.mapState), queryState: tassign(a.queryState)}); } case mapActions.SETVIEWEXTENT: { let a = action as mapActions.SetViewExtent; return tassign(state, { viewExtent: a.extent }); } case mapActions.SETPARENT: { let a = action as mapActions.SetParent; return tassign(state, { parentCode : a.parentCode }); } case mapActions.STARTSEARCHSUCCESS: { let a = action as mapActions.StartSearchSuccess; return tassign(state, { features: a.features, inSearch:false }); } case mapActions.SETFEATURES: { let a = action as mapActions.SetFeatures; return tassign(state, { features: a.features }); } case mapActions.SELECTFEATURE: { let a = action as mapActions.SelectFeature; return tassign(state, { selectedFeature: state.selectedItem?state.selectedFeature: a.feature }); } case mapActions.SELECTITEM: { let a = action as mapActions.SelectItem; let itemCode = state.selectedItem ? state.selectedItem.code : ""; let inSearch = a.itemCode != itemCode; return tassign(state, { selectedItem: null, selectedItemLayer: null, showDataLayerSlide: false, features:[], inSearch:inSearch }); } case mapActions.SELECTITEMSUCCESS: { let a = action as mapActions.SelectItemSuccess; return tassign(state, { inSearch:false, selectedItem: a.item, parentItem: a.parentItem, panelVisible: a.item != null, clearEnabled: a.item != null, searchCollapsed: false, searchMinified: true, queryState: tassign(state.queryState, {itemCode:a.item ? a.item.code:null}) }); } case mapActions.SETSELECTEDITEMLAYER: { let a = action as mapActions.SetSelectedItemLayer; var itemLayer = null; if (a.item && "vnd.farmmaps.itemtype.layer,vnd.farmmaps.itemtype.shape.processed,vnd.farmmaps.itemtype.geotiff.processed".indexOf(a.item.itemType) >=0 ) { itemLayer = new ItemLayer(a.item); itemLayer.layerIndex = a.layerIndex>=0?a.layerIndex:a.item.data.layers?a.item.data.layers[0].index:-1; } else if (a.item && a.item.itemType == "vnd.farmmaps.itemtype.temporal") { itemLayer = new TemporalItemLayer(a.item); } return tassign(state, { selectedItemLayer: itemLayer, }); } case mapActions.SELECTTEMPORALITEMSSUCCESS:{ let a = action as mapActions.SelectTemporalItemsSuccess; let selectedItemLayer=tassign(state.selectedItemLayer) as TemporalItemLayer; let layerIndex=-1; selectedItemLayer.temporalItems = a.temporalItems; if(a.temporalItems.length>0) { let item = a.temporalItems[a.temporalItems.length-1]; layerIndex = item.data.layers[0].index; selectedItemLayer.selectedItemLayer = new ItemLayer(item,1,true,layerIndex); } else { selectedItemLayer.selectedItemLayer = null; } selectedItemLayer.previousItemLayer = a.temporalItems.length>1?new ItemLayer(a.temporalItems[a.temporalItems.length-2],0,true,layerIndex):null; selectedItemLayer.nextItemLayer = null; if(selectedItemLayer.selectedItemLayer) { let layerIndex = selectedItemLayer.selectedItemLayer.item.data.layers[0].index; selectedItemLayer.layerIndex = layerIndex; } return tassign(state,{selectedItemLayer:tassign(state.selectedItemLayer,selectedItemLayer as ItemLayer)}); } case mapActions.NEXTTEMPORAL: { let temporalLayer = state.selectedItemLayer as ITemporalItemLayer; if(temporalLayer.temporalItems && temporalLayer.temporalItems.length>0) { let index = temporalLayer.temporalItems.indexOf(temporalLayer.selectedItemLayer.item); if(index == (temporalLayer.temporalItems.length-1)) { return state; } else { temporalLayer.previousItemLayer = temporalLayer.selectedItemLayer; if( temporalLayer.previousItemLayer) { temporalLayer.previousItemLayer.opacity=0; temporalLayer.previousItemLayer.layerIndex = temporalLayer.layerIndex; } temporalLayer.selectedItemLayer = temporalLayer.nextItemLayer; if( temporalLayer.selectedItemLayer) { temporalLayer.selectedItemLayer.opacity=1; temporalLayer.selectedItemLayer.layerIndex=temporalLayer.layerIndex; } temporalLayer.nextItemLayer = index+2 < temporalLayer.temporalItems.length ? new ItemLayer(temporalLayer.temporalItems[index+2],0,true,temporalLayer.layerIndex):null; if( temporalLayer.nextItemLayer) { temporalLayer.nextItemLayer.opacity=0; temporalLayer.nextItemLayer.layerIndex = temporalLayer.layerIndex; } return tassign(state,{selectedItemLayer:tassign(state.selectedItemLayer,temporalLayer as ItemLayer)}); } } else { return state; } } case mapActions.PREVIOUSTEMPORAL: { let temporalLayer = state.selectedItemLayer as ITemporalItemLayer; if(temporalLayer.temporalItems && temporalLayer.temporalItems.length>0) { let index = temporalLayer.temporalItems.indexOf(temporalLayer.selectedItemLayer.item); if(index == 0) { return state; } else { temporalLayer.nextItemLayer = temporalLayer.selectedItemLayer; if( temporalLayer.nextItemLayer) { temporalLayer.nextItemLayer.opacity=0; temporalLayer.nextItemLayer.layerIndex = temporalLayer.layerIndex; } temporalLayer.selectedItemLayer = temporalLayer.previousItemLayer; if( temporalLayer.selectedItemLayer) { temporalLayer.selectedItemLayer.opacity=1; temporalLayer.selectedItemLayer.layerIndex = temporalLayer.layerIndex; } temporalLayer.previousItemLayer = index-2 >=0? new ItemLayer(temporalLayer.temporalItems[index-2],0,true,temporalLayer.layerIndex):null; if( temporalLayer.previousItemLayer) { temporalLayer.previousItemLayer.opacity=0; temporalLayer.previousItemLayer.layerIndex = temporalLayer.layerIndex; } return tassign(state,{selectedItemLayer:tassign(state.selectedItemLayer,temporalLayer as ItemLayer)}); } } else { return state; } } case mapActions.SELECTTEMPORAL:{ //todo implement } case mapActions.STARTSEARCH: { let a = action as mapActions.StartSearch; let panelVisible = a.queryState.itemCode!=null ||a.queryState.itemType!=null||a.queryState.parentCode!=null || a.queryState.query != null || a.queryState.tags != null; return tassign(state, { selectedItem: null, features:[], selectedItemLayer:null, searchCollapsed: !panelVisible, panelVisible: panelVisible, clearEnabled: panelVisible, searchMinified: panelVisible, inSearch:panelVisible }); } case commonActions.FAIL:{ return tassign(state,{inSearch:false}); } case mapActions.DOQUERY: { let a = action as mapActions.DoQuery; return tassign(state, { query: tassign(state.query, { querystate: tassign(a.query, { bbox: a.query.bboxFilter ? state.viewExtent : [] }), replace:a.replace }) }) } case mapActions.SETPERIOD: { return tassign(state,{ period: action.period}); } case mapActions.ADDFEATURESUCCESS: { let a = action as mapActions.AddFeatureSuccess; let features = state.features.slice(); features.push(a.feature); return tassign(state, { panelVisible: true, selectedFeature: a.feature, extent: a.feature.getGeometry().getExtent(), searchCollapsed: false, clearEnabled:true, features:features }); } case mapActions.UPDATEFEATURESUCCESS: { let a = action as mapActions.UpdateFeatureSuccess; let features: any[] = []; var index = -1; for (var i = 0; i < state.features.length; i++) { if (state.features[i].getId() == a.feature.getId()) { features.push(a.feature); } else { features.push(state.features[i]); } } return tassign(state, { features: features }); } case mapActions.EXPANDSEARCH: { return tassign(state, { searchCollapsed: false }); } case mapActions.COLLAPSESEARCH: { return tassign(state, { searchCollapsed: state.panelVisible ? false: true}); } case commonActions.CLOSEALL: { return tassign(state, { searchCollapsed: state.panelVisible ? false: true,showLayerSwitcher:false}); } case mapActions.SETEXTENT: { let a = action as mapActions.SetExtent; return tassign(state, { extent: a.extent }); } case mapActions.ADDLAYER: { let a = action as mapActions.AddLayer; let itemLayers = state.overlayLayers.slice(0); let itemLayer = new ItemLayer(a.item); itemLayer.layerIndex = a.layerIndex == -1 ? 0 : a.layerIndex; let existing = itemLayers.filter(il => il.item.code == itemLayer.item.code && il.layerIndex == itemLayer.layerIndex); if(existing.length==0) { itemLayers.push(itemLayer); return tassign(state, { overlayLayers: itemLayers, selectedOverlayLayer: itemLayer }); } else { return state; } } case mapActions.REMOVELAYER: { let a = action as mapActions.RemoveLayer; let newLayers = state.overlayLayers.slice(0); let i = state.overlayLayers.indexOf(a.itemLayer); var selectedOverlayLayer: IItemLayer = null; if (i>0 && state.overlayLayers.length > 1) selectedOverlayLayer = state.overlayLayers[i - 1]; else if (i == 0 && state.overlayLayers.length > 1) selectedOverlayLayer = state.overlayLayers[i + 1]; newLayers.splice(i, 1); return tassign(state, { overlayLayers: newLayers, selectedOverlayLayer: selectedOverlayLayer }); } case mapActions.CLEARLAYERS: { return tassign(state, {overlayLayers: [], selectedOverlayLayer: null}); } case mapActions.SETVISIBILITY: { let a = action as mapActions.SetVisibility; if(state.selectedItemLayer == a.itemLayer) { return tassign(state,{selectedItemLayer: tassign(state.selectedItemLayer,{visible:a.visibility})}); } else { let newLayers = state.overlayLayers.slice(0); let i = state.overlayLayers.indexOf(a.itemLayer); newLayers[i].visible = a.visibility; return tassign(state, { overlayLayers: newLayers }); } } case mapActions.SETOPACITY: { let a = action as mapActions.SetOpacity; if(state.selectedItemLayer == a.itemLayer) { return tassign(state,{selectedItemLayer: tassign(state.selectedItemLayer,{opacity:a.opacity})}); } else { let newLayers = state.overlayLayers.slice(0); let i = state.overlayLayers.indexOf(a.itemLayer); newLayers[i].opacity = a.opacity; return tassign(state, { overlayLayers: newLayers }); } } case mapActions.SETLAYERINDEX: { let a = action as mapActions.SetLayerIndex; if (a.itemLayer == null) { if(state.selectedItemLayer.item.itemType == "vnd.farmmaps.itemtype.temporal") { var newItemlayer = tassign(state.selectedItemLayer,{layerIndex:a.layerIndex}); let tl = newItemlayer as ITemporalItemLayer; if(tl.previousItemLayer) { let nl = new ItemLayer(tl.previousItemLayer.item); nl.opacity = tl.previousItemLayer.opacity; nl.visible = tl.previousItemLayer.visible; nl.layerIndex = a.layerIndex; tl.previousItemLayer = nl; } if(tl.selectedItemLayer) { let nl = new ItemLayer(tl.selectedItemLayer.item); nl.opacity = tl.selectedItemLayer.opacity; nl.visible = tl.selectedItemLayer.visible; nl.layerIndex = a.layerIndex; tl.selectedItemLayer = nl; } if(tl.nextItemLayer) { let nl = new ItemLayer(tl.nextItemLayer.item); nl.opacity = tl.nextItemLayer.opacity; nl.visible = tl.nextItemLayer.visible; nl.layerIndex = a.layerIndex; tl.nextItemLayer = nl; } } else { var newItemlayer = new ItemLayer(state.selectedItemLayer.item); newItemlayer.layerIndex = a.layerIndex; } return tassign(state, { selectedItemLayer: newItemlayer}) } else { let newLayers = state.overlayLayers.slice(0); let i = state.overlayLayers.indexOf(a.itemLayer); newLayers[i].layerIndex = a.layerIndex; return tassign(state, { overlayLayers: newLayers }); } } case mapActions.LOADBASELAYERSSUCCESS: { let a =action as mapActions.LoadBaseLayersSuccess; let baseLayers:ItemLayer[] = []; for (let item of a.items) { var l = new ItemLayer(item); l.visible = false; baseLayers.push(l); } var selectedBaseLayer: IItemLayer = null; var mapState = tassign(state.mapState); let sb = baseLayers.filter(layer => layer.item.code === mapState.baseLayerCode); let db = baseLayers.filter(layer => layer.item.data && layer.item.data.default === true); if (baseLayers.length > 0 && mapState.baseLayerCode != "" && sb.length>0) { selectedBaseLayer = sb[0]; selectedBaseLayer.visible = true; } else if (baseLayers.length >0 && db.length>0){ selectedBaseLayer = db[0]; selectedBaseLayer.visible = true; } else if (baseLayers.length > 0) { selectedBaseLayer = baseLayers[0]; selectedBaseLayer.visible = true; mapState.baseLayerCode = selectedBaseLayer.item.code; } return tassign(state, { mapState:mapState, baseLayers: baseLayers, selectedBaseLayer: selectedBaseLayer }); } case mapActions.SELECTBASELAYER: { let a = action as mapActions.SelectBaseLayer; let baseLayers = state.baseLayers.slice(0); baseLayers.forEach((l) => l.visible = false); let i = state.baseLayers.indexOf(a.itemLayer); baseLayers[i].visible = true; var mapState = tassign(state.mapState); mapState.baseLayerCode = a.itemLayer.item.code; return tassign(state, {mapState:mapState, baseLayers:baseLayers,selectedBaseLayer:a.itemLayer }); } case mapActions.SELECTOVERLAYLAYER: { let a = action as mapActions.SelectOverlayLayer; return tassign(state, { selectedOverlayLayer: a.itemLayer }); } case mapActions.CLEAR: { let newQueryState = tassign(state.queryState, { query: null, tags: null, itemCode: null, parentCode: null, itemType: null }); return tassign(state, { panelVisible: false, panelCollapsed:false, selectedItem: null, selectedItemLayer: null, selectedFeature: null, queryState: newQueryState, clearEnabled: false, layerValuesEnabled: false, searchCollapsed: true, searchMinified: false, features: [], query:initialState.query, showLayerSwitcher: false, extent: null, showDataLayerSlide: false }); } case mapActions.SETSTYLE:{ let a = action as mapActions.SetStyle; let styles = tassign(state.styles); styles[a.itemType] = a.style; return tassign(state,{styles:styles}); } case mapActions.SHOWLAYERSWITCHER:{ let a = action as mapActions.ShowLayerSwitcher; return tassign(state,{showLayerSwitcher:a.show}); } case mapActions.TOGGLESHOWDATALAYERSLIDE:{ return tassign(state,{showDataLayerSlide:!state.showDataLayerSlide}); } case mapActions.SETREPLACEURL: { let a= action as mapActions.SetReplaceUrl; return tassign(state,{replaceUrl:a.replaceUrl}); } case mapActions.TOGGLELAYERVALUESENABLED: { return tassign(state,{layerValuesEnabled:!state.layerValuesEnabled}); } case mapActions.SETLAYERVALUESLOCATION: { let a= action as mapActions.SetLayerValuesLocation; return tassign(state,{layerValuesX: a.x, layerValuesY:a.y,layerValues:[]}); } case mapActions.GETLAYERVALUESUCCESS:{ let a= action as mapActions.GetLayerValueSuccess; let v = state.layerValues.slice(0); v.push(a.layervalue); return tassign(state,{layerValues:v}); } case commonActions.ITEMDELETEDEVENT:{ let a= action as commonActions.ItemDeletedEvent; if(state.selectedItem && state.selectedItem.code == a.itemCode) { return tassign(state,{ selectedItem: null, selectedItemLayer: null, showDataLayerSlide: false, features:[] }); } if(state.features.length>0) { var index = -1; for (var i = 0; i < state.features.length; i++) { if (state.features[i].getId() == a.itemCode ) { index=i; } } if(index>=0) { let newFeatures = state.features.slice(0); newFeatures.splice(index,1); return tassign(state,{features:newFeatures}); } } return state; } default: { return state; } } } export const getMapState = (state: State) => state.mapState; export const getParentCode = (state: State) => state.parentCode; export const getFeatures = (state: State) => state.features; export const getPanelVisible = (state: State) => state.panelVisible; export const getPanelCollapsed = (state: State) => state.panelCollapsed; export const getSelectedFeature = (state: State) => state.selectedFeature; export const getSelectedItem = (state: State) => state.selectedItem; export const getParentItem = (state: State) => state.parentItem; export const getQueryState = (state: State) => state.queryState; export const getClearEnabled = (state: State) => state.clearEnabled; export const getSearchCollapsed = (state: State) => state.searchCollapsed; export const getSearchMinified = (state: State) => state.searchMinified; export const getExtent = (state: State) => state.extent; export const getOverlayLayers = (state: State) => state.overlayLayers; export const getBaseLayers = (state: State) => state.baseLayers; export const getProjection = (state: State) => state.projection; export const getSelectedBaseLayer = (state: State) => state.selectedBaseLayer; export const getSelectedOverlayLayer = (state: State) => state.selectedOverlayLayer; export const getQuery = (state: State) => state.query; export const getSelectedItemLayer = (state: State) => state.selectedItemLayer; export const getPeriod = (state:State) => state.period; export const getStyles = (state:State) => state.styles; export const getShowLayerSwitcher = (state:State) => state.showLayerSwitcher; export const getShowDataLayerSlide = (state:State) => state.showDataLayerSlide; export const getInSearch = (state:State) => state.inSearch; export const getState = (state:State) => {return {mapState:state.mapState,queryState:state.queryState,replaceUrl:state.replaceUrl};} export const getLayerValuesEnabled = (state:State) => state.layerValuesEnabled; export const getLayerValues = (state:State) => state.layerValues; export const getLayerValuesX = (state:State) => state.layerValuesX; export const getLayerValuesY = (state:State) => state.layerValuesY; export const selectMapState = createFeatureSelector(MODULE_NAME); export const selectGetMapState= createSelector(selectMapState, getMapState); export const selectGetParentCode = createSelector(selectMapState, getParentCode); export const selectGetFeatures = createSelector(selectMapState, getFeatures); export const selectGetPanelVisible = createSelector(selectMapState, getPanelVisible); export const selectGetPanelCollapsed = createSelector(selectMapState, getPanelCollapsed); export const selectGetSelectedFeature = createSelector(selectMapState, getSelectedFeature); export const selectGetSelectedItem = createSelector(selectMapState, getSelectedItem); export const selectGetParentItem = createSelector(selectMapState, getParentItem); export const selectGetQueryState = createSelector(selectMapState, getQueryState); export const selectGetClearEnabled = createSelector(selectMapState, getClearEnabled); export const selectGetSearchCollapsed = createSelector(selectMapState, getSearchCollapsed); export const selectGetSearchMinified = createSelector(selectMapState, getSearchMinified); export const selectGetExtent = createSelector(selectMapState, getExtent); export const selectGetOverlayLayers = createSelector(selectMapState, getOverlayLayers); export const selectGetBaseLayers = createSelector(selectMapState, getBaseLayers); export const selectGetProjection = createSelector(selectMapState, getProjection); export const selectGetSelectedBaseLayer = createSelector(selectMapState, getSelectedBaseLayer); export const selectGetSelectedOverlayLayer = createSelector(selectMapState, getSelectedOverlayLayer); export const selectGetQuery = createSelector(selectMapState, getQuery); export const selectGetSelectedItemLayer = createSelector(selectMapState, getSelectedItemLayer); export const selectGetPeriod = createSelector(selectMapState, getPeriod); export const selectGetStyles = createSelector(selectMapState, getStyles); export const selectGetShowLayerSwitcher = createSelector(selectMapState,getShowLayerSwitcher); export const selectGetShowdataLayerSlide = createSelector(selectMapState,getShowDataLayerSlide); export const selectGetInSearch = createSelector(selectMapState,getInSearch); export const selectGetState = createSelector(selectMapState,getState); export const selectGetLayerValuesEnabled = createSelector(selectMapState,getLayerValuesEnabled); export const selectGetLayerValues = createSelector(selectMapState,getLayerValues); export const selectGetLayerValuesX = createSelector(selectMapState,getLayerValuesX); export const selectGetLayerValuesY = createSelector(selectMapState,getLayerValuesY);