- npm updates

- add map-view.component (instead of initializing the map component inside app component)-
- add custom zoom control
This commit is contained in:
Arno Kaimbacher 2021-09-10 15:29:08 +02:00
parent feab502c1d
commit 53a9cfa0d4
21 changed files with 3322 additions and 3799 deletions

6756
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -3,16 +3,16 @@ import { RouterModule, Routes } from '@angular/router';
//neu
import { DashboardComponent } from './dashboard/dashboard.component';
import { MapComponent } from './map/map.component';
import { MapViewComponent } from './views/map-view/map-view.component';
// import { HeroDetailComponent } from './hero-detail/hero-detail.component';
// const routes: Routes = [];
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: '', redirectTo: '/map', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
// { path: 'detail/:id', component: HeroDetailComponent },
{ path: 'map', component: MapComponent }
{ path: 'map', component: MapViewComponent }
];
@NgModule({

View file

@ -21,8 +21,11 @@
<div class="navbar-start">
<span id='map-title' class="navbar-item">
</span>
<a class="navbar-item">
Documentation
<a class="navbar-item" routerLink="/dashboard" routerLinkActive="is-active">
Dashboard
</a>
<a class="navbar-item" routerLink="/map" routerLinkActive="is-active">
Map
</a>
</div>
<div class="navbar-end">
@ -43,13 +46,14 @@
<div class="main columns">
<div class="canvas-area is-8 column">
<div id="div-map">
<!-- <div id="div-map">
<app-map [mapId]="'map'" [mapOptions]="mapOptions" [serviceUrl]="providerUrl" [baseMaps]="baseMaps"
(onSelected)="onStationSelected($event)" (onMapInitializedEvent)="onMapInitialized($event)">
</app-map>
<!-- <router-outlet></router-outlet> -->
</div>
</div> -->
<router-outlet></router-outlet>
</div>
<div class="input-area is-4 column">

View file

@ -1,22 +1,22 @@
import { Component, VERSION } from "@angular/core";
import { Component, VERSION, AfterViewInit } from "@angular/core";
import '../styles.scss';
// import '../../node_modules/leaflet/dist/leaflet.css';
import { ParameterFilter, Phenomenon, Station } from '@helgoland/core';
import { LayerOptions } from '@helgoland/map';
import { Marker, MapOptions, Control, icon, LatLngBoundsExpression } from 'leaflet';
// optional, to adapt leaflet markers
// import { ParameterFilter, Phenomenon, Station } from '@helgoland/core';
// import { LayerOptions } from '@helgoland/map';
// import { Marker, MapOptions, Control, icon, LatLngBoundsExpression } from 'leaflet';
// // optional, to adapt leaflet markers
Marker.prototype.options.icon = icon({
iconRetinaUrl: 'assets/img/marker-icon-2x.png',
iconUrl: 'assets/img/marker-icon.png',
shadowUrl: 'assets/img/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
tooltipAnchor: [16, -28],
shadowSize: [41, 41]
});
// Marker.prototype.options.icon = icon({
// iconRetinaUrl: 'assets/img/marker-icon-2x.png',
// iconUrl: 'assets/img/marker-icon.png',
// shadowUrl: 'assets/img/marker-shadow.png',
// iconSize: [25, 41],
// iconAnchor: [12, 41],
// popupAnchor: [1, -34],
// tooltipAnchor: [16, -28],
// shadowSize: [41, 41]
// });
@Component({
@ -24,35 +24,56 @@ Marker.prototype.options.icon = icon({
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
export class AppComponent implements AfterViewInit {
constructor() { }
ngAfterViewInit(): void {
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
// Check if there are any navbar burgers
if ($navbarBurgers.length > 0) {
// Add a click event on each of them
$navbarBurgers.forEach(el => {
el.addEventListener('click', () => {
// Get the target from the "data-target" attribute
const target = el.dataset.target;
const $target = document.getElementById(target);
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
});
});
}
}
public name = 'Angular test ' + VERSION.major;
x: number = 123;
// public providerUrl = 'https://geo.irceline.be/sos/api/v2/';
public providerUrl = 'https://geomon.geologie.ac.at/52n-sos-webapp/api/';
// // public providerUrl = 'https://geo.irceline.be/sos/api/v2/';
// public providerUrl = 'https://geomon.geologie.ac.at/52n-sos-webapp/api/';
public fitBounds: LatLngBoundsExpression = [[ 9.47996951665, 46.4318173285], [16.9796667823, 49.0390742051]];
// public zoomControlOptions: L.Control.ZoomOptions = { position: 'topleft' };
public avoidZoomToSelection = false;
public baseMaps: Map<string, LayerOptions> = new Map<string, LayerOptions>();
public overlayMaps: Map<string, LayerOptions> = new Map<string, LayerOptions>();
public layerControlOptions: Control.LayersOptions = { position: 'bottomleft' };
public cluster = false;
public loadingStations: boolean;
public stationFilter: ParameterFilter = {
// phenomenon: '8'
};
public statusIntervals = false;
public mapOptions: MapOptions = { dragging: true, zoomControl: false };
// public fitBounds: LatLngBoundsExpression = [[9.47996951665, 46.4318173285], [16.9796667823, 49.0390742051]];
// // public zoomControlOptions: L.Control.ZoomOptions = { position: 'topleft' };
// public avoidZoomToSelection = false;
// public baseMaps: Map<string, LayerOptions> = new Map<string, LayerOptions>();
// public overlayMaps: Map<string, LayerOptions> = new Map<string, LayerOptions>();
// public layerControlOptions: Control.LayersOptions = { position: 'bottomleft' };
// public cluster = false;
// public loadingStations: boolean;
// public stationFilter: ParameterFilter = {
// // phenomenon: '8'
// };
// public statusIntervals = false;
// public mapOptions: MapOptions = { dragging: true, zoomControl: false };
public onStationSelected(station: Station) {
console.log('Clicked station: ' + station.properties.label);
}
// public onStationSelected(station: Station) {
// console.log('Clicked station: ' + station.properties.label);
// }
public onMapInitialized(newItem: string) {
console.log(newItem);
}
// public onMapInitialized(newItem: string) {
// console.log(newItem);
// }
}

View file

@ -6,6 +6,7 @@ import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { MapComponent } from './map/map.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { MapViewComponent } from "./views/map-view/map-view.component";
import { ComponentsModule } from '../../src/common/components/components.module';
@ -17,7 +18,7 @@ import { HttpService } from "./services/http.service";
import { StationService } from "./services/station.service";
import { MessagesComponent } from './messages/messages.component';
import { MessageService } from "./services/message.service";
import { MapCache } from '../common/components/services/map-cache.service';
import { MapService } from '../common/components/services/map.service';
// import { LocateService } from '@helgoland/map';
// import { MapCache } from '@helgoland/map';
@ -34,11 +35,11 @@ import { MapCache } from '../common/components/services/map-cache.service';
@NgModule({
// declarations: The components, directives, and pipes that belong to this NgModule.
declarations: [AppComponent, MapComponent, DashboardComponent, MessagesComponent],
declarations: [AppComponent, MapComponent, DashboardComponent, MessagesComponent, MapViewComponent],
// imports: Other modules whose exported classes are needed by component templates declared in this NgModule.
imports: [BrowserModule, HttpClientModule, AppRoutingModule, ComponentsModule],
providers: [
MarkerService, PopupService, HttpService, DatasetApiService, StationService, MessageService, MapCache
MarkerService, PopupService, HttpService, DatasetApiService, StationService, MessageService, MapService
// {
// provide: DatasetApiInterface,
// useClass: SplittedDataDatasetApiInterface,

View file

@ -3,7 +3,7 @@ import { Map, Control, MapOptions, LatLngBoundsExpression, tileLayer, TileLayer
// import { MarkerService } from '../services/marker.service';
import { LayerOptions, LayerMap } from './map-options';
import { MapCache } from '../../common/components/services/map-cache.service';
import { MapService } from '../../common/components/services/map.service';
const DEFAULT_BASE_LAYER_NAME = 'BaseLayer';
const DEFAULT_BASE_LAYER_URL = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
@ -64,7 +64,7 @@ export abstract class BaseMapComponent implements OnChanges, OnInit {
protected map: Map;
protected zoomControl: Control.Zoom;
constructor(protected mapCache: MapCache) { }
constructor(protected mapService: MapService) { }
// constructor(private markerService: MarkerService) { }
// constructor(markerService: MarkerService) {
// this.markerService = markerService;
@ -86,11 +86,8 @@ export abstract class BaseMapComponent implements OnChanges, OnInit {
}
protected initMap(): void {
this.map = new Map(this.mapId, {
center: [48.208174, 16.373819],
zoom: 3
});
this.mapCache.setMap(this.mapId, this.map);
this.map = new Map(this.mapId, this.mapOptions);
this.mapService.setMap(this.mapId, this.map);
this.onMapInitializedEvent.emit(this.mapId);
if (this.baseMaps && this.baseMaps.size > 0) {
this.baseMaps.forEach((layerOptions, key) => this.addBaseMap(layerOptions));
@ -104,7 +101,7 @@ export abstract class BaseMapComponent implements OnChanges, OnInit {
}
}
private addBaseMap(layerOptions?: LayerOptions) {
private addBaseMap(layerOptions?: LayerOptions): void {
if (this.map) {
if (!this.baseMaps || this.baseMaps.size === 0) {
// let tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {

View file

@ -5,4 +5,6 @@
</div> -->
<div [attr.id]="mapId" class="map-container mapDesktop">
<gba-locate-button [mapId]="mapId"></gba-locate-button>
<gba-zoom-control [mapId]="mapId"></gba-zoom-control>
</div>

View file

@ -5,7 +5,7 @@ import { MarkerService } from '../services/marker.service';
import { DatasetApiService } from '../services/dataset-api.service';
import { BaseMapComponent } from './base-map.component';
import { PopupService } from '../services/popup.service';
import { MapCache } from '../../common/components/services/map-cache.service';
import { MapService } from '../../common/components/services/map.service';
@Component({
selector: 'app-map',
@ -43,11 +43,11 @@ export class MapComponent
// constructor() { }
constructor(
protected mapCache: MapCache,
protected mapService: MapService,
protected markerService: MarkerService,
private popupService: PopupService,
protected datasetApiService: DatasetApiService) {
super(mapCache);
super(mapService);
this.markerFeatureGroup = new FeatureGroup();
}

View file

@ -0,0 +1,12 @@
<!-- <div class="map">
<n52-station-map-selector class="h-100" [mapId]="'timeseries'" [serviceUrl]="selectedService.apiUrl"
[filter]="stationFilter" (onSelected)="onStationSelected($event)" [cluster]="cluster"
class="vbox boxItem fullHeight">
</n52-station-map-selector>
</div> -->
<div id="div-map">
<app-map [mapId]="'map'" [mapOptions]="mapOptions" [serviceUrl]="providerUrl" [baseMaps]="baseMaps"
(onSelected)="onStationSelected($event)" (onMapInitializedEvent)="onMapInitialized($event)" class="vbox boxItem fullHeight">
</app-map>
</div>

View file

@ -0,0 +1,4 @@
.map {
flex: 1;
position: relative;
}

View file

@ -0,0 +1,66 @@
import { Component, OnInit } from '@angular/core';
import { ParameterFilter, Station } from '@helgoland/core';
import { LayerOptions } from '@helgoland/map';
import { Marker, MapOptions, Control, icon, LatLngBoundsExpression } from 'leaflet';
// optional, to adapt leaflet markers
Marker.prototype.options.icon = icon({
iconRetinaUrl: 'assets/img/marker-icon-2x.png',
iconUrl: 'assets/img/marker-icon.png',
shadowUrl: 'assets/img/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
tooltipAnchor: [16, -28],
shadowSize: [41, 41]
});
@Component({
selector: 'gba-map-view',
templateUrl: './map-view.component.html',
styleUrls: ['./map-view.component.scss']
})
export class MapViewComponent implements OnInit {
constructor() {
//
}
ngOnInit(): void {
// this.serviceConnector.getServices(this.configSrvc.configuration?.defaultService.apiUrl).subscribe(services => {
// this.selectedService = services.find(e => e.id === this.configSrvc.configuration?.defaultService.serviceId);
// this.updateFilter();
// });
}
// public providerUrl = 'https://geo.irceline.be/sos/api/v2/';
public providerUrl = 'https://geomon.geologie.ac.at/52n-sos-webapp/api/';
public fitBounds: LatLngBoundsExpression = [[9.47996951665, 46.4318173285], [16.9796667823, 49.0390742051]];
// public zoomControlOptions: L.Control.ZoomOptions = { position: 'topleft' };
public avoidZoomToSelection = false;
public baseMaps: Map<string, LayerOptions> = new Map<string, LayerOptions>();
public overlayMaps: Map<string, LayerOptions> = new Map<string, LayerOptions>();
public layerControlOptions: Control.LayersOptions = { position: 'bottomleft' };
public cluster = false;
public loadingStations: boolean;
public stationFilter: ParameterFilter = {
// phenomenon: '8'
};
public statusIntervals = false;
public mapOptions: MapOptions = {
center: [48.208174, 16.373819],
zoom: 3,
zoomControl: false
};
public onStationSelected(station: Station) {
console.log('Clicked station: ' + station.properties.label);
}
public onMapInitialized(newItem: string) {
console.log(newItem);
}
}

View file

@ -4,9 +4,10 @@ import { NgModule } from '@angular/core';
// import { HelgolandCoreModule } from '@helgoland/core';
// import { HelgolandMapModule } from '@helgoland/map';
import { LocateButtonComponent } from './locate-button/locate-button.component';
import { ZoomControlComponent } from './zoom-control/zoom.component';
// import { LocateService } from '@helgoland/map';
// import { MapCache } from '@helgoland/map';
import { MapCache } from './services/map-cache.service';
import { MapService } from './services/map.service';
import { LocateService } from './services/locate.service';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
@ -15,15 +16,15 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
CommonModule, FontAwesomeModule
],
declarations: [
LocateButtonComponent,
LocateButtonComponent, ZoomControlComponent
],
exports: [
LocateButtonComponent,
LocateButtonComponent, ZoomControlComponent
],
providers: [
// LocateService,
MapCache, LocateService
MapService, LocateService
]
})
export class ComponentsModule { }

View file

@ -3,8 +3,8 @@
<i class="fa fa-map-marker-alt"></i>
</button>
</div> -->
<div class="gba-control-locate btn-group-vertical btn-group-sm map-control">
<button type="button" class="button is-small" (click)="locateUser()" [ngClass]="isToggled ? 'is-primary': 'is-active'">
<div class="gba-control-locate btn-group-vertical map-control">
<button type="button" class="button is-light is-small" (click)="locateUser()" [ngClass]="isToggled ? 'is-primary': 'is-active'">
<fa-icon [icon]="faSearchLocation"></fa-icon>
</button>
</div>

View file

@ -1,6 +1,6 @@
.gba-control-locate button {
width: 30px;
height: 30px;
// width: 30px;
// height: 30px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
@ -8,10 +8,10 @@
cursor: pointer;
border-radius: 4px;
// display: block;
text-align: center;
// text-align: center;
color: black;
position: absolute;
left: 10px;
top: 80px;
z-index: 999;
z-index: 29;
}

View file

@ -1,6 +1,6 @@
import { Component, Input } from '@angular/core';
import { MapCache } from '../services/map-cache.service';
import { MapService } from '../services/map.service';
import { LocateService } from '../services/locate.service';
import { faSearchLocation, faMapPin } from '@fortawesome/free-solid-svg-icons';
@ -20,7 +20,7 @@ export class LocateButtonComponent {
constructor(
protected locateService: LocateService,
protected mapCache: MapCache
protected mapCache: MapService
) {
// super(mapCache);
}

View file

@ -1,7 +1,6 @@
import { Injectable } from '@angular/core';
import * as L from 'leaflet';
import { MapCache } from './map-cache.service';
import { Map, Marker } from 'leaflet';
import { MapService } from './map.service';
const LOCATION_FOUND_EVENT = 'locationfound';
const LOCATION_ERROR = 'locationerror';
@ -11,14 +10,14 @@ const LOCATED_MARKER_ID = 'located';
export class LocateService {
constructor(
protected mapCache: MapCache
protected mapService: MapService
) { }
public startLocate(id: string) {
const map = this.mapCache.getMap(id);
const map = this.mapService.getMap(id);
map.on(LOCATION_FOUND_EVENT, (evt: L.LocationEvent) => {
this.removeMarker(map);
const marker = L.marker(evt.latlng).addTo(map);
const marker = new Marker(evt.latlng).addTo(map);
marker.options.title = LOCATED_MARKER_ID;
});
map.on(LOCATION_ERROR, (error) => {
@ -32,15 +31,15 @@ export class LocateService {
}
public stopLocate(id: string) {
const map = this.mapCache.getMap(id);
const map = this.mapService.getMap(id);
map.stopLocate();
map.off(LOCATION_FOUND_EVENT);
this.removeMarker(map);
}
private removeMarker(map: L.Map) {
private removeMarker(map: Map) {
map.eachLayer((entry) => {
if (entry instanceof L.Marker && entry.options.title === LOCATED_MARKER_ID) {
if (entry instanceof Marker && entry.options.title === LOCATED_MARKER_ID) {
map.removeLayer(entry);
}
});

View file

@ -2,24 +2,24 @@ import { Injectable } from '@angular/core';
import * as L from 'leaflet';
@Injectable()
export class MapCache {
export class MapService {
private mapCache: Map<string, any> = new Map<string, any>();
private mapService: Map<string, any> = new Map<string, any>();
public getMap(id: string): L.Map {
return this.mapCache.get(id);
return this.mapService.get(id);
}
public setMap(id: string, map: L.Map) {
this.mapCache.set(id, map);
this.mapService.set(id, map);
}
public hasMap(id: string): boolean {
return this.mapCache.has(id);
return this.mapService.has(id);
}
public deleteMap(id: string): boolean {
return this.mapCache.delete(id);
return this.mapService.delete(id);
}
}

View file

@ -0,0 +1,8 @@
<div class="gba-control-zoom btn-group-vertical map-control">
<button type="button" class="button is-light is-small" (click)="zoomIn()">
<fa-icon [icon]="faPlus"></fa-icon>
</button>
<button type="button" class="button is-light is-small" (click)="zoomOut()">
<fa-icon [icon]="faMinus"></fa-icon>
</button>
</div>

View file

@ -0,0 +1,27 @@
.gba-control-zoom {
// width: 30px;
// height: 30px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: pointer;
border-radius: 4px;
// text-align: center;
// color: black;
position: absolute;
left: 10px;
top: 10px;
z-index:29;
}
.btn-group-vertical {
button {
display: block;
& + button {
margin-left: 0;
margin-top: .5em;
}
}
}

View file

@ -0,0 +1,34 @@
import { Component, Input } from '@angular/core';
import { MapService } from '../services/map.service';
import { faPlus, faMinus } from '@fortawesome/free-solid-svg-icons';
@Component({
selector: 'gba-zoom-control',
templateUrl: './zoom.component.html',
styleUrls: ['./zoom.component.scss']
})
export class ZoomControlComponent {
faPlus = faPlus;
faMinus = faMinus;
/**
* Connect map id.
*/
@Input() public mapId: string;
constructor(
protected mapService: MapService
) {
}
public zoomIn() {
let map = this.mapService.getMap(this.mapId);
map.zoomIn();
}
public zoomOut() {
let map = this.mapService.getMap(this.mapId);
map.zoomOut();
}
}

View file

@ -1,3 +1,6 @@
.leaflet-pane {
z-index: 28;
}
/* You can add global styles to this file, and also import other style files */
/* @import '../node_modules/leaflet/dist/leaflet.css'; */
@import '~leaflet/dist/leaflet.css';
@ -45,6 +48,9 @@ $control-border-width: 2px;
$input-border-color: transparent;
// $input-shadow: none;
$navbar-item-hover-background-color: #EFF0EB;
$navbar-item-active-background-color: #EFF0EB;
.main.columns:last-child {
margin-bottom: 0;
}
@ -53,7 +59,6 @@ $input-border-color: transparent;
height: 51px;
}
.main.columns:last-child {
margin-bottom: 0;
}