From f6ea3be74614ddff5d80b1c1b38297dad968e385 Mon Sep 17 00:00:00 2001 From: sedum Date: Tue, 6 Dec 2022 00:03:53 +0100 Subject: [PATCH] geocoding and tilelayer tests are working also on setup, add support for photon --- components/WhereInput.vue | 91 ++++++++++++++----- components/admin/Geolocation.vue | 144 +++++++++++++++--------------- components/admin/Places.vue | 9 +- components/admin/Settings.vue | 9 +- locales/en.json | 9 +- locales/it.json | 10 ++- server/api/controller/place.js | 31 +++++-- server/api/controller/settings.js | 1 + server/api/index.js | 3 +- server/helpers.js | 1 + store/index.js | 1 + 11 files changed, 192 insertions(+), 117 deletions(-) diff --git a/components/WhereInput.vue b/components/WhereInput.vue index 520b83b8..68517cc3 100644 --- a/components/WhereInput.vue +++ b/components/WhereInput.vue @@ -46,7 +46,7 @@ v-row.mb-4 :items="addressList" :hint="$t('event.address_description' + (settings.allow_geolocation && '_osm'))") template(v-slot:message="{message, key}") - span(v-html='message' :key="key") + span(v-html='message' :key="key") template(v-slot:item="{ item, attrs, on }") v-list-item(v-bind='attrs' v-on='on') v-icon.pr-4(v-text='loadCoordinatesResultIcon(item)') @@ -76,7 +76,7 @@ export default { props: { value: { type: Object, default: () => ({}) } }, - data () { + data ( {$store} ) { return { mdiMap, mdiMapMarker, mdiPlus, mdiMapSearch, mdiLatitude, mdiLongitude, mdiRoadVariant, mdiHome, mdiCityVariant, place: { }, @@ -91,7 +91,14 @@ export default { node: mdiMapMarker, relation: mdiCityVariant, }, - nominatim_class: ['amenity', 'shop', 'tourism', 'leisure', 'building'] + nominatim_class: ['amenity', 'shop', 'tourism', 'leisure', 'building'], + photon_osm_key: ['amenity', 'shop', 'tourism', 'leisure', 'building'], + photon_osm_type: { + 'W': mdiRoadVariant, + 'N': mdiMapMarker, + 'R': mdiCityVariant, + }, + geocoding_provider_type: $store.state.settings.geocoding_provider_type || 'Nominatim' } }, computed: { @@ -126,10 +133,17 @@ export default { } }, 100), loadCoordinatesResultIcon(item) { - if ( this.nominatim_class.includes(item.class)) { - return this.mdiHome + if (this.geocoding_provider_type == "Nominatim") { + if ( this.nominatim_class.includes(item.class)) { + return this.mdiHome + } + return this.nominatim_osm_type[item.type] + } else if (this.geocoding_provider_type == "Photon") { + if ( this.photon_osm_key.includes(item.class)) { + return this.mdiHome + } + return this.photon_osm_type[item.type] } - return this.nominatim_osm_type[item.type] }, selectPlace (p) { if (!p) { return } @@ -220,22 +234,55 @@ export default { if (searchCoordinates.length) { this.loading = true - const ret = await this.$axios.$get(`placeNominatim/${searchCoordinates}`) - if (ret && ret.length) { - this.addressList = ret.map(v => { - const name = get(v.namedetails, 'alt_name', get(v.namedetails, 'name')) - const address = v.display_name ? v.display_name.replace(name, '').replace(/^, ?/, '') : '' - return { - class: v.class, - type: v.osm_type, - lat: v.lat, - lon: v.lon, - name, - address - } - }) - } else { - this.addressList = [] + const ret = await this.$axios.$get(`placeOSM/${this.geocoding_provider_type}/${searchCoordinates}`) + if (this.geocoding_provider_type == "Nominatim") { + if (ret && ret.length) { + this.addressList = ret.map(v => { + const name = get(v.namedetails, 'alt_name', get(v.namedetails, 'name')) + const address = v.display_name ? v.display_name.replace(name, '').replace(/^, ?/, '') : '' + return { + class: v.class, + type: v.osm_type, + lat: v.lat, + lon: v.lon, + name, + address + } + }) + } else { + this.addressList = [] + } + } else if (this.geocoding_provider_type == "Photon") { + let photon_properties = ['housenumber', 'street', 'district', 'city', 'county', 'state', 'postcode', 'country'] + + if (ret) { + this.addressList = ret.features.map(v => { + let pre_name = v.properties.name || v.properties.street || '' + let pre_address = '' + + photon_properties.forEach((item, i) => { + let last = i == (photon_properties.length - 1) + if (v.properties[item] && !last) { + pre_address += v.properties[item]+', ' + } else if (v.properties[item]) { + pre_address += v.properties[item] + } + }); + + let name = pre_name + let address = pre_address + return { + class: v.properties.osm_key, + type: v.properties.osm_type, + lat: v.geometry.coordinates[1], + lon: v.geometry.coordinates[0], + name, + address + } + }) + } else { + this.addressList = [] + } } this.loading = false } diff --git a/components/admin/Geolocation.vue b/components/admin/Geolocation.vue index f96f9cd9..e5c1c67d 100644 --- a/components/admin/Geolocation.vue +++ b/components/admin/Geolocation.vue @@ -1,9 +1,17 @@ @@ -49,20 +56,26 @@ import { isoCountries } from '../../server/helpers/geolocation' import "leaflet/dist/leaflet.css" export default { + props: { + setup: { type: Boolean, default: false } + }, data ({ $store }) { return { - isValid: false, loading: false, testGeocodingLoading: false, testTileLayerLoading: false, + geocoding_provider_type_items: ['Nominatim', 'Photon'], + geocoding_provider_type: $store.state.settings.geocoding_provider_type || '', + geocoding_provider_type_default: 'Nominatim', geocoding_provider: $store.state.settings.geocoding_provider || '', - geocoding_provider_default: "https://nominatim.openstreetmap.org/" , + geocoding_provider_default: "https://nominatim.openstreetmap.org/search" , geocoding_countrycodes: $store.state.settings.geocoding_countrycodes || [], tilelayer_provider: $store.state.settings.tilelayer_provider || '', + tilelayer_provider_default: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', tilelayer_provider_attribution: $store.state.settings.tilelayer_provider_attribution || '', - tilelayer_provider_default: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + tilelayer_provider_attribution_default: 'OpenStreetMap contributors', countries: isoCountries, - mapTest: {}, + mapPreviewTest: null, } }, created() { @@ -70,69 +83,49 @@ export default { const L = require('leaflet') } }, - computed: { - ...mapState(['settings', 'events']), - }, + computed: mapState(['settings', 'events']), methods: { ...mapActions(['setSetting']), async testGeocodingProvider () { this.testGeocodingLoading = true + const geocodingProviderTest = this.geocoding_provider || this.geocoding_provider_default + const geocodingSoftwareTest = this.geocoding_provider_type || this.geocoding_provider_type_default + const geocodingQuery = 'building' + try { - const geolocation = await this.$axios.$get(`${this.geocoding_provider}search`, {timeout: 3000, params: {format: 'json', q: 'building', limit: 1}}) - this.$root.$message(this.$t('admin.geocoding_test_success', { service_name: this.geocoding_provider }), { color: 'success' }) + if (geocodingSoftwareTest === 'Nominatim') { + const geolocation = await this.$axios.$get(`${geocodingProviderTest}`, {timeout: 3000, params: {q: `${geocodingQuery}`, format: 'json', limit: 1 }} ) + } else if (geocodingSoftwareTest === 'Photon') { + const geolocation = await this.$axios.$get(`${geocodingProviderTest}`, {timeout: 3000, params: {q: `${geocodingQuery}`, limit: 1}} ) + } + + this.$root.$message(this.$t('admin.geocoding_test_success', { service_name: geocodingProviderTest }), { color: 'success' }) } catch (e) { - // console.error(e) - this.$root.$message(e, { color: 'error' }) + this.$root.$message(this.$t('admin.tilelayer_test_error', { service_name: geocodingProviderTest }), { color: 'error' }) } this.testGeocodingLoading = false }, async testTileLayerProvider () { this.testTileLayerLoading = true - try { - // clean - // if (this.mapTest !== null) { - // this.mapTest.off(); - // this.mapTest.remove(); - // } - // init tilelayer - this.mapTest = L.map("leaflet-map").setView([40,40],10); - this.tileLayer = L.tileLayer(`${this.tilelayer_provider}`, {attribution: `${this.tilelayer_provider_attribution}`}) - const tileLayer = await this.tileLayer.addTo(this.mapTest) + const tileThis = this + const tileLayerTest = this.tilelayer_provider || this.tilelayer_provider_default + const tileLayerAttributionTest = this.tilelayer_provider_attribution || this.tilelayer_provider_attribution_default - - this.tileLayer.on('loading', function (event) { - console.log(event) - // this.mapTest.fireEvent('dataloading', event); - }); - - // this.tileLayer.on('load', function (event) { - // // this.mapTest.fireEvent('dataload', event); - // }); - - // this.tileLayer.on('tileerror', function(error, tile) { - // console.log(error); - // console.log(tile); - // }); - // - // this.tileLayer.on('tileabort', this.tileLayer.remove()) - // - this.mapTest.off() - this.mapTest.remove() - - // mapTest.on('dataload', handler) - - - // function handler(event) { - // if (mapTest && mapTest.remove) { - // mapTest.off(); - // mapTest.remove(); - // } - // } - - } catch (e) { - console.error(e) - this.$root.$message(e.response && e.response.data, { color: 'error' }) + // init tilelayer + if (this.mapPreviewTest == null) { + this.mapPreviewTest = L.map("leaflet-map-preview").setView([40,40],10); } + this.tileLayer = L.tileLayer(`${tileLayerTest}`, {attribution: `${tileLayerAttributionTest}`}) + this.tileLayer.addTo(this.mapPreviewTest) + + // tilelayer events inherited from gridlayer https://leafletjs.com/reference.html#gridlayer + this.tileLayer.on('tileload', function (event) { + tileThis.tileLayerTestSucess(event, tileLayerTest) + }); + this.tileLayer.on('tileerror', function(error, tile) { + tileThis.tileLayerTestError(event, tileLayerTest) + tileThis.tileLayer = null + }); this.testTileLayerLoading = false }, save (key, value) { @@ -143,15 +136,22 @@ export default { done () { this.$emit('close') }, - handlerLoad(event) { - // this.mapTest.fireEvent('dataload', (event) => { - this.$root.$message(this.$t('admin.tilelayer_test_success', { service_name: this.tilelayer_provider }), { color: 'success' }) - if (this.mapTest !== null) { - this.mapTest.off(); - this.mapTest.remove(); - } + geocodingTestError(event, tileLayerTest) { + this.$root.$message(this.$t('admin.geocoding_test_error', { service_name: geocodingTest }), { color: 'error' }) + }, + tileLayerTestSucess(event, tileLayerTest) { + this.$root.$message(this.$t('admin.tilelayer_test_success', { service_name: tileLayerTest }), { color: 'success' }) + }, + tileLayerTestError(event, tileLayerTest) { + this.$root.$message(this.$t('admin.tilelayer_test_error', { service_name: tileLayerTest }), { color: 'error' }) } } } + + diff --git a/components/admin/Places.vue b/components/admin/Places.vue index 78a773f5..63e14ee5 100644 --- a/components/admin/Places.vue +++ b/components/admin/Places.vue @@ -84,7 +84,8 @@ export default { { value: 'address', text: this.$t('common.address') }, { value: 'map', text: 'Map' }, { value: 'actions', text: this.$t('common.actions'), align: 'right' } - ] + ], + geocoding_provider_type: $store.state.settings.geocoding_provider_type || 'Nominatim' } }, async fetch() { @@ -124,7 +125,7 @@ export default { this.place.latitude = this.place.longitude = null } this.$emit('input', { ...this.place }) - }, + }, searchAddress: debounce(async function(ev) { const pre_searchCoordinates = ev.target.value.trim().toLowerCase() // allow pasting coordinates lat/lon and lat,lon @@ -159,7 +160,7 @@ export default { if (searchCoordinates.length) { this.loading = true - const ret = await this.$axios.$get(`placeNominatim/${searchCoordinates}`) + const ret = await this.$axios.$get(`placeOSM/${this.geocoding_provider_type}/${searchCoordinates}`) if (ret && ret.length) { this.addressList = ret.map(v => { const name = get(v.namedetails, 'alt_name', get(v.namedetails, 'name')) @@ -176,7 +177,7 @@ export default { } this.loading = false } - }, 300) + }, 300) } } diff --git a/components/admin/Settings.vue b/components/admin/Settings.vue index 82eb3fd0..b8769034 100644 --- a/components/admin/Settings.vue +++ b/components/admin/Settings.vue @@ -54,20 +54,19 @@ v-container v-dialog(v-model='showSMTP' destroy-on-close max-width='700px' :fullscreen='$vuetify.breakpoint.xsOnly') SMTP(@close='showSMTP = false') - v-card-actions v-btn(text @click='showSMTP=true') {{$t('admin.show_smtp_setup')}} - v-btn(text @click='$emit("complete")' color='primary' v-if='setup') {{$t('common.next')}} - v-icon(v-text='mdiArrowRight') v-dialog(v-model='showGeolocationConfigs' destroy-on-close max-width='700px' :fullscreen='$vuetify.breakpoint.xsOnly') - Geolocation(@close='showGeolocationConfigs = false') - + Geolocation(setup, @close='showGeolocationConfigs = false') v-card-actions v-btn(text @click='showGeolocationConfigs=true') {{$t('admin.show_geolocation_setup')}} + v-btn(text @click='$emit("complete")' color='primary' v-if='setup') {{$t('common.next')}} + v-icon(v-text='mdiArrowRight') +