Projekt

Obecné

Profil

Stáhnout (20.7 KB) Statistiky
| Větev: | Revize:
1
let app = angular.module('pvpk', ['ngRoute', 'ngResource', 'ngSanitize']);
2

    
3
app.constant('config', {
4
    APP_NAME: 'PVPK',
5
    APP_VERSION: '1.2.0',
6
    API_URL: API_URL,
7
    API_TOKEN: API_TOKEN,
8
    DEFAULT_POSITION: {LAT: 49.53, LNG: 13.3},
9
    DEFAULT_ZOOM: 10,
10
    DEFAULT_ZOOM_MAX: 7,
11
});
12

    
13
app.controller('mainController', function ($rootScope, $scope, $location, $window) {
14

    
15
    this.$onInit = function () {
16
        $scope.showLoadingScreen = true;
17
    };
18

    
19
    $window.onload = function () {
20
        let params = $location.search();
21
        if (params.deviceId) {
22
            $rootScope.$emit('activeMarker', {id: params.deviceId});
23
        }
24

    
25
        $scope.$apply(function () {
26
            $scope.showLoadingScreen = false;
27
        });
28
    };
29

    
30
    $rootScope.$on('$locationChangeSuccess', function (event, newUrl, oldUrl) {
31
        let params = $location.search();
32

    
33
        if (newUrl !== oldUrl && $scope.historyUrl) {
34
            if ($scope.historyUrl.q !== $scope.historyUrl.q || $scope.historyUrl.isDirection != params.isDirection) {
35
                $rootScope.$emit('setSearchFromUrl', null);
36
            }
37

    
38
            if ($scope.historyUrl.fromDate !== params.fromDate || $scope.historyUrl.toDate !== params.toDate ||
39
                $scope.historyUrl.fromTime !== params.fromTime || $scope.historyUrl.toTime !== params.toTime) {
40
                $rootScope.$emit('setRangeFromUrl', null);
41
                if (params.deviceId) {
42
                    $rootScope.$emit('infoLocation', {id: params.deviceId, direction: params.direction});
43
                }
44
            } else if (params.deviceId && ($scope.historyUrl.deviceId !== params.deviceId || $scope.historyUrl.direction !== params.direction)) {
45
                $rootScope.$emit('infoLocation', {id: params.deviceId, direction: params.direction});
46
                $rootScope.$emit('activeMarker', {id: params.deviceId});
47
            } else if (!params.deviceId && $scope.historyUrl.deviceId) {
48
                $rootScope.selectDevice = null;
49
                $rootScope.$emit('setDefaultMap', null);
50
            }
51
        } else if (params.deviceId) {
52
            $rootScope.$emit('infoLocation', {id: params.deviceId, direction: params.direction});
53
        }
54

    
55
        $scope.historyUrl = $location.search();
56
    });
57

    
58
    $rootScope.handleErrorResponse = function (response) {
59

    
60
        let modalError = jQuery('#modalError');
61
        switch (response.status) {
62
            case 400:
63
                console.log('API ERROR 400');
64
                $scope.modalError = {
65
                    title: 'Neplatný požadavek',
66
                    body: 'Požadavek nemůže být vyřízen, poněvadž byl syntakticky nesprávně zapsán.',
67
                    button: 'OK'
68
                };
69
                modalError.modal('show');
70
                break;
71
            case 401:
72
                $scope.modalError = {
73
                    title: 'Platnost webové aplikace vypršela',
74
                    body: 'Pro obnovení platnosti stačí stisknout tlačítko <strong>Obnovit</strong>.',
75
                    button: 'Obnovit',
76
                    clickButton: $scope.reloadApp
77
                };
78
                modalError.modal({backdrop: 'static', keyboard: false});
79
                break;
80
            case 404:
81
                console.log('API ERROR 404');
82
                $scope.modalError = {title: 'Nenalezen', body: 'Záznam nebyl nalezen.', button: 'OK'};
83
                modalError.modal('show');
84
                break;
85
            case 500:
86
                console.log('API ERROR 500');
87
                $scope.modalError = {title: 'Chyba', body: 'Chyba serveru. Zopakujte akci později.', button: 'OK'};
88
                modalError.modal('show');
89
                break;
90
            case -1:
91
                console.log('API NOT CONNECTED');
92
                $scope.modalError = {
93
                    title: 'Připojení k internetu',
94
                    body: 'Nejste připojeni k internetu. Zkontrolujte připojení.',
95
                    button: 'OK'
96
                };
97
                modalError.modal('show');
98
                break;
99
            default:
100
                console.log('API UNKNOWN ERROR');
101
                $scope.modalError = {title: 'Neočekávaná chyba', body: 'Nastala neočekávaná chyba.', button: 'OK'};
102
                modalError.modal('show');
103
                break;
104
        }
105
    };
106

    
107
    $scope.reloadApp = function () {
108
        $window.location.reload();
109
    }
110
});
111

    
112

    
113
app.controller('searchController', function ($rootScope, $scope, $location, config, Device) {
114

    
115
    this.$onInit = function () {
116
        $scope.config = config;
117
        $scope.locations = [];
118
        $scope.showSearchLoading = false;
119

    
120
        $rootScope.$emit('setSearchFromUrl', null);
121
    };
122

    
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

    
129
        if (!$scope.search.q || $scope.search.q.length <= 1) {
130
            $scope.locations = [];
131
            return;
132
        }
133

    
134
        $scope.showSearchLoading = true;
135

    
136
        Device.query({
137
            address: $scope.search.q,
138
            showDirection: $scope.search.isDirection ? 1 : 0
139
        }, function (data) {
140
            $scope.locations = data;
141
            $scope.showSearchLoading = false;
142
        }, function (response) {
143
            $scope.showSearchLoading = false;
144
            console.log('Error api all Devices');
145
            $rootScope.handleErrorResponse(response);
146
        });
147
    };
148

    
149
    $rootScope.$on('setSearchFromUrl', function (event, args) {
150
        let params = $location.search();
151
        $scope.search = {
152
            q: params.q,
153
            isDirection: params.isDirection ? !!+params.isDirection : false
154
        };
155
        $scope.searchLocations();
156
    });
157

    
158
    $scope.selectDevice = function (id, direction) {
159
        $rootScope.$emit('activeMarker', {id: id});
160
        $rootScope.$emit('infoLocation', {id: id, direction: direction});
161
    };
162

    
163
});
164

    
165

    
166
app.controller('infoController', function ($rootScope, $scope, $location, config, Device, Vehicle) {
167

    
168
    this.$onInit = function () {
169
        $rootScope.selectDevice = null;
170
        $scope.showInfoLoading = false;
171
        $scope.vehicles = [];
172
        $scope.filterVehicles = [];
173

    
174
        Vehicle.query(null, function (data) {
175
            $scope.vehicles = data;
176
        }, function (response) {
177
            $rootScope.graphShow = false;
178
            console.log('Error api all Vehicles');
179
            $rootScope.handleErrorResponse(response);
180
        });
181

    
182
        $rootScope.$emit('setRangeFromUrl', null);
183
    };
184

    
185
    $rootScope.$on('setRangeFromUrl', function (event, args) {
186
        let params = $location.search();
187
        let defaultRange = $scope.defaultRange();
188

    
189
        $scope.range = {
190
            fromDate: moment(params.fromDate, 'YYYY-MM-DD').isValid() ? moment(params.fromDate).toDate() : defaultRange.fromDate.toDate(),
191
            toDate: moment(params.toDate, 'YYYY-MM-DD').isValid() ? moment(params.toDate).toDate() : defaultRange.toDate.toDate(),
192
            fromTime: moment(params.fromTime, 'HH:mm').isValid() ? moment(params.fromTime, 'HH:mm').toDate() : defaultRange.fromTime.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
195
        };
196

    
197
    });
198

    
199
    $rootScope.$on('infoLocation', function (event, args) {
200
        $scope.showInfoLoading = true;
201

    
202
        let params = $location.search();
203
        params.deviceId = args.id;
204
        params.direction = args.direction;
205
        $location.search(params);
206

    
207
        let range = $scope.getRange();
208

    
209
        // if (!$rootScope.selectDevice || args.id !== $rootScope.selectDevice.id)
210
        //     $rootScope.selectDevice = {name: '...', street: '...', town: '...'};
211

    
212

    
213
        Device.get({
214
            period: range.isTime ? 'time-period' : 'day-period',
215
            id: args.id,
216
            direction: args.direction,
217
            dateFrom: range.fromDate.format('YYYY-MM-DD'),
218
            dateTo: range.toDate.format('YYYY-MM-DD'),
219
            timeFrom: range.isTime ? range.fromTime.format('HH:mm') : null,
220
            timeTo: range.isTime ? range.toTime.format('HH:mm') : null,
221
        }, function (data) {
222
            $rootScope.selectDevice = data;
223

    
224
            $scope.renderGraphAverageSpeed();
225
            $scope.renderGraphNumberVehicles();
226

    
227
            $scope.showInfoLoading = false;
228
        }, function (response) {
229
            $rootScope.selectDevice = null;
230
            $scope.showInfoLoading = false;
231
            console.log('Error api get Devices');
232
            $rootScope.handleErrorResponse(response);
233
        });
234

    
235
    });
236

    
237

    
238
    $scope.changeRange = function () {
239
        if ($scope.range.fromDate >= $scope.range.toDate || ($scope.range.isTime && $scope.range.fromTime >= $scope.range.toTime)) {
240
            $rootScope.selectDevice.traffics = [];
241
            return;
242
        }
243

    
244
        let range = $scope.getRange();
245

    
246
        let params = $location.search();
247
        params.fromDate = range.fromDate.format('YYYY-MM-DD');
248
        params.toDate = range.toDate.format('YYYY-MM-DD');
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;
252
        $location.search(params);
253

    
254
        if ($rootScope.selectDevice)
255
            $rootScope.$emit('infoLocation', {
256
                id: $rootScope.selectDevice.id,
257
                direction: $rootScope.selectDevice.direction
258
            });
259
    };
260

    
261
    $scope.getRange = function () {
262
        let defaultRange = $scope.defaultRange();
263

    
264
        return {
265
            fromDate: moment($scope.range.fromDate).isValid() ? moment($scope.range.fromDate) : defaultRange.fromDate,
266
            toDate: moment($scope.range.toDate).isValid() ? moment($scope.range.toDate) : defaultRange.toDate,
267
            fromTime: moment($scope.range.fromTime).isValid() ? moment($scope.range.fromTime) : defaultRange.fromTime,
268
            toTime: moment($scope.range.toTime).isValid() ? moment($scope.range.toTime) : defaultRange.toTime,
269
            isTime: $scope.range.isTime ? true : false
270
        };
271
    };
272

    
273
    $scope.defaultRange = function () {
274
        return {
275
            fromDate: moment().day(-30),
276
            toDate: moment().day(-1),
277
            fromTime: moment({hour: 7}),
278
            toTime: moment({hour: 16}),
279
            isTime: true
280
        };
281
    };
282

    
283
    $scope.renderGraphAverageSpeed = function () {
284

    
285
        let t = $rootScope.selectDevice.traffics.reduce(function (l, r) {
286
            let key = $scope.range.isTime ? r.timeFrom : r.date;
287
            if (typeof l[key] === 'undefined') {
288
                l[key] = {
289
                    numberVehicle: 0,
290
                    speedSum: 0
291
                };
292
            }
293

    
294
            if (r.speedAverage > 0) {
295
                l[key].numberVehicle += r.numberVehicle;
296
                l[key].speedSum += r.speedAverage * r.numberVehicle;
297
            }
298
            return l;
299
        }, {});
300

    
301
        let labels = jQuery.unique($rootScope.selectDevice.traffics.map(function (d) {
302
            return $scope.range.isTime ? d.timeFrom : moment(d.date, 'YYYY-MM-DD').format('D.M.YYYY');
303
        }));
304
        let data = Object.values(t).map(function (d) {
305
            return Math.round(d.speedSum / d.numberVehicle);
306
        });
307

    
308
        let canvasGraphAverageSpeed = document.getElementById('graphAverageSpeed').getContext('2d');
309

    
310
        if ($scope.graphAverageSpeed)
311
            $scope.graphAverageSpeed.destroy();
312

    
313
        $scope.graphAverageSpeed = new Chart(canvasGraphAverageSpeed, {
314
            type: 'line',
315
            data: {
316
                labels: labels,
317
                datasets: [{
318
                    data: data,
319
                    borderWidth: 2,
320
                    label: "Rychlost",
321
                    fill: 'start',
322
                    backgroundColor: 'rgba(0, 123, 255, 0.3)',
323
                    borderColor: 'rgba(0, 123, 255,1)',
324
                    cubicInterpolationMode: 'monotone',
325
                    pointRadius: 0
326
                }]
327
            },
328
            options: {
329
                responsive: true,
330
                pointDot: false,
331
                legend: {
332
                    display: false
333
                },
334
                scales: {
335
                    xAxes: [{
336
                        ticks: {
337
                            autoSkip: true,
338
                            maxTicksLimit: 15
339
                        }
340
                    }],
341
                    yAxes: [{
342
                        scaleLabel: {
343
                            display: true,
344
                            labelString: 'km/h'
345
                        },
346
                        ticks: {
347
                            beginAtZero: true,
348
                            max: Math.max(Math.round((Math.max.apply(null, data) + 10) / 10) * 10, 70)
349
                        }
350
                    }]
351
                },
352
                tooltips: {
353
                    mode: 'index',
354
                    intersect: false,
355
                    callbacks: {
356
                        label: function (tooltipItems) {
357
                            return tooltipItems.yLabel + ' km/h';
358
                        }
359
                    }
360
                }
361
            }
362
        });
363
    };
364

    
365

    
366
    $scope.renderGraphNumberVehicles = function () {
367
        let color = ['rgba(158, 158, 158, #alpha)', 'rgba(213, 0, 0, #alpha)', 'rgba(0, 123, 255, #alpha)', 'rgba(170, 0, 255, #alpha)',
368
            'rgba(0, 200, 83, #alpha)', 'rgba(255, 214, 0, #alpha)', 'rgba(255, 109, 0, #alpha)',
369
            'rgba(174, 234, 0, #alpha)', 'rgba(98, 0, 234, #alpha)', 'rgba(255, 171, 0, #alpha)', 'rgba(100, 221, 23, #alpha)', 'rgba(0, 184, 212, #alpha)'];
370

    
371

    
372
        let labels = jQuery.unique($rootScope.selectDevice.traffics.map(function (d) {
373
            return $scope.range.isTime ? d.timeFrom : moment(d.date, 'YYYY-MM-DD').format('D.M.YYYY');
374
        }));
375

    
376
        let useVehiclesIds = jQuery.unique($rootScope.selectDevice.traffics.map(function (d) {
377
            return d.typeVehicleId;
378
        }));
379

    
380
        $scope.filterVehicles = jQuery.grep($scope.vehicles, function (n) {
381
            return useVehiclesIds.indexOf(n.id) >= 0;
382
        });
383

    
384
        let datasets = [];
385
        for (let i = 0, vehicle; vehicle = $scope.filterVehicles[i]; i++) {
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);
400
                    }
401
                }
402
                if (traffic.typeVehicleId === vehicle.id) {
403
                    dataset.data.push($scope.range.isTime ? traffic.numberVehicleAverage : traffic.numberVehicle);
404
                }
405
            }
