Reworked watcher events and describing texts
This commit is contained in:
+61
-7
@@ -251,13 +251,57 @@ button,
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
#start-tracking.ui-button {
|
||||
width: 100%;
|
||||
min-height: 3rem;
|
||||
.route-controls {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: .5rem;
|
||||
margin: 0 0 1rem;
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.route-controls button {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
min-width: 0;
|
||||
min-height: 3.25rem;
|
||||
box-sizing: border-box;
|
||||
padding: .55rem;
|
||||
border: 1px solid transparent;
|
||||
border-radius: .55rem;
|
||||
box-shadow: 0 .12rem .35rem rgba(0, 0, 0, .12);
|
||||
cursor: pointer;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
.route-controls button:focus-visible {
|
||||
outline: .2rem solid var(--focus);
|
||||
outline-offset: .15rem;
|
||||
}
|
||||
|
||||
.route-controls button:disabled {
|
||||
cursor: default;
|
||||
filter: grayscale(.65);
|
||||
opacity: .42;
|
||||
}
|
||||
|
||||
.route-controls img {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#start-route {
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
border-color: var(--primary-dark);
|
||||
}
|
||||
|
||||
#pause-route {
|
||||
background: #9a6500;
|
||||
border-color: #704a00;
|
||||
}
|
||||
|
||||
#stop-route {
|
||||
background: #9b2c2c;
|
||||
border-color: #701f1f;
|
||||
}
|
||||
|
||||
#slideshow {
|
||||
@@ -371,11 +415,21 @@ button,
|
||||
|
||||
.app-page > header .back-button.ui-button:hover,
|
||||
.app-page > header .back-button.ui-button:focus,
|
||||
#start-tracking.ui-button:hover,
|
||||
#start-tracking.ui-button:focus {
|
||||
#start-route:not(:disabled):hover,
|
||||
#start-route:not(:disabled):focus {
|
||||
background: var(--primary-dark);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#pause-route:not(:disabled):hover,
|
||||
#pause-route:not(:disabled):focus {
|
||||
background: #704a00;
|
||||
}
|
||||
|
||||
#stop-route:not(:disabled):hover,
|
||||
#stop-route:not(:disabled):focus {
|
||||
background: #701f1f;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 32rem) {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" role="img" aria-hidden="true"><path fill="#fff" d="M12 8h9v32h-9zm15 0h9v32h-9z"/></svg>
|
||||
|
After Width: | Height: | Size: 149 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" role="img" aria-hidden="true"><path fill="#fff" d="M14 8v32l26-16z"/></svg>
|
||||
|
After Width: | Height: | Size: 136 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" role="img" aria-hidden="true"><path fill="#fff" d="M10 10h28v28H10z"/></svg>
|
||||
|
After Width: | Height: | Size: 137 B |
+11
-1
@@ -79,7 +79,17 @@
|
||||
<div><dt>POIs</dt><dd id="route-poi-count">–</dd></div>
|
||||
</dl>
|
||||
|
||||
<button id="start-tracking" type="button">GPS-Begleitung starten</button>
|
||||
<div class="route-controls" role="group" aria-label="Routensteuerung">
|
||||
<button id="start-route" type="button" aria-label="Route starten" title="Route starten">
|
||||
<img src="images/icons/play.svg" alt="">
|
||||
</button>
|
||||
<button id="pause-route" type="button" aria-label="Route pausieren" title="Route pausieren" disabled>
|
||||
<img src="images/icons/pause.svg" alt="">
|
||||
</button>
|
||||
<button id="stop-route" type="button" aria-label="Route beenden" title="Route beenden" disabled>
|
||||
<img src="images/icons/stop.svg" alt="">
|
||||
</button>
|
||||
</div>
|
||||
<p id="tracking-status" class="notice" hidden></p>
|
||||
|
||||
<h2>Stationen</h2>
|
||||
|
||||
+80
-29
@@ -6,7 +6,7 @@
|
||||
route: null,
|
||||
position: null,
|
||||
triggered: new Set(),
|
||||
tracking: false,
|
||||
routeState: 'idle',
|
||||
activePage: null,
|
||||
routeProgressIndex: null,
|
||||
deviceHeading: null
|
||||
@@ -151,27 +151,55 @@
|
||||
$('#app-shell').addClass('has-navigation');
|
||||
}
|
||||
|
||||
function updateTrackingButton() {
|
||||
const button = $('#start-tracking');
|
||||
button.button('option', {
|
||||
label: state.tracking ? 'GPS-Begleitung stoppen' : 'GPS-Begleitung starten',
|
||||
icon: state.tracking ? 'ui-icon-stop' : 'ui-icon-pin-s'
|
||||
});
|
||||
}
|
||||
|
||||
function stopTracking() {
|
||||
state.tracking = false;
|
||||
state.routeProgressIndex = null;
|
||||
state.deviceHeading = null;
|
||||
function stopRouteSensors() {
|
||||
ns.Geo.stop();
|
||||
ns.Orientation.stop();
|
||||
$('#tracking-status').prop('hidden', true).text('');
|
||||
state.deviceHeading = null;
|
||||
}
|
||||
|
||||
function updateRouteControls() {
|
||||
const running = state.routeState === 'running';
|
||||
const paused = state.routeState === 'paused';
|
||||
const startLabel = paused ? 'Route fortsetzen' : 'Route starten';
|
||||
|
||||
$('#start-route')
|
||||
.prop('disabled', running)
|
||||
.attr({ 'aria-label': startLabel, title: startLabel });
|
||||
$('#pause-route').prop('disabled', !running);
|
||||
$('#stop-route').prop('disabled', state.routeState === 'idle');
|
||||
}
|
||||
|
||||
function endRoute({ announce = true } = {}) {
|
||||
const wasActive = state.routeState !== 'idle';
|
||||
state.routeState = 'idle';
|
||||
state.routeProgressIndex = null;
|
||||
state.triggered.clear();
|
||||
stopRouteSensors();
|
||||
hideNavigation();
|
||||
updateTrackingButton();
|
||||
|
||||
if (announce && wasActive) {
|
||||
$('#tracking-status').prop('hidden', false).text('Route beendet.');
|
||||
} else {
|
||||
$('#tracking-status').prop('hidden', true).text('');
|
||||
}
|
||||
|
||||
updateRouteControls();
|
||||
}
|
||||
|
||||
function pauseRoute() {
|
||||
if (state.routeState !== 'running') return;
|
||||
|
||||
state.routeState = 'paused';
|
||||
stopRouteSensors();
|
||||
$('#tracking-status')
|
||||
.prop('hidden', false)
|
||||
.text('Route pausiert. Die Standortverfolgung ist angehalten.');
|
||||
showNavigation('Route pausiert', $('#navigation-distance').text() || '–');
|
||||
updateRouteControls();
|
||||
}
|
||||
|
||||
function renderRoute(route) {
|
||||
if (state.tracking) stopTracking();
|
||||
if (state.routeState !== 'idle') endRoute({ announce: false });
|
||||
|
||||
state.route = route;
|
||||
state.triggered.clear();
|
||||
@@ -181,6 +209,8 @@
|
||||
$('#route-distance').text(ns.Distance.format(route.distanceM));
|
||||
$('#route-elevation').text(`${Math.round(route.elevationGainM)} m`);
|
||||
$('#route-poi-count').text(route.pois.length);
|
||||
$('#tracking-status').prop('hidden', true).text('');
|
||||
updateRouteControls();
|
||||
|
||||
const list = $('#poi-list').empty();
|
||||
if (!route.pois.length) {
|
||||
@@ -235,7 +265,7 @@
|
||||
|
||||
function updateNavigation(position) {
|
||||
const points = state.route?.points || [];
|
||||
if (!state.tracking || !points.length) return;
|
||||
if (state.routeState !== 'running' || !points.length) return;
|
||||
|
||||
const nearestIndex = nearestRoutePointIndex(position);
|
||||
if (nearestIndex == null) return;
|
||||
@@ -298,7 +328,7 @@
|
||||
|
||||
function evaluatePosition(position) {
|
||||
state.position = position;
|
||||
if (!state.route || !state.tracking) return;
|
||||
if (!state.route || state.routeState !== 'running') return;
|
||||
|
||||
updateNavigation(position);
|
||||
|
||||
@@ -321,13 +351,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function startTracking() {
|
||||
state.tracking = true;
|
||||
state.routeProgressIndex = null;
|
||||
async function startRoute() {
|
||||
if (!state.route || state.routeState === 'running') return;
|
||||
|
||||
const resumed = state.routeState === 'paused';
|
||||
if (!resumed) {
|
||||
state.routeProgressIndex = null;
|
||||
state.triggered.clear();
|
||||
}
|
||||
|
||||
state.routeState = 'running';
|
||||
state.deviceHeading = null;
|
||||
updateTrackingButton();
|
||||
$('#tracking-status').prop('hidden', false).text('GPS wird gestartet.');
|
||||
showNavigation();
|
||||
updateRouteControls();
|
||||
$('#tracking-status')
|
||||
.prop('hidden', false)
|
||||
.text(resumed ? 'Route wird fortgesetzt.' : 'Route wird gestartet. GPS wird aktiviert.');
|
||||
showNavigation(resumed ? 'Route wird fortgesetzt' : 'Position wird ermittelt');
|
||||
|
||||
ns.Geo.start(
|
||||
evaluatePosition,
|
||||
@@ -335,7 +374,12 @@
|
||||
);
|
||||
|
||||
const orientationAvailable = await ns.Orientation.start(updateHeading);
|
||||
if (!orientationAvailable && state.tracking) {
|
||||
if (state.routeState !== 'running') {
|
||||
ns.Orientation.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!orientationAvailable) {
|
||||
$('#navigation-mode').text('Norden oben · nächster Routenpunkt');
|
||||
}
|
||||
}
|
||||
@@ -372,9 +416,16 @@
|
||||
else navigate(target, { replace: true });
|
||||
});
|
||||
|
||||
activate('#start-tracking', async function () {
|
||||
if (state.tracking) stopTracking();
|
||||
else await startTracking();
|
||||
activate('#start-route', async function () {
|
||||
await startRoute();
|
||||
});
|
||||
|
||||
activate('#pause-route', function () {
|
||||
pauseRoute();
|
||||
});
|
||||
|
||||
activate('#stop-route', function () {
|
||||
endRoute();
|
||||
});
|
||||
|
||||
window.addEventListener('popstate', event => {
|
||||
@@ -415,7 +466,7 @@
|
||||
context.markStep('location', 'done');
|
||||
initializeRouteSearch();
|
||||
renderRoutes();
|
||||
updateTrackingButton();
|
||||
updateRouteControls();
|
||||
hideNavigation();
|
||||
}
|
||||
};
|
||||
|
||||
Vendored
-1
@@ -44,7 +44,6 @@
|
||||
const $ = window.jQuery;
|
||||
$('#bootstrap-retry').button({ icon: 'ui-icon-refresh' });
|
||||
$('.back-button').button({ icon: 'ui-icon-caret-1-w' });
|
||||
$('#start-tracking').button({ icon: 'ui-icon-pin-s' });
|
||||
$('#clear-route-search').button({ icon: 'ui-icon-close', showLabel: false });
|
||||
$('#slide-prev').button({ icon: 'ui-icon-caret-1-w', showLabel: false });
|
||||
$('#slide-next').button({ icon: 'ui-icon-caret-1-e', showLabel: false });
|
||||
|
||||
Reference in New Issue
Block a user