349 lines
13 KiB
JavaScript
349 lines
13 KiB
JavaScript
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();
|
|
} |