406
            datasets.push(dataset);
407
        }
408

    
409
        let canvasGraphNumberVehicles = document.getElementById('graphNumberVehicles').getContext('2d');
410

    
411
        if ($scope.graphNumberVehicles)
412
            $scope.graphNumberVehicles.destroy();
413

    
414
        $scope.graphNumberVehicles = new Chart(canvasGraphNumberVehicles, {
415
            type: 'bar',
416
            data: {
417
                labels: labels,
418
                datasets: datasets
419
            },
420
            options: {
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
                },
429
                scales: {
430
                    xAxes: [{
431
                        stacked: true,
432
                        ticks: {
433
                            autoSkip: true,
434
                            maxTicksLimit: 15
435
                        }
436
                    }],
437
                    yAxes: [{
438
                        scaleLabel: {
439
                            display: true,
440
                            labelString: "počet vozidel"
441
                        },
442
                        stacked: true
443
                    }]
444
                },
445
                tooltips: {
446
                    mode: 'index',
447
                    intersect: false
448
                }
449
            }
450
        });
451
    };
452

    
453
    $scope.infoClose = function () {
454
        $rootScope.selectDevice = null;
455

    
456
        let params = $location.search();
457
        params.deviceId = null;
458
        params.direction = null;
459
        $location.search(params);
460

    
461
        $rootScope.$emit('setDefaultMap', null);
462
    };
