File size: 6,817 Bytes
cd11707
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9b906dd
 
 
 
cd11707
 
9b906dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cd11707
9b906dd
 
 
cd11707
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
document.addEventListener('DOMContentLoaded', function() {
    // Initialize any interactive elements
    initDemoSimulation();
    
    // Smooth scroll for anchor links
    document.querySelectorAll('a[href^="#"]').forEach(anchor => {
        anchor.addEventListener('click', function (e) {
            e.preventDefault();
            document.querySelector(this.getAttribute('href')).scrollIntoView({
                behavior: 'smooth'
            });
        });
    });
});
async function initTransportSystem() {
    console.log("Initializing Delhi Metro system...");
    
    try {
        // Load static GTFS data from GitHub repository
        const routes = await fetch('https://raw.githubusercontent.com/emote-warrior/GTFSDelhi/main/routes.txt')
            .then(res => res.text());
        const trips = await fetch('https://raw.githubusercontent.com/emote-warrior/GTFSDelhi/main/trips.txt')
            .then(res => res.text());
        const stops = await fetch('https://raw.githubusercontent.com/emote-warrior/GTFSDelhi/main/stops.txt')
            .then(res => res.text());
        
        // Parse CSV data
        const routesData = parseCSV(routes);
        const tripsData = parseCSV(trips);
        const stopsData = parseCSV(stops);
        
        // Process and visualize data
        visualizeNetwork(routesData, tripsData, stopsData);
        updateRealTimeStatus();
        
    } catch (error) {
        console.error('Error loading transport data:', error);
        document.querySelector('#network-visualization').innerHTML = 
            `<p class="text-red-500">Error loading data. Please try again later.</p>`;
    }
}

function parseCSV(csvText) {
    const lines = csvText.split('\n');
    const headers = lines[0].split(',');
    const result = [];
    
    for (let i = 1; i < lines.length; i++) {
        if (!lines[i]) continue;
        const obj = {};
        const currentline = lines[i].split(',');
        
        for (let j = 0; j < headers.length; j++) {
            obj[headers[j]] = currentline[j];
        }
        result.push(obj);
    }
    
    return result;
}
let map;
let routeLayers = {};
let stopMarkers = {};
let tripLines = {};

function visualizeNetwork(routes, trips, stops) {
    // Initialize map centered on Delhi
    map = L.map('network-visualization').setView([28.6139, 77.2090], 12);
    
    // Add base tile layer
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);

    // Process stops data (need to convert stop_lat/stop_lon to numbers)
    stops.forEach(stop => {
        stop.stop_lat = parseFloat(stop.stop_lat);
        stop.stop_lon = parseFloat(stop.stop_lon);
    });

    // Group stops by route (simplified - in real app you'd use trips.txt and stop_times.txt)
    const stopsByRoute = {};
    routes.forEach(route => {
        stopsByRoute[route.route_id] = stops.slice(0, 10); // Just show first 10 stops per route for demo
    });

    // Create route layers
    routes.forEach(route => {
        const routeStops = stopsByRoute[route.route_id] || [];
        const routeCoordinates = routeStops.map(stop => [stop.stop_lat, stop.stop_lon]);
        
        routeLayers[route.route_id] = L.polyline(routeCoordinates, {
            color: `#${route.route_color || '333'}`,
            weight: 5,
            opacity: 0.7
        }).bindPopup(`<b>${route.route_long_name}</b><br>Route ID: ${route.route_id}`);
    });

    // Create stop markers
    stops.forEach(stop => {
        stopMarkers[stop.stop_id] = L.circleMarker([stop.stop_lat, stop.stop_lon], {
            radius: 6,
            fillColor: "#ff7800",
            color: "#000",
            weight: 1,
            opacity: 1,
            fillOpacity: 0.8
        }).bindPopup(`<b>${stop.stop_name}</b><br>Stop ID: ${stop.stop_id}`);
    });

    // Create trip lines (simplified - in real app you'd use actual trip paths)
    trips.slice(0, 20).forEach(trip => { // Limit to 20 trips for demo
        const routeStops = stopsByRoute[trip.route_id] || [];
        if (routeStops.length > 1) {
            const tripCoordinates = [
                [routeStops[0].stop_lat, routeStops[0].stop_lon],
                [routeStops[routeStops.length-1].stop_lat, routeStops[routeStops.length-1].stop_lon]
            ];
            
            tripLines[trip.trip_id] = L.polyline(tripCoordinates, {
                color: '#555',
                weight: 2,
                dashArray: '5, 5'
            }).bindPopup(`Trip ID: ${trip.trip_id}<br>Route: ${trip.route_id}`);
        }
    });

    // Set up layer controls
    document.getElementById('show-routes').addEventListener('click', () => {
        Object.values(routeLayers).forEach(layer => map.addLayer(layer));
    });
    
    document.getElementById('show-stops').addEventListener('click', () => {
        Object.values(stopMarkers).forEach(marker => map.addLayer(marker));
    });
    
    document.getElementById('show-trips').addEventListener('click', () => {
        Object.values(tripLines).forEach(line => map.addLayer(line));
    });
    
    document.getElementById('reset-view').addEventListener('click', () => {
        map.setView([28.6139, 77.2090], 12);
        map.eachLayer(layer => {
            if (layer instanceof L.Polyline || layer instanceof L.CircleMarker) {
                map.removeLayer(layer);
            }
        });
    });

    // Show routes by default
    Object.values(routeLayers).forEach(layer => map.addLayer(layer));
}
function updateRealTimeStatus() {
    // Simulate real-time updates
    setInterval(() => {
        const alerts = document.querySelectorAll('#current-alerts li');
        const suggestions = document.querySelectorAll('#optimization-suggestions li');
        
        // Rotate alerts and suggestions
        if (alerts.length > 0) {
            const firstAlert = alerts[0];
            firstAlert.parentNode.appendChild(firstAlert);
            firstAlert.classList.add('animate-pulse');
            setTimeout(() => firstAlert.classList.remove('animate-pulse'), 1000);
        }
        
        if (suggestions.length > 0) {
            const firstSuggestion = suggestions[0];
            firstSuggestion.parentNode.appendChild(firstSuggestion);
        }
    }, 8000);
}

// Initialize on DOM load
document.addEventListener('DOMContentLoaded', function() {
    initTransportSystem();
    
    document.querySelectorAll('a[href^="#"]').forEach(anchor => {
        anchor.addEventListener('click', function (e) {
            e.preventDefault();
            document.querySelector(this.getAttribute('href')).scrollIntoView({
                behavior: 'smooth'
            });
        });
    });
});