Improved www.ttss.krakow.pl
Jacek Kowalski
2017-04-17 7ca6a15943ffd4dc600aca0afd22835b18ce99c0
commit | author | age
57b8d3 1 //var ttss_base = 'http://www.ttss.krakow.pl/internetservice';
JK 2 var ttss_base = '/proxy.php';
3 var ttss_refresh = 5000; // 5 seconds
4
5 var vehicles_xhr = null;
6 var vehicles_timer = null;
7 var vehicles_last_update = 0;
8 var vehicles_source = null;
9 var vehicles_layer = null;
10
11 var stops_xhr = null;
12 var stops_source = null;
13 var stops_layer = null;
14 var stop_points_source = null;
15 var stop_points_layer = null;
16
17 var map = null;
18 var popup_feature_id = null;
19 var popup_element = document.getElementById('popup');
20 var popup = null;
21 var fail_element = document.getElementById('fail');
22
7ca6a1 23 var ignore_hashchange = false;
JK 24
57b8d3 25 function fail(msg) {
JK 26     console.log(msg);
27     
28     setText(fail_element, msg);
29     fail_element.style.top = '0.5em';
30 }
31
32 function fail_ajax(data) {
33     // abort() is not a failure
34     if(data.readyState == 0 && data.statusText == 'abort') return;
35     
36     if(data.status == 0) {
37         fail(lang.error_request_failed_connectivity, data);
38     } else if (data.statusText) {
39         fail(lang.error_request_failed_status.replace('$status', data.statusText), data);
40     } else {
41         fail(lang.error_request_failed, data);
42     }
43 }
44
45 function popupHide() {
46     popup.setPosition(undefined);
47     popup_feature_id = null;
48 }
49
50 function popupShow(coordinates, id) {
51     popup.setPosition(coordinates);
52     if(id) {
53         popup_feature_id = id;
54     }
55 }
56
57 function getGeometry(object) {
58     return new ol.geom.Point(ol.proj.fromLonLat([object.longitude / 3600000.0, object.latitude / 3600000.0]))
59 }
60
61 function updateVehicles() {
62     if(vehicles_timer) clearTimeout(vehicles_timer);
63     if(vehicles_xhr) vehicles_xhr.abort();
64     
65     vehicles_xhr = $.get(
66         ttss_base + '/geoserviceDispatcher/services/vehicleinfo/vehicles' 
67             + '?positionType=CORRECTED'
68             + '&colorType=ROUTE_BASED'
69             + '&lastUpdate=' + encodeURIComponent(vehicles_last_update)
70     ).done(function(data) {
71         vehicles_last_update = data.lastUpdate;
72         
73         for(var i = 0; i < data.vehicles.length; i++) {
74             var vehicle = data.vehicles[i];
75             
76             var vehicle_feature = vehicles_source.getFeatureById('v' + vehicle.id);
77             if(vehicle.isDeleted) {
78                 if(vehicle_feature) {
79                     vehicles_source.removeFeature(vehicle_feature);
80                     if(popup_feature_id == vehicle_feature.getId()) {
81                         popupHide();
82                     }
83                 }
84                 continue;
85             }
86             
87             var vehicle_name_space = vehicle.name.indexOf(' ');
88             vehicle.line = vehicle.name.substr(0, vehicle_name_space);
89             vehicle.direction = vehicle.name.substr(vehicle_name_space+1);
90             if(special_directions[vehicle.direction]) {
91                 vehicle.line = special_directions[vehicle.direction];
92             }
93             
94             vehicle.geometry = getGeometry(vehicle);
95             vehicle.vehicle_type = parseVehicle(vehicle.id);
96             
97             if(!vehicle_feature) {
98                 vehicle_feature = new ol.Feature(vehicle);
99                 vehicle_feature.setId('v' + vehicle.id);
100                 
101                 var color_type = 'black';
102                 if(vehicle.vehicle_type) {
103                     switch(vehicle.vehicle_type.low) {
104                         case 0:
105                             color_type = 'orange';
106                             break;
107                         case 1:
108                             color_type = 'blue';
109                             break;
110                         case 2:
111                             color_type = 'green';
112                             break;
113                     }
114                 }
115                 
116                 vehicle_feature.setStyle(new ol.style.Style({
117                     image: new ol.style.RegularShape({
118                         fill: new ol.style.Fill({color: '#3399ff'}),
119                         stroke: new ol.style.Stroke({color: color_type, width: 2}),
120                         points: 3,
121                         radius: 12,
122                         rotation: Math.PI * parseFloat(vehicle.heading) / 180.0,
123                         rotateWithView: true,
124                         angle: 0
125                     }),
126                     text: new ol.style.Text({
127                         font: 'bold 10px sans-serif',
128                         text: vehicle.line,
129                         fill: new ol.style.Fill({color: 'white'}),
130                     }),
131                 }));
132                 vehicles_source.addFeature(vehicle_feature);
133             } else {
134                 vehicle_feature.setProperties(vehicle);
135                 vehicle_feature.getStyle().getImage().setRotation(Math.PI * parseFloat(vehicle.heading) / 180.0);
136                 
137                 if(popup_feature_id == vehicle_feature.getId()) {
138                     popupShow(vehicle_feature.getGeometry().getCoordinates());
139                 }
140             }
141         }
142         
143         vehicles_timer = setTimeout(function() {
144             updateVehicles();
145         }, ttss_refresh);
146     }).fail(fail_ajax);
7ca6a1 147     
JK 148     return vehicles_xhr;
57b8d3 149 }
JK 150
151 function updateStopSource(stops, prefix, source) {
152     source.clear();
153     
154     for(var i = 0; i < stops.length; i++) {
155         var stop = stops[i];
156         stop.geometry = getGeometry(stop);
157         var stop_feature = new ol.Feature(stop);
158         
159         stop_feature.setId(prefix + stop.id);
160         stop_feature.setStyle(new ol.style.Style({
161             image: new ol.style.Circle({
162                 fill: new ol.style.Fill({color: 'orange'}),
163                 stroke: new ol.style.Stroke({color: 'red', width: 1}),
164                 radius: 3,
165             }),
166         }));
167         
168         source.addFeature(stop_feature);
169     }
170 }
171
172 function updateStops() {
7ca6a1 173     return $.get(
57b8d3 174         ttss_base + '/geoserviceDispatcher/services/stopinfo/stops'
JK 175             + '?left=-648000000'
176             + '&bottom=-324000000'
177             + '&right=648000000'
178             + '&top=324000000'
179     ).done(function(data) {
180         updateStopSource(data.stops, 's', stops_source);
181     }).fail(fail_ajax);
182 }
183
184 function updateStopPoints() {
7ca6a1 185     return $.get(
57b8d3 186         ttss_base + '/geoserviceDispatcher/services/stopinfo/stopPoints'
JK 187             + '?left=-648000000'
188             + '&bottom=-324000000'
189             + '&right=648000000'
190             + '&top=324000000'
191     ).done(function(data) {
192         updateStopSource(data.stopPoints, 'p', stop_points_source);
193     }).fail(fail_ajax);
7ca6a1 194 }
JK 195
196 function featureClicked(feature) {
197     if(!feature) {
198         popupHide();
199         
200         ignore_hashchange = true;
201         window.location.hash = '';
202         
203         return;
204     }
205     
206     var coordinates = feature.getGeometry().getCoordinates();
207     
208     deleteChildren(popup_element);
209     
210     addParaWithText(popup_element, feature.get('name')).className = 'bold';
211     switch(feature.getId().substr(0, 1)) {
212         case 'v':
213             var vehicle_type = parseVehicle(feature.get('id'));
214             if(vehicle_type) {
215                 addParaWithText(popup_element, vehicle_type.num + ' ' + vehicle_type.type);
216             }
217         break;
218     }
219     
220     ignore_hashchange = true;
221     window.location.hash = '#!' + feature.getId();
222     
223     popupShow(coordinates, feature.getId());
224 }
225
226 function hash() {
227     if(ignore_hashchange) {
228         ignore_hashchange = false;
229         return;
230     }
231     
232     var tramId = null;
233     
234     var vehicleId = null;
235     var stopId = null;
236     var stopPointId = null;
237     
238     var feature = null;
239     
240     if(window.location.hash.match(/^#!t[0-9]{3}$/)) {
241         tramId = parseInt(window.location.hash.substr(3));
242     } else if(window.location.hash.match(/^#![A-Za-z]{2}[0-9]{3}$/)) {
243         tramId = parseInt(window.location.hash.substr(4));
244     } else if(window.location.hash.match(/^#!v[0-9]+$/)) {
245         vehicleId = window.location.hash.substr(3);
246     } else if(window.location.hash.match(/^#!s[0-9]+$/)) {
247         stopId = window.location.hash.substr(3);
248     } else if(window.location.hash.match(/^#!p[0-9]+$/)) {
249         stopPointId = window.location.hash.substr(3);
250     }
251     
252     if(tramId) {
253         vehicleId = tramIdToVehicleId(tramId);
254     }
255     
256     if(vehicleId) {
257         feature = vehicles_source.getFeatureById('v' + vehicleId);
258     } else if(stopId) {
259         feature = stops_source.getFeatureById('s' + stopId);
260     } else if(stopPointId) {
261         feature = stop_points_source.getFeatureById('p' + stopPointId);
262     }
263     
264     featureClicked(feature);
265     if(feature) {
266         map.getView().setCenter(feature.getGeometry().getCoordinates());
267     }
57b8d3 268 }
JK 269
270 function init() {
271     if(!window.jQuery) {
272         fail(lang.jquery_not_loaded);
273         return;
274     }
275     
276     $.ajaxSetup({
277         dataType: 'json',
278         timeout: 10000,
279     });
280     
281     stops_source = new ol.source.Vector({
282         features: [],
283     });
284     stops_layer = new ol.layer.Vector({
285         source: stops_source,
286     });
287     
288     stop_points_source = new ol.source.Vector({
289         features: [],
290     });
291     stop_points_layer = new ol.layer.Vector({
292         source: stop_points_source,
293         visible: false,
294     });
295     
296     vehicles_source = new ol.source.Vector({
297         features: [],
298     });
299     vehicles_layer = new ol.layer.Vector({
300         source: vehicles_source,
301     });
302     
303     popup = new ol.Overlay({
304         element: popup_element,
305         positioning: 'bottom-center',
306         stopEvent: false,
307         offset: [0, -12]
308     });
309     
310     map = new ol.Map({
311         target: 'map',
312         layers: [
313             new ol.layer.Tile({
314                 source: new ol.source.OSM()
315             }),
316             stops_layer,
317             stop_points_layer,
318             vehicles_layer,
319         ],
320         overlays: [popup],
321         view: new ol.View({
322             center: ol.proj.fromLonLat([19.94, 50.06]),
323             zoom: 13
324         }),
325         controls: ol.control.defaults({
326             attributionOptions: ({
327                 collapsible: false,
328             })
329         }).extend([
330             new ol.control.Control({
331                 element: document.getElementById('title'),
332             }),
333             new ol.control.Control({
334                 element: fail_element,
335             })
336         ]),
337     });
338     
339     // Display popup on click
340     map.on('singleclick', function(e) {
341         var feature = map.forEachFeatureAtPixel(e.pixel, function(feature) { return feature; });
7ca6a1 342         featureClicked(feature);
57b8d3 343     });
JK 344
345     // Change mouse cursor when over marker
346     map.on('pointermove', function(e) {
347         var hit = map.hasFeatureAtPixel(e.pixel);
348         var target = map.getTargetElement();
349         target.style.cursor = hit ? 'pointer' : '';
350     });
351     
352     // Change layer visibility on zoom
353     map.getView().on('change:resolution', function(e) {
354         if(map.getView().getZoom() >= 16) {
355             stops_layer.setVisible(false);
356             stop_points_layer.setVisible(true);
357         } else {
358             stops_layer.setVisible(true);
359             stop_points_layer.setVisible(false);
360         }
361     });
362     
7ca6a1 363     $.when(
JK 364         updateVehicles(),
365         updateStops(),
366         updateStopPoints()
367     ).done(function() {
368         hash();
369     });
370     
371     window.addEventListener('hashchange', hash);
57b8d3 372     
JK 373     setTimeout(function() {
374         if(vehicles_xhr) vehicles_xhr.abort();
375         if(vehicles_timer) clearTimeout(vehicles_timer);
376           
377         fail(lang.error_refresh);
378     }, 1800000);
379 }
380
381 init();