diff --git a/src/assets/styles/base.css b/src/assets/styles/base.css index 00f8d4f9a991c0cfd25f9bdda21fd88d49e6c5fb..c25e98d716f4725f7441ac69adc8b3acd1c8a3ef 100644 --- a/src/assets/styles/base.css +++ b/src/assets/styles/base.css @@ -378,55 +378,3 @@ body { background: #f3f3f3 !important; color: #35495e !important; } - -/* OPENLAYERS */ -.ol-zoom{ - right: 5px !important; - left:unset !important; -} - -.ol-popup { - position: absolute; - background-color: white; - padding: 15px; - border-radius: 10px; - border: 1px solid #cccccc; - bottom: 12px; - left: -106px; - width: 212px; - line-height: 1.4; - -webkit-box-shadow: 0px 0px 15px -1px #000000; - box-shadow: 0px 0px 15px -1px #000000; - font: 12px/1.5 Helvetica Neue,Arial,Helvetica,sans-serif; -} - -.ol-popup:after, .ol-popup:before { - top: 100%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; -} -.ol-popup:after { - border-top-color: white; - border-width: 10px; - left: 50%; - margin-left: -10px; -} -.ol-popup:before { - border-top-color: #cccccc; - border-width: 11px; - left: 50%; - margin-left: -11px; -} -.ol-popup-closer { - text-decoration: none; - position: absolute; - top: 2px; - right: 8px; -} -.ol-popup-closer:after { - content: "✖"; -} diff --git a/src/assets/styles/openlayers-custom.css b/src/assets/styles/openlayers-custom.css index b73eac42fd961037c9e5721833f6880af22b0b37..ae0d89b123f4edc8ea0f4ec182de4b2c65c85cd8 100644 --- a/src/assets/styles/openlayers-custom.css +++ b/src/assets/styles/openlayers-custom.css @@ -1,3 +1,60 @@ +/* OPENLAYERS */ +.ol-zoom{ + right: 5px !important; + left:unset !important; +} + +.ol-popup { + position: absolute; + background-color: white; + padding: 15px; + border-radius: 10px; + bottom: 12px; + left: -106px; + min-width: 212px; + line-height: 1.4; + -webkit-box-shadow: 0 3px 14px rgba(0,0,0,.4); + box-shadow: 0 3px 14px rgba(0,0,0,.4); +} +.ol-popup #popup-content { + white-space: nowrap; + color: #2d2d2d; +} + +.ol-popup:after, .ol-popup:before { + top: 100%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; +} +.ol-popup:after { + border-top-color: white; + border-width: 10px; + left: 50%; + margin-left: -10px; +} +.ol-popup:before { + border-top-color: #cccccc; + border-width: 11px; + left: 50%; + margin-left: -11px; +} +.ol-popup-closer { + text-decoration: none; + position: absolute; + top: 4px; + right: 0; + width: 24px; + height: 24px; + font: 18px/24px Tahoma,Verdana,sans-serif; + color: #757575; +} +.ol-popup-closer:after { + content: "×"; +} .ol-scale-line { left: 2em; background: hsla(0,0%,100%,.5); @@ -34,41 +91,6 @@ background-color: #ebebeb; } -/* .leaflet-bar { - box-shadow: none !important; -} - -.leaflet-bar a { - background-color: #fff; - color: #000; - height: 30px !important; - width: 30px !important; - font: 700 16px Lucida Console,Monaco,monospace; - margin: 0; -} -.leaflet-bar a:hover { - cursor: pointer; - background-color: #ebebeb; -} - -.leaflet-bar a > i { - margin: 0; -} */ - - -/* For geocoder search bar */ -.multiselect { - font: 500 12px Lucida Console,Monaco,monospace; -} -.multiselect__content-wrapper { - border: 2px solid rgba(0,0,0,.2) !important; - background-clip: padding-box !important; - padding: 0 !important; - border-top: none !important; - left: -2px; - width: calc(100% + 4px) !important; -} - /* hide the popup before the map get loaded */ .map-container > #popup.ol-popup { display: none; diff --git a/src/components/Map/SidebarLayers.vue b/src/components/Map/SidebarLayers.vue index 093708ed05fd5536508657e34326a6dac2e4eeaf..4fc128c702dafec74b6afd8128d515fcde0940f7 100644 --- a/src/components/Map/SidebarLayers.vue +++ b/src/components/Map/SidebarLayers.vue @@ -228,7 +228,11 @@ export default { onQueryLayerChange(layer) { this.selectedQueryLayer = layer.name; - this.baseMaps[0].layers.find((l) => l.title === layer.name).query = true; + if (this.baseMaps[0].layers.find((l) => l.title === layer.name)) { + this.baseMaps[0].layers.find((l) => l.title === layer.name).query = true; + } else { + console.error('No such param \'query\' found among basemap[0].layers'); + } layer.query = true; }, @@ -365,7 +369,7 @@ export default { addLayers(baseMap) { baseMap.layers.forEach((layer) => { - var layerOptions = this.availableLayers.find((l) => l.id === layer.id); + const layerOptions = this.availableLayers.find((l) => l.id === layer.id); layer = Object.assign(layer, layerOptions); layer.options.basemapId = baseMap.id; }); diff --git a/src/components/Project/Detail/ProjectFeatureTypes.vue b/src/components/Project/Detail/ProjectFeatureTypes.vue index 4ba419bd064c23f4bdd2c64cd97a0e26ff38fd9f..81cfd78cd9125a44120f088e849d5c02eeff45de 100644 --- a/src/components/Project/Detail/ProjectFeatureTypes.vue +++ b/src/components/Project/Detail/ProjectFeatureTypes.vue @@ -591,7 +591,7 @@ export default { onGeoJSONFileChange(e) { this.importing = true; - var files = e.target.files || e.dataTransfer.files; + const files = e.target.files || e.dataTransfer.files; if (!files.length) { return; } @@ -620,7 +620,7 @@ export default { onCSVFileChange(e) { this.featureTypeImporting = true; - var files = e.target.files || e.dataTransfer.files; + const files = e.target.files || e.dataTransfer.files; if (!files.length) { return; } diff --git a/src/services/map-service.js b/src/services/map-service.js index 6c37c0b27841519b75063469643672828ab40044..e7110447754398651092bd8e478460f396921667 100644 --- a/src/services/map-service.js +++ b/src/services/map-service.js @@ -24,24 +24,6 @@ import router from '@/router'; let dictLayersToLeaflet = {}; -let statusList = [ - { - name: 'Brouillon', - value: 'draft', - }, - { - name: 'Publié', - value: 'published', - }, - { - name: 'Archivé', - value: 'archived', - }, - { - name: 'En attente de publication', - value: 'pending', - }, -]; const mapService = { layers: [], @@ -58,9 +40,11 @@ const mapService = { getMap() { return this.map; }, + destroyMap() { this.map = undefined; }, + createMap(el, options) { const { lat, @@ -133,8 +117,8 @@ const mapService = { router.push({ name: 'details-signalement', params: { - slug_type_signal: featureTypeSlug, //'1-polygones' - slug_signal: featureId, //'d267c6fa-d676-45c9-8e34-ec3d1bcc7c25' + slug_type_signal: featureTypeSlug, + slug_signal: featureId, }, }); } @@ -143,7 +127,7 @@ const mapService = { router.push({ name: 'details-type-signalement', params: { - feature_type_slug: featureTypeSlug, //'1-polygones' + feature_type_slug: featureTypeSlug, }, }); } @@ -152,11 +136,13 @@ const mapService = { }, onMapClick(event) { + //* retrieve features under pointer const features = this.map.getFeaturesAtPixel(event.pixel, { - layerFilter: (l) => l === this.mvtLayer + layerFilter: (l) => l === this.mvtLayer || this.olLayer }); + //* prepare popup content if (features && features.length > 0) { - const popupContent = this._createContentPopup(features[0], this.mvtLayer.featureTypes); + const popupContent = this._createContentPopup(features[0], this.featureTypes); this.content.innerHTML = popupContent.html; this.overlay.setPosition(event.coordinate); this.addRouterToPopup(popupContent.feature_type.slug, popupContent.featureId); @@ -188,42 +174,31 @@ const mapService = { } }); params.url = urlInfos[0]; - let self = this; axios.get( window.proxy_url, - { - params: params, - } + { params } ).then(response => { const data = response.data; - var err = typeof data === 'object' ? null : data; - if (data.features || err) { - self.showGetFeatureInfo(err, event, data, queryLayer); - } - }) - .catch(error => { - throw (error); - } - ); + const err = typeof data === 'object' ? null : data; + if (data.features || err) this.showGetFeatureInfo(err, event, data, queryLayer); + }).catch(error => { + throw error; + }); } } }, - showGetFeatureInfo: function (err, event, data, layer) { + showGetFeatureInfo: function (err, event, data, layer) { let content; - if (err) { content = ` <h4>${layer.options.title}</h4> <p>Données de la couche inaccessibles</p> `; - this.content.innerHTML = content; this.overlay.setPosition(event.coordinate); - } else { - - // Otherwise show the content in a popup + } else { // Otherwise show the content in a popup const contentLines = []; let contentTitle; if (data.features.length > 0) { @@ -238,10 +213,10 @@ const mapService = { this.content.innerHTML = content; this.overlay.setPosition(event.coordinate); - } } }, + getFeatureInfoUrl(event, layer) { const olLayer = dictLayersToLeaflet[layer.id]; const source = olLayer.getSource(); @@ -253,12 +228,14 @@ const mapService = { } return url; }, + fitBounds(bounds) { let ext = boundingExtent([[bounds[0][1], bounds[0][0]], [bounds[1][1], bounds[1][0]]]); ext = transformExtent(ext, 'EPSG:4326', 'EPSG:3857'); this.map.getView().fit(ext, { padding: [25, 25, 25, 25] }); }, + fitExtent(ext) { //ext = transformExtent(ext, 'EPSG:4326', 'EPSG:3857'); this.map.getView().fit(ext, { padding: [25, 25, 25, 25] }); @@ -270,7 +247,6 @@ const mapService = { if (layers) { //* if admin has defined basemaps for this project let count = 0; layers.forEach((layer) => { - if (layer) { count +=1; const options = layer.options; @@ -335,14 +311,12 @@ const mapService = { Object.values(dictLayersToLeaflet).forEach(element => { this.map.removeLayer(element); }); - dictLayersToLeaflet = {}; }, updateOpacity(layerId, opacity) { const layer = dictLayersToLeaflet[layerId]; layer.setOpacity(parseFloat(opacity)); - }, updateOrder(layers) { @@ -366,9 +340,8 @@ const mapService = { } }, - addVectorTileLayer: function (url, projectId, projectSlug, featureTypes, formFilters) { - let format_cfg = {/*featureClass: Feature*/ }; - + addVectorTileLayer: function (url, projectId, featureTypes, formFilters) { + const format_cfg = {/*featureClass: Feature*/ }; const mvt = new MVT(format_cfg); const options = { urls: [], @@ -384,8 +357,7 @@ const mapService = { style: styleFunction, source: layerSource }); - this.mvtLayer.featureTypes = featureTypes; - this.mvtLayer.project_slug = projectSlug; + this.featureTypes = featureTypes; // store featureTypes for popups this.mvtLayer.setZIndex(30); this.map.addLayer(this.mvtLayer); window.layerMVT = this.mvtLayer; @@ -471,7 +443,7 @@ const mapService = { let retour; // TODO verifier utilité de cette boucle et remplacer par readFeatures plutot features.forEach((feature) => { - retour = new GeoJSON().readFeature(feature, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' }); + retour = new GeoJSON().readFeature(feature, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857' }, featureTypes); drawSource.addFeature(retour); // const featureProperties = feature.properties ? feature.properties : feature; // const featureType = featureTypes @@ -493,6 +465,8 @@ const mapService = { }); olLayer.setZIndex(29); this.map.addLayer(olLayer); + this.olLayer = olLayer; + this.featureTypes = featureTypes; // store featureTypes for popups return drawSource; }, @@ -502,33 +476,36 @@ const mapService = { _createContentPopup: function (feature, featureTypes) { const formatDate = (current_datetime) => { - let formatted_date = current_datetime.getFullYear() + '-' + ('0' + (current_datetime.getMonth() + 1)).slice(-2) + '-' + ('0' + current_datetime.getDate()).slice(-2) + ' ' + + let formatted_date = current_datetime.getFullYear() + '-' + ('0' + (current_datetime.getMonth() + 1)).slice(-2) + '-' + ('0' + current_datetime.getDate()).slice(-2) + ' ' + ('0' + current_datetime.getHours()).slice(-2) + ':' + ('0' + current_datetime.getMinutes()).slice(-2); return formatted_date; }; let feature_type; let status; let date_maj; - + let creator; + if (feature.getProperties) { status = feature.getProperties().status; + if (status) status = status.label; date_maj = feature.getProperties().updated_on; - } else { + creator = feature.getProperties().creator; + if (featureTypes) { + feature_type = feature.getProperties().feature_type || + featureTypes.find((x) => x.slug.split('-')[0] === '' + feature.getProperties().feature_type_id); + } + } else { //? I couldn't find when this code is used, is this still in use ? status = feature.status; + if (status) status = status.name; date_maj = feature.updated_on; + creator = feature.creator; + if (featureTypes) { + feature_type = featureTypes.find((x) => x.slug === feature.feature_type.slug); + } } - - if (featureTypes) { // => VectorTile - feature_type = featureTypes.find((x) => x.slug.split('-')[0] === '' + feature.getProperties().feature_type_id); - status = statusList.find((x) => x.value === feature.getProperties().status).name; - date_maj = formatDate(new Date(feature.getProperties().updated_on)); - } else { - feature_type = feature.getProperties ? feature.getProperties().feature_type : feature.feature_type; - status = feature.getProperties ? feature.getProperties().status.label : feature.status.label; - } + if(date_maj && date_maj.updated_on) date_maj = formatDate(new Date(date_maj.updated_on)); let author = ''; - const creator = feature.getProperties ? feature.getProperties().creator : feature.creator; if (creator) { author = creator.full_name ? `<div> @@ -549,13 +526,14 @@ const mapService = { Type : <a id="goToFeatureTypeDetail" class="pointer"> ${feature_type.title} </a> </div> <div> - Dernière mise à jour : ${date_maj} + Dernière mise à jour : ${date_maj} </div> ${author} `; const featureId = feature.getProperties ? feature.getProperties().feature_id : feature.id; return { html, feature_type, featureId }; }, + zoomTo(location, zoomlevel, lon, lat) { if (lon && lat) { location = [+lon, +lat]; @@ -565,8 +543,8 @@ const mapService = { }, addOverlay(loc) { - var pos = fromLonLat(loc); - var marker = new Overlay({ + const pos = fromLonLat(loc); + const marker = new Overlay({ position: pos, positioning: OverlayPositioning.CENTER_CENTER, element: document.getElementById('marker'), diff --git a/src/views/Project/FeaturesListAndMap.vue b/src/views/Project/FeaturesListAndMap.vue index ec2d2bd5012c056ab30e1f0f0b4dc52f719368e7..37d3784dd293ee5af158649bec5c70f254900611 100644 --- a/src/views/Project/FeaturesListAndMap.vue +++ b/src/views/Project/FeaturesListAndMap.vue @@ -351,16 +351,14 @@ export default { }); // --------- End sidebar events ---------- - let self=this; setTimeout(() => { const project_id = this.projectSlug.split('-')[0]; const mvtUrl = `${this.API_BASE_URL}features.mvt/`; mapService.addVectorTileLayer( mvtUrl, project_id, - self.projectSlug, - self.feature_types, - self.form + this.feature_types, + this.form ); }, 1000); diff --git a/src/views/Project/ProjectDetail.vue b/src/views/Project/ProjectDetail.vue index 3a9f4f75f222ac54c9581bde85e326cdcbf5c5b5..ee473009b4cbba8e5911b1359053a75536071e05 100644 --- a/src/views/Project/ProjectDetail.vue +++ b/src/views/Project/ProjectDetail.vue @@ -437,12 +437,11 @@ export default { if (this.project && this.permissions.can_view_project) { await this.INITIATE_MAP(this.$refs.map); this.checkForOfflineFeature(); - let project_id = this.$route.params.slug.split('-')[0]; + const project_id = this.$route.params.slug.split('-')[0]; const mvtUrl = `${this.API_BASE_URL}features.mvt`; mapService.addVectorTileLayer( mvtUrl, project_id, - this.$route.params.slug, this.feature_types ); this.mapLoading = false;