new setting: begin drawing a new trail from current location (#592)

* new setting: begin drawing a new trail from  current location

* apply only when drawing

* fix application when editing an existing route

* documentation

* ignore pointer events on location circles

* fix i18n

---------

Co-authored-by: Flomp <Flomp@users.noreply.github.com>
Co-authored-by: Christian Beutel <>
This commit is contained in:
slothful-vassal
2026-02-28 10:15:43 +01:00
committed by GitHub
parent 230f42d639
commit bd293e6739
19 changed files with 151 additions and 19 deletions

View File

@@ -0,0 +1,41 @@
package migrations
import (
"github.com/pocketbase/pocketbase/core"
m "github.com/pocketbase/pocketbase/migrations"
)
func init() {
m.Register(func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("uavt73rsqcn1n13")
if err != nil {
return err
}
// add field
if err := collection.Fields.AddMarshaledJSONAt(12, []byte(`{
"hidden": false,
"id": "json1001103536",
"maxSize": 0,
"name": "behavior",
"presentable": false,
"required": false,
"system": false,
"type": "json"
}`)); err != nil {
return err
}
return app.Save(collection)
}, func(app core.App) error {
collection, err := app.FindCollectionByNameOrId("uavt73rsqcn1n13")
if err != nil {
return err
}
// remove field
collection.Fields.RemoveById("json1001103536")
return app.Save(collection)
})
}

View File

@@ -38,3 +38,12 @@ To add the respective URLs navigate to `Settings -> Display` and add them in the
2. Locate the compass control in the top-right corner of the map.
3. Click and drag the compass control to tilt the map into 3D mode.
4. Adjust the tilt and rotation as desired to view the terrain in 3D.
## Route drawing behavior
You can configure how new route drawing starts in `Settings -> Display`.
- Enable `Begin drawing a new trail from your current location` to automatically center route drawing on your current GPS location.
- Disable it to start drawing at the current map view instead.
This option only affects creating a **new** trail in the route editor.

View File

