Implement pan to, fix zooming on map change
All checks were successful
FarmMaps.Develop/FarmMapsLib/develop This commit looks good

This commit is contained in:
Willem Dantuma
2020-01-02 18:11:02 +01:00
parent ac5efdb40f
commit 64c02614ba
8 changed files with 325 additions and 173 deletions

View File

@@ -1,58 +1,81 @@
<aol-map #map (onMoveEnd)="handleOnMoveEnd($event)" (click)="handleOnMouseDown($event)" [ngClass]="{'panel-visible':(panelVisible|async)}" class="map">
<div>
</div>
<aol-view [zoom]="(mapState|async).zoom" [rotation]="(mapState|async).rotation">
<aol-coordinate [x]="(mapState|async).xCenter" [y]="(mapState|async).yCenter" [srid]="'EPSG:4326'"></aol-coordinate>
<fm-map-zoom-to-extent [extent]="extent|async" [animate]="true"></fm-map-zoom-to-extent>
</aol-view>
<aol-interaction-default></aol-interaction-default>
<aol-interaction-dragrotateandzoom></aol-interaction-dragrotateandzoom>
<fm-map-item-layers [itemLayers]="baseLayers|async"></fm-map-item-layers>
<fm-map-item-layers [itemLayers]="overlayLayers|async"></fm-map-item-layers>
<fm-map-item-layers [itemLayer]="selectedItemLayer|async"></fm-map-item-layers>
<aol-layer-vector>
<fm-map-item-source-vector [features]="features|async" (onFeaturesSelected)="handleFeaturesSelected($event)" [selectedFeature]="selectedFeature|async" [selectedItem]="selectedItem|async"></fm-map-item-source-vector>
</aol-layer-vector>
<fm-map-gps-location [position]="position|async" [headingTolerance]="20" [showHeading]="true"></fm-map-gps-location>
<div class="control-container">
<!-- <switch2d3d></switch2d3d>-->
<fm-map-rotation-reset></fm-map-rotation-reset>
</div>
<fm-map-file-drop-target [parentCode]="(parentCode | async)" (onFileDropped)="handleFileDropped($event)"></fm-map-file-drop-target>
</aol-map>
<fm-map-map-search #mapSearch [openedModalName]="openedModalName|async" (onOpenModal)="handleOpenModal($event)" (onCloseModal)="handleCloseModal()" [ngClass]="{'menuVisible':(menuVisible|async)}" (onToggleMenu)="handleToggleMenu($event)" (onSearchCollapse)="handleSearchCollapse($event)" (onSearchExpand)="handleSearchExpand($event)" [collapsed]="searchCollapsed|async" [searchMinified]="(searchMinified | async)" (onSearch)="handleSearch($event)" (onClear)="handleClearSearch($event)" [filterOptions]="queryState|async" [clearEnabled]="clearEnabled|async" [period]="period|async"></fm-map-map-search>
<fm-side-panel [resizeable]="true" [visible]="(panelVisible|async)" [collapsed]="(panelCollapsed|async)" [collapsable]="false">
<div class="panel-wrapper">
<div class="panel-top bg-secondary" *ngIf="!(searchMinified | async)">
</div>
<div class="panel-bottom">
<div *ngIf="!(selectedItem|async)">
<fm-map-feature-list-container [features]="(features | async)" [queryState]="(queryState|async)"></fm-map-feature-list-container>
</div>
<div *ngIf="(selectedItem | async);let item">
<fm-map-selected-item-container [item]="item"></fm-map-selected-item-container>
</div>
<div *ngIf="(features|async).length == 0" class="no-results m-2">
<div *ngIf="(queryState|async)?.query">Cannot find <span>{{(queryState|async)?.query}}</span></div>
<div *ngIf="(queryState|async)?.tags">Cannot find tag <span>{{(queryState|async)?.tags}}</span></div>
</div>
</div>
</div>
</fm-side-panel>
<fm-side-panel [visible]="(menuVisible|async)" class="menu">
<div class="container-fluid">
<div class="body">
<div class="d-flex flex-row">
<div class="mt-2 mb-2 flex-grow-1 logo"><router-outlet name="side-panel-logo"></router-outlet></div>
<div class="mt-2 mb-2 ml-2"><button type="button" class="btn btn-outline-secondary" (click)="handleToggleMenu($event)"><i class="fa fa-times" aria-hidden="true"></i></button></div>
</div>
<div class="d-flex flex-column cards">
<router-outlet name="side-panel-menu"></router-outlet>
</div>
</div>
</div>
</fm-side-panel>
<ng-container *ngIf="{
mapState:mapState$|async,
extent:extent$|async,
baseLayers:baseLayers$|async,
overlayLayers:overlayLayers$|async,
selectedItemLayer:selectedItemLayer$|async,
features:features$|async,
position:position$|async,
parentCode:parentCode$|async,
panelVisible:panelVisible$|async,
openedModalName:openedModalName$|async,
panelCollapsed:panelCollapsed$|async,
searchMinified:searchMinified$|async,
selectedItem:selectedItem$|async,
queryState:queryState$|async,
menuVisible:menuVisible$|async,
searchCollapsed:searchCollapsed$|async,
clearEnabled:clearEnabled$|async,
period:period$|async
} as state">
<aol-map #map (moveEnd)="handleOnMoveEnd($event)" (click)="handleOnMouseDown($event)" [ngClass]="{'panel-visible':state.panelVisible}" class="map">
<div>
</div>
<aol-view [zoom]="state.mapState.zoom" [rotation]="state.mapState.rotation">
<aol-coordinate [x]="state.mapState.xCenter" [y]="state.mapState.yCenter" [srid]="'EPSG:4326'"></aol-coordinate>
<fm-map-zoom-to-extent [extent]="state.extent" [animate]="true"></fm-map-zoom-to-extent>
</aol-view>
<aol-interaction-default></aol-interaction-default>
<aol-interaction-dragrotateandzoom></aol-interaction-dragrotateandzoom>
<fm-map-item-layers [itemLayers]="state.baseLayers"></fm-map-item-layers>
<fm-map-item-layers [itemLayers]="state.overlayLayers"></fm-map-item-layers>
<fm-map-item-layers [itemLayer]="state.selectedItemLayer"></fm-map-item-layers>
<aol-layer-vector>
<fm-map-item-source-vector [features]="state.features" (onFeaturesSelected)="handleFeaturesSelected($event)" [selectedFeature]="state.selectedFeature" [selectedItem]="state.selectedItem"></fm-map-item-source-vector>
</aol-layer-vector>
<fm-map-gps-location [position]="state.position" [headingTolerance]="20" [showHeading]="true"></fm-map-gps-location>
<div class="control-container">
<!-- <switch2d3d></switch2d3d>-->
<fm-map-pan-to-location [position]="state.position" [mapState]="state.mapState" [animate]="true"></fm-map-pan-to-location>
<fm-map-rotation-reset></fm-map-rotation-reset>
</div>
<fm-map-file-drop-target [parentCode]="state.parentCode" (onFileDropped)="handleFileDropped($event)"></fm-map-file-drop-target>
</aol-map>
<fm-map-map-search #mapSearch [openedModalName]="state.openedModalName" (onOpenModal)="handleOpenModal($event)" (onCloseModal)="handleCloseModal()" [ngClass]="{'menuVisible':state.menuVisible}" (onToggleMenu)="handleToggleMenu($event)" (onSearchCollapse)="handleSearchCollapse($event)" (onSearchExpand)="handleSearchExpand($event)" [collapsed]="state.searchCollapsed" [searchMinified]="state.searchMinified" (onSearch)="handleSearch($event)" (onClear)="handleClearSearch($event)" [filterOptions]="state.queryState" [clearEnabled]="state.clearEnabled" [period]="state.period"></fm-map-map-search>
<fm-side-panel [resizeable]="true" [visible]="state.panelVisible" [collapsed]="state.panelCollapsed" [collapsable]="false">
<div class="panel-wrapper">
<div class="panel-top bg-secondary" *ngIf="!(state.searchMinified)">
</div>
<div class="panel-bottom">
<div *ngIf="!(state.selectedItem)">
<fm-map-feature-list-container [features]="state.features" [queryState]="state.queryState"></fm-map-feature-list-container>
</div>
<div *ngIf="state.selectedItem;let item">
<fm-map-selected-item-container [item]="item"></fm-map-selected-item-container>
</div>
<div *ngIf="state.features.length == 0" class="no-results m-2">
<div *ngIf="state.queryState.query">Cannot find <span>{{state.queryState?.query}}</span></div>
<div *ngIf="state.queryState?.tags">Cannot find tag <span>{{state.queryState?.tags}}</span></div>
</div>
</div>
</div>
</fm-side-panel>
<fm-side-panel [visible]="state.menuVisible" class="menu">
<div class="container-fluid">
<div class="body">
<div class="d-flex flex-row">
<div class="mt-2 mb-2 flex-grow-1 logo"><router-outlet name="side-panel-logo"></router-outlet></div>
<div class="mt-2 mb-2 ml-2"><button type="button" class="btn btn-outline-secondary" (click)="handleToggleMenu($event)"><i class="fa fa-times" aria-hidden="true"></i></button></div>
</div>
<div class="d-flex flex-column cards">
<router-outlet name="side-panel-menu"></router-outlet>
</div>
</div>
</div>
</fm-side-panel>
</ng-container>

