<!-- Copyright (c) 2022 NIBIO <http://www.nibio.no/>. This file is part of VIPSObservationApp. VIPSObservationApp is free software: you can redistribute it and/or modify it under the terms of the NIBIO Open Source License as published by NIBIO, either version 1 of the License, or (at your option) any later version. VIPSObservationApp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the NIBIO Open Source License for more details. You should have received a copy of the NIBIO Open Source License along with VIPSObservationApp. If not, see <http://www.nibio.no/licenses/>. Author: Bhabesh Bhabani Mukhopadhyay Author: Tor-Einar Skog <tor-einar.skog@nibio.no> Dated : 19-Aug-2021 --> <template> <div> <div id='map-observation'> <div v-if="isMyMapPanelVisible"> <div v-if="isMapClicked"> <div id="btnBack"> <router-link id='btnBack_1' :to="{name: 'Observation', params:{observationId:myObservationId, paramGeoinfo:initGeoInfo, paramObservation:mapObservation }}" class="vips-btn"> {{ $t("map.link.cancel.label") }} <i class="fas fa-times"></i> </router-link> <router-link id='btnBack_2' :to="{name: 'Observation', params:{observationId:myObservationId, paramGeoinfo:myGeoInfo, paramObservation:mapObservation}}" class="vips-btn"> {{ $t("map.link.OK.label") }} <i class="fas fa-check"></i> </router-link> </div> </div> <div v-else> <router-link id='btnBack' :to="{name: 'Observation', params:{observationId:myObservationId, paramGeoinfo:myGeoInfo, paramObservation:mapObservation}}" class="vips-btn"> {{ $t("map.link.back.label") }} </router-link> </div> </div> <div v-if="isMyMapPanelVisible" id='map-mylocation' style="margin: 5px;"> <a v-on:click="myposition" style="cursor:pointer; "> <font-awesome-icon style="font-size: x-large; padding: 5px; color: white; background-color:#3d8052;" icon="location-crosshairs" /></a> </div> </div> <div id="ObservationMapPanel" v-if="isMyMapPanelVisible" ref='ObservationMapPanel'> <div> <select class="form-control" v-model="poi.pointOfInterestId" v-on:change="selectPOI($event)" ref="dropDownPOI"> <option v-for="poi in lstPOI" v-bind:value="poi.pointOfInterestId">{{poi.name}}</option> </select> <div id="poiMarker"> <img src="@/assets/map_icon.png"> </div> </div> </div> <div v-else> <div id='divPrivacy' ref='divPrivacy' class="form-group"> <visibility :locationIsPrivate="locationIsPrivate" :polygonService="polygonService" v-on:visibilityMapAction="visibilityMapAction" /> </div> </div> <common-util ref="CommonUtil" /> </div> </template> <script> import CommonUtil from '@/components/CommonUtil' import 'ol/ol.css'; import Map from 'ol/Map'; import OSM from 'ol/source/OSM'; import TileLayer from 'ol/layer/Tile'; import View from 'ol/View'; import WMTS, {optionsFromCapabilities} from 'ol/source/WMTS'; import WMTSCapabilities from 'ol/format/WMTSCapabilities'; import {Vector as VectorSource} from 'ol/source'; import {Vector as VectorLayer} from 'ol/layer'; import Collection from 'ol/Collection'; import {fromLonLat} from 'ol/proj'; import Circle from 'ol/geom/Circle'; import {Circle as CircleStyle, Fill, Stroke, Style, Icon} from 'ol/style'; import Feature from 'ol/Feature'; import GeoJSON from 'ol/format/GeoJSON'; import {toStringXY} from 'ol/coordinate'; import {transform} from 'ol/proj'; import Point from 'ol/geom/Point'; import {Modify} from 'ol/interaction'; import Draw from 'ol/interaction/Draw'; import Overlay from 'ol/Overlay'; import Geolocation from 'ol/Geolocation'; import Visibility from '@/components/Visibility' import i18n from '@/App' let parser = new WMTSCapabilities(); export default { name: 'MapObservation', props: ['observationId', 'geoinfo', 'isMapPanelVisible', 'locationPointOfInterestId', 'locationIsPrivate', 'polygonService', 'observation'], components: {CommonUtil, Visibility}, data() { return { CONST_URL_DOMAIN: '', isMyMapPanelVisible: '', myGeoInfo: '', initGeoInfo: '', latitude: 0, longitude: 0, mapZoom: 0, mapInteractions: '', lstPOI: [], poi: {pointOfInterestId: 'undefined', name: this.$i18n.t("mapobservation.label.selectPOI")}, myMap: '', myObservationId: '', mapObservation: {}, isMapClicked: false, } }, methods: { visibilityMapAction(paramPrivate, paramPolygonService) { this.$emit('visibilityObservationAction', paramPrivate, paramPolygonService); }, /** My current location */ myposition() { let options = {enableHighAccuracy: true}; navigator.geolocation.getCurrentPosition(this.geolocationSuccess, this.geolocationError, options); }, /** * Get GeoInfo * */ geolocationSuccess(pos) { this.poi.pointOfInterestId = 'undefined'; this.longitude = pos.coords.latitude; this.latitude = pos.coords.longitude; let coord = [pos.coords.longitude, pos.coords.latitude]; let transFormCord = transform(coord, 'EPSG:3857', 'EPSG:4326'); this.myMap.getView().setCenter(fromLonLat(coord)); this.clearMapLayers(); let myImage = this.myImage(); let vectorSource = new VectorSource({}); var iconFeature = new Feature({ geometry: new Point(fromLonLat(coord)) }); vectorSource.addFeature(iconFeature); var vectorLayer = new VectorLayer({ source: vectorSource, style: new Style({ image: myImage, }), }); let geoJSON = new GeoJSON(); let resultGeoJSON = geoJSON.writeFeatures(vectorLayer.getSource().getFeatures()); this.myGeoInfo = JSON.parse(resultGeoJSON); this.myGeoInfo.features[0].geometry.coordinates = coord; this.myMap.addLayer(vectorLayer); this.myMap.getView().setZoom(CommonUtil.CONST_GPS_OBSERVATION_ZOOM); }, geolocationError(error) { console.log('geolocation error : ' + geolocationError); }, /** Display of Map */ initMap(myLatitude, myLongitude) { let pointOfInterestId = this.poi.pointOfInterestId; let This = this; let urlMap = CommonUtil.CONST_GPS_URL_NORWAY_MAP; // Norway Map let myGeoInfo = this.myGeoInfo; let latitude = myLatitude; let longitude = myLongitude; let mapZoom = this.mapZoom; let image = this.myImage(); let vectorSource = this.myVectorGeoSource(); let vectorGeoLayer = this.myVectorGeoLayer(vectorSource, image); let mapInteractions = this.myInteractions(this.mapInteractions); let mapView = this.myView(latitude, longitude, mapZoom); let localIsMyMapPanelVisible = this.isMyMapPanelVisible; let coordinate = [latitude, longitude]; let pointMarker = this.myOverLay(coordinate); let pointMarkerCoord = this.myOverLayCoord(latitude, longitude); /* Fetch Norway Map */ fetch(urlMap) .then(function (response) { return response.text(); }) .then(function (text) { let parser = new WMTSCapabilities(); let result = parser.read(text); let options = optionsFromCapabilities(result, { layer: 'topo4', matrixSet: 'EPSG:3857', }); //console.info(options); // Need to force https on the tiles URL (bug in the service?) options.urls[0] = options.urls[0].replace("http","https"); This.myMap = new Map({ layers: [ new TileLayer({ opacity: 1, source: new WMTS(options), }), vectorGeoLayer ], controls: [], interactions: mapInteractions, target: 'map-observation', view: mapView, overlays: [pointMarkerCoord], renderer: 'canvas', }); /* On click event of map to get the location */ This.myMap.on(['singleclick'], function (event) { if (localIsMyMapPanelVisible) { This.isMapClicked = true; This.poi.pointOfInterestId = 'undefined'; let transFormCord = transform(event.coordinate, 'EPSG:3857', 'EPSG:4326'); This.latitude = transFormCord[0]; This.longitude = transFormCord[1]; let mapNewCord = toStringXY(transform(event.coordinate, 'EPSG:3857', 'EPSG:4326'), 4); This.myMap.getView().setCenter(fromLonLat(transFormCord)); /******* Below code for vector marker positioning */ var iconFeature = new Feature({ geometry: new Point(fromLonLat(transFormCord)) }); This.clearMapLayers(); if (vectorSource) {} else { vectorSource = new VectorSource({}); } if (vectorSource) { vectorSource.addFeature(iconFeature); var vectorLayer = new VectorLayer({ source: vectorSource, style: new Style({ image: image, }), }); This.myMap.addLayer(vectorLayer); let geoGSON = new GeoJSON(); let resultGeoGSON = geoGSON.writeFeatures(vectorLayer.getSource().getFeatures(), { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' }); This.myGeoInfo = JSON.parse(resultGeoGSON); } } }); }) }, myVectorGeoSource() { if (this.myGeoInfo) { return new VectorSource({ features: new GeoJSON({ dataProjection: "EPSG:4326", featureProjection: "EPSG:3857" }).readFeatures(this.myGeoInfo), }) } }, myVectorGeoLayer(vectorSource, image) { return new VectorLayer({ source: vectorSource, style: new Style({ image: image, }), }) }, myView(latitude, longitude, mapZoom) { return new View({ center: fromLonLat([latitude, longitude]), zoom: mapZoom }) }, myImage() { var fill = new Fill({ color: 'white' }); return new CircleStyle({ radius: 15, fill: fill, stroke: new Stroke({color: '#3d8052', width: 15}), }); }, myOverLay(coordinates) { return new Overlay({ position: fromLonLat(coordinates), positioning: 'bottom-center', element: document.getElementById('poiMarker'), stopEvent: false }); }, myOverLayCoord(latitude, longitude) { let coordinate = [latitude, longitude]; return this.myOverLay(coordinate); }, myStyleFunction(styles, feature) { return styles[feature.getGeometry().getType()]; }, myInteractions(mapInteractions) { return (mapInteractions) ? [] : ''; }, /* Get point of interest */ getMyPointOfInterst(lstPOI) { let userUUID = localStorage.getItem(CommonUtil.CONST_STORAGE_UUID); let jsonHeader = {Authorization: userUUID}; lstPOI.push({pointOfInterestId: 'undefined', name: this.$i18n.t("mapobservation.label.noPOIselected")}); fetch(this.CONST_URL_DOMAIN + CommonUtil.CONST_URL_USER_POI, { method: "GET", headers: jsonHeader, }).then((response) => { if (response.status == 200) { return response.json() } }) .then((jsonLstPOI) => { $.each(jsonLstPOI, function (index, poi) { let myPOI = poi; lstPOI.push(myPOI); }) }) }, /* Clear existing sources in map layers */ clearMapLayers() { let myLayers = this.myMap.getLayers(); if (myLayers) { this.myMap.getLayers().forEach(function (layer) { let source = layer.get('source'); if (source) { source.clear(); } }) } }, selectPOI(event) { let myPOI = this.poi; if (event.target.value != 0) { $.each(this.lstPOI, function (index, poi) { if (poi.pointOfInterestId === JSON.parse(event.target.value)) { myPOI = poi; return false; } }) this.myGeoInfo = JSON.parse(myPOI.geoJSON); let coordinate = this.myGeoInfo.features[0].geometry.coordinates; this.latitude = coordinate[0]; this.longitude = coordinate[1]; let myImage = this.myImage(); let transFormCord = [this.latitude, this.longitude]; //let vectorSource = this.myVectorGeoSource(); let vectorSource = new VectorSource({}); var iconFeature = new Feature({ geometry: new Point(fromLonLat(transFormCord)) }); vectorSource.addFeature(iconFeature); var vectorLayer = new VectorLayer({ source: vectorSource, style: new Style({ image: myImage, }), }); this.clearMapLayers(); this.myMap.addLayer(vectorLayer); this.myMap.getView().setCenter(fromLonLat(coordinate)); this.myMap.getView().setZoom(CommonUtil.CONST_GPS_OBSERVATION_ZOOM); } } }, mounted() { this.CONST_URL_DOMAIN = CommonUtil.CONST_URL_DOMAIN; this.latitude = CommonUtil.CONST_GPS_DEFAULT_LATITUDE_NORWAY; this.longitude = CommonUtil.CONST_GPS_DEFAULT_LONGITUDE_NORWAY; let routeParam = this.$route.params; // This ensures that the map fills the entire viewport var mapDiv = document.getElementById("map-observation"); var navDiv = document.getElementById("vipsobsappmenu"); var appDiv = document.getElementById("app"); var panelObDiv = document.getElementById("ObservationMapPanel"); var divPrivacy = document.getElementById("divPrivacy"); if (routeParam.observation) { this.mapObservation = routeParam.observation; } if (routeParam.observationId) { this.myObservationId = routeParam.observationId; } if (this.observationId) { this.myObservationId = this.observationId; } if (routeParam.isMapPanelVisible) { this.isMyMapPanelVisible = routeParam.isMapPanelVisible; } if (this.isMapPanelVisible) { this.isMyMapPanelVisible = this.isMapPanelVisible; } if (this.isMyMapPanelVisible) { mapDiv.style.height = (screen.height - navDiv.offsetHeight) + "px"; this.mapInteractions = ''; appDiv.style.marginTop = "0"; appDiv.style.paddingRight = "0"; appDiv.style.paddingLeft = "0"; this.getMyPointOfInterst(this.lstPOI); } else { mapDiv.style.height = 300 + "px"; this.mapInteractions = 'interactions:[]'; } if (routeParam.geoinfo) { this.myGeoInfo = routeParam.geoinfo; this.initGeoInfo = routeParam.geoinfo; } if (this.geoinfo) { this.myGeoInfo = this.geoinfo; this.initGeoInfo = this.geoinfo; } if (this.myGeoInfo) { this.latitude = this.myGeoInfo.features[0].geometry.coordinates[0]; this.longitude = this.myGeoInfo.features[0].geometry.coordinates[1]; this.mapZoom = CommonUtil.CONST_GPS_OBSERVATION_ZOOM; } else { this.mapZoom = CommonUtil.CONST_GPS_DEFAULT_ZOOM; //this.mapZoom = CommonUtil.CONST_GPS_OBSERVATION_ZOOM; } if (routeParam.locationPointOfInterestId) { this.poi.pointOfInterestId = routeParam.locationPointOfInterestId; } this.$nextTick(function () { this.initMap(this.latitude, this.longitude); }); }, beforeDestroy() { // This resets the container layout when leaving the router page var appDiv = document.getElementById("app"); //appDiv.style.marginTop="60px"; appDiv.style.paddingRight = "15px"; appDiv.style.paddingLeft = "15px"; }, } </script> <style scoped> html, body, #map-observation { margin: 0; width: 100%; } #ObservationMapPanel { position: absolute; bottom: 0; left: 0; } #btnBack { position: fixed; z-index: 2000; } #map-mylocation { position: fixed; right: 0; z-index: 2000; } </style>