mirror of
https://framagit.org/les/gancio.git
synced 2025-01-31 16:42:22 +01:00
added place.latitude and place.longitude, fix routes
This commit is contained in:
parent
838d1988ad
commit
0fb39b2c07
12 changed files with 168 additions and 118 deletions
|
@ -1,40 +1,42 @@
|
|||
<template lang="pug">
|
||||
v-container
|
||||
LMap(ref="map"
|
||||
id="leaflet-map"
|
||||
:zoom="zoom"
|
||||
:center="center")
|
||||
LTileLayer(
|
||||
:url="url"
|
||||
:attribution="attribution")
|
||||
LMarker(
|
||||
v-for="item in markers"
|
||||
:key="item.id"
|
||||
:lat-lng="item.position"
|
||||
:visible="item.visible"
|
||||
:draggable="item.draggable")
|
||||
|
||||
v-row.my-4.d-flex.justify-center
|
||||
v-btn.ml-2(icon large :href="routeByWalk()")
|
||||
v-icon(v-text='mdiWalk' color='white')
|
||||
v-btn.ml-2(icon large :href="routeByBike()")
|
||||
v-icon(v-text='mdiBike' color='white')
|
||||
v-btn.ml-2(icon large :href="routeByBus()")
|
||||
v-icon(v-text='mdiBus' color='white')
|
||||
v-btn.ml-2(icon large :href="routeByCar()")
|
||||
v-icon(v-text='mdiCar' color='white')
|
||||
|
||||
client-only(placeholder='Loading...' )
|
||||
v-container
|
||||
LMap(ref="map"
|
||||
id="leaflet-map"
|
||||
:zoom="zoom"
|
||||
:center="center")
|
||||
LTileLayer(
|
||||
:url="url"
|
||||
:attribution="attribution")
|
||||
LMarker(
|
||||
v-for="item in markers"
|
||||
@add="openPopup"
|
||||
:key="item.id"
|
||||
:lat-lng="item.coordinates")
|
||||
LPopup(:content="item.address")
|
||||
|
||||
v-row.my-4.d-flex.flex-column.align-center
|
||||
.text-h6
|
||||
v-icon(v-text='mdiMapMarker' )
|
||||
nuxt-link.ml-2.p-name.text-decoration-none(v-text="event.place.name" :to='`/place/${event.place.name}`')
|
||||
v-text.mx-2(v-text="`${event.place.address}`")
|
||||
v-text.my-4(v-text="$t('common.getting_there')")
|
||||
v-row
|
||||
v-btn.ml-2(icon large :href="routeByWalk()")
|
||||
v-icon(v-text='mdiWalk' color='white')
|
||||
v-btn.ml-2(icon large :href="routeByBike()")
|
||||
v-icon(v-text='mdiBike' color='white')
|
||||
v-btn.ml-2(icon large :href="routeByCar()")
|
||||
v-icon(v-text='mdiCar' color='white')
|
||||
|
||||
</template>
|
||||
<script>
|
||||
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import { LMap, LTileLayer, LMarker, LPopup } from 'vue2-leaflet';
|
||||
import dayjs from 'dayjs';
|
||||
import { mapActions, mapState } from 'vuex'
|
||||
import { Icon } from 'leaflet';
|
||||
import { mdiWalk, mdiBike, mdiCar, mdiBus } from '@mdi/js'
|
||||
import { mdiWalk, mdiBike, mdiCar, mdiMapMarker } from '@mdi/js'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -45,21 +47,25 @@ export default {
|
|||
},
|
||||
data ({ $store }) {
|
||||
return {
|
||||
mdiWalk, mdiBike, mdiCar, mdiBus,
|
||||
mdiWalk, mdiBike, mdiCar, mdiMapMarker,
|
||||
// url: "https://a.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png",
|
||||
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
attribution:
|
||||
'© <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a> contributors',
|
||||
zoom: 10,
|
||||
center: [42, 12],
|
||||
markers: [],
|
||||
zoom: 14,
|
||||
center: [this.event.place.latitude, this.event.place.longitude],
|
||||
markers: [
|
||||
{
|
||||
address: this.event.place.address,
|
||||
coordinates: {lat: this.event.place.latitude, lon: this.event.place.longitude}
|
||||
}
|
||||
],
|
||||
osm_navigation: 'https://www.openstreetmap.org/directions?from=&to=',
|
||||
routingType: [
|
||||
{foot: "engine=fossgis_osrm_foot"},
|
||||
{bike: "engine=fossgis_osrm_bike"},
|
||||
{transit: null},
|
||||
{car: "engine=fossgis_osrm_car"},
|
||||
]
|
||||
routingType: {
|
||||
foot: "engine=fossgis_osrm_foot",
|
||||
bike: "engine=fossgis_osrm_bike",
|
||||
car: "engine=fossgis_osrm_car"
|
||||
}
|
||||
}
|
||||
},
|
||||
props: {
|
||||
|
@ -82,46 +88,23 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
...mapActions(['setSetting']),
|
||||
|
||||
openPopup(event) {
|
||||
this.$nextTick(() => {
|
||||
event.target.openPopup();
|
||||
});
|
||||
},
|
||||
route (routingTypes) {
|
||||
return this.osm_navigation+this.event.place.latitude+','+this.event.place.longitude+'&'+routingTypes
|
||||
},
|
||||
routeByWalk() {
|
||||
console.log(this.$root.$event)
|
||||
// return this.osm_navigation+this.$root.event.place.details+'&'+this.routingType.bike
|
||||
return this.route(this.routingType.foot)
|
||||
},
|
||||
routeByBike() {
|
||||
console.log(this.event.place)
|
||||
// return this.osm_navigation+this.$root.event.place.details+'&'+this.routingType.bike
|
||||
},
|
||||
routeByBus() {
|
||||
console.log(this.$root)
|
||||
// return this.osm_navigation+this.$root.event.place.details+'&'+this.routingType.bike
|
||||
return this.route(this.routingType.bike)
|
||||
},
|
||||
routeByCar() {
|
||||
console.log(this.$root)
|
||||
// return this.osm_navigation+this.$root.event.place.details+'&'+this.routingType.bike
|
||||
return this.route(this.routingType.car)
|
||||
},
|
||||
route() {
|
||||
|
||||
}
|
||||
// loadMarker(d) {
|
||||
// this.event = JSON.stringify(d);
|
||||
//
|
||||
// let newMarker = [{
|
||||
// id: d.id,
|
||||
// title: d.title,
|
||||
// event: JSON.stringify(d),
|
||||
// description: d.description,
|
||||
// place: d.place,
|
||||
// tags: d.tags,
|
||||
// multidate: d.multidate,
|
||||
// start_datetime: d.start_datetime,
|
||||
// end_datetime: d.end_datetime,
|
||||
// position: { lat: d.place.details.geometry.coordinates[1], lng: d.place.details.geometry.coordinates[0] },
|
||||
// draggable: false,
|
||||
// visible: true
|
||||
// }]
|
||||
//
|
||||
// this.markers.push.apply(this.markers, newMarker)
|
||||
// },
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +114,7 @@ export default {
|
|||
#leaflet-map {
|
||||
height: 55vh;
|
||||
width: 100%;
|
||||
border-radius: .5rem;
|
||||
border-radius: .3rem;
|
||||
border: 1px solid #fff;
|
||||
z-index: 1;
|
||||
}
|
||||
|
|
|
@ -30,28 +30,38 @@ v-row
|
|||
:label="$t('common.address')"
|
||||
@change="changeAddress"
|
||||
:value="value.address")
|
||||
v-combobox.mr-4(ref='detailsView' v-if='settings.allow_geolocation'
|
||||
:prepend-icon='mdiMapSearch'
|
||||
:disabled='disableDetails'
|
||||
@input.native='searchCoordinates'
|
||||
:label="$t('common.coordinates')"
|
||||
:value='value.detailsView'
|
||||
persistent-hint hide-no-data clearable no-filter
|
||||
:loading='loading'
|
||||
@change='selectDetails'
|
||||
@focus='searchCoordinates'
|
||||
:items="detailsList"
|
||||
:hint="$t('event.coordinates_description')")
|
||||
template(v-slot:item="{ item, attrs, on }")
|
||||
v-list-item(v-bind='attrs' v-on='on')
|
||||
v-list-item-content(two-line v-if='item')
|
||||
v-list-item-title(v-text='item.display_name')
|
||||
v-list-item-subtitle(v-text='`${item.lat}`+`,`+`${item.lon}`')
|
||||
v-text-field(ref='details' v-if='settings.allow_geolocation')
|
||||
v-col(cols=12 md=6 v-if='settings.allow_geolocation')
|
||||
v-combobox.mr-4(ref='detailsView'
|
||||
:prepend-icon='mdiMapSearch'
|
||||
:disabled='disableDetails'
|
||||
@input.native='searchCoordinates'
|
||||
:label="$t('common.coordinates')"
|
||||
:value='value.detailsView'
|
||||
persistent-hint hide-no-data clearable no-filter
|
||||
:loading='loading'
|
||||
@change='selectDetails'
|
||||
@focus='searchCoordinates'
|
||||
:items="detailsList"
|
||||
:hint="$t('event.coordinates_description')")
|
||||
template(v-slot:item="{ item, attrs, on }")
|
||||
v-list-item(v-bind='attrs' v-on='on')
|
||||
v-list-item-content(two-line v-if='item')
|
||||
v-list-item-title(v-text='item.display_name')
|
||||
v-list-item-subtitle(v-text='`${item.lat}`+`,`+`${item.lon}`')
|
||||
v-col(cols=12 md=3 v-if='settings.allow_geolocation')
|
||||
v-text-field(ref='latitude' :value='value.latitude'
|
||||
:prepend-icon='mdiLatitude'
|
||||
:disabled='disableDetails'
|
||||
:label="$t('common.latitude')" )
|
||||
v-col(cols=12 md=3 v-if='settings.allow_geolocation')
|
||||
v-text-field(ref='longitude' :value='value.longitude'
|
||||
:prepend-icon='mdiLongitude'
|
||||
:disabled='disableDetails'
|
||||
:label="$t('common.longitude')")
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import { mdiMap, mdiMapMarker, mdiPlus, mdiMapSearch } from '@mdi/js'
|
||||
import { mdiMap, mdiMapMarker, mdiPlus, mdiMapSearch, mdiLatitude, mdiLongitude } from '@mdi/js'
|
||||
import debounce from 'lodash/debounce'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
|
@ -62,7 +72,7 @@ export default {
|
|||
},
|
||||
data () {
|
||||
return {
|
||||
mdiMap, mdiMapMarker, mdiPlus, mdiMapSearch,
|
||||
mdiMap, mdiMapMarker, mdiPlus, mdiMapSearch, mdiLatitude, mdiLongitude,
|
||||
place: { },
|
||||
placeName: '',
|
||||
places: [],
|
||||
|
@ -112,6 +122,8 @@ export default {
|
|||
this.place.address = p.address
|
||||
if (this.settings.allow_geolocation) {
|
||||
this.place.details = p.details
|
||||
this.place.latitude = p.latitude
|
||||
this.place.longitude = p.longitude
|
||||
}
|
||||
this.place.id = p.id
|
||||
this.disableAddress = true
|
||||
|
@ -130,6 +142,8 @@ export default {
|
|||
this.place.address = ''
|
||||
if (this.settings.allow_geolocation) {
|
||||
this.place.details = p.details
|
||||
this.place.latitude = p.latitude
|
||||
this.place.longitude = p.longitude
|
||||
}
|
||||
this.disableAddress = false
|
||||
this.$refs.place.blur()
|
||||
|
@ -152,6 +166,8 @@ export default {
|
|||
c.lon = v.lon
|
||||
if (typeof c === 'object') {
|
||||
this.place.details = JSON.stringify(c)
|
||||
this.place.latitude = v.lat
|
||||
this.place.longitude = v.lon
|
||||
}
|
||||
}
|
||||
this.$emit('input', { ...this.place })
|
||||
|
@ -161,6 +177,36 @@ export default {
|
|||
const pre_searchCoordinates = ev.target.value.trim().toLowerCase()
|
||||
// allow pasting coordinates lat/lon
|
||||
const searchCoordinates = pre_searchCoordinates.replace('/', ',')
|
||||
// console.log(pre_searchCoordinates)
|
||||
|
||||
var regex_coords_comma = "-?[1-9][0-9]*(\\.[0-9]+)?,\\s*-?[1-9][0-9]*(\\.[0-9]+)?";
|
||||
var regex_coords_slash = "-?[1-9][0-9]*(\\.[0-9]+)?/\\s*-?[1-9][0-9]*(\\.[0-9]+)?";
|
||||
|
||||
const setCoords = (v) => {
|
||||
this.place.latitude = v[0].trim()
|
||||
this.place.longitude = v[1].trim()
|
||||
|
||||
if (this.place.latitude < -90 || this.place.latitude > 90) {
|
||||
// non existent
|
||||
}
|
||||
if (this.place.latitude < -180 || this.place.latitude > 180) {
|
||||
// non existent
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
if (pre_searchCoordinates.match(regex_coords_comma)) {
|
||||
let v = pre_searchCoordinates.split(",")
|
||||
setCoords(v)
|
||||
return
|
||||
}
|
||||
if (pre_searchCoordinates.match(regex_coords_slash)) {
|
||||
let v = pre_searchCoordinates.split("/")
|
||||
setCoords(v)
|
||||
return
|
||||
}
|
||||
|
||||
if (searchCoordinates.length) {
|
||||
this.detailsList = await this.$axios.$get(`placeNominatim/${searchCoordinates}`)
|
||||
}
|
||||
|
|
|
@ -25,12 +25,18 @@ v-container
|
|||
v-model='place.address'
|
||||
:placeholder='$t("common.address")')
|
||||
|
||||
v-textarea(v-if="settings.allow_geolocation"
|
||||
row-height="15"
|
||||
:disabled="true"
|
||||
:label="$t('common.details')"
|
||||
v-model='place.details'
|
||||
:placeholder='$t("common.details")')
|
||||
v-text-field(v-if="settings.allow_geolocation"
|
||||
:rules="[$validators.required('common.latitude')]"
|
||||
:label="$t('common.latitude')"
|
||||
v-model='place.latitude'
|
||||
:placeholder='$t("common.latitude")')
|
||||
|
||||
v-text-field(v-if="settings.allow_geolocation"
|
||||
:rules="[$validators.required('common.longitude')]"
|
||||
:label="$t('common.longitude')"
|
||||
v-model='place.longitude'
|
||||
:placeholder='$t("common.longitude")')
|
||||
|
||||
|
||||
v-card-actions
|
||||
v-spacer
|
||||
|
@ -84,7 +90,8 @@ export default {
|
|||
this.place.name = item.name
|
||||
this.place.address = item.address
|
||||
if (this.settings.allow_geolocation) {
|
||||
this.place.details = JSON.parse(item.details)
|
||||
this.place.latitude = item.latitude
|
||||
this.place.longitude = item.longitude
|
||||
}
|
||||
this.place.id = item.id
|
||||
this.dialog = true
|
||||
|
|
|
@ -91,7 +91,10 @@
|
|||
"label": "Label",
|
||||
"collections": "Collections",
|
||||
"close": "Close",
|
||||
"show_map": "Show map"
|
||||
"show_map": "Show map",
|
||||
"latitude": "Latitude",
|
||||
"longitude": "Longitude",
|
||||
"getting_there": "Getting there"
|
||||
},
|
||||
"login": {
|
||||
"description": "By logging in you can publish new events.",
|
||||
|
|
|
@ -135,7 +135,7 @@ export default {
|
|||
valid: false,
|
||||
openImportDialog: false,
|
||||
event: {
|
||||
place: { name: '', address: '', details: {} },
|
||||
place: { name: '', address: '', latitude: null, longitude: null },
|
||||
title: '',
|
||||
description: '',
|
||||
tags: [],
|
||||
|
@ -214,7 +214,8 @@ export default {
|
|||
}
|
||||
formData.append('place_name', this.event.place.name)
|
||||
formData.append('place_address', this.event.place.address)
|
||||
formData.append('place_details', this.event.place.details)
|
||||
formData.append('place_latitude', this.event.place.latitude)
|
||||
formData.append('place_longitude', this.event.place.longitude)
|
||||
formData.append('description', this.event.description)
|
||||
formData.append('multidate', !!this.date.multidate)
|
||||
formData.append('start_datetime', dayjs(this.date.from).unix())
|
||||
|
|
|
@ -35,8 +35,7 @@ v-container#event.pa-0.pa-sm-2
|
|||
v-btn.mt-2(small v-text="$t('common.show_map')" :aria-label="$t('common.show_map')" @click="mapModal = true")
|
||||
v-dialog(v-model='mapModal' :fullscreen='$vuetify.breakpoint.xsOnly' destroy-on-close)
|
||||
v-card
|
||||
client-only(placeholder='Loading...' )
|
||||
Map(:event='event')
|
||||
Map(:event='event')
|
||||
|
||||
//- tags, hashtags
|
||||
v-card-text.pt-0(v-if='event.tags && event.tags.length')
|
||||
|
|
|
@ -34,7 +34,7 @@ const eventController = {
|
|||
Sequelize.where(Sequelize.fn('LOWER', Sequelize.col('address')), 'LIKE', '%' + search + '%')
|
||||
]
|
||||
},
|
||||
attributes: [['name', 'label'], 'address', 'details', 'id', [Sequelize.cast(Sequelize.fn('COUNT', Sequelize.col('events.placeId')), 'INTEGER'), 'w']],
|
||||
attributes: [['name', 'label'], 'address', 'latitude', 'longitude', 'id', [Sequelize.cast(Sequelize.fn('COUNT', Sequelize.col('events.placeId')), 'INTEGER'), 'w']],
|
||||
include: [{ model: Event, where: { is_visible: true }, required: true, attributes: [] }],
|
||||
group: ['place.id'],
|
||||
raw: true
|
||||
|
@ -110,7 +110,7 @@ const eventController = {
|
|||
attributes: ['tag'],
|
||||
through: { attributes: [] }
|
||||
},
|
||||
{ model: Place, required: true, attributes: ['id', 'name', 'address', 'details'] }
|
||||
{ model: Place, required: true, attributes: ['id', 'name', 'address', 'latitude', 'longitude'] }
|
||||
],
|
||||
replacements,
|
||||
limit: 30,
|
||||
|
@ -192,7 +192,7 @@ const eventController = {
|
|||
},
|
||||
include: [
|
||||
{ model: Tag, required: false, attributes: ['tag'], through: { attributes: [] } },
|
||||
{ model: Place, attributes: ['name', 'address', 'details', 'id'] },
|
||||
{ model: Place, attributes: ['name', 'address', 'latitude', 'longitude', 'id'] },
|
||||
{
|
||||
model: Resource,
|
||||
where: !is_admin && { hidden: false },
|
||||
|
@ -406,7 +406,8 @@ const eventController = {
|
|||
place = await Place.create({
|
||||
name: body.place_name,
|
||||
address: body.place_address,
|
||||
details: body.place_details
|
||||
latitude: body.place_latitude,
|
||||
longitude: body.place_longitude
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -561,7 +562,8 @@ const eventController = {
|
|||
place = await Place.create({
|
||||
name: body.place_name,
|
||||
address: body.place_address,
|
||||
details: body.place_details
|
||||
latitude: body.place_latitude,
|
||||
longitude: body.place_longitude
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -700,7 +702,7 @@ const eventController = {
|
|||
attributes: ['tag'],
|
||||
through: { attributes: [] }
|
||||
},
|
||||
{ model: Place, required: true, attributes: ['id', 'name', 'address', 'details'] }
|
||||
{ model: Place, required: true, attributes: ['id', 'name', 'address', 'latitude', 'longitude'] }
|
||||
],
|
||||
...pagination,
|
||||
replacements
|
||||
|
|
|
@ -62,7 +62,7 @@ module.exports = {
|
|||
{ address: where(fn('LOWER', col('address')), 'LIKE', '%' + search + '%')},
|
||||
]
|
||||
},
|
||||
attributes: ['name', 'address', 'details', 'id'],
|
||||
attributes: ['name', 'address', 'latitude', 'longitude', 'id'],
|
||||
include: [{ model: Event, where: { is_visible: true }, required: true, attributes: [] }],
|
||||
group: ['place.id'],
|
||||
raw: true,
|
||||
|
|
|
@ -110,7 +110,8 @@ if (config.status !== 'READY') {
|
|||
* @param {string} description - event's description (html accepted and sanitized)
|
||||
* @param {string} place_name - the name of the place
|
||||
* @param {string} [place_address] - the address of the place
|
||||
* @param {array} [place_details] - the details of the place
|
||||
* @param {float} [place_latitude] - the latitude of the place
|
||||
* @param {float} [place_longitude] - the longitude of the place
|
||||
* @param {integer} start_datetime - start timestamp
|
||||
* @param {integer} multidate - is a multidate event?
|
||||
* @param {array} tags - List of tags
|
||||
|
|
|
@ -106,7 +106,8 @@ Event.prototype.toAP = function (username, locale, to = []) {
|
|||
location: {
|
||||
name: this.place.name,
|
||||
address: this.place.address,
|
||||
details: this.place.details
|
||||
latitude: this.place.latitude,
|
||||
longitude: this.place.longitude
|
||||
},
|
||||
attachment,
|
||||
tag: tags && tags.map(tag => ({
|
||||
|
|
|
@ -11,7 +11,8 @@ Place.init({
|
|||
allowNull: false
|
||||
},
|
||||
address: DataTypes.STRING,
|
||||
details: DataTypes.JSON
|
||||
latitude: DataTypes.FLOAT,
|
||||
longitude: DataTypes.FLOAT,
|
||||
}, { sequelize, modelName: 'place' })
|
||||
|
||||
module.exports = Place
|
||||
|
|
|
@ -8,8 +8,11 @@ module.exports = {
|
|||
* Example:
|
||||
* await queryInterface.createTable('users', { id: Sequelize.INTEGER });
|
||||
*/
|
||||
return queryInterface.addColumn('places', 'details', { type: Sequelize.JSON })
|
||||
|
||||
return Promise.all(
|
||||
[
|
||||
await queryInterface.addColumn('places', 'latitude', { type: Sequelize.FLOAT }),
|
||||
await queryInterface.addColumn('places', 'longitude', { type: Sequelize.FLOAT })
|
||||
])
|
||||
},
|
||||
|
||||
async down (queryInterface, Sequelize) {
|
||||
|
@ -19,7 +22,10 @@ module.exports = {
|
|||
* Example:
|
||||
* await queryInterface.dropTable('users');
|
||||
*/
|
||||
return queryInterface.removeColumn('places', 'details')
|
||||
|
||||
return Promise.all(
|
||||
[
|
||||
await queryInterface.removeColumn('places', 'latitude'),
|
||||
await queryInterface.removeColumn('places', 'longitude')
|
||||
])
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue