diff --git a/web/ticket-order.js b/web/ticket-order.js index 55c023e..b36867c 100644 --- a/web/ticket-order.js +++ b/web/ticket-order.js @@ -1,4 +1,4 @@ -(() => { +(() => { const $ = (sel) => document.querySelector(sel); const fromEl = $('#from'); const toEl = $('#to'); @@ -438,46 +438,82 @@ } function renderRouteOverlay() { - const svgEl = mapContainer.querySelector('svg'); - if (!svgEl) return; + const svgEl = mapContainer.querySelector('svg'); + if (!svgEl) return; - const existing = svgEl.querySelector('.route-overlay-group'); - if (existing) existing.remove(); + const existing = svgEl.querySelector('.route-overlay-group'); + if (existing) existing.remove(); - if (!Array.isArray(currentRoute) || currentRoute.length < 2) return; + if (!Array.isArray(currentRoute) || currentRoute.length < 2) return; - const points = currentRoute.map(getStationPoint).filter(Boolean); - if (points.length < 2) return; + const points = currentRoute.map(getStationPoint).filter(Boolean); + if (points.length < 2) return; - const ns = 'http://www.w3.org/2000/svg'; - const group = document.createElementNS(ns, 'g'); - group.setAttribute('class', 'route-overlay-group'); + const ns = 'http://www.w3.org/2000/svg'; + const group = document.createElementNS(ns, 'g'); + group.setAttribute('class', 'route-overlay-group'); - const pathData = points.map((pt, idx) => `${idx === 0 ? 'M' : 'L'} ${pt.x} ${pt.y}`).join(' '); + const pathData = points.map((pt, idx) => `${idx === 0 ? 'M' : 'L'} ${pt.x} ${pt.y}`).join(' '); - const glow = document.createElementNS(ns, 'path'); - glow.setAttribute('d', pathData); - glow.setAttribute('fill', 'none'); - glow.setAttribute('stroke', 'rgba(250, 204, 21, 0.38)'); - glow.setAttribute('stroke-width', '18'); - glow.setAttribute('stroke-linecap', 'round'); - glow.setAttribute('stroke-linejoin', 'round'); + const glow = document.createElementNS(ns, 'path'); + glow.setAttribute('d', pathData); + glow.setAttribute('fill', 'none'); + glow.setAttribute('stroke', 'rgba(250, 204, 21, 0.38)'); + glow.setAttribute('stroke-width', '18'); + glow.setAttribute('stroke-linecap', 'round'); + glow.setAttribute('stroke-linejoin', 'round'); - const main = document.createElementNS(ns, 'path'); - main.setAttribute('d', pathData); - main.setAttribute('fill', 'none'); - main.setAttribute('stroke', '#facc15'); - main.setAttribute('stroke-width', '8'); - main.setAttribute('stroke-linecap', 'round'); - main.setAttribute('stroke-linejoin', 'round'); + const main = document.createElementNS(ns, 'path'); + main.setAttribute('d', pathData); + main.setAttribute('fill', 'none'); + main.setAttribute('stroke', '#facc15'); + main.setAttribute('stroke-width', '8'); + main.setAttribute('stroke-linecap', 'round'); + main.setAttribute('stroke-linejoin', 'round'); - group.appendChild(glow); - group.appendChild(main); + group.appendChild(glow); + group.appendChild(main); - const firstStation = svgEl.querySelector('.map-station'); - if (firstStation) svgEl.insertBefore(group, firstStation); - else svgEl.appendChild(group); - } + // Dynamic arrows pointing to the destination + let totalDist = 0; + for (let i = 0; i < points.length - 1; i++) { + const dx = points[i+1].x - points[i].x; + const dy = points[i+1].y - points[i].y; + totalDist += Math.sqrt(dx * dx + dy * dy); + } + + const speed = 100; // pixels per second + const duration = Math.max(1, totalDist / speed); + const numArrows = Math.max(1, Math.floor(duration / 0.7)); // one arrow approx every 0.7s + const interval = duration / numArrows; + + for (let i = 0; i < numArrows; i++) { + const arrowG = document.createElementNS(ns, 'g'); + const arrowPath = document.createElementNS(ns, 'path'); + // Chevron shape + arrowPath.setAttribute('d', 'M -6 -5 L 4 0 L -6 5'); + arrowPath.setAttribute('fill', 'none'); + arrowPath.setAttribute('stroke', '#854d0e'); // Dark brown/orange to contrast with yellow + arrowPath.setAttribute('stroke-width', '2.5'); + arrowPath.setAttribute('stroke-linecap', 'round'); + arrowPath.setAttribute('stroke-linejoin', 'round'); + + const animateMotion = document.createElementNS(ns, 'animateMotion'); + animateMotion.setAttribute('dur', `${duration}s`); + animateMotion.setAttribute('repeatCount', 'indefinite'); + animateMotion.setAttribute('path', pathData); + animateMotion.setAttribute('rotate', 'auto'); + animateMotion.setAttribute('begin', `-${i * interval}s`); + + arrowG.appendChild(arrowPath); + arrowG.appendChild(animateMotion); + group.appendChild(arrowG); + } + + const firstStation = svgEl.querySelector('.map-station'); + if (firstStation) svgEl.insertBefore(group, firstStation); + else svgEl.appendChild(group); +} function updateSelectionUI(skipPreview = false) { if (!(selection[0] && selection[1])) {