463
});
464

    
465

    
466
app.controller('mapController', function ($rootScope, $scope, config, Device) {
467

    
468
    this.$onInit = function () {
469
        $scope.markers = [];
470

    
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,
475
            zoomControl: true,
476
            mapTypeControl: false,
477
            scaleControl: false,
478
            streetViewControl: false,
479
            rotateControl: false,
480
            fullscreenControl: false,
481
            mapTypeId: google.maps.MapTypeId.ROADMAP
482
        });
483

    
484
        Device.query({showDirection: 0}, function (data) {
485
            for (let i = 0, lctn; lctn = data[i]; i++) {
486
                $scope.createMarker(lctn);
487
            }
488
        }, function (response) {
489
            console.log('Error api all Devices');
490
            $rootScope.handleErrorResponse(response);
491
        });
492
    };
493

    
494
    $scope.createMarker = function (lctn) {
495
        if (lctn.lat && lctn.lng) {
496
            let marker = new google.maps.Marker({
497
                map: $scope.map,
498
                position: {lat: lctn.lat, lng: lctn.lng},
499
                title: lctn.name,
500
                infoWindow: new google.maps.InfoWindow({
501
                    content: '<h6 class="mb-1">' + lctn.name + '</h6>'
502
                    + '<address>' + lctn.street + ', ' + lctn.town + '</address>'
503
                }),
504
                id: lctn.id
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);
514
        }
515
    };
516

    
517
    $rootScope.$on('activeMarker', function (event, args) {
518
        let id = args.id;
519
        for (let i = 0, marker; marker = $scope.markers[i]; i++) {
520
            if (marker.id && marker.id === id && marker.infoWindow) {
521
                $scope.map.setCenter(marker.getPosition());
522
                $scope.map.setZoom(12);
523
                marker.infoWindow.open($scope.map, marker);
524
            } else {
525
                marker.infoWindow.close();
526
            }
527
        }
528
    });
529

    
530
    $rootScope.$on('setDefaultMap', function (event, args) {
531
        $scope.map.setCenter({lat: config.DEFAULT_POSITION.LAT, lng: config.DEFAULT_POSITION.LNG});
532
        $scope.map.setZoom(config.DEFAULT_ZOOM);
533
        $scope.closeInfoWindows();
534
    });
535

    
536
    $scope.closeInfoWindows = function () {
537
        for (let i = 0, marker; marker = $scope.markers[i]; i++) {
538
            marker.infoWindow.close();
539
        }
540
    };
541
});
542

    
543

    
544
app.factory('Device', function ($resource, config) {
545
    return $resource(config.API_URL + '/devices/:id', {id: '@id', period: '@period'}, {
546
        'get': {
547
            url: config.API_URL + '/devices/:id/:period',
548
            method: 'GET',
549
            headers: {
550
                'Content-Type': 'application/json',
551
                'Accept': 'application/json',
552
                'jwt': config.API_TOKEN
553
            }
554
        },
555
        'query': {
556
            url: config.API_URL + '/devices',
557
            method: 'GET',
558
            isArray: true,
559
            headers: {
560
                'Content-Type': 'application/json',
561
                'Accept': 'application/json',
562
                'jwt': config.API_TOKEN
563
            }
564
        }
565
    });
566
});
567

    
568
app.factory('Vehicle', function ($resource, config) {
569
    return $resource(config.API_URL + '/vehicles', null, {
570
        'query': {
571
            url: config.API_URL + '/vehicles',
572
            method: 'GET',
573
            isArray: true,
574
            headers: {
575
                'Content-Type': 'application/json',
576
                'Accept': 'application/json',
577
                'jwt': config.API_TOKEN
578
            }
579
        }
580
    });
581
});
(2-2/6)