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",
],
"dice-five": ["water_park", "theme_park", "casino"],
"arrow-right": ["other"],
"train": ["train"],
"car-side":["car"],
"bycicle":["bike"],
"plane":["plane", "flight"],
"": ["?", "neighbourhood", "quarter", "highway", "place"],
};

View File

@ -44,7 +44,7 @@ const process_results = function (tpe: "nominatim" | "travel", r: geoloc[]) {
});
case "travel":
return r.map((el) => {
(el as any).path = getGeoLine(
el.path = getGeoLine(
{
lat: (el as any).from_geo.lat,
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 toast from "./types/toast";
import search_drawer from "./types/search_drawer";
import { to_xy } from "./types/geom";
Vue.component("l-map", window.Vue2Leaflet.LMap);
Vue.component("l-tile-layer", window.Vue2Leaflet.LTileLayer);
@ -36,10 +37,12 @@ const app = new Vue({
generate_rotation: function (index, list) {
if (index < 0 || index >= list.length) return 0;
const c0 = list[(index == 0) ? index : (index - 1)]
const c1 = list[(index == (list.length - 1)) ? index : (index + 1)]
const brng = Math.atan2(c1[1] - c0[1], c1[0] - c0[0]);
return `rotate:${brng - Math.PI / 2}rad`;
const c0 = to_xy(list[(index == 0) ? 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])- Math.PI / 2;
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) {
@ -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>`;
},
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) {
e.target.style['height'] = 'auto';
e.target.style['height'] = e.target.scrollHeight + 'px';
@ -91,7 +70,7 @@ const app = new Vue({
sname: this.search_drawer.query.query,
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) => {
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() }

View File

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

View File

@ -160,6 +160,15 @@ function recursiveMidPoint(src: LatLng, dst: LatLng, opt: { step?: number, dist?
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)
}

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.places.activities = v.places.activities || (v as any).places.places;
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)
return e;

View File

@ -1,5 +1,6 @@
import { search_flight, search_nominatim } from "../helper/api";
import { leg_template } from "./format";
import journey_wrapper from "./wrapper";
declare global {
@ -10,21 +11,22 @@ declare global {
interface query {
type: query_type | note_type | "",
sub: sub_type | "",
query: String,
query: string,
res: any[],
load: Boolean,
load: boolean,
/* DELETE BELOW IF POSIBLE */
addmarker: Boolean,
}
interface map_override {
active: Boolean,
elements: geoloc[]
elements: number[][]
}
}
class search_drawer {
map_override: map_override = { active: false, elements: [] };
multipath : any[]=[];
query: query = {
type: "", query: "", sub: "", res: [], load: false, addmarker: false,
@ -45,12 +47,21 @@ class search_drawer {
is_note() {
return ["notes"].includes(this.query.type)
}
is_place(){
return ["hotel", "restaurant", "place"].includes(this.query.type)
}
is_query() {
return ["hotel", "restaurant", "place", "flight"].includes(this.query.type)
return this.is_place()|| this.is_flight() || this.is_multipath()
}
is_sub_travel() {
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[]) {
this.query.load = false;
@ -59,6 +70,8 @@ class search_drawer {
}
reset() {
this.query.res = [];
this.multipath = [];
this.map_override.elements = []
this.query.type = "";
this.query.addmarker = false;
setTimeout(() => this.resfresh_map(), 500);
@ -88,6 +101,48 @@ class search_drawer {
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 'restaurant': return this.leg_get().places.restaurants.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);
}
}

View File

@ -12,26 +12,61 @@
.spinner(v-if="search_drawer.query.load")
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" )
.query-result.col-12.bg-white.text-dark(
:key="'q'+idx"
@mouseover="drawer_hover_item(item)"
@mouseleave="drawer_hover_item()"
@click="drawer_click_item(item)" )
@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="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")
template(v-for="(item, idx) in search_drawer.query.res" )
.query-result.col-12.bg-white.text-dark(
:key="'q'+idx"
@mouseover="drawer_hover_item(item)"
@mouseleave="drawer_hover_item()"
@click="drawer_click_item(item)" )
@mouseover="search_drawer.hover_item(item)"
@mouseleave="search_drawer.hover_item()"
@click="search_drawer.click_item(journey,item)" )
div( v-html="generate_icon(item, 'var(--dark)')")
.col-10()
| {{ item.name }}

View File

@ -4,6 +4,10 @@ l-map(
@click="onMapClick"
style="height:100%"
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':''"
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')"
)
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')"
)
span.row.text-small.text-dark(v-else) {{ place.notes }}

View File

@ -1,5 +1,5 @@
.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')")
div(v-if="!search_drawer.is_query()" @click="search_drawer.enable('hotel')")
.map-menu-item( v-html="generate_icon('bed')")
@ -8,14 +8,14 @@
div(v-if="!search_drawer.is_query()" @click="search_drawer.enable('place')")
.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-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('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('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
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')")
div(v-if="!search_drawer.is_note()" @click="search_drawer.enable('notes')")
.map-menu-item( v-html="generate_icon('pencil')")

View File

@ -3,7 +3,7 @@ mixin flight_popup()
:options="{maxWidth:400, minWidth:300}"
)
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")
.row.input(style="margin-bottom:0")
textarea.col-12.col-sm-12.text-small(
@ -14,7 +14,7 @@ mixin flight_popup()
span(v-if="journey.edit")
.leaflet-popup-button-group()
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')"
)
@ -24,9 +24,10 @@ div(v-for= "(travel, idx) in journey.leg_get().travel")
l-marker(
v-for="(place, index) in travel.path"
:key="'plane'+index"
:key="'trvl'+index"
: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()