@@ -5,7 +5,6 @@
import type { Trail } from "$lib/models/trail";
import type { Waypoint } from "$lib/models/waypoint";
import { theme } from "$lib/stores/theme_store";
import { fetchGPX } from "$lib/stores/trail_store";
import { findStartAndEndPoints } from "$lib/util/geojson_util";
import {
createMarkerFromWaypoint,
@@ -69,6 +68,7 @@
trail: Trail,
) => void;
oninit?: (map: M.Map) => void;
autoGeolocateOnDrawing?: boolean;
}
let {
@@ -99,6 +99,7 @@
onclick,
onUnclusteredClick,
oninit,
autoGeolocateOnDrawing = false,
}: Props = $props();
let mapContainer: HTMLDivElement;
@@ -592,6 +593,10 @@
if (trails[activeTrail]) {
removeStartEndMarkers(trails[activeTrail].id);
}
if (autoGeolocateOnDrawing) {
geolocate();
}
}
function stopDrawing() {
@@ -731,6 +736,8 @@
}
}
let geolocateControl : M.GeolocateControl;
onMount(async () => {
const initialState = {
lng: 0,
@@ -800,8 +807,7 @@
"top-left",
);
map.addControl(
new M.GeolocateControl({
geolocateControl = new M.GeolocateControl({
positionOptions: {
enableHighAccuracy: true,
},
@@ -809,7 +815,8 @@
animate: fitBounds == "animate",
},
trackUserLocation: true,
}));
});
map.addControl(geolocateControl);
if (showStyleSwitcher) {
map.addControl(switcherControl);
@@ -901,6 +908,17 @@
showWaypoints();
});
function geolocate() {
if (!page.data.settings?.behavior) return;
if (page.data.settings.behavior.allowAutoGeolocate === true) {
if (geolocateControl._watchState === 'OFF') {
geolocateControl.options.trackUserLocation = true;
geolocateControl.trigger();
}
}
}
onDestroy(() => {
map?.remove();
});
@@ -982,4 +1000,8 @@
padding-bottom: 2.5px;
@apply bg-menu-item-background-focus w-3 aspect-square rounded-full;
}
:global(.maplibregl-user-location-accuracy-circle, .maplibregl-user-location-dot) {
pointer-events: none;
}
</style>

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Routen hinzugefügt zu",
"after": "Nach",
"all-activities": "Alle Aktivitäten",
"allow-auto-geolocate": "Beginne das Zeichnen einer neuen Route am aktuellen Standort",
"alphabetical": "Alphabetisch",
"already-account": "Du hast bereits ein Konto?",
"altitude": "Höhe",
@@ -35,6 +36,7 @@
"basic-info": "Basisinformation",
"basque": "Baskisch",
"before": "Vor",
"behavior": "Verhalten",
"bicycle-parking": "Fahrrad-Parkplatz",
"bicycle-rental": "Fahrradverleih",
"bicycle-shop": "Fahrrad-Reparatur",
@@ -215,8 +217,8 @@
"invalid-username": "Ungültiger Nutzername",
"italian": "Italienisch",
"joined": "Beigetreten",
"keep-private": "Ohne Veröffentlichung fortfahren",
"keep-original": "",
"keep-private": "Ohne Veröffentlichung fortfahren",
"language": "Sprache",
"latitude": "Breitengrad",
"layer": "{n, plural, =1 {Ebene} other {Ebenen}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Added trails to",
"after": "After",
"all-activities": "All activities",
"allow-auto-geolocate": "Begin drawing a new trail from your current location",
"alphabetical": "Alphabetical",
"already-account": "Already have an account?",
"altitude": "Altitude",
@@ -35,6 +36,7 @@
"basic-info": "Basic Info",
"basque": "Basque",
"before": "Before",
"behavior": "Behavior",
"bicycle-parking": "Bicycle Parking",
"bicycle-rental": "Bicycle Rental",
"bicycle-shop": "Bicycle Shop",
@@ -215,8 +217,8 @@
"invalid-username": "Invalid username",
"italian": "Italian",
"joined": "Joined",
"keep-private": "Keep private",
"keep-original": "Keep original",
"keep-private": "Keep private",
"language": "Language",
"latitude": "Latitude",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Rutas añadidas a",
"after": "Después",
"all-activities": "Todas las actividades",
"allow-auto-geolocate": "",
"alphabetical": "Alfabético",
"already-account": "¿Ya tienes una cuenta?",
"altitude": "Altitud",
@@ -213,9 +214,9 @@
"invalid-date": "Fecha no válida",
"invalid-username": "Usuario no válido",
"italian": "Italiano",
"keep-private": "Keep private",
"joined": "Afiliado",
"keep-original": "",
"keep-private": "Keep private",
"language": "Idioma",
"latitude": "Latitud",
"layer": "{n, plural, one {}=1 {Lista} other {Listas}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Ibilbideak hona gehitu dira",
"after": "Ondoren",
"all-activities": "Ekintza guztiak",
"allow-auto-geolocate": "",
"alphabetical": "Alfabetikoa",
"already-account": "Baduzu kontua lehendik?",
"altitude": "Altuera",
@@ -215,8 +216,8 @@
"invalid-username": "Erabiltzailea ez da zuzena",
"italian": "Italiera",
"joined": "Sartu da",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Hizkuntza",
"latitude": "Latitudea",
"layer": "{n, plural, one {}=1 {geruza} other {geruza}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Ajouter les itinéraires à",
"after": "Après",
"all-activities": "Toutes les activités",
"allow-auto-geolocate": "",
"alphabetical": "Alphabétique",
"already-account": "Déjà un compte ?",
"altitude": "Altitude",
@@ -215,8 +216,8 @@
"invalid-username": "Nom d'utilisateur invalide",
"italian": "Italien",
"joined": "Rejoint",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Langue",
"latitude": "Latitude",
"layer": "{n, plural, =1 {Calque} other {Calques}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Hozzáadott nyomvonalak a",
"after": "After",
"all-activities": "All activities",
"allow-auto-geolocate": "",
"alphabetical": "Betűrendben",
"already-account": "Már rendelkezik fiókkal?",
"altitude": "Magasság",
@@ -215,8 +216,8 @@
"invalid-username": "Érvénytelen felhasználó",
"italian": "Olasz",
"joined": "Joined",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Nyelf",
"latitude": "Szélesség",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Percorsi aggiunto a",
"after": "Dopo",
"all-activities": "Tutte le Attività",
"allow-auto-geolocate": "",
"alphabetical": "Alfabetico",
"already-account": "Hai già un account?",
"altitude": "Altitudine",
@@ -215,8 +216,8 @@
"invalid-username": "Nome utente non valido",
"italian": "Italiano",
"joined": "Aggiunto",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Lingua",
"latitude": "Latitudine",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Route toegevoegd aan",
"after": "Na",
"all-activities": "Alle activiteiten",
"allow-auto-geolocate": "",
"alphabetical": "Alfabetisch",
"already-account": "Heb je al een account?",
"altitude": "Hoogte",
@@ -216,8 +217,8 @@
"invalid-username": "Ongeldige gebruikersnaam",
"italian": "Italiaans",
"joined": "Aangesloten",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Taal",
"latitude": "Breedtegraad",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Dodaj szlaki do",
"after": "Po",
"all-activities": "Wszystkie aktywności",
"allow-auto-geolocate": "",
"alphabetical": "Alfabetyczne",
"already-account": "Czy masz już konto?",
"altitude": "Wysokość",
@@ -215,8 +216,8 @@
"invalid-username": "Błędna nazwa użytkownika",
"italian": "Włoski",
"joined": "Dołączono",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Język",
"latitude": "Szerokość",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "trilhas adicionada para",
"after": "Depois",
"all-activities": "Todas as atividades",
"allow-auto-geolocate": "",
"alphabetical": "Alfabético",
"already-account": "Já tem uma conta?",
"altitude": "Altitude",
@@ -215,8 +216,8 @@
"invalid-username": "Nome de usuário inválido",
"italian": "Italiano",
"joined": "Joined",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Língua",
"latitude": "Latitude",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Added trails to",
"after": "После",
"all-activities": "Все активности",
"allow-auto-geolocate": "",
"alphabetical": "По алфавиту",
"already-account": "Уже есть аккаунт?",
"altitude": "Высота",
@@ -215,8 +216,8 @@
"invalid-username": "Некорректное имя пользователя",
"italian": "Итальянский",
"joined": "Зарегистрирован",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Язык",
"latitude": "Широта",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "添加路线到",
"after": "之后",
"all-activities": "所有活动",
"allow-auto-geolocate": "",
"alphabetical": "字母",
"already-account": "已注册账户?",
"altitude": "海拔",
@@ -215,8 +216,8 @@
"invalid-username": "无效用户名",
"italian": "意大利语",
"joined": "已加入",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "语言",
"latitude": "纬度",
"layer": "{n, plural, =1 {层} other {层}}",