View File

@@ -40,39 +40,39 @@ import { tassign } from 'tassign';
export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
title: string = 'Map';
public openedModalName: Observable<string>;
public itemTypes: Observable<{ [id: string]: IItemType }>;
public mapState: Observable<IMapState>;
public features: Observable<Array<Feature>>;
public overlayLayers: Observable<Array<IItemLayer>>;
public selectedOverlayLayer: Observable<IItemLayer>;
public selectedItemLayer: Observable<IItemLayer>;
public baseLayers: Observable<Array<IItemLayer>>;
public selectedBaseLayer: Observable<IItemLayer>;
public projection: Observable<string>;
public selectedFeatures: Subject<ISelectedFeatures> = new Subject<ISelectedFeatures>();
public droppedFile: Subject<IDroppedFile> = new Subject<IDroppedFile>();
public openedModalName$: Observable<string>;
public itemTypes$: Observable<{ [id: string]: IItemType }>;
public mapState$: Observable<IMapState>;
public features$: Observable<Array<Feature>>;
public overlayLayers$: Observable<Array<IItemLayer>>;
public selectedOverlayLayer$: Observable<IItemLayer>;
public selectedItemLayer$: Observable<IItemLayer>;
public baseLayers$: Observable<Array<IItemLayer>>;
public selectedBaseLayer$: Observable<IItemLayer>;
public projection$: Observable<string>;
public selectedFeatures$: Subject<ISelectedFeatures> = new Subject<ISelectedFeatures>();
public droppedFile$: Subject<IDroppedFile> = new Subject<IDroppedFile>();
private paramSub: Subscription;
private itemTypeSub: Subscription;
private mapStateSub: Subscription;
private queryStateSub: Subscription;
public parentCode: Observable<string>;
public panelVisible: Observable<boolean>;
public panelCollapsed: Observable<boolean>;
public selectedFeature: Observable<Feature>;
public selectedItem: Observable<IItem>;
public queryState: Observable<IQueryState>;
public period: Observable<IPeriodState>;
public clearEnabled: Observable<boolean>;
public searchCollapsed: Observable<boolean>;
public searchMinified: Observable<boolean>;
public menuVisible: Observable<boolean>;
public query: Observable<IQueryState>;
public position: Observable<Position>;
public parentCode$: Observable<string>;
public panelVisible$: Observable<boolean>;
public panelCollapsed$: Observable<boolean>;
public selectedFeature$: Observable<Feature>;
public selectedItem$: Observable<IItem>;
public queryState$: Observable<IQueryState>;
public period$: Observable<IPeriodState>;
public clearEnabled$: Observable<boolean>;
public searchCollapsed$: Observable<boolean>;
public searchMinified$: Observable<boolean>;
public menuVisible$: Observable<boolean>;
public query$: Observable<IQueryState>;
public position$: Observable<Position>;
public baseLayersCollapsed:boolean = true;
public overlayLayersCollapsed: boolean = true;
public extent: Observable<Extent>;
@ViewChild('map', { static: true }) map;
public extent$: Observable<Extent>;
@ViewChild('map', { static: false }) map;
constructor(private store: Store<mapReducers.State | commonReducers.State>,
private route: ActivatedRoute,
@@ -81,8 +81,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
private serializeService: StateSerializerService,
public itemTypeService: ItemTypeService,
private location: Location,
private geolocationService: GeolocationService,
private _ref: ChangeDetectorRef ) {
private geolocationService: GeolocationService) {
}
@HostListener('document:keyup', ['$event'])
@@ -118,36 +117,36 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
ngOnInit() {
this.store.dispatch(new mapActions.Init());
this.selectedFeatures.next({x:0,y:0,features:[]});
this.mapState = this.store.select(mapReducers.selectGetMapState);
this.parentCode = this.store.select(mapReducers.selectGetParentCode);
this.features = this.store.select(mapReducers.selectGetFeatures);
this.overlayLayers = this.store.select(mapReducers.selectGetOverlayLayers);
this.selectedOverlayLayer = this.store.select(mapReducers.selectGetSelectedOverlayLayer);
this.baseLayers = this.store.select(mapReducers.selectGetBaseLayers);
this.projection = this.store.select(mapReducers.selectGetProjection);
this.selectedBaseLayer = this.store.select(mapReducers.selectGetSelectedBaseLayer);
this.panelVisible = this.store.select(mapReducers.selectGetPanelVisible);
this.panelCollapsed = this.store.select(mapReducers.selectGetPanelCollapsed);
this.selectedFeature = this.store.select(mapReducers.selectGetSelectedFeature);
this.selectedItem = this.store.select(mapReducers.selectGetSelectedItem);
this.queryState = this.store.select(mapReducers.selectGetQueryState);
this.clearEnabled = this.store.select(mapReducers.selectGetClearEnabled);
this.searchCollapsed = this.store.select(mapReducers.selectGetSearchCollapsed);
this.searchMinified = this.store.select(mapReducers.selectGetSearchMinified);
this.menuVisible = this.store.select(mapReducers.selectGetMenuVisible);
this.openedModalName = this.store.select(commonReducers.selectOpenedModalName);
this.query = this.store.select(mapReducers.selectGetQuery);
this.extent = this.store.select(mapReducers.selectGetExtent);
this.selectedFeatures.next(null);
this.selectedItemLayer = this.store.select(mapReducers.selectGetSelectedItemLayer);
this.period = this.store.select(mapReducers.selectGetPeriod);
this.position = this.geolocationService.getCurrentPosition();
this.selectedFeatures$.next({x:0,y:0,features:[]});
this.mapState$ = this.store.select(mapReducers.selectGetMapState);
this.parentCode$ = this.store.select(mapReducers.selectGetParentCode);
this.features$ = this.store.select(mapReducers.selectGetFeatures);
this.overlayLayers$ = this.store.select(mapReducers.selectGetOverlayLayers);
this.selectedOverlayLayer$ = this.store.select(mapReducers.selectGetSelectedOverlayLayer);
this.baseLayers$ = this.store.select(mapReducers.selectGetBaseLayers);
this.projection$ = this.store.select(mapReducers.selectGetProjection);
this.selectedBaseLayer$ = this.store.select(mapReducers.selectGetSelectedBaseLayer);
this.panelVisible$ = this.store.select(mapReducers.selectGetPanelVisible);
this.panelCollapsed$ = this.store.select(mapReducers.selectGetPanelCollapsed);
this.selectedFeature$ = this.store.select(mapReducers.selectGetSelectedFeature);
this.selectedItem$ = this.store.select(mapReducers.selectGetSelectedItem);
this.queryState$ = this.store.select(mapReducers.selectGetQueryState);
this.clearEnabled$ = this.store.select(mapReducers.selectGetClearEnabled);
this.searchCollapsed$ = this.store.select(mapReducers.selectGetSearchCollapsed);
this.searchMinified$ = this.store.select(mapReducers.selectGetSearchMinified);
this.menuVisible$ = this.store.select(mapReducers.selectGetMenuVisible);
this.openedModalName$ = this.store.select(commonReducers.selectOpenedModalName);
this.query$ = this.store.select(mapReducers.selectGetQuery);
this.extent$ = this.store.select(mapReducers.selectGetExtent);
this.selectedFeatures$.next(null);
this.selectedItemLayer$ = this.store.select(mapReducers.selectGetSelectedItemLayer);
this.period$ = this.store.select(mapReducers.selectGetPeriod);
this.position$ = this.geolocationService.getCurrentPosition();
this.mapState.pipe(withLatestFrom(this.queryState)).subscribe((state) => {
this.mapState$.pipe(withLatestFrom(this.queryState$)).subscribe((state) => {
this.replaceUrl(state[0], state[1], true);
});
this.query.pipe(withLatestFrom(this.mapState)).subscribe((state) => {
this.query$.pipe(withLatestFrom(this.mapState$)).subscribe((state) => {
this.replaceUrl(state[1], state[0],false);
});
}
@@ -194,9 +193,9 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
}
this.stateSetCount += 1;
});
setTimeout(() => {
this.map.instance.updateSize();
}, 500);
// setTimeout(() => {
// this.map.instance.updateSize();
// }, 500);
}
handleSearchCollapse(event) {
@@ -245,7 +244,6 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
parts.push(mapState.baseLayerCode);
parts.push( this.serializeService.serialize(queryState));
this.router.navigate(parts, { replaceUrl: replace,relativeTo:this.route.parent });
this._ref.markForCheck();
}
}
@@ -259,7 +257,7 @@ export class MapComponent implements OnInit, OnDestroy,AfterViewInit {
let mapState: IMapState = { xCenter: center[0], yCenter: center[1], zoom: zoom, rotation: rotation, baseLayerCode: null };
let state = { mapState: mapState, extent: extent };
let source = from([state]);
source.pipe(withLatestFrom(this.selectedBaseLayer), withLatestFrom(this.queryState)).subscribe(([[state, baselayer], queryState]) => {
source.pipe(withLatestFrom(this.selectedBaseLayer$), withLatestFrom(this.queryState$)).subscribe(([[state, baselayer], queryState]) => {
if (mapState && baselayer && queryState) {
let newMapState = tassign(state.mapState, { baseLayerCode: baselayer.item.code });
this.replaceUrl(newMapState, tassign(queryState, { bbox: queryState.bboxFilter ? state.extent : queryState.bbox }));