Revize fb12df6d
Přidáno uživatelem Jan Kohlíček před téměř 7 roky(ů)
frontend/app.js | ||
---|---|---|
2 | 2 |
|
3 | 3 |
app.constant('config', { |
4 | 4 |
APP_NAME: 'PVPK', |
5 |
APP_VERSION: 1.0,
|
|
5 |
APP_VERSION: '1.2.0',
|
|
6 | 6 |
API_URL: API_URL, |
7 | 7 |
API_TOKEN: API_TOKEN, |
8 | 8 |
DEFAULT_POSITION: {LAT: 49.53, LNG: 13.3}, |
9 |
DEFAULT_ZOOM: 10 |
|
9 |
DEFAULT_ZOOM: 10, |
|
10 |
DEFAULT_ZOOM_MAX: 7, |
|
10 | 11 |
}); |
11 | 12 |
|
12 |
//PRIPRAVA PRO REFAKTORING |
|
13 |
// app.config(function($stateProvider, $locationProvider) { |
|
14 |
// // $stateProvider |
|
15 |
// // .state('report',{ |
|
16 |
// // views: { |
|
17 |
// // 'search': { |
|
18 |
// // templateUrl: 'report-filters.html', |
|
19 |
// // controller: searchController |
|
20 |
// // }, |
|
21 |
// // 'graph': { |
|
22 |
// // templateUrl: 'report-table.html', |
|
23 |
// // controller: graphController |
|
24 |
// // }, |
|
25 |
// // 'map': { |
|
26 |
// // templateUrl: 'report-graph.html', |
|
27 |
// // controller: mapController |
|
28 |
// // } |
|
29 |
// // } |
|
30 |
// // }); |
|
31 |
// $locationProvider.html5Mode(true); |
|
32 |
// }); |
|
33 |
|
|
34 |
|
|
35 | 13 |
app.controller('mainController', function ($rootScope, $scope, $location, $window) { |
36 | 14 |
|
37 | 15 |
this.$onInit = function () { |
38 |
|
|
16 |
$scope.showLoadingScreen = true; |
|
39 | 17 |
}; |
40 | 18 |
|
41 | 19 |
$window.onload = function () { |
42 | 20 |
let params = $location.search(); |
43 | 21 |
if (params.deviceId) { |
44 |
$rootScope.$emit('infoLocation', {id: params.deviceId, direction: params.direction}); |
|
45 | 22 |
$rootScope.$emit('activeMarker', {id: params.deviceId}); |
46 | 23 |
} |
47 | 24 |
|
48 |
$scope.showLoadingScreen = false; |
|
25 |
$scope.$apply(function () { |
|
26 |
$scope.showLoadingScreen = false; |
|
27 |
}); |
|
49 | 28 |
}; |
50 | 29 |
|
51 | 30 |
$rootScope.$on('$locationChangeSuccess', function (event, newUrl, oldUrl) { |
31 |
let params = $location.search(); |
|
52 | 32 |
|
53 | 33 |
if (newUrl !== oldUrl && $scope.historyUrl) { |
54 |
let params = $location.search(); |
|
55 |
|
|
56 | 34 |
if ($scope.historyUrl.q !== $scope.historyUrl.q || $scope.historyUrl.isDirection != params.isDirection) { |
57 | 35 |
$rootScope.$emit('setSearchFromUrl', null); |
58 | 36 |
} |
... | ... | |
66 | 44 |
} else if (params.deviceId && ($scope.historyUrl.deviceId !== params.deviceId || $scope.historyUrl.direction !== params.direction)) { |
67 | 45 |
$rootScope.$emit('infoLocation', {id: params.deviceId, direction: params.direction}); |
68 | 46 |
$rootScope.$emit('activeMarker', {id: params.deviceId}); |
69 |
}else if(!params.deviceId && $scope.historyUrl.deviceId){
|
|
47 |
} else if (!params.deviceId && $scope.historyUrl.deviceId) {
|
|
70 | 48 |
$rootScope.selectDevice = null; |
71 | 49 |
$rootScope.$emit('setDefaultMap', null); |
72 | 50 |
} |
51 |
} else if (params.deviceId) { |
|
52 |
$rootScope.$emit('infoLocation', {id: params.deviceId, direction: params.direction}); |
|
73 | 53 |
} |
74 | 54 |
|
75 | 55 |
$scope.historyUrl = $location.search(); |
... | ... | |
133 | 113 |
app.controller('searchController', function ($rootScope, $scope, $location, config, Device) { |
134 | 114 |
|
135 | 115 |
this.$onInit = function () { |
116 |
$scope.config = config; |
|
136 | 117 |
$scope.locations = []; |
137 | 118 |
$scope.showSearchLoading = false; |
138 | 119 |
|
... | ... | |
140 | 121 |
}; |
141 | 122 |
|
142 | 123 |
$scope.searchLocations = function () { |
124 |
let params = $location.search(); |
|
125 |
params.q = $scope.search.q; |
|
126 |
params.isDirection = $scope.search.isDirection ? 1 : null; |
|
127 |
$location.search(params); |
|
128 |
|
|
143 | 129 |
if (!$scope.search.q || $scope.search.q.length <= 1) { |
144 | 130 |
$scope.locations = []; |
145 | 131 |
return; |
... | ... | |
147 | 133 |
|
148 | 134 |
$scope.showSearchLoading = true; |
149 | 135 |
|
150 |
let params = $location.search(); |
|
151 |
params.q = $scope.search.q; |
|
152 |
params.isDirection = $scope.search.isDirection ? 1 : 0; |
|
153 |
$location.search(params); |
|
154 |
|
|
155 | 136 |
Device.query({ |
156 | 137 |
address: $scope.search.q, |
157 | 138 |
showDirection: $scope.search.isDirection ? 1 : 0 |
... | ... | |
167 | 148 |
|
168 | 149 |
$rootScope.$on('setSearchFromUrl', function (event, args) { |
169 | 150 |
let params = $location.search(); |
170 |
|
|
171 | 151 |
$scope.search = { |
172 | 152 |
q: params.q, |
173 | 153 |
isDirection: params.isDirection ? !!+params.isDirection : false |
... | ... | |
189 | 169 |
$rootScope.selectDevice = null; |
190 | 170 |
$scope.showInfoLoading = false; |
191 | 171 |
$scope.vehicles = []; |
192 |
$scope.typeVehicle = null; |
|
193 | 172 |
$scope.filterVehicles = []; |
194 | 173 |
|
195 | 174 |
Vehicle.query(null, function (data) { |
... | ... | |
211 | 190 |
fromDate: moment(params.fromDate, 'YYYY-MM-DD').isValid() ? moment(params.fromDate).toDate() : defaultRange.fromDate.toDate(), |
212 | 191 |
toDate: moment(params.toDate, 'YYYY-MM-DD').isValid() ? moment(params.toDate).toDate() : defaultRange.toDate.toDate(), |
213 | 192 |
fromTime: moment(params.fromTime, 'HH:mm').isValid() ? moment(params.fromTime, 'HH:mm').toDate() : defaultRange.fromTime.toDate(), |
214 |
toTime: moment(params.toTime, 'HH:mm').isValid() ? moment(params.toTime, 'HH:mm').toDate() : defaultRange.toTime.toDate() |
|
193 |
toTime: moment(params.toTime, 'HH:mm').isValid() ? moment(params.toTime, 'HH:mm').toDate() : defaultRange.toTime.toDate(), |
|
194 |
isTime: params.isTime == 0 ? false : defaultRange.isTime |
|
215 | 195 |
}; |
216 | 196 |
|
217 | 197 |
}); |
... | ... | |
226 | 206 |
|
227 | 207 |
let range = $scope.getRange(); |
228 | 208 |
|
209 |
// if (!$rootScope.selectDevice || args.id !== $rootScope.selectDevice.id) |
|
210 |
// $rootScope.selectDevice = {name: '...', street: '...', town: '...'}; |
|
211 |
|
|
212 |
|
|
229 | 213 |
Device.get({ |
214 |
period: range.isTime ? 'time-period' : 'day-period', |
|
230 | 215 |
id: args.id, |
231 | 216 |
direction: args.direction, |
232 | 217 |
dateFrom: range.fromDate.format('YYYY-MM-DD'), |
233 | 218 |
dateTo: range.toDate.format('YYYY-MM-DD'), |
234 |
timeFrom: range.fromTime.format('HH:mm'),
|
|
235 |
timeTo: range.toTime.format('HH:mm'),
|
|
219 |
timeFrom: range.isTime ? range.fromTime.format('HH:mm') : null,
|
|
220 |
timeTo: range.isTime ? range.toTime.format('HH:mm') : null,
|
|
236 | 221 |
}, function (data) { |
237 | 222 |
$rootScope.selectDevice = data; |
238 | 223 |
|
239 |
$scope.typeVehicle = null; |
|
240 | 224 |
$scope.renderGraphAverageSpeed(); |
241 | 225 |
$scope.renderGraphNumberVehicles(); |
242 | 226 |
|
... | ... | |
250 | 234 |
|
251 | 235 |
}); |
252 | 236 |
|
237 |
|
|
253 | 238 |
$scope.changeRange = function () { |
254 |
if ($scope.range.fromDate >= $scope.range.toDate || $scope.range.fromTime >= $scope.range.toTime) {
|
|
239 |
if ($scope.range.fromDate >= $scope.range.toDate || ($scope.range.isTime && $scope.range.fromTime >= $scope.range.toTime)) {
|
|
255 | 240 |
$rootScope.selectDevice.traffics = []; |
256 | 241 |
return; |
257 | 242 |
} |
... | ... | |
261 | 246 |
let params = $location.search(); |
262 | 247 |
params.fromDate = range.fromDate.format('YYYY-MM-DD'); |
263 | 248 |
params.toDate = range.toDate.format('YYYY-MM-DD'); |
264 |
params.fromTime = range.fromTime.format('HH:mm'); |
|
265 |
params.toTime = range.toTime.format('HH:mm'); |
|
249 |
params.fromTime = range.isTime ? range.fromTime.format('HH:mm') : null; |
|
250 |
params.toTime = range.isTime ? range.toTime.format('HH:mm') : null; |
|
251 |
params.isTime = range.isTime ? null : 0; |
|
266 | 252 |
$location.search(params); |
267 | 253 |
|
268 | 254 |
if ($rootScope.selectDevice) |
... | ... | |
279 | 265 |
fromDate: moment($scope.range.fromDate).isValid() ? moment($scope.range.fromDate) : defaultRange.fromDate, |
280 | 266 |
toDate: moment($scope.range.toDate).isValid() ? moment($scope.range.toDate) : defaultRange.toDate, |
281 | 267 |
fromTime: moment($scope.range.fromTime).isValid() ? moment($scope.range.fromTime) : defaultRange.fromTime, |
282 |
toTime: moment($scope.range.toTime).isValid() ? moment($scope.range.toTime) : defaultRange.toTime |
|
268 |
toTime: moment($scope.range.toTime).isValid() ? moment($scope.range.toTime) : defaultRange.toTime, |
|
269 |
isTime: $scope.range.isTime ? true : false |
|
283 | 270 |
}; |
284 | 271 |
}; |
285 | 272 |
|
... | ... | |
288 | 275 |
fromDate: moment().day(-30), |
289 | 276 |
toDate: moment().day(-1), |
290 | 277 |
fromTime: moment({hour: 7}), |
291 |
toTime: moment({hour: 16}) |
|
278 |
toTime: moment({hour: 16}), |
|
279 |
isTime: true |
|
292 | 280 |
}; |
293 | 281 |
}; |
294 | 282 |
|
295 |
|
|
296 | 283 |
$scope.renderGraphAverageSpeed = function () { |
297 | 284 |
|
298 | 285 |
let t = $rootScope.selectDevice.traffics.reduce(function (l, r) { |
299 |
let key = r.timeFrom;
|
|
286 |
let key = $scope.range.isTime ? r.timeFrom : r.date;
|
|
300 | 287 |
if (typeof l[key] === 'undefined') { |
301 | 288 |
l[key] = { |
302 | 289 |
numberVehicle: 0, |
... | ... | |
312 | 299 |
}, {}); |
313 | 300 |
|
314 | 301 |
let labels = jQuery.unique($rootScope.selectDevice.traffics.map(function (d) { |
315 |
return d.timeFrom;
|
|
302 |
return $scope.range.isTime ? d.timeFrom : moment(d.date, 'YYYY-MM-DD').format('D.M.YYYY');
|
|
316 | 303 |
})); |
317 | 304 |
let data = Object.values(t).map(function (d) { |
318 | 305 |
return Math.round(d.speedSum / d.numberVehicle); |
319 | 306 |
}); |
320 | 307 |
|
321 |
|
|
322 | 308 |
let canvasGraphAverageSpeed = document.getElementById('graphAverageSpeed').getContext('2d'); |
323 | 309 |
|
324 | 310 |
if ($scope.graphAverageSpeed) |
... | ... | |
336 | 322 |
backgroundColor: 'rgba(0, 123, 255, 0.3)', |
337 | 323 |
borderColor: 'rgba(0, 123, 255,1)', |
338 | 324 |
cubicInterpolationMode: 'monotone', |
339 |
radius: 0
|
|
325 |
pointRadius: 0
|
|
340 | 326 |
}] |
341 | 327 |
}, |
342 | 328 |
options: { |
343 | 329 |
responsive: true, |
344 | 330 |
pointDot: false, |
331 |
legend: { |
|
332 |
display: false |
|
333 |
}, |
|
345 | 334 |
scales: { |
346 | 335 |
xAxes: [{ |
347 | 336 |
ticks: { |
... | ... | |
355 | 344 |
labelString: 'km/h' |
356 | 345 |
}, |
357 | 346 |
ticks: { |
358 |
beginAtZero: true |
|
347 |
beginAtZero: true, |
|
348 |
max: Math.max(Math.round((Math.max.apply(null, data) + 10) / 10) * 10, 70) |
|
359 | 349 |
} |
360 | 350 |
}] |
361 | 351 |
}, |
362 | 352 |
tooltips: { |
363 |
enabled: true,
|
|
364 |
mode: 'single',
|
|
353 |
mode: 'index',
|
|
354 |
intersect: false,
|
|
365 | 355 |
callbacks: { |
366 | 356 |
label: function (tooltipItems) { |
367 | 357 |
return tooltipItems.yLabel + ' km/h'; |
... | ... | |
380 | 370 |
|
381 | 371 |
|
382 | 372 |
let labels = jQuery.unique($rootScope.selectDevice.traffics.map(function (d) { |
383 |
return d.timeFrom;
|
|
373 |
return $scope.range.isTime ? d.timeFrom : moment(d.date, 'YYYY-MM-DD').format('D.M.YYYY');
|
|
384 | 374 |
})); |
385 | 375 |
|
386 | 376 |
let useVehiclesIds = jQuery.unique($rootScope.selectDevice.traffics.map(function (d) { |
... | ... | |
393 | 383 |
|
394 | 384 |
let datasets = []; |
395 | 385 |
for (let i = 0, vehicle; vehicle = $scope.filterVehicles[i]; i++) { |
396 |
if ($scope.typeVehicle == null || $scope.typeVehicle === vehicle.id) { |
|
397 |
let dataset = { |
|
398 |
label: vehicle.name, |
|
399 |
backgroundColor: color[vehicle.id].replace("#alpha", "0.3"), |
|
400 |
borderColor: color[vehicle.id].replace("#alpha", "1"), |
|
401 |
borderWidth: 2, |
|
402 |
data: [] |
|
403 |
}; |
|
404 |
|
|
405 |
let l = 0; |
|
406 |
for (let j = 0, traffic; traffic = $rootScope.selectDevice.traffics[j]; j++) { |
|
407 |
if (labels[l] !== traffic.timeFrom) { |
|
408 |
l++; |
|
409 |
if (dataset.data.length < l) { |
|
410 |
dataset.data.push(0); |
|
411 |
} |
|
412 |
} |
|
413 |
if (traffic.typeVehicleId === vehicle.id) { |
|
414 |
dataset.data.push(traffic.numberVehicleAverage); |
|
386 |
let dataset = { |
|
387 |
label: vehicle.name, |
|
388 |
backgroundColor: color[vehicle.id].replace("#alpha", "0.3"), |
|
389 |
borderColor: color[vehicle.id].replace("#alpha", "1"), |
|
390 |
borderWidth: 2, |
|
391 |
data: [] |
|
392 |
}; |
|
393 |
|
|
394 |
let l = 0; |
|
395 |
for (let j = 0, traffic; traffic = $rootScope.selectDevice.traffics[j]; j++) { |
|
396 |
if (($scope.range.isTime && labels[l] !== traffic.timeFrom) || (!$scope.range.isTime && labels[l] !== moment(traffic.date, 'YYYY-MM-DD').format('D.M.YYYY'))) { |
|
397 |
l++; |
|
398 |
if (dataset.data.length < l) { |
|
399 |
dataset.data.push(0); |
|
415 | 400 |
} |
416 | 401 |
} |
417 |
datasets.push(dataset); |
|
402 |
if (traffic.typeVehicleId === vehicle.id) { |
|
403 |
dataset.data.push($scope.range.isTime ? traffic.numberVehicleAverage : traffic.numberVehicle); |
|
404 |
} |
|
418 | 405 |
} |
406 |
datasets.push(dataset); |
|
419 | 407 |
} |
420 | 408 |
|
421 | 409 |
let canvasGraphNumberVehicles = document.getElementById('graphNumberVehicles').getContext('2d'); |
... | ... | |
430 | 418 |
datasets: datasets |
431 | 419 |
}, |
432 | 420 |
options: { |
433 |
tooltips: { |
|
434 |
mode: 'index', |
|
435 |
intersect: false |
|
436 |
}, |
|
437 | 421 |
responsive: true, |
422 |
onResize: function (chart, size) { |
|
423 |
chart.options.legend.display = size.height > 240; |
|
424 |
chart.update(); |
|
425 |
}, |
|
426 |
legend: { |
|
427 |
position: 'bottom', |
|
428 |
}, |
|
438 | 429 |
scales: { |
439 | 430 |
xAxes: [{ |
440 | 431 |
stacked: true, |
... | ... | |
450 | 441 |
}, |
451 | 442 |
stacked: true |
452 | 443 |
}] |
444 |
}, |
|
445 |
tooltips: { |
|
446 |
mode: 'index', |
|
447 |
intersect: false |
|
453 | 448 |
} |
454 | 449 |
} |
455 | 450 |
}); |
456 | 451 |
}; |
457 | 452 |
|
458 |
|
|
459 | 453 |
$scope.infoClose = function () { |
460 | 454 |
$rootScope.selectDevice = null; |
461 | 455 |
|
... | ... | |
472 | 466 |
app.controller('mapController', function ($rootScope, $scope, config, Device) { |
473 | 467 |
|
474 | 468 |
this.$onInit = function () { |
469 |
$scope.markers = []; |
|
475 | 470 |
|
476 |
$scope.map = new GMaps({ |
|
477 |
div: '#map', |
|
471 |
$scope.map = new google.maps.Map(document.getElementById('map'), { |
|
472 |
center: {lat: config.DEFAULT_POSITION.LAT, lng: config.DEFAULT_POSITION.LNG}, |
|
473 |
zoom: config.DEFAULT_ZOOM, |
|
474 |
minZoom: config.DEFAULT_ZOOM_MAX, |
|
478 | 475 |
zoomControl: true, |
479 | 476 |
mapTypeControl: false, |
480 | 477 |
scaleControl: false, |
481 | 478 |
streetViewControl: false, |
482 | 479 |
rotateControl: false, |
483 | 480 |
fullscreenControl: false, |
484 |
mapTypeId: 'roadmap', |
|
485 |
zoom: config.DEFAULT_ZOOM, |
|
486 |
lat: config.DEFAULT_POSITION.LAT, |
|
487 |
lng: config.DEFAULT_POSITION.LNG, |
|
488 |
// styles: [ |
|
489 |
// { |
|
490 |
// featureType: "poi", |
|
491 |
// elementType: "labels", |
|
492 |
// stylers: [{ visibility: "off" }] |
|
493 |
// } |
|
494 |
// ] |
|
481 |
mapTypeId: google.maps.MapTypeId.ROADMAP |
|
495 | 482 |
}); |
496 | 483 |
|
497 | 484 |
Device.query({showDirection: 0}, function (data) { |
... | ... | |
504 | 491 |
}); |
505 | 492 |
}; |
506 | 493 |
|
507 |
|
|
508 | 494 |
$scope.createMarker = function (lctn) { |
509 | 495 |
if (lctn.lat && lctn.lng) { |
510 |
$scope.map.addMarker({
|
|
511 |
lat: lctn.lat,
|
|
512 |
lng: lctn.lng,
|
|
496 |
let marker = new google.maps.Marker({
|
|
497 |
map: $scope.map,
|
|
498 |
position: {lat: lctn.lat, lng: lctn.lng},
|
|
513 | 499 |
title: lctn.name, |
514 |
click: function () { |
|
515 |
$rootScope.$emit('infoLocation', {id: lctn.id}); |
|
516 |
}, |
|
517 |
infoWindow: { |
|
500 |
infoWindow: new google.maps.InfoWindow({ |
|
518 | 501 |
content: '<h6 class="mb-1">' + lctn.name + '</h6>' |
519 | 502 |
+ '<address>' + lctn.street + ', ' + lctn.town + '</address>' |
520 |
}, |
|
503 |
}),
|
|
521 | 504 |
id: lctn.id |
522 | 505 |
}); |
506 |
|
|
507 |
marker.addListener('click', function () { |
|
508 |
$scope.closeInfoWindows(); |
|
509 |
marker.infoWindow.open($scope.map, marker); |
|
510 |
$rootScope.$emit('infoLocation', {id: lctn.id}); |
|
511 |
}); |
|
512 |
|
|
513 |
$scope.markers.push(marker); |
|
523 | 514 |
} |
524 | 515 |
}; |
525 | 516 |
|
526 | 517 |
$rootScope.$on('activeMarker', function (event, args) { |
527 | 518 |
let id = args.id; |
528 |
for (let i = 0, marker; marker = $scope.map.markers[i]; i++) {
|
|
519 |
for (let i = 0, marker; marker = $scope.markers[i]; i++) { |
|
529 | 520 |
if (marker.id && marker.id === id && marker.infoWindow) { |
530 |
$scope.map.setCenter(marker.position.lat(), marker.position.lng());
|
|
521 |
$scope.map.setCenter(marker.getPosition());
|
|
531 | 522 |
$scope.map.setZoom(12); |
532 |
$scope.map.hideInfoWindows(); |
|
533 | 523 |
marker.infoWindow.open($scope.map, marker); |
534 |
return; |
|
524 |
} else { |
|
525 |
marker.infoWindow.close(); |
|
535 | 526 |
} |
536 | 527 |
} |
537 | 528 |
}); |
538 | 529 |
|
539 | 530 |
$rootScope.$on('setDefaultMap', function (event, args) { |
540 |
$scope.map.setCenter(config.DEFAULT_POSITION.LAT, config.DEFAULT_POSITION.LNG);
|
|
531 |
$scope.map.setCenter({lat: config.DEFAULT_POSITION.LAT, lng: config.DEFAULT_POSITION.LNG});
|
|
541 | 532 |
$scope.map.setZoom(config.DEFAULT_ZOOM); |
542 |
$scope.map.hideInfoWindows();
|
|
533 |
$scope.closeInfoWindows();
|
|
543 | 534 |
}); |
535 |
|
|
536 |
$scope.closeInfoWindows = function () { |
|
537 |
for (let i = 0, marker; marker = $scope.markers[i]; i++) { |
|
538 |
marker.infoWindow.close(); |
|
539 |
} |
|
540 |
}; |
|
544 | 541 |
}); |
545 | 542 |
|
546 | 543 |
|
547 | 544 |
app.factory('Device', function ($resource, config) { |
548 |
return $resource(config.API_URL + '/devices/:id', {id: '@id'}, { |
|
545 |
return $resource(config.API_URL + '/devices/:id', {id: '@id', period: '@period'}, {
|
|
549 | 546 |
'get': { |
550 |
url: config.API_URL + '/devices/:id/time-period',
|
|
547 |
url: config.API_URL + '/devices/:id/:period',
|
|
551 | 548 |
method: 'GET', |
552 | 549 |
headers: { |
553 | 550 |
'Content-Type': 'application/json', |
Také k dispozici: Unified diff
refs #7014: přidané grafy denní průměry, optimalizace API, styly převedeny do SASS, zvětšený prostor pro grafy