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