View File

@@ -21,8 +21,8 @@ const SettingsCreateSchema = z.object({
trails: z.enum(["public", "private"]),
lists: z.enum(["public", "private"])
}).optional().nullable(),
notifications: z.record(z.enum(Object.values(NotificationType) as [string, ...string[]]), z.object({ web: z.boolean(), email: z.boolean() })).optional().nullable()
notifications: z.record(z.enum(Object.values(NotificationType) as [string, ...string[]]), z.object({ web: z.boolean(), email: z.boolean() })).optional().nullable(),
behavior: z.object({ allowAutoGeolocate: z.boolean() }).optional().nullable(),
}) satisfies ZodType<Settings>
ZodType<Partial<Comment>>

View File

@@ -30,6 +30,7 @@ class Settings {
user?: string;
privacy?: { account: "public" | "private", trails: "public" | "private", lists: "public" | "private" } | null
notifications?: Record<NotificationType, { web: boolean, email: boolean }> | null
behavior?: Behavior | null;
constructor(
unit: "metric" | "imperial",
@@ -54,5 +55,9 @@ class Settings {
}
}
export type Behavior = {
allowAutoGeolocate: boolean;
}
export { Settings };

View File

@@ -14,13 +14,41 @@
} from "$lib/stores/search_store";
import { settings_update } from "$lib/stores/settings_store";
import { currentUser } from "$lib/stores/user_store";
import { country_codes } from "$lib/util/country_code_util";
import { getIconForLocation } from "$lib/util/icon_util";
import { onMount } from "svelte";
import { _ } from "svelte-i18n";
import Toggle from "$lib/components/base/toggle.svelte";
import { show_toast } from "$lib/stores/toast_store.svelte.js";
let settings = $derived(page.data.settings);
let allowAutoGeolocate = $state(
page.data.settings.behavior?.allowAutoGeolocate ?? false,
);
async function handleAllowAutoGeolocateChange() {
if (!settings) {
return;
}
try {
if (!settings.behavior) {
settings.behavior = { allowAutoGeolocate: allowAutoGeolocate };
} else {
settings.behavior.allowAutoGeolocate = allowAutoGeolocate;
}
await settings_update(settings);
} catch (e) {
show_toast({
type: "error",
icon: "close",
text: "Error updating behavior settings",
});
console.error(e);
}
}
const mapFocus: SelectItem[] = [
{ text: $_("trail", { values: { n: 2 } }), value: "trails" },
{ text: $_("location"), value: "location" },
@@ -138,6 +166,18 @@
></Search>
</div>
{/if}
<div
class="mt-4 grid gap-4"
style="grid-template-columns: 1fr min-content ;"
>
<p>{$_("allow-auto-geolocate")}</p>
<div>
<Toggle
bind:value={allowAutoGeolocate}
onchange={handleAllowAutoGeolocateChange}
></Toggle>
</div>
</div>
</div>
<div>
<h4 class="text-xl font-medium mb-2">{$_("tilesets")}</h4>

View File

@@ -1504,6 +1504,7 @@
waypoints={$formData.expand?.waypoints_via_trail}
drawing={drawingActive}
showTerrain={true}
autoGeolocateOnDrawing={page.params.id === "new"}
onmarkerdragend={moveMarker}
activeTrail={0}
bind:map