function handleFileSelect(event) { const files = event.target.files; const routesFile = Array.from(files).find(file => file.name === 'routes.txt'); const tripsFile = Array.from(files).find(file => file.name === 'trips.txt'); const stopsFile = Array.from(files).find(file => file.name === 'stops.txt'); const stopTimesFile = Array.from(files).find(file => file.name === 'stop_times.txt'); if (routesFile && tripsFile && stopsFile && stopTimesFile) { // Read and parse the routes file const routesReader = new FileReader(); routesReader.onload = function(e) { routesData = parseCSV(e.target.result); displayRouteIds(routesData); }; routesReader.readAsText(routesFile); // Read and parse the trips file const tripsReader = new FileReader(); tripsReader.onload = function(e) { tripsData = parseCSV(e.target.result); }; tripsReader.readAsText(tripsFile); // Read and parse the stops file const stopsReader = new FileReader(); stopsReader.onload = function(e) { stopsData = parseCSV(e.target.result); //console.log(stopsData[0]); for (let stop of stopsData) { let id = stop["stop_id"]; // console.log("id: ", id); let stop_lat = stop["stop_lat"]; let stop_lon = stop["stop_lon"]; if (stop_lat == undefined || stop_lon == undefined) { continue; } else { //console.log("stop_lat: ", stop_lat); //console.log("stop_lon: ", stop_lon); shapes["stops"][id] = { lat: stop_lat, lon: stop_lon }; //console.log(shapes["stops"][stop["stop_id"]]); addClickablePoint([stop_lat, stop_lon], id); } } }; stopsReader.readAsText(stopsFile); // Read and parse the stops file const stopTimesReader = new FileReader(); stopTimesReader.onload = function(e) { stopTimesData = parseCSV(e.target.result); }; stopTimesReader.readAsText(stopTimesFile); console.log(stopsData.length); } else { alert('Please select a valid GTFS folder containing routes.txt, trips.txt, stops.txt, and stop_times.txt files.'); } // Handle shapes file let shapesFile; for (let file of files) { if (file.name === 'shapes.txt') { shapesFile = file; break; } } if (shapesFile) { // Parse shapes.txt file and draw on the map parseShapesFile(shapesFile); } else { alert('shapes.txt file not found in the selected folder.'); } } function displayRouteIds(routes) { const currentRoutes = document.getElementById('currentRoutes'); const routeList = document.createElement('div'); routeList.className = 'list-group route-list'; routes.forEach(route => { const routeItem = document.createElement('a'); routeItem.className = 'list-group-item list-group-item-action'; routeItem.textContent = route.route_id; //routeItem.onclick = () => showTrips(route.route_id); routeItem.href = '/?timetable=' + route.route_id; routeList.appendChild(routeItem); }); currentRoutes.appendChild(routeList); } function showTrips(chosenRouteId) { // Filter the routesData rows where route_id is equal to the targetRouteId const filteredTrips = tripsData.filter(route => route.route_id == chosenRouteId); console.log('chosenRouteId: ', chosenRouteId); console.log('filteredTrips[0]: ', filteredTrips[0]); // Map the filtered rows to their shape_id values const shapeIds = filteredTrips.map(trip => trip.shape_id); console.log('shapeIds[0]: ', shapeIds[0]); highlightShapes(shapeIds, "routes"); const tripsTable = document.getElementById('tripsTable'); tripsTable.innerHTML = ''; if (filteredTrips.length > 0) { const tripIds = filteredTrips.map(trip => trip.trip_id);; console.log('headers: ', tripIds); const headerRow = document.createElement('tr'); tripIds.forEach(tripId => { const th = document.createElement('th'); th.textContent = tripId; headerRow.appendChild(th); }); tripsTable.appendChild(headerRow); // Now filter data for table rows const filteredStopTimes = stopTimesData.filter(stopTime => tripIds.includes(stopTime.trip_id)); const filteredDepartureTimes = filteredStopTimes.map(stopTime => stopTime.departure_time) const uniqueStopIds = [...new Set(filteredStopTimes.map(stopTime => stopTime.stop_id))]; // Create stop_names array by finding the stop_name for each unique stop_id const rowValues = uniqueStopIds.map(stopId => { const stop = stopsData.find(stop => stop.stop_id === stopId); stop_name = stop ? stop.stop_name : 'Unknown Stop'; currentStopTimes = filteredStopTimes.filter(stopTime => stopTime.stop_id == stopId) const sortedStopTimes = currentStopTimes.sort((a, b) => { return tripIds.indexOf(a.trip_id) - tripIds.indexOf(b.trip_id); }).map(stop => stop.departure_time); return [stop_name].concat(sortedStopTimes); }); console.log(rowValues); // Create rows with stop_names as row headers stop_names.forEach(stopName => { const row = document.createElement('tr'); const rowHeader = document.createElement('th'); rowHeader.textContent = stopName; row.appendChild(rowHeader); // Add empty cells for each tripId tripIds.forEach(() => { const cell = document.createElement('td'); row.appendChild(cell); }); tripsTable.appendChild(row); }); } else { const noDataRow = document.createElement('tr'); const noDataCell = document.createElement('td'); noDataCell.colSpan = Object.keys(trips[0] || {}).length; noDataCell.textContent = 'No trips found for this route.'; noDataRow.appendChild(noDataCell); tripsTable.appendChild(noDataRow); } $('#tripsModal').modal('show'); } function addNewShape() { console.log("Function addNewShape() not defined."); } function drawNewShape() { shapeStops = []; cancelShapeEdit(); // Create a container div for the buttons const buttonContainer = document.createElement('div'); buttonContainer.className = 'button-container mt-3 p-3 border rounded'; // Create Toggle OSM router machine button const editButton = document.createElement('button'); editButton.className = 'btn btn-primary btn-block my-2'; editButton.textContent = 'Toggle OSM router machine'; editButton.onclick = () => { // Open route editing tool shapeToOSRM(shapes["routes"][shapeId].polyline); }; buttonContainer.appendChild(editButton); // Create Save button const saveButton = document.createElement('button'); saveButton.className = 'btn btn-secondary btn-block my-2'; saveButton.textContent = 'Save Shape'; saveButton.setAttribute('ready-to-save', 'false'); saveButton.onclick = () => { if (saveButton.getAttribute('ready-to-save') === 'true') { // Append coordinates to stops list var latlngs = currentLayer.getLatLngs(); latlngs.forEach(function(latlng) { //stops.push([latlng.lat, latlng.lng]); }); // Transform the polyline into the specified format in the shapes dictionary shape_id = "n_" + numNewShapes; numNewShapes += 1; shapes["routes"][shape_id] = []; latlngs.forEach(function(latlng, index) { shapes["routes"][shape_id].push({ sequence: index + 1, lat: latlng.lat, lon: latlng.lng }); }); // Delete the layer with the drawn polyline map.removeLayer(currentLayer); // Create polyline and add to map addClickableShape (latlngs, shape_id); // Log the results console.log('Stops:', stops); console.log('Shapes:', shapes["routes"]); // Change button esthetics to default saveButton.style.backgroundColor = ''; saveButton.style.color = ''; cancelShapeEdit(); } }; buttonContainer.appendChild(saveButton); // Create Cancel button const cancelButton = document.createElement('button'); cancelButton.className = 'btn btn-secondary btn-block my-2'; cancelButton.textContent = 'Cancel'; cancelButton.onclick = () => { cancelShapeEdit(); }; buttonContainer.appendChild(cancelButton); // Append the button container to the chosenShape element chosenShape.appendChild(buttonContainer); polylineDrawer.enable(); // Add created polylines to the map map.on(L.Draw.Event.CREATED, function (event) { var layer = event.layer; currentLayer = layer; drawnItems.addLayer(layer); }); // Add created shapes to the map and handle the polyline map.on(L.Draw.Event.CREATED, function (event) { var layer = event.layer; // Check if the drawn shape is a polyline if (layer instanceof L.Polyline && !(layer instanceof L.Polygon)) { // Disable the drawing control map.removeControl(drawControl); saveButton.style.backgroundColor = 'green'; saveButton.style.color = 'white'; // Ensure the text is readable saveButton.setAttribute('ready-to-save', 'true'); } else { // Add the drawn layer to the map if it's not a polyline drawnItems.addLayer(layer); } }); } function displayShapeOptions(shapeId, shapes) { const chosenShape = document.getElementById('chosenShape'); // Clear any existing content inside chosenShape while (chosenShape.firstChild) { chosenShape.removeChild(chosenShape.firstChild); } // Add text content at the top const textContent = document.createElement('div'); textContent.textContent = "Shape " + shapeId; chosenShape.appendChild(textContent); // Create a container div for the buttons const buttonContainer = document.createElement('div'); buttonContainer.className = 'button-container mt-3 p-3 border rounded'; // Create Edit button const editButton = document.createElement('button'); editButton.className = 'btn btn-primary btn-block my-2'; editButton.textContent = 'Edit Shape'; editButton.onclick = () => { // Open route editing tool shapeToOSRM(shapes["routes"][shapeId].polyline); }; buttonContainer.appendChild(editButton); // Create Delete button const deleteButton = document.createElement('button'); deleteButton.className = 'btn btn-danger btn-block my-2'; deleteButton.textContent = 'Delete Shape'; deleteButton.onclick = () => { // Cancel the edit view for the current shape cancelShapeEdit(); // Delete the current shape and its representation from the map deleteShape(shapeId); }; buttonContainer.appendChild(deleteButton); // Create Cancel button const cancelButton = document.createElement('button'); cancelButton.className = 'btn btn-secondary btn-block my-2'; cancelButton.textContent = 'Cancel'; cancelButton.onclick = () => { cancelShapeEdit(); }; buttonContainer.appendChild(cancelButton); // Append the button container to the chosenShape element chosenShape.appendChild(buttonContainer); } function cancelShapeEdit () { // Define reference to the chosenShape field const chosenShape = document.getElementById('chosenShape'); // Remove any existing routing control (if needed) if (window.routingControl) { map.removeControl(window.routingControl); } // Disable the current drawing polylineDrawer.disable(); // Clear all drawn items drawnItems.clearLayers(); // Clear any existing content inside chosenShape while (chosenShape.firstChild) { chosenShape.removeChild(chosenShape.firstChild); } // Add text content at the top const textContent = document.createElement('div'); textContent.textContent = "Chosen Shape"; chosenShape.appendChild(textContent); makeShapesBlue(); }