Improved www.ttss.krakow.pl
Jacek Kowalski
2017-04-22 7a2fc1b6a2e7baee8c61fb70b5d5a38cad55b218
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
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({
7a2fc1 117                     image: new ol.style.Icon({
JK 118                         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 119                         rotation: Math.PI * parseFloat(vehicle.heading) / 180.0,
JK 120                     }),
121                     text: new ol.style.Text({
122                         font: 'bold 10px sans-serif',
123                         text: vehicle.line,
124                         fill: new ol.style.Fill({color: 'white'}),
125                     }),
126                 }));
127                 vehicles_source.addFeature(vehicle_feature);
128             } else {
129                 vehicle_feature.setProperties(vehicle);
130                 vehicle_feature.getStyle().getImage().setRotation(Math.PI * parseFloat(vehicle.heading) / 180.0);
131                 
132                 if(popup_feature_id == vehicle_feature.getId()) {
133                     popupShow(vehicle_feature.getGeometry().getCoordinates());
134                 }
135             }
136         }
137         
138         vehicles_timer = setTimeout(function() {
139             updateVehicles();
140         }, ttss_refresh);
141     }).fail(fail_ajax);
7ca6a1 142     
JK 143     return vehicles_xhr;
57b8d3 144 }
JK 145
146 function updateStopSource(stops, prefix, source) {
147     source.clear();
148     
149     for(var i = 0; i < stops.length; i++) {
150         var stop = stops[i];
e61357 151         
JK 152         if(stop.category == 'other') continue;
153         
57b8d3 154         stop.geometry = getGeometry(stop);
JK 155         var stop_feature = new ol.Feature(stop);
156         
157         stop_feature.setId(prefix + stop.id);
158         stop_feature.setStyle(new ol.style.Style({
159             image: new ol.style.Circle({
160                 fill: new ol.style.Fill({color: 'orange'}),
161                 stroke: new ol.style.Stroke({color: 'red', width: 1}),
162                 radius: 3,
163             }),
164         }));
165         
166         source.addFeature(stop_feature);
167     }
168 }
169
170 function updateStops() {
7ca6a1 171     return $.get(
57b8d3 172         ttss_base + '/geoserviceDispatcher/services/stopinfo/stops'
JK 173             + '?left=-648000000'
174             + '&bottom=-324000000'
175             + '&right=648000000'
176             + '&top=324000000'
177     ).done(function(data) {
178         updateStopSource(data.stops, 's', stops_source);
179     }).fail(fail_ajax);
180 }
181
182 function updateStopPoints() {
7ca6a1 183     return $.get(
57b8d3 184         ttss_base + '/geoserviceDispatcher/services/stopinfo/stopPoints'
JK 185             + '?left=-648000000'
186             + '&bottom=-324000000'
187             + '&right=648000000'
188             + '&top=324000000'
189     ).done(function(data) {
190         updateStopSource(data.stopPoints, 'p', stop_points_source);
191     }).fail(fail_ajax);
7ca6a1 192 }
JK 193
194 function featureClicked(feature) {
195     if(!feature) {
196         popupHide();
197         
198         ignore_hashchange = true;
199         window.location.hash = '';
200         
201         return;
202     }
203     
204     var coordinates = feature.getGeometry().getCoordinates();
205     
206     deleteChildren(popup_element);
207     
208     addParaWithText(popup_element, feature.get('name')).className = 'bold';
209     switch(feature.getId().substr(0, 1)) {
210         case 'v':
211             var vehicle_type = parseVehicle(feature.get('id'));
212             if(vehicle_type) {
213                 addParaWithText(popup_element, vehicle_type.num + ' ' + vehicle_type.type);
214             }
215         break;
216     }
217     
218     ignore_hashchange = true;
219     window.location.hash = '#!' + feature.getId();
220     
221     popupShow(coordinates, feature.getId());
222 }
223
224 function hash() {
225     if(ignore_hashchange) {
226         ignore_hashchange = false;
227         return;
228     }
229     
230     var tramId = null;
231     
232     var vehicleId = null;
233     var stopId = null;
234     var stopPointId = null;
235     
236     var feature = null;
237     
238     if(window.location.hash.match(/^#!t[0-9]{3}$/)) {
239         tramId = parseInt(window.location.hash.substr(3));
240     } else if(window.location.hash.match(/^#![A-Za-z]{2}[0-9]{3}$/)) {
241         tramId = parseInt(window.location.hash.substr(4));
242     } else if(window.location.hash.match(/^#!v[0-9]+$/)) {
243         vehicleId = window.location.hash.substr(3);
244     } else if(window.location.hash.match(/^#!s[0-9]+$/)) {
245         stopId = window.location.hash.substr(3);
246     } else if(window.location.hash.match(/^#!p[0-9]+$/)) {
247         stopPointId = window.location.hash.substr(3);
248     }
249     
250     if(tramId) {
251         vehicleId = tramIdToVehicleId(tramId);
252     }
253     
254     if(vehicleId) {
255         feature = vehicles_source.getFeatureById('v' + vehicleId);
256     } else if(stopId) {
257         feature = stops_source.getFeatureById('s' + stopId);
258     } else if(stopPointId) {
259         feature = stop_points_source.getFeatureById('p' + stopPointId);
260     }
261     
262     featureClicked(feature);
263     if(feature) {
264         map.getView().setCenter(feature.getGeometry().getCoordinates());
265     }
57b8d3 266 }
JK 267
268 function init() {
269     if(!window.jQuery) {
270         fail(lang.jquery_not_loaded);
271         return;
272     }
273     
274     $.ajaxSetup({
275         dataType: 'json',
276         timeout: 10000,
277     });
278     
279     stops_source = new ol.source.Vector({
280         features: [],
281     });
282     stops_layer = new ol.layer.Vector({
283         source: stops_source,
284     });
285     
286     stop_points_source = new ol.source.Vector({
287         features: [],
288     });
289     stop_points_layer = new ol.layer.Vector({
290         source: stop_points_source,
291         visible: false,
292     });
293     
294     vehicles_source = new ol.source.Vector({
295         features: [],
296     });
297     vehicles_layer = new ol.layer.Vector({
298         source: vehicles_source,
299     });
300     
301     popup = new ol.Overlay({
302         element: popup_element,
303         positioning: 'bottom-center',
304         stopEvent: false,
305         offset: [0, -12]
306     });
307     
308     map = new ol.Map({
309         target: 'map',
310         layers: [
311             new ol.layer.Tile({
312                 source: new ol.source.OSM()
313             }),
314             stops_layer,
315             stop_points_layer,
316             vehicles_layer,
317         ],
318         overlays: [popup],
319         view: new ol.View({
320             center: ol.proj.fromLonLat([19.94, 50.06]),
321             zoom: 13
322         }),
323         controls: ol.control.defaults({
324             attributionOptions: ({
325                 collapsible: false,
326             })
327         }).extend([
328             new ol.control.Control({
329                 element: document.getElementById('title'),
330             }),
331             new ol.control.Control({
332                 element: fail_element,
333             })
334         ]),
335     });
336     
337     // Display popup on click
338     map.on('singleclick', function(e) {
339         var feature = map.forEachFeatureAtPixel(e.pixel, function(feature) { return feature; });
7ca6a1 340         featureClicked(feature);
57b8d3 341     });
JK 342
343     // Change mouse cursor when over marker
344     map.on('pointermove', function(e) {
345         var hit = map.hasFeatureAtPixel(e.pixel);
346         var target = map.getTargetElement();
347         target.style.cursor = hit ? 'pointer' : '';
348     });
349     
350     // Change layer visibility on zoom
351     map.getView().on('change:resolution', function(e) {
352         if(map.getView().getZoom() >= 16) {
353             stops_layer.setVisible(false);
354             stop_points_layer.setVisible(true);
355         } else {
356             stops_layer.setVisible(true);
357             stop_points_layer.setVisible(false);
358         }
359     });
360     
7ca6a1 361     $.when(
JK 362         updateVehicles(),
363         updateStops(),
364         updateStopPoints()
365     ).done(function() {
366         hash();
367     });
368     
369     window.addEventListener('hashchange', hash);
57b8d3 370     
JK 371     setTimeout(function() {
372         if(vehicles_xhr) vehicles_xhr.abort();
373         if(vehicles_timer) clearTimeout(vehicles_timer);
374           
375         fail(lang.error_refresh);
376     }, 1800000);
377 }
378
379 init();