wip
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
soraefir 2025-03-13 01:01:17 +01:00
parent 43dfc87546
commit a2303c215e
Signed by: sora
GPG Key ID: A362EA0491E2EEA0
13 changed files with 152 additions and 58 deletions

View File

@ -139,6 +139,11 @@ export const icon_type = (item: string | NominatimResult): string => {
"nature_reserve", "nature_reserve",
], ],
"dice-five": ["water_park", "theme_park", "casino"], "dice-five": ["water_park", "theme_park", "casino"],
"arrow-right": ["other"],
"train": ["train"],
"car-side":["car"],
"bycicle":["bike"],
"plane":["plane", "flight"],
"": ["?", "neighbourhood", "quarter", "highway", "place"], "": ["?", "neighbourhood", "quarter", "highway", "place"],
}; };

View File

@ -44,7 +44,7 @@ const process_results = function (tpe: "nominatim" | "travel", r: geoloc[]) {
}); });
case "travel": case "travel":
return r.map((el) => { return r.map((el) => {
(el as any).path = getGeoLine( el.path = getGeoLine(
{ {
lat: (el as any).from_geo.lat, lat: (el as any).from_geo.lat,
lng: (el as any).from_geo.lon, lng: (el as any).from_geo.lon,

View File

@ -6,6 +6,7 @@ import { focus_day, focus_leg, nav_mouseleave, nav_mousemove } from "./helper/na
import { set_search_set_results } from "./helper/api"; import { set_search_set_results } from "./helper/api";
import toast from "./types/toast"; import toast from "./types/toast";
import search_drawer from "./types/search_drawer"; import search_drawer from "./types/search_drawer";
import { to_xy } from "./types/geom";
Vue.component("l-map", window.Vue2Leaflet.LMap); Vue.component("l-map", window.Vue2Leaflet.LMap);
Vue.component("l-tile-layer", window.Vue2Leaflet.LTileLayer); Vue.component("l-tile-layer", window.Vue2Leaflet.LTileLayer);
@ -36,10 +37,12 @@ const app = new Vue({
generate_rotation: function (index, list) { generate_rotation: function (index, list) {
if (index < 0 || index >= list.length) return 0; if (index < 0 || index >= list.length) return 0;
const c0 = list[(index == 0) ? index : (index - 1)] const c0 = to_xy(list[(index == 0) ? index : (index - 1)])
const c1 = list[(index == (list.length - 1)) ? index : (index + 1)] const c1 = to_xy(list[(index == (list.length - 1)) ? index : (index + 1)])
const brng = Math.atan2(c1[1] - c0[1], c1[0] - c0[0]); const brng = Math.atan2(c1[1] - c0[1], c1[0] - c0[0])- Math.PI / 2;
return `rotate:${brng - Math.PI / 2}rad`; const flip = (brng>-Math.PI/2)?'transform: scale(1,1);': 'transform: scale(1, -1);';
const rot = `rotate:${brng}rad;`
return `${rot}${flip}`;
}, },
generate_marker: function (item, fcolor) { generate_marker: function (item, fcolor) {
@ -54,30 +57,6 @@ const app = new Vue({
return `<i class="fa fa-${api.icon_type(item) || "star"} fa-2x ${classes}" style="${styling}; color:${fcolor || "white"}; text-align:center; align-content:center;"></i>`; return `<i class="fa fa-${api.icon_type(item) || "star"} fa-2x ${classes}" style="${styling}; color:${fcolor || "white"}; text-align:center; align-content:center;"></i>`;
}, },
drawer_hover_item: function (item) {
if (item) {
this.search_drawer.map_override.active = true
if (item.type == 'flight') {
this.search_drawer.map_override.elements = [[item.from_geo.lat, item.from_geo.lon], [item.to_geo.lat, item.to_geo.lon]]
} else {
this.search_drawer.map_override.elements = [[item.lat, item.lon]]
}
} else {
this.search_drawer.map_override.active = false
}
},
drawer_click_item: function (item) {
const tpe = this.search_drawer.query.type
this.search_drawer.reset();
this.drawer_hover_item();
if (item) {
item.step = -1;
journey_add_place(this.journey, tpe, item)
}
},
refreshTextAreaHeight: function (e) { refreshTextAreaHeight: function (e) {
e.target.style['height'] = 'auto'; e.target.style['height'] = 'auto';
e.target.style['height'] = e.target.scrollHeight + 'px'; e.target.style['height'] = e.target.scrollHeight + 'px';
@ -91,7 +70,7 @@ const app = new Vue({
sname: this.search_drawer.query.query, sname: this.search_drawer.query.query,
type: this.search_drawer.query.type, type: this.search_drawer.query.type,
}; };
this.drawer_click_item(newMarker) this.search_drawer.click_item(this.journey,newMarker)
} }
}, },
}, },
@ -123,7 +102,7 @@ const app = new Vue({
api.load(this.journey.id).then((r) => { api.load(this.journey.id).then((r) => {
app.journey.data = migrator(r) app.journey.data = migrator(r)
setTimeout(() => focus_leg(this.journey) && focus_day(this.journey) && this.$refs.map.mapObject.keyboard.disable(), 25); setTimeout(() => focus_leg(this.journey) && focus_day(this.journey) && this.$refs.map.mapObject.keyboard.disable(), 50);
; ;
this.search_drawer.refresh_map = () => { this.$refs.map.mapObject.invalidateSize() } this.search_drawer.refresh_map = () => { this.$refs.map.mapObject.invalidateSize() }

View File

@ -7,10 +7,12 @@ declare global {
} }
interface geoloc { interface geoloc {
title: string title: string
osm_id: number
latlon: [number, number]
notes: string notes: string
step: -1 type?: string
osm_id?: number
latlon?: [number, number]
step?: -1
path?: number[][]
} }
interface map { interface map {

View File

@ -160,6 +160,15 @@ function recursiveMidPoint(src: LatLng, dst: LatLng, opt: { step?: number, dist?
return geom; return geom;
} }
export function getGeoLine(src: LatLng, dst: LatLng, opt: { step?: number, dist?: number }) { export function to_xy(point: number[]){
const R = 6378137; // Earth's radius in meters (WGS84 standard)
const lon =((point[0] + 180) % 360 + 360) % 360 - 180;
const lat = ((point[1] + 90) % 180 + 180) % 180 - 90;
const x = R * (lon* Math.PI / 180);
const y = R * Math.log(Math.tan((Math.PI / 4) + (lat * Math.PI / 360)));
return [x, y];
}
export function getGeoLine(src: LatLng, dst: LatLng, opt: { step?: number, dist?: number }): LatLng[] {
return recursiveMidPoint(src, dst, opt, 1) return recursiveMidPoint(src, dst, opt, 1)
} }

View File

@ -8,7 +8,7 @@ function migrate_A_to_0(e: journey): journey {
v.day_title = v.day_title || (v as any).step_title; v.day_title = v.day_title || (v as any).step_title;
v.places.activities = v.places.activities || (v as any).places.places; v.places.activities = v.places.activities || (v as any).places.places;
v.travel = v.travel || []; v.travel = v.travel || [];
v.day_title = typeof (v.day_title) == "string" ? [v.day_title] : [] v.day_title = typeof (v.day_title) == "string" ? [v.day_title] : [];
}) })
console.log(e) console.log(e)
return e; return e;

View File

@ -1,5 +1,6 @@
import { search_flight, search_nominatim } from "../helper/api"; import { search_flight, search_nominatim } from "../helper/api";
import { leg_template } from "./format"; import { leg_template } from "./format";
import journey_wrapper from "./wrapper";
declare global { declare global {
@ -10,21 +11,22 @@ declare global {
interface query { interface query {
type: query_type | note_type | "", type: query_type | note_type | "",
sub: sub_type | "", sub: sub_type | "",
query: String, query: string,
res: any[], res: any[],
load: Boolean, load: boolean,
/* DELETE BELOW IF POSIBLE */ /* DELETE BELOW IF POSIBLE */
addmarker: Boolean, addmarker: Boolean,
} }
interface map_override { interface map_override {
active: Boolean, active: Boolean,
elements: geoloc[] elements: number[][]
} }
} }
class search_drawer { class search_drawer {
map_override: map_override = { active: false, elements: [] }; map_override: map_override = { active: false, elements: [] };
multipath : any[]=[];
query: query = { query: query = {
type: "", query: "", sub: "", res: [], load: false, addmarker: false, type: "", query: "", sub: "", res: [], load: false, addmarker: false,
@ -45,12 +47,21 @@ class search_drawer {
is_note() { is_note() {
return ["notes"].includes(this.query.type) return ["notes"].includes(this.query.type)
} }
is_place(){
return ["hotel", "restaurant", "place"].includes(this.query.type)
}
is_query() { is_query() {
return ["hotel", "restaurant", "place", "flight"].includes(this.query.type) return this.is_place()|| this.is_flight() || this.is_multipath()
} }
is_sub_travel() { is_sub_travel() {
return ["travel"].includes(this.query.sub) return ["travel"].includes(this.query.sub)
} }
is_multipath(){
return ["flight", "train", "car","bike", "other"].includes(this.query.type)
}
is_flight(){
return ["flight"].includes(this.query.type)
}
results(r: any[]) { results(r: any[]) {
this.query.load = false; this.query.load = false;
@ -59,6 +70,8 @@ class search_drawer {
} }
reset() { reset() {
this.query.res = []; this.query.res = [];
this.multipath = [];
this.map_override.elements = []
this.query.type = ""; this.query.type = "";
this.query.addmarker = false; this.query.addmarker = false;
setTimeout(() => this.resfresh_map(), 500); setTimeout(() => this.resfresh_map(), 500);
@ -88,6 +101,48 @@ class search_drawer {
if (this.is_query()) this.search() if (this.is_query()) this.search()
} }
hover_item (item?:any) {
if (item) {
this.map_override.active = true
if (item.type == 'flight') {
this.map_override.elements.push([item.from_geo.lat, item.from_geo.lon])
this.map_override.elements.push([item.to_geo.lat, item.to_geo.lon])
} else {
this.map_override.elements.push([item.lat, item.lon])
}
} else {
this.map_override.active = false
}
}
click_item (journey: journey_wrapper, item?:any) {
const tpe = this.query.type
if(this.is_multipath()){
if(this.query.addmarker){
if(item){
this.map_override.active = true
this.map_override.elements.push(item.latlon? item.latlon: [item.lat,item.lon])
this.multipath.push(item)
return;
}else{
let new_item :geoloc = {
type: (tpe as string),
path: this.map_override.elements,
title: '-',
notes: "",
}
this.map_override.active = false
journey.add_place(tpe, new_item)
}
}
}
this.reset();
this.hover_item();
if (item) {
item.step = -1;
journey.add_place(tpe, item)
}
}
} }

View File

@ -174,8 +174,12 @@ class journey_wrapper {
case 'hotel': return this.leg_get().hotel = item; case 'hotel': return this.leg_get().hotel = item;
case 'restaurant': return this.leg_get().places.restaurants.push(item); case 'restaurant': return this.leg_get().places.restaurants.push(item);
case 'place': return this.leg_get().places.activities.push(item); case 'place': return this.leg_get().places.activities.push(item);
case 'other': return; case 'other':
case 'train':
case 'car':
case 'bike':
case 'flight': return this.leg_get().travel.push(item); case 'flight': return this.leg_get().travel.push(item);
} }
} }

View File

@ -12,26 +12,61 @@
.spinner(v-if="search_drawer.query.load") .spinner(v-if="search_drawer.query.load")
div(v-if="search_drawer.is_query()") div(v-if="search_drawer.is_query()")
div(v-if="['flight'].includes(search_drawer.query.type)") div(v-if="search_drawer.is_flight()")
template(v-for="(item, idx) in search_drawer.query.res" ) template(v-for="(item, idx) in search_drawer.query.res" )
.query-result.col-12.bg-white.text-dark( .query-result.col-12.bg-white.text-dark(
:key="'q'+idx" :key="'q'+idx"
@mouseover="drawer_hover_item(item)" @mouseover="search_drawer.hover_item(item)"
@mouseleave="drawer_hover_item()" @mouseleave="search_drawer.hover_item()"
@click="drawer_click_item(item)" ) @click="search_drawer.click_item(journey,item)" )
div( v-html="generate_icon('plane', 'var(--dark)')") div( v-html="generate_icon('plane', 'var(--dark)')")
.col-10() .col-10()
| {{ item.from }} => {{item.to}} | {{ item.from }} => {{item.to}}
.bg-dark.divider( .bg-dark.divider(
:key="'qdiv'+idx" style="height:1px" ) :key="'qdiv'+idx" style="height:1px" )
.query-result.col-12.bg-white.text-dark(
v-if="!search_drawer.query.addmarker"
@click="search_drawer.query.addmarker=true" )
div( v-html="generate_icon('star', 'var(--dark)')")
.col-10()
| Start custom
.query-result.col-12.bg-white.text-dark(
v-else
@click="search_drawer.click_item(journey)" )
div( v-html="generate_icon('star', 'var(--dark)')")
.col-10()
| Finish
div(v-else-if="search_drawer.is_multipath()")
template(v-for="(item, idx) in search_drawer.query.res" )
.query-result.col-12.bg-white.text-dark(
:key="'q'+idx"
@mouseover="search_drawer.hover_item(item)"
@mouseleave="search_drawer.hover_item()"
@click="search_drawer.click_item(journey,item)" )
div( v-html="generate_icon('plane', 'var(--dark)')")
.col-10()
| {{ item.from }} => {{item.to}}
.bg-dark.divider(
:key="'qdiv'+idx" style="height:1px" )
.query-result.col-12.bg-white.text-dark(
v-if="!search_drawer.query.addmarker"
@click="search_drawer.query.addmarker=true" )
div( v-html="generate_icon('star', 'var(--dark)')")
.col-10()
| Start custom
.query-result.col-12.bg-white.text-dark(
v-else
@click="search_drawer.click_item(journey)" )
div( v-html="generate_icon('star', 'var(--dark)')")
.col-10()
| Finish
div(v-else-if="true") div(v-else-if="true")
template(v-for="(item, idx) in search_drawer.query.res" ) template(v-for="(item, idx) in search_drawer.query.res" )
.query-result.col-12.bg-white.text-dark( .query-result.col-12.bg-white.text-dark(
:key="'q'+idx" :key="'q'+idx"
@mouseover="drawer_hover_item(item)" @mouseover="search_drawer.hover_item(item)"
@mouseleave="drawer_hover_item()" @mouseleave="search_drawer.hover_item()"
@click="drawer_click_item(item)" ) @click="search_drawer.click_item(journey,item)" )
div( v-html="generate_icon(item, 'var(--dark)')") div( v-html="generate_icon(item, 'var(--dark)')")
.col-10() .col-10()
| {{ item.name }} | {{ item.name }}

View File

@ -4,6 +4,10 @@ l-map(
@click="onMapClick" @click="onMapClick"
style="height:100%" style="height:100%"
no-blocking-animations=true no-blocking-animations=true
:max-bounds="[[-90, -180],[90, 180]]"
:max-bounds-viscosity="1.0"
:world-copy-jump="true"
:no-wrap="true"
:style="search_drawer.query.addmarker?'cursor:crosshair':''" :style="search_drawer.query.addmarker?'cursor:crosshair':''"
ref="map" ref="map"
) )

View File

@ -31,7 +31,7 @@ mixin map_marker(place, color_sel_c, color_sel_o, color_else)
v-html="generate_icon(((place.step==journey.sel_day)?'calendar-xmark':'calendar-plus'), 'NA')" v-html="generate_icon(((place.step==journey.sel_day)?'calendar-xmark':'calendar-plus'), 'NA')"
) )
a.text-gray( a.text-gray(
v-on:click.prevent="place_delete(journey,\""+place+"\",index)" v-on:click.prevent="journey.del_place(\""+place+"\",index)"
v-html="generate_icon('trash', 'NA')" v-html="generate_icon('trash', 'NA')"
) )
span.row.text-small.text-dark(v-else) {{ place.notes }} span.row.text-small.text-dark(v-else) {{ place.notes }}

View File

@ -1,5 +1,5 @@
.map-menu.map-menu-top .map-menu.map-menu-top
div(v-if="search_drawer.is_query()" @click="drawer_click_item()" ) div(v-if="search_drawer.is_query()" @click="search_drawer.click_item(journey)" )
.map-menu-item(v-html="generate_icon('close')") .map-menu-item(v-html="generate_icon('close')")
div(v-if="!search_drawer.is_query()" @click="search_drawer.enable('hotel')") div(v-if="!search_drawer.is_query()" @click="search_drawer.enable('hotel')")
.map-menu-item( v-html="generate_icon('bed')") .map-menu-item( v-html="generate_icon('bed')")
@ -8,14 +8,14 @@
div(v-if="!search_drawer.is_query()" @click="search_drawer.enable('place')") div(v-if="!search_drawer.is_query()" @click="search_drawer.enable('place')")
.map-menu-item( v-html="generate_icon('star')") .map-menu-item( v-html="generate_icon('star')")
.map-menu-sub(v-if="!search_drawer.is_query()" @mouseenter="search_drawer.query.sub='travel'" @mouseleave="search_drawer.query.sub=''" ) .map-menu-sub(v-if="!search_drawer.is_query()" @mouseenter="search_drawer.query.sub='travel'" @mouseleave="search_drawer.query.sub=''" )
.map-menu-item(v-html="generate_icon('route')") .map-menu-item(@click="search_drawer.enable('other')" v-html="generate_icon('route')")
.map-menu-item(v-if="search_drawer.is_sub_travel()" @click="search_drawer.enable('flight')" v-html="generate_icon('plane')") .map-menu-item(v-if="search_drawer.is_sub_travel()" @click="search_drawer.enable('flight')" v-html="generate_icon('plane')")
.map-menu-item(v-if="search_drawer.is_sub_travel()" @click="search_drawer.enable('train')" v-html="generate_icon('train')") .map-menu-item(v-if="search_drawer.is_sub_travel()" @click="search_drawer.enable('train')" v-html="generate_icon('train')")
.map-menu-item(v-if="search_drawer.is_sub_travel()" @click="search_drawer.enable('car')" v-html="generate_icon('car')") .map-menu-item(v-if="search_drawer.is_sub_travel()" @click="search_drawer.enable('car')" v-html="generate_icon('car')")
.map-menu-item(v-if="search_drawer.is_sub_travel()" @click="search_drawer.enable('other')" v-html="generate_icon('person-biking')") .map-menu-item(v-if="search_drawer.is_sub_travel()" @click="search_drawer.enable('bike')" v-html="generate_icon('person-biking')")
.map-menu.map-menu-center .map-menu.map-menu-center
div(v-if="search_drawer.is_note()" @click="drawer_click_item()" ) div(v-if="search_drawer.is_note()" @click="search_drawer.click_item(journey)" )
.map-menu-item(v-html="generate_icon('close')") .map-menu-item(v-html="generate_icon('close')")
div(v-if="!search_drawer.is_note()" @click="search_drawer.enable('notes')") div(v-if="!search_drawer.is_note()" @click="search_drawer.enable('notes')")
.map-menu-item( v-html="generate_icon('pencil')") .map-menu-item( v-html="generate_icon('pencil')")

View File

@ -3,7 +3,7 @@ mixin flight_popup()
:options="{maxWidth:400, minWidth:300}" :options="{maxWidth:400, minWidth:300}"
) )
h1.row.text-medium.text-center.text-uppercase {{ travel.id }} h1.row.text-medium.text-center.text-uppercase {{ travel.id }}
span.row.text-small.text-gray {{ travel.from }} - {{travel.to}} span.row.text-small.text-gray {{ travel.title? travel.title:`${travel.from||'?'}-${travel.to||'?'}` }}
span(v-if="journey.edit") span(v-if="journey.edit")
.row.input(style="margin-bottom:0") .row.input(style="margin-bottom:0")
textarea.col-12.col-sm-12.text-small( textarea.col-12.col-sm-12.text-small(
@ -14,7 +14,7 @@ mixin flight_popup()
span(v-if="journey.edit") span(v-if="journey.edit")
.leaflet-popup-button-group() .leaflet-popup-button-group()
a.text-gray( a.text-gray(
v-on:click.prevent="place_delete(journey,'flight',idx)" v-on:click.prevent="journey.del_place('flight',idx)"
v-html="generate_icon('trash', 'NA')" v-html="generate_icon('trash', 'NA')"
) )
@ -24,9 +24,10 @@ div(v-for= "(travel, idx) in journey.leg_get().travel")
l-marker( l-marker(
v-for="(place, index) in travel.path" v-for="(place, index) in travel.path"
:key="'plane'+index" :key="'trvl'+index"
:lat-lng="place" :lat-lng="place"
style="margin-left:0;"
) )
l-icon(v-html="generate_icon('plane', travel.color || 'gray', generate_rotation(index,travel.path), 'travel-path-icon')" l-icon(v-html="generate_icon(travel, travel.color || 'gray', generate_rotation(index,travel.path)+'margin:-6px -6px; position:absolute', 'travel-path-icon')"
) )
+flight_popup() +flight_popup()