Some refactoring

This commit is contained in:
Willem Dantuma 2020-04-21 12:31:20 +02:00
parent c6d7f6b0cb
commit 4e83bc6158
3 changed files with 129 additions and 89 deletions

View File

@ -1,8 +1,8 @@
import { Component, OnInit, OnDestroy, HostListener, Inject, ViewChild, AfterViewInit,ChangeDetectorRef,NgZone } from '@angular/core'; import { Component, OnInit, OnDestroy, HostListener, ViewChild, AfterViewInit,NgZone } from '@angular/core';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { Observable, Subject, Subscription,combineLatest, from,interval } from 'rxjs'; import { Observable, Subject, Subscription, from,of } from 'rxjs';
import { debounce, withLatestFrom, first, combineAll,throttle } from 'rxjs/operators'; import { withLatestFrom, switchMap } from 'rxjs/operators';
import { Router, ActivatedRoute, ParamMap, Event } from '@angular/router'; import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
//import { proj,Map } from 'openlayers'; //import { proj,Map } from 'openlayers';
@ -16,7 +16,6 @@ import { IQueryState } from '@farmmaps/common';
import { IPeriodState } from '../../models/period.state'; import { IPeriodState } from '../../models/period.state';
import {IStyles} from '../../models/style.cache'; import {IStyles} from '../../models/style.cache';
import { IDroppedFile } from '../aol/file-drop-target/file-drop-target.component'; import { IDroppedFile } from '../aol/file-drop-target/file-drop-target.component';
import { IMetaData } from '../meta-data-modal/meta-data-modal.component';
import { StateSerializerService } from '@farmmaps/common'; import { StateSerializerService } from '@farmmaps/common';
import { GeolocationService} from '../../services/geolocation.service'; import { GeolocationService} from '../../services/geolocation.service';
import {DeviceOrientationService} from '../../services/device-orientation.service'; import {DeviceOrientationService} from '../../services/device-orientation.service';
@ -30,7 +29,6 @@ import {commonActions} from '@farmmaps/common';
import {Feature} from 'ol'; import {Feature} from 'ol';
import {Extent,createEmpty,extend } from 'ol/extent'; import {Extent,createEmpty,extend } from 'ol/extent';
import {transform} from 'ol/proj'; import {transform} from 'ol/proj';
import { query } from '@angular/animations';
import { tassign } from 'tassign'; import { tassign } from 'tassign';
import * as style from 'ol/style'; import * as style from 'ol/style';
@ -57,7 +55,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
public droppedFile$: Subject<IDroppedFile> = new Subject<IDroppedFile>(); public droppedFile$: Subject<IDroppedFile> = new Subject<IDroppedFile>();
private paramSub: Subscription; private paramSub: Subscription;
private itemTypeSub: Subscription; private itemTypeSub: Subscription;
private mapStateSub: Subscription; private stateSub: Subscription;
private queryStateSub: Subscription; private queryStateSub: Subscription;
private querySub: Subscription; private querySub: Subscription;
public parentCode$: Observable<string> =this.store.select(mapReducers.selectGetParentCode); public parentCode$: Observable<string> =this.store.select(mapReducers.selectGetParentCode);
@ -67,6 +65,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
public clickedFeature: Subject<Feature> = new Subject<Feature>(); public clickedFeature: Subject<Feature> = new Subject<Feature>();
public selectedItem$: Observable<IItem> = this.store.select(mapReducers.selectGetSelectedItem); public selectedItem$: Observable<IItem> = this.store.select(mapReducers.selectGetSelectedItem);
public queryState$: Observable<IQueryState> = this.store.select(mapReducers.selectGetQueryState); public queryState$: Observable<IQueryState> = this.store.select(mapReducers.selectGetQueryState);
public state$:Observable<{mapState:IMapState,queryState:IQueryState,setStateCount:number}> = this.store.select(mapReducers.selectGetState);
public period$: Observable<IPeriodState> = this.store.select(mapReducers.selectGetPeriod); public period$: Observable<IPeriodState> = this.store.select(mapReducers.selectGetPeriod);
public clearEnabled$: Observable<boolean> = this.store.select(mapReducers.selectGetClearEnabled); public clearEnabled$: Observable<boolean> = this.store.select(mapReducers.selectGetClearEnabled);
public searchCollapsed$: Observable<boolean> = this.store.select(mapReducers.selectGetSearchCollapsed); public searchCollapsed$: Observable<boolean> = this.store.select(mapReducers.selectGetSearchCollapsed);
@ -80,6 +79,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
public extent$: Observable<Extent> = this.store.select(mapReducers.selectGetExtent); public extent$: Observable<Extent> = this.store.select(mapReducers.selectGetExtent);
public styles$:Observable<IStyles> = this.store.select(mapReducers.selectGetStyles); public styles$:Observable<IStyles> = this.store.select(mapReducers.selectGetStyles);
private setStateCount$:Observable<number> = this.store.select(mapReducers.selectgetSetStateCount); private setStateCount$:Observable<number> = this.store.select(mapReducers.selectgetSetStateCount);
private lastUrl = "";
@ViewChild('map') map; @ViewChild('map') map;
@ -121,19 +121,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
} }
} }
} }
}); });
this.mapStateSub = this.mapState$.pipe(withLatestFrom(this.queryState$),withLatestFrom(this.setStateCount$)).subscribe(([[mapState,queryState],setStateCount]) =>{
if(setStateCount>0) {
console.debug(`Mapstate ${setStateCount}`);
this.replaceUrl(mapState,queryState,true);
}
});
this.queryStateSub = this.queryState$.pipe(withLatestFrom(this.mapState$),withLatestFrom(this.setStateCount$)).subscribe(([[queryState,mapState],setStateCount]) =>{
if(setStateCount>0) {
console.debug(`Querystate ${setStateCount}`);
this.replaceUrl(mapState,queryState,true);
}
})
} }
@HostListener('document:keyup', ['$event']) @HostListener('document:keyup', ['$event'])
@ -172,8 +160,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
console.debug("Init"); console.debug("Init");
this.store.dispatch(new mapActions.Clear()); this.store.dispatch(new mapActions.Clear());
this.selectedFeatures$.next({x:0,y:0,features:[]}); this.selectedFeatures$.next({x:0,y:0,features:[]});
this.selectedFeatures$.next(null); this.selectedFeatures$.next(null);
} }
initCustomStyles() { initCustomStyles() {
@ -195,47 +182,107 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
}))); })));
} }
round(value:number,decimals:number):number {
let d = Math.pow(10, decimals);
return Math.round((value + Number.EPSILON)*d)/d;
}
getMapStateFromUrl(params:ParamMap):IMapState {
var hasUrlmapState = params.has("xCenter") && params.has("yCenter");
if (hasUrlmapState) {
let xCenter = parseFloat(params.get("xCenter"));
let yCenter = parseFloat(params.get("yCenter"));
let zoom = parseFloat(params.get("zoom"));
let rotation = parseFloat(params.get("rotation"));
let baseLayer = params.get("baseLayer")?params.get("baseLayer"):"";
var newMapState = {zoom: zoom, rotation: rotation, xCenter: xCenter, yCenter: yCenter, baseLayerCode: baseLayer };
return newMapState;
} else {
return null;
}
}
normalizeMapState(mapState:IMapState):IMapState {
if(!mapState) return null;
return {zoom: this.round(mapState.zoom,0),
rotation: this.round(mapState.rotation,2),
xCenter: this.round(mapState.xCenter,5),
yCenter: this.round(mapState.yCenter,5),
baseLayerCode: mapState.baseLayerCode };
}
serializeMapState(mapState:IMapState):string {
return JSON.stringify(this.normalizeMapState(mapState));
}
getQueryStateFromUrl(params:ParamMap):IQueryState {
if (params.has("queryState")) {
let queryState = params.get("queryState");
var newQueryState = tassign(mapReducers.initialQueryState);
if (queryState != "") {
newQueryState = this.serializeService.deserialize(queryState);
}
return newQueryState;
} else {
return null;
}
}
ngAfterViewInit() { ngAfterViewInit() {
console.debug("View init"); console.debug("View init");
this.initCustomStyles(); this.initCustomStyles();
this.paramSub = this.route.paramMap.pipe(withLatestFrom(this.setStateCount$),withLatestFrom(this.queryState$),withLatestFrom(this.mapState$)).subscribe( ([[[params,setStateCount],lastQueryState],lastMapState]) => {
console.debug(`Url change ${setStateCount}`); // url to state
var newMapState: IMapState = lastMapState;
var newQueryState: IQueryState = lastQueryState; this.paramSub = this.route.paramMap.pipe(withLatestFrom(this.state$),switchMap(([params,state]) => {
var hasUrlmapState = params.has("xCenter") && params.has("yCenter"); var newMapState: IMapState = state.mapState;
var newQueryState: IQueryState = state.queryState;
var queryStateChanged = false; var queryStateChanged = false;
if (hasUrlmapState) { var mapStateChanged = false;
let xCenter = parseFloat(params.get("xCenter")); let urlMapState = this.getMapStateFromUrl(params);
let yCenter = parseFloat(params.get("yCenter")); if(urlMapState) {
let zoom = parseFloat(params.get("zoom")); newMapState = urlMapState;
let rotation = parseFloat(params.get("rotation")); mapStateChanged = this.serializeMapState(state.mapState) != this.serializeMapState(newMapState);
let baseLayer = params.get("baseLayer")?params.get("baseLayer"):"";
newMapState = { xCenter: xCenter, yCenter: yCenter, zoom: zoom, rotation: rotation, baseLayerCode: baseLayer }
window.localStorage.setItem("FarmMapsCommonMap_mapState",JSON.stringify(newMapState));
} }
if (params.has("queryState")) {
let queryState = params.get("queryState"); let urlQueryState = this.getQueryStateFromUrl(params);
newQueryState = tassign(mapReducers.initialQueryState); if(urlQueryState) {
if (queryState != "") { newQueryState = urlQueryState;
newQueryState = this.serializeService.deserialize(queryState); queryStateChanged = this.serializeService.serialize(state.queryState) != this.serializeService.serialize(urlQueryState);
queryState = this.serializeService.serialize(newQueryState); }
}
queryStateChanged = this.serializeService.serialize(lastQueryState) != queryState; if(queryStateChanged || mapStateChanged) {
} return of(new mapActions.SetState(newMapState,newQueryState));
console.debug(newQueryState); } else {
console.debug(queryStateChanged?"Changed":""); return of(null);
let t =0; }
if(setStateCount==0) t=600; })).subscribe((action) => {
setTimeout(() => { if(action) {
this.zone.run(()=> { window.localStorage.setItem("FarmMapsCommonMap_mapState",this.serializeMapState(action.mapState));
if (setStateCount ==0) { console.debug("Url to state");
this.store.dispatch(new mapActions.SetState(newMapState,newQueryState)); this.store.dispatch(action);
} else if(queryStateChanged) { }
this.store.dispatch(new mapActions.SetQueryState(newQueryState));
}
})
},t);
}); });
// state to url
this.stateSub = this.state$.pipe(withLatestFrom(this.route.paramMap),switchMap(([state,params]) => {
let newUrl = this.serializeMapState(state.mapState) + "_" + this.serializeService.serialize(state.queryState);
if(this.lastUrl!=newUrl && state.setStateCount>0) {
this.lastUrl=newUrl;
return of(state);
}
else {
return of(null);
}
})).subscribe((newUrlState) =>{
if(newUrlState) {
console.debug(`State to url ${newUrlState.setStateCount}`);
this.replaceUrl(newUrlState.mapState,newUrlState.queryState,true);
}
});
setTimeout(() => { setTimeout(() => {
this.map.instance.updateSize(); this.map.instance.updateSize();
}, 500); }, 500);
@ -278,7 +325,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
if(mapState.baseLayerCode!="") { if(mapState.baseLayerCode!="") {
parts.push(mapState.baseLayerCode); parts.push(mapState.baseLayerCode);
parts.push( this.serializeService.serialize(queryState)); parts.push( this.serializeService.serialize(queryState));
console.debug("Replace url",mapState,queryState,replace); console.debug("Replace url",parts);
this.router.navigate(parts, { replaceUrl: replace,relativeTo:this.route.parent }); this.router.navigate(parts, { replaceUrl: replace,relativeTo:this.route.parent });
} }
} }
@ -296,7 +343,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
let state = { mapState: mapState, extent: extent }; let state = { mapState: mapState, extent: extent };
let source = from([state]); let source = from([state]);
source.pipe(withLatestFrom(this.selectedBaseLayer$),withLatestFrom(this.setStateCount$)).subscribe(([[state, baselayer],setStateCount]) => { source.pipe(withLatestFrom(this.selectedBaseLayer$),withLatestFrom(this.setStateCount$)).subscribe(([[state, baselayer],setStateCount]) => {
if (mapState && baselayer && setStateCount > 0) { // do not react on first move if (mapState && baselayer) { // do not react on first move
let newMapState = tassign(state.mapState, { baseLayerCode: baselayer.item.code }); let newMapState = tassign(state.mapState, { baseLayerCode: baselayer.item.code });
this.store.dispatch(new mapActions.SetMapState(newMapState)); this.store.dispatch(new mapActions.SetMapState(newMapState));
this.store.dispatch(new mapActions.SetViewExtent(state.extent)); this.store.dispatch(new mapActions.SetViewExtent(state.extent));
@ -350,7 +397,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
ngOnDestroy() { ngOnDestroy() {
if (this.paramSub) this.paramSub.unsubscribe(); if (this.paramSub) this.paramSub.unsubscribe();
if (this.itemTypeSub) this.itemTypeSub.unsubscribe(); if (this.itemTypeSub) this.itemTypeSub.unsubscribe();
if (this.mapStateSub) this.mapStateSub.unsubscribe(); if (this.stateSub) this.stateSub.unsubscribe();
if (this.queryStateSub) this.queryStateSub.unsubscribe(); if (this.queryStateSub) this.queryStateSub.unsubscribe();
if (this.querySub) this.querySub.unsubscribe(); if (this.querySub) this.querySub.unsubscribe();
} }

View File

@ -27,6 +27,7 @@ import {FeatureIconService} from '../services/feature-icon.service';
import * as style from 'ol/style'; import * as style from 'ol/style';
import { ItemTypeService } from '@farmmaps/common'; import { ItemTypeService } from '@farmmaps/common';
import { IQueryState } from 'dist/common/public-api';
@Injectable() @Injectable()
@ -248,23 +249,27 @@ export class MapEffects {
} }
})); }));
getActionFromQueryState(queryState:IQueryState, inSearch:boolean):Observable<Action>|[] {
if(!inSearch && (queryState.itemType || queryState.parentCode || queryState.itemType)) {
var newAction:Action;
if (queryState.itemCode && queryState.itemCode != "") {
newAction= new mapActions.SelectItem(queryState.itemCode);
} else {
newAction= new mapActions.StartSearch(queryState);
}
return of(newAction);
} else {
return [];
}
}
@Effect() @Effect()
setQueryState$: Observable<Action> = this.actions$.pipe( setQueryState$: Observable<Action> = this.actions$.pipe(
ofType(mapActions.SETQUERYSTATE), ofType(mapActions.SETQUERYSTATE),
withLatestFrom(this.store$.select(mapReducers.selectGetInSearch)), withLatestFrom(this.store$.select(mapReducers.selectGetInSearch)),
switchMap(([action,inSearch]) => { switchMap(([action,inSearch]) => {
if(!inSearch) { let a = action as mapActions.SetQueryState;
let a = action as mapActions.SetQueryState; return this.getActionFromQueryState(a.queryState,inSearch);
var newAction:Action;
if (a.queryState.itemCode && a.queryState.itemCode != "") {
newAction= new mapActions.SelectItem(a.queryState.itemCode);
} else {
newAction= new mapActions.StartSearch(a.queryState);
}
return of(newAction);
} else {
return [];
}
})); }));
@Effect() @Effect()
@ -272,18 +277,8 @@ export class MapEffects {
ofType(mapActions.SETSTATE), ofType(mapActions.SETSTATE),
withLatestFrom(this.store$.select(mapReducers.selectGetInSearch)), withLatestFrom(this.store$.select(mapReducers.selectGetInSearch)),
switchMap(([action,inSearch]) => { switchMap(([action,inSearch]) => {
if(!inSearch) { let a = action as mapActions.SetState;
let a = action as mapActions.SetQueryState; return this.getActionFromQueryState(a.queryState,inSearch);
var newAction:Action;
if (a.queryState.itemCode && a.queryState.itemCode != "") {
newAction= new mapActions.SelectItem(a.queryState.itemCode);
} else {
newAction= new mapActions.StartSearch(a.queryState);
}
return of(newAction);
} else {
return [];
}
})); }));
constructor(private actions$: Actions, private store$: Store<mapReducers.State>, private folderService$: FolderService, private itemService$: ItemService,private featureIconService$:FeatureIconService,private itemTypeService$:ItemTypeService) { constructor(private actions$: Actions, private store$: Store<mapReducers.State>, private folderService$: FolderService, private itemService$: ItemService,private featureIconService$:FeatureIconService,private itemTypeService$:ItemTypeService) {

View File

@ -466,11 +466,7 @@ export function reducer(state = initialState, action: mapActions.Actions | commo
case mapActions.SHOWLAYERSWITCHER:{ case mapActions.SHOWLAYERSWITCHER:{
let a = action as mapActions.ShowLayerSwitcher; let a = action as mapActions.ShowLayerSwitcher;
return tassign(state,{showLayerSwitcher:a.show}); return tassign(state,{showLayerSwitcher:a.show});
} }
case commonActions.INITUSER: {
return tassign(state,{setStateCount:0,features:[],selectedFeature:null,selectedItem:null});
}
default: { default: {
return state; return state;
} }
@ -501,6 +497,7 @@ export const getStyles = (state:State) => state.styles;
export const getShowLayerSwitcher = (state:State) => state.showLayerSwitcher; export const getShowLayerSwitcher = (state:State) => state.showLayerSwitcher;
export const getSetStateCount = (state:State) => state.setStateCount; export const getSetStateCount = (state:State) => state.setStateCount;
export const getInSearch = (state:State) => state.inSearch; export const getInSearch = (state:State) => state.inSearch;
export const getState = (state:State) => {return {mapState:state.mapState,queryState:state.queryState,setStateCount:state.setStateCount};}
export const selectMapState = createFeatureSelector<State>(MODULE_NAME); export const selectMapState = createFeatureSelector<State>(MODULE_NAME);
export const selectGetMapState= createSelector(selectMapState, getMapState); export const selectGetMapState= createSelector(selectMapState, getMapState);
@ -527,5 +524,6 @@ export const selectGetStyles = createSelector(selectMapState, getStyles);
export const selectGetShowLayerSwitcher = createSelector(selectMapState,getShowLayerSwitcher); export const selectGetShowLayerSwitcher = createSelector(selectMapState,getShowLayerSwitcher);
export const selectgetSetStateCount = createSelector(selectMapState,getSetStateCount); export const selectgetSetStateCount = createSelector(selectMapState,getSetStateCount);
export const selectGetInSearch = createSelector(selectMapState,getInSearch); export const selectGetInSearch = createSelector(selectMapState,getInSearch);
export const selectGetState = createSelector(selectMapState,getState);