-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
195 lines (188 loc) · 17.1 KB
/
index.html
File metadata and controls
195 lines (188 loc) · 17.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Take all lines in your city!</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" crossorigin="" />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="icon" href="favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="style.css">
</head>
<body class="bg-gray-100 text-gray-800 flex flex-col h-screen antialiased">
<div id="gtfsModal" class="fixed inset-0 z-[9999] flex items-center justify-center bg-black bg-opacity-75 transition-opacity duration-300 ease-in-out">
<div class="bg-white rounded-lg shadow-xl w-full max-w-lg mx-4 my-8 overflow-y-auto max-h-[95vh] flex flex-col">
<header class="px-6 py-4 border-b border-gray-200">
<h1 class="text-2xl font-bold text-indigo-600 text-center">🎉 Take all the lines in your city!</h1>
<details class="mt-2 text-center">
<summary class="cursor-pointer text-sm text-indigo-700 hover:underline">What is this?</summary>
<p class="text-sm text-indigo-800 mt-2 px-2">
🚍 <strong>Welcome!</strong> This tool tries to find an itinerary that lets you ride
<strong>every transit line</strong> in your city at least once. Upload a GTFS file, select a
day,
and discover the most efficient way to cover all lines.
</p>
</details>
</header>
<form class="px-6 py-4 flex-grow">
<fieldset id="step1">
<legend class="text-lg font-medium text-gray-800 mb-3">Step 1 – Load GTFS Data</legend>
<div class="mb-4">
<label for="gtfsFile" class="block text-sm font-medium text-gray-700 mb-1">GTFS Zip File</label>
<input type="file" id="gtfsFile" accept=".zip" class="mt-1 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border file:border-gray-300 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" />
</div>
<div class="p-4 bg-gray-50 rounded-md border border-gray-200" id="getGtfsInfo">
<p class="text-sm text-gray-600">
Not sure where to get data? Visit
<a href="https://mobilitydatabase.org/" target="_blank" rel="noopener" class="underline text-indigo-600 hover:text-indigo-800">
mobilitydatabase.org
</a>
or use a sample:
</p>
<div id="demoDataButtonsContainer" class="mt-3 grid grid-cols-1 sm:grid-cols-2 gap-2">
</div>
</div>
</fieldset>
<fieldset id="step2" style="display: none;">
<legend class="text-lg font-medium text-gray-800 mb-3">Step 2 – Date & Route Types</legend>
<div class="mb-4">
<label for="startDate" class="block text-sm font-medium text-gray-700 mb-1">Travel Date</label>
<input type="date" id="startDate" class="mt-1 block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500" />
<p id="gtfsDateRange" class="mt-1 text-xs text-gray-500"></p>
</div>
<div id="gtfsInfo" class="text-sm text-gray-600 hidden">
<p class="text-sm font-medium text-gray-700 mb-2">Select Route Types to Include:</p>
<div id="availableRouteTypesContainer" class="space-y-2 max-h-40 overflow-y-auto p-2 border rounded-md bg-gray-50">
<p class="text-xs text-gray-500">Route types will appear after file selection.</p>
</div>
<div id="nightBusOptionModalContainer" class="mt-3 pl-5 hidden">
<label class="flex items-center">
<input type="checkbox" id="includeNightBusToggleModal" class="h-4 w-4 text-indigo-600 border-gray-300 rounded focus:ring-indigo-500">
<span class="ml-2 text-sm text-gray-700">Include Night Buses (start with “N”)</span>
</label>
</div>
</div>
</fieldset>
<details class="mt-5 border-t pt-4 border-gray-200">
<summary class="cursor-pointer text-sm font-medium text-gray-700 hover:text-indigo-600">
Advanced Options
</summary>
<div class="mt-3 pl-1 space-y-3">
<div>
<label for="routeNamePreferenceModal" class="block text-xs font-medium text-gray-600 mb-1">Route Name Preference</label>
<select id="routeNamePreferenceModal" class="block w-full p-1.5 border border-gray-300 rounded-md shadow-sm text-sm focus:ring-indigo-500 focus:border-indigo-500 bg-white">
<option value="short_then_long">Short Name (fallback to Long)</option>
<option value="short_only">Short Name Only</option>
<option value="long_only">Long Name Only</option>
<option value="long_then_short">Long Name (fallback to Short)</option>
</select>
</div>
</div>
</details>
<div id="loadingIndicatorModal" class="hidden inset-0 bg-white bg-opacity-90 items-center justify-center flex-col z-10">
<div class="loader"></div>
<p id="loadingStatusModal" class="mt-4 text-sm text-gray-700 font-medium">Loading GTFS data...</p>
<div class="mt-2 w-3/4 max-w-xs">
<div class="progress-bar-container">
<div id="progressBarModal" class="progress-bar">0%</div>
</div>
<p id="loadingDetailsModal" class="mt-1 text-xs text-gray-500 text-center"></p>
</div>
</div>
<div id="dataWarningModal" class="mt-4 px-3 py-2 text-sm text-red-700 bg-red-100 border border-red-300 rounded-md hidden"></div>
</form>
<footer class="px-6 py-4 border-t border-gray-200">
<button type="button" id="loadGtfsButton" disabled class="w-full py-2.5 px-4 rounded-md bg-indigo-600 hover:bg-indigo-700 text-white font-semibold shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition-colors duration-150 disabled:opacity-60 disabled:cursor-not-allowed">
🚀 Load Data & Start Exploring!
</button>
<p class="pt-3 text-center text-xs text-gray-500">Your data never leaves your browser. Happy exploring! 🚌🚆</p>
</footer>
</div>
</div>
<header id="topBar" class="sticky top-0 z-30 bg-white shadow-md px-2 sm:px-3 py-2.5 rounded-b-lg">
<div class="flex items-center justify-between mb-2">
<h2 class="text-base sm:text-lg font-semibold text-gray-800">🧭 Route Search</h2>
<button id="toggleAdvancedOptions" class="text-xs sm:text-sm text-indigo-600 hover:text-indigo-800 px-2 py-1 rounded hover:bg-indigo-50 transition-colors duration-150 focus:outline-none focus:ring-2 focus:ring-indigo-400">
Search Options ⚙️
</button>
</div>
<div class="flex flex-wrap gap-2 items-end">
<div class="flex flex-col">
<label for="startTime" class="text-[11px] sm:text-xs text-gray-600 mb-0.5">Time</label>
<div class="flex items-center gap-1">
<input type="time" id="startTime" class="w-24 p-1.5 border border-gray-300 rounded text-xs sm:text-sm focus:ring-indigo-500 focus:border-indigo-500" />
<button type="button" id="setNowButton" class="p-1.5 rounded bg-gray-100 hover:bg-gray-200 transition-colors" title="Set to current time">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-600" fill="none" viewBox="0 0 24 24" stroke="currentColor"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none" /><path stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M12 6v6l4 2" /></svg>
</button>
</div>
</div>
<div class="flex flex-col min-w-[150px] flex-1">
<label for="startLocationInput" class="text-[11px] sm:text-xs text-gray-600 mb-0.5">Start</label>
<div class="flex items-center gap-1">
<input id="startLocationInput" placeholder="Stop name or click map" class="w-full p-1.5 border border-gray-300 rounded text-xs sm:text-sm focus:ring-indigo-500 focus:border-indigo-500" />
<button type="button" id="useCurrentLocationButton" class="p-1.5 rounded bg-gray-100 hover:bg-gray-200 transition-colors" title="Use current location">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-gray-600" fill="none" viewBox="0 0 24 24" stroke="currentColor"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none" /><line x1="12" y1="2" x2="12" y2="6" stroke="currentColor" stroke-width="2" stroke-linecap="round" /><line x1="12" y1="18" x2="12" y2="22" stroke="currentColor" stroke-width="2" stroke-linecap="round" /><line x1="2" y1="12" x2="6" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round" /><line x1="18" y1="12" x2="22" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round" /><circle cx="12" cy="12" r="2" fill="currentColor" /></svg>
</button>
</div>
</div>
<div class="flex flex-col w-24 sm:w-28">
<label for="startRadiusInput" class="text-[11px] sm:text-xs text-gray-600 mb-0.5">Radius (m)</label>
<input type="number" id="startRadiusInput" value="500" min="50" step="50" class="w-full p-1.5 border border-gray-300 rounded text-xs sm:text-sm focus:ring-indigo-500 focus:border-indigo-500" />
</div>
<button id="runSearchButton" disabled class="bg-green-600 hover:bg-green-700 text-white font-semibold py-1.5 px-3 rounded text-xs sm:text-sm disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap self-end mb-px transition-colors">
Find Route
</button>
</div>
<div id="advancedOptions" class="collapsible collapsed grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-x-4 gap-y-3 text-xs sm:text-sm bg-gray-50 rounded-lg p-3 mt-2.5 border border-gray-200 shadow">
<label class="flex items-center gap-1.5 col-span-1 cursor-pointer"><input type="checkbox" id="returnToStartToggle" class="accent-indigo-600 h-3.5 w-3.5 rounded"><span>Return to Start</span></label>
<label class="flex items-center gap-1.5 col-span-1 cursor-pointer"><input type="checkbox" id="returnEarlyToggle" class="accent-indigo-600 h-3.5 w-3.5 rounded" checked><span>Stop Early if Covered</span></label>
<label class="flex items-center gap-1.5 col-span-1 cursor-pointer"><input type="checkbox" id="showMapDuringSearchToggle" class="accent-indigo-600 h-3.5 w-3.5 rounded"><span>Show Map During Search</span></label>
<div class="flex flex-col gap-0.5"><label for="agentSelect" class="text-gray-700">Search Agent</label><select id="agentSelect" class="w-full p-1.5 border border-gray-300 rounded text-xs bg-white focus:ring-indigo-500 focus:border-indigo-500"><option value="beam" selected>Beam Search Agent</option><option value="astar">A* Coverage Agent</option></select></div>
<div class="col-span-full sm:col-span-2 md:col-span-2 lg:col-span-2 flex flex-col gap-1"><label for="maxIterationsInput" class="text-gray-700">Iterations: <span id="maxIterationsValue" class="font-medium text-indigo-700">100,000</span></label><input type="range" id="maxIterationsInput" min="1000" max="1000000" value="100000" step="1000" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-indigo-600 focus:outline-none" /><span id="estimatedIterationsText" class="text-[10px] text-gray-500 h-3"></span></div>
<div class="flex flex-col gap-0.5"><label for="minTransferTime" class="text-gray-700">Min Transfer (min)</label><input type="number" id="minTransferTime" value="2" min="0" class="w-full p-1 border border-gray-300 rounded text-xs focus:ring-indigo-500 focus:border-indigo-500" /></div>
<div class="flex flex-col gap-0.5"><label for="maxWaitTime" class="text-gray-700">Max Wait (min)</label><input type="number" id="maxWaitTime" value="20" min="0" class="w-full p-1 border border-gray-300 rounded text-xs focus:ring-indigo-500 focus:border-indigo-500" /></div>
<div class="flex flex-col gap-0.5"><label for="walkSpeed" class="text-gray-700">Walk Speed (m/s)</label><input type="number" id="walkSpeed" value="0.8" step="0.1" min="0.1" class="w-full p-1 border border-gray-300 rounded text-xs focus:ring-indigo-500 focus:border-indigo-500" /></div>
<div class="flex flex-col gap-0.5"><label for="walkRadiusInput" class="text-gray-700">Walk Radius (m)</label><input type="number" id="walkRadiusInput" value="120" min="0" step="10" class="w-full p-1 border border-gray-300 rounded text-xs focus:ring-indigo-500 focus:border-indigo-500" /></div>
<div class="flex flex-col gap-0.5"><label for="alphaInput" class="text-gray-700">Alpha (Coverage Weight)</label><input type="number" id="alphaInput" value="5000" min="0" step="100" class="w-full p-1 border border-gray-300 rounded text-xs focus:ring-indigo-500 focus:border-indigo-500" /></div>
<div class="flex flex-col gap-0.5"><label for="maxSpeedHeuristicInput" class="text-gray-700">Max Vehicle Speed (km/h)</label><input type="number" id="maxSpeedHeuristicInput" value="50" min="5" step="5" class="w-full p-1 border border-gray-300 rounded text-xs focus:ring-indigo-500 focus:border-indigo-500" /></div>
<div id="linesForExclusion" class="col-span-full max-h-32 sm:max-h-36 overflow-y-auto border p-2 rounded-md text-[10px] sm:text-xs bg-white shadow-sm">
<p class="font-medium text-gray-700 mb-1.5">Pre-covered Lines (to exclude from search):</p>
<p class="text-gray-500">Load GTFS data to see lines.</p>
</div>
</div>
</header>
<main class="flex-grow relative flex flex-col overflow-hidden">
<div id="map" class="flex-grow z-0"></div>
<div id="bottomPanel" class="z-20 bg-white shadow-2xl rounded-t-xl max-h-[40vh] sm:max-h-[35vh] md:max-h-[33vh] flex flex-col transform transition-transform duration-300 ease-in-out translate-y-0">
<header class="px-3 py-2.5 border-b border-gray-200">
<h3 class="text-base sm:text-md font-semibold text-gray-800">Path Instructions</h3>
</header>
<div id="searchLoadingIndicator" class="hidden text-center my-4 px-3">
<div class="loader-small inline-block"></div>
<p id="searchStatusText" class="text-sm font-semibold text-indigo-700 mt-2">Searching for best route...</p>
<p id="searchProgressDetails" class="text-xs text-gray-600 mt-1">Please wait, this may take a moment.</p>
<div class="progress-bar-container mt-2 w-full max-w-md mx-auto">
<div id="searchProgressBar" class="progress-bar text-xs">0%</div>
</div>
</div>
<div id="pathInstructionsContainer" class="text-sm space-y-1.5 overflow-y-auto flex-grow p-3 custom-scrollbar">
<p id="noPathMessage" class="text-gray-500 p-2">No itinerary yet. Load data and run a search.</p>
</div>
</div>
</main>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" crossorigin=""></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.4.1/papaparse.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/kdbush"></script>
<script src="https://cdn.jsdelivr.net/npm/heap/lib/heap.min.js"></script>
<script src="js/config.js"></script>
<script src="js/utils.js"></script>
<script src="js/gtfs_data_handler.js"></script>
<script src="js/astar_agent.js"></script>
<script src="js/other_agents.js"></script>
<script src="js/map_interaction.js"></script>
<script src="js/ui_helpers.js"></script>
<script src="js/app.js"></script>
</body>
</html>