Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 01189277

Přidáno uživatelem kohlicekjan před více než 6 roky(ů)

Closes #3, #4, #5, #6, #7; přidaná možnost měnit směr v sekci #info, kontrola časového rozmezí, přispůsobování popisků grafu, zobrazení špatných dat jako 0, odkazu byl přidán rel="noopener", aktualizace knihoven

Zobrazit rozdíly:

backend/app/Http/Controllers/RangeController.php
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: Zdenda
5
 * Date: 20.4.2018
6
 * Time: 20:09
7
 */
8

  
9
namespace App\Http\Controllers;
10

  
11
use App\Model\Device;
12
use App\Model\Zarizeni;
13
use App\Model\Zaznam;
14
use Illuminate\Http\Request;
15
use phpDocumentor\Reflection\Types\Array_;
16
use phpDocumentor\Reflection\Types\Mixed_;
17

  
18
class RangeController extends Controller
19
{
20

  
21
    /**
22
     * Vrati časový rozsah záznamů
23
     *
24
     * @return Zarizeni
25
     */
26
    public function getRange()
27
    {
28
        $rangeDate = Zaznam::lastDateAndFirstDate();
29

  
30
        if ($rangeDate != null) {
31
            return json_encode($rangeDate);
32
        } else {
33
            return response('Not found.', 404);
34
        }
35
    }
36

  
37
}
backend/app/Http/routes.php
30 30
    'uses' => 'DeviceController@getDevice'
31 31
]);
32 32

  
33
/**
34
 * Vrati časový rozsah
35
 */
36
$app->get($apiUrlRoot.'range', [
37
    'middleware' => [$corsMiddle, $jwtMiddle],
38
    'uses' => 'RangeController@getRange'
39
]);
33 40

  
34 41
/**
35 42
 * Vrati zaznamy o doprave za casovy usek pro dane zarizeni.
backend/app/Model/Zaznam.php
47 47
            ->get();
48 48
    }
49 49

  
50
    /**
51
     * Vrati posledni datum pro ktere existuji zaznamy v tabulce zaznam_prum_den.
52
     * @return String Posledni datum pro ktere existuji zaznamy.
53
     */
54
    public static function lastDateAndFirstDate() {
55
        return DB::table('zaznam_prum_den')
56
            ->join('datum', 'zaznam_prum_den.datum_id', '=', 'datum.id')
57
            ->select(DB::raw('
58
                max(date(datum.od)) as last_date,
59
                min(date(datum.od)) as first_date'
60
            ))
61
            ->first();
62
    }
63

  
50 64
    /**
51 65
     * Vrati prumery dopravy v casovem useku podle typu vozidla.
52 66
     *
frontend/app.js
1
angular.module('pvpk', ['ngResource', 'ngSanitize']);
1
angular.module('pvpk', ['ngResource']);
2 2
angular.module('pvpk')
3 3
    .constant('config', {
4 4
        APP_NAME: 'PVPK',
5
        APP_VERSION: '1.3.0',
5
        APP_VERSION: '1.3.3',
6 6
        API_URL: API_URL,
7 7
        API_TOKEN: API_TOKEN,
8 8
        DEFAULT_POSITION: {lat: 49.53, lng: 13.3},
......
12 12
        DEFAULT_RANGE_TIME_HOUR: {from: 7, to: 16}
13 13
    });
14 14
angular.module('pvpk')
15
    .controller('infoController', ['$rootScope', '$scope', '$location', 'config', 'Device', 'Vehicle', function ($rootScope, $scope, $location, config, Device, Vehicle) {
15
    .factory('Device', ['$resource', 'config', function ($resource, config) {
16
        return $resource(config.API_URL + '/devices/:id', {id: '@id', period: '@period'}, {
17
            'get': {
18
                url: config.API_URL + '/devices/:id/:period',
19
                method: 'GET',
20
                headers: {
21
                    'Content-Type': 'application/json',
22
                    'Accept': 'application/json',
23
                    'jwt': config.API_TOKEN
24
                }
25
            },
26
            'query': {
27
                url: config.API_URL + '/devices',
28
                method: 'GET',
29
                isArray: true,
30
                headers: {
31
                    'Content-Type': 'application/json',
32
                    'Accept': 'application/json',
33
                    'jwt': config.API_TOKEN
34
                }
35
            }
36
        });
37
    }]);
38
angular.module('pvpk')
39
    .factory('Range', ['$resource', 'config', function ($resource, config) {
40
        return $resource(config.API_URL + '/range', null, {
41
            'get': {
42
                url: config.API_URL + '/range',
43
                method: 'GET',
44
                headers: {
45
                    'Content-Type': 'application/json',
46
                    'Accept': 'application/json',
47
                    'jwt': config.API_TOKEN
48
                }
49
            }
50
        });
51
    }]);
52
angular.module('pvpk')
53
    .factory('Vehicle', ['$resource', 'config', function ($resource, config) {
54
        return $resource(config.API_URL + '/vehicles', null, {
55
            'query': {
56
                url: config.API_URL + '/vehicles',
57
                method: 'GET',
58
                isArray: true,
59
                headers: {
60
                    'Content-Type': 'application/json',
61
                    'Accept': 'application/json',
62
                    'jwt': config.API_TOKEN
63
                }
64
            }
65
        });
66
    }]);
67
angular.module('pvpk')
68
    .controller('infoController', ['$rootScope', '$scope', '$location', 'config', 'Device', 'Vehicle', 'Range', function ($rootScope, $scope, $location, config, Device, Vehicle, Range) {
16 69

  
17 70
        this.$onInit = function () {
18 71
            $rootScope.selectDevice = null;
19 72
            $scope.showInfoLoading = false;
20 73
            $scope.vehicles = [];
21 74
            $scope.urlExportCsv = null;
75
            $scope.directions = [
76
                {id: undefined, name: 'po směru i proti směru'},
77
                {id: 1, name: 'po směru'},
78
                {id: 2, name: 'proti směru'}];
79
            $scope.isLoadRange = false;
22 80

  
23 81
            Vehicle.query(null, function (data) {
24 82
                $scope.vehicles = data;
......
33 91

  
34 92
        $rootScope.$on('setRangeFromUrl', function (event, args) {
35 93
            var params = $location.search();
94

  
36 95
            $scope.range = {
37 96
                fromDate: moment(params.fromDate, 'YYYY-MM-DD').isValid() ? moment(params.fromDate).toDate() : moment().add(config.DEFAULT_RANGE_DATE_DAY.from, 'd').toDate(),
38 97
                toDate: moment(params.toDate, 'YYYY-MM-DD').isValid() ? moment(params.toDate).toDate() : moment().add(config.DEFAULT_RANGE_DATE_DAY.to, 'd').toDate(),
39 98
                fromTime: moment(params.fromTime, 'HH:mm').isValid() ? moment(params.fromTime, 'HH:mm').toDate() : moment({hour: config.DEFAULT_RANGE_TIME_HOUR.from}).toDate(),
40 99
                toTime: moment(params.toTime, 'HH:mm').isValid() ? moment(params.toTime, 'HH:mm').toDate() : moment({hour: config.DEFAULT_RANGE_TIME_HOUR.to}).toDate(),
41
                isTime: params.isTime == 0 ? false : true
100
                isTime: params.isTime == 0 ? false : true,
101
                maxDate: $scope.range == null ? null : $scope.range.maxDate,
102
                minDate: $scope.range == null ? null : $scope.range.minDate
42 103
            };
104

  
105
            if (!$scope.isLoadRange) {
106
                Range.get(null, function (data) {
107
                    $scope.range.fromDate = moment.max(moment(data.last_date).add(config.DEFAULT_RANGE_DATE_DAY.from, 'd'), moment(data.first_date)).toDate();
108
                    $scope.range.toDate = moment.min(moment($scope.range.toDate), moment(data.last_date)).toDate();
109
                    $scope.range.maxDate = moment(data.last_date).toDate();
110
                    $scope.range.minDate = moment(data.first_date).toDate();
111
                    $scope.isLoadRange = true;
112
                }, function (response) {
113
                    console.log('Error api get Range');
114
                    $rootScope.handleErrorResponse(response);
115
                });
116
            }
43 117
        });
44 118

  
45 119
        $rootScope.$on('infoLocation', function (event, args) {
......
92 166
                return;
93 167
            }
94 168

  
169
            if (!($scope.range.fromDate >= $scope.range.minDate && $scope.range.toDate <= $scope.range.maxDate
170
                && $scope.range.toDate >= $scope.range.minDate && $scope.range.fromDate <= $scope.range.maxDate)) {
171
                $rootScope.selectDevice.traffics = [];
172
                return;
173
            }
174

  
175

  
95 176
            var range = $scope.getRange();
96 177

  
97 178
            var params = $location.search();
......
109 190
                });
110 191
        };
111 192

  
193
        $scope.changeDirection = function () {
194

  
195
            $rootScope.$emit('infoLocation', {
196
                id: $rootScope.selectDevice.id,
197
                direction: $rootScope.selectDevice.direction
198
            });
199
        };
200

  
112 201
        $scope.getRange = function () {
113 202
            return {
114 203
                fromDate: moment($scope.range.fromDate).isValid() ? moment($scope.range.fromDate) : moment().add(config.DEFAULT_RANGE_DATE_DAY.from, 'd'),
......
153 242
                    borderWidth: 2,
154 243
                    label: vehicle.name,
155 244
                    fill: false,
156
                    //fill: 'start',
157 245
                    backgroundColor: color[vehicle.id].replace("#alpha", "0.3"),
158 246
                    borderColor: color[vehicle.id].replace("#alpha", "1"),
159 247
                    cubicInterpolationMode: 'monotone',
......
166 254
                        l++;
167 255
                        if (datasetNumberVehicles.data.length < l) {
168 256
                            datasetNumberVehicles.data.push(0);
169
                            datasetAverageSpeed.data.push(null);
257
                            datasetAverageSpeed.data.push(0);
170 258
                        }
171 259
                    }
172 260
                    if (traffic.typeVehicleId === vehicle.id) {
173 261
                        datasetNumberVehicles.data.push($scope.range.isTime ? traffic.numberVehicleAverage : traffic.numberVehicle);
174
                        datasetAverageSpeed.data.push(traffic.speedAverage <= 0 ? null : traffic.speedAverage);
262
                        datasetAverageSpeed.data.push(traffic.speedAverage <= 0 ? 0 : traffic.speedAverage);
175 263
                    }
176 264
                }
177 265
                datasetsNumberVehicles.push(datasetNumberVehicles);
......
267 355
                case 401:
268 356
                    $scope.modalError = {
269 357
                        title: 'Platnost webové aplikace vypršela',
270
                        body: 'Pro obnovení platnosti stačí stisknout tlačítko <strong>Obnovit</strong>.',
358
                        body: 'Pro obnovení platnosti stačí stisknout tlačítko Obnovit.',
271 359
                        button: 'Obnovit',
272 360
                        clickButton: $scope.reloadApp
273 361
                    };
......
434 522
    }]);
435 523
angular.module('pvpk')
436 524
    .component('graphAverageSpeed', {
437
        template: '<div><canvas id="graphAverageSpeed" class="graphSize mb-5"></canvas></div>',
525
        template: '<div><canvas id="graphAverageSpeed" class="graph-size mb-5"></canvas></div>',
438 526
        controller: ['$rootScope', '$scope', function ($rootScope, $scope) {
439 527

  
440 528
            $rootScope.$on('renderGraphAverageSpeed', function (event, args) {
......
488 576
    });
489 577
angular.module('pvpk')
490 578
    .component('graphNumberVehicles', {
491
        template: '<div><canvas id="graphNumberVehicles" class="graphSize mb-5"></canvas></div>',
579
        template: '<div><canvas id="graphNumberVehicles" class="graph-size mb-5"></canvas></div>',
492 580
        controller: ['$rootScope', '$scope', function ($rootScope, $scope) {
493 581

  
494 582
            $rootScope.$on('renderGraphNumberVehicles', function (event, args) {
......
535 623
            });
536 624

  
537 625
        }]
538
    });
539
angular.module('pvpk')
540
    .factory('Device', ['$resource', 'config', function ($resource, config) {
541
        return $resource(config.API_URL + '/devices/:id', {id: '@id', period: '@period'}, {
542
            'get': {
543
                url: config.API_URL + '/devices/:id/:period',
544
                method: 'GET',
545
                headers: {
546
                    'Content-Type': 'application/json',
547
                    'Accept': 'application/json',
548
                    'jwt': config.API_TOKEN
549
                }
550
            },
551
            'query': {
552
                url: config.API_URL + '/devices',
553
                method: 'GET',
554
                isArray: true,
555
                headers: {
556
                    'Content-Type': 'application/json',
557
                    'Accept': 'application/json',
558
                    'jwt': config.API_TOKEN
559
                }
560
            }
561
        });
562
    }]);
563
angular.module('pvpk')
564
    .factory('Vehicle', ['$resource', 'config', function ($resource, config) {
565
        return $resource(config.API_URL + '/vehicles', null, {
566
            'query': {
567
                url: config.API_URL + '/vehicles',
568
                method: 'GET',
569
                isArray: true,
570
                headers: {
571
                    'Content-Type': 'application/json',
572
                    'Accept': 'application/json',
573
                    'jwt': config.API_TOKEN
574
                }
575
            }
576
        });
577
    }]);
626
    });
frontend/app.min.js
1
angular.module("pvpk",["ngResource","ngSanitize"]),angular.module("pvpk").constant("config",{APP_NAME:"PVPK",APP_VERSION:"1.3.0",API_URL:API_URL,API_TOKEN:API_TOKEN,DEFAULT_POSITION:{lat:49.53,lng:13.3},DEFAULT_ZOOM:10,DEFAULT_ZOOM_MIN:7,DEFAULT_RANGE_DATE_DAY:{from:-30,to:-1},DEFAULT_RANGE_TIME_HOUR:{from:7,to:16}}),angular.module("pvpk").controller("infoController",["$rootScope","$scope","$location","config","Device","Vehicle",function(u,h,r,i,n,e){this.$onInit=function(){u.selectDevice=null,h.showInfoLoading=!1,h.vehicles=[],h.urlExportCsv=null,e.query(null,function(e){h.vehicles=e},function(e){u.graphShow=!1,console.log("Error api all Vehicles"),u.handleErrorResponse(e)}),u.$emit("setRangeFromUrl",null)},u.$on("setRangeFromUrl",function(e,o){var t=r.search();h.range={fromDate:moment(t.fromDate,"YYYY-MM-DD").isValid()?moment(t.fromDate).toDate():moment().add(i.DEFAULT_RANGE_DATE_DAY.from,"d").toDate(),toDate:moment(t.toDate,"YYYY-MM-DD").isValid()?moment(t.toDate).toDate():moment().add(i.DEFAULT_RANGE_DATE_DAY.to,"d").toDate(),fromTime:moment(t.fromTime,"HH:mm").isValid()?moment(t.fromTime,"HH:mm").toDate():moment({hour:i.DEFAULT_RANGE_TIME_HOUR.from}).toDate(),toTime:moment(t.toTime,"HH:mm").isValid()?moment(t.toTime,"HH:mm").toDate():moment({hour:i.DEFAULT_RANGE_TIME_HOUR.to}).toDate(),isTime:0!=t.isTime}}),u.$on("infoLocation",function(e,o){h.showInfoLoading=!0;var t=r.search();t.deviceId=o.id,t.direction=o.direction,r.search(t);var i=h.getRange(),a={period:i.isTime?"time-period":"day-period",id:o.id,direction:o.direction,dateFrom:i.fromDate.format("YYYY-MM-DD"),dateTo:i.toDate.format("YYYY-MM-DD"),timeFrom:i.isTime?i.fromTime.format("HH:mm"):null,timeTo:i.isTime?i.toTime.format("HH:mm"):null};n.get(a,function(e){u.selectDevice=e,h.renderGraph(),h.urlExportCsv=h.generateUrlExportCsv(a),h.showInfoLoading=!1},function(e){u.selectDevice=null,h.showInfoLoading=!1,console.log("Error api get Devices"),u.handleErrorResponse(e)})}),h.generateUrlExportCsv=function(e){var o="/devices/:id/:period/csv?".replace(":id",e.id).replace(":period",e.period);delete e.id,delete e.period;var t=jQuery.param(e);return i.API_URL+o+t},h.changeRange=function(){if(h.range.fromDate>=h.range.toDate||h.range.isTime&&h.range.fromTime>=h.range.toTime)u.selectDevice.traffics=[];else{var e=h.getRange(),o=r.search();o.fromDate=e.fromDate.format("YYYY-MM-DD"),o.toDate=e.toDate.format("YYYY-MM-DD"),o.fromTime=e.isTime?e.fromTime.format("HH:mm"):null,o.toTime=e.isTime?e.toTime.format("HH:mm"):null,o.isTime=e.isTime?null:0,r.search(o),u.selectDevice&&u.$emit("infoLocation",{id:u.selectDevice.id,direction:u.selectDevice.direction})}},h.getRange=function(){return{fromDate:moment(h.range.fromDate).isValid()?moment(h.range.fromDate):moment().add(i.DEFAULT_RANGE_DATE_DAY.from,"d"),toDate:moment(h.range.toDate).isValid()?moment(h.range.toDate):moment().add(i.DEFAULT_RANGE_DATE_DAY.to,"d"),fromTime:moment(h.range.fromTime).isValid()?moment(h.range.fromTime):moment({hour:i.DEFAULT_RANGE_TIME_HOUR.from}),toTime:moment(h.range.toTime).isValid()?moment(h.range.toTime):moment({hour:i.DEFAULT_RANGE_TIME_HOUR.to}),isTime:!!h.range.isTime}},h.renderGraph=function(){for(var e,o=["rgba(158, 158, 158, #alpha)","rgba(213, 0, 0, #alpha)","rgba(0, 123, 255, #alpha)","rgba(170, 0, 255, #alpha)","rgba(0, 200, 83, #alpha)","rgba(255, 214, 0, #alpha)","rgba(255, 109, 0, #alpha)","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)"],t=jQuery.unique(u.selectDevice.traffics.map(function(e){return h.range.isTime?e.timeFrom:moment(e.date,"YYYY-MM-DD").format("D.M.YYYY")})),i=jQuery.unique(u.selectDevice.traffics.map(function(e){return e.typeVehicleId})),a=jQuery.grep(h.vehicles,function(e){return 0<=i.indexOf(e.id)}),r=[],n=[],l=0;e=a[l];l++){for(var c,s={label:e.name,backgroundColor:o[e.id].replace("#alpha","0.3"),borderColor:o[e.id].replace("#alpha","1"),borderWidth:2,data:[]},m={data:[],borderWidth:2,label:e.name,fill:!1,backgroundColor:o[e.id].replace("#alpha","0.3"),borderColor:o[e.id].replace("#alpha","1"),cubicInterpolationMode:"monotone",pointRadius:0},d=0,p=0;c=u.selectDevice.traffics[p];p++)(h.range.isTime&&t[d]!==c.timeFrom||!h.range.isTime&&t[d]!==moment(c.date,"YYYY-MM-DD").format("D.M.YYYY"))&&(d++,s.data.length<d&&(s.data.push(0),m.data.push(null))),c.typeVehicleId===e.id&&(s.data.push(h.range.isTime?c.numberVehicleAverage:c.numberVehicle),m.data.push(c.speedAverage<=0?null:c.speedAverage));r.push(s),n.push(m)}u.$emit("renderGraphNumberVehicles",{data:{labels:t,datasets:r}}),u.$emit("renderGraphAverageSpeed",{data:{labels:t,datasets:n}})},h.infoClose=function(){u.selectDevice=null;var e=r.search();e.deviceId=null,e.direction=null,r.search(e),u.$emit("setDefaultMap",null)}}]),angular.module("pvpk").controller("mainController",["$rootScope","$scope","$location","$window",function(a,r,n,e){this.$onInit=function(){r.showLoadingScreen=!0},e.onload=function(){var e=n.search();e.deviceId&&a.$emit("activeMarker",{id:e.deviceId}),r.$apply(function(){r.showLoadingScreen=!1})},a.$on("$locationChangeSuccess",function(e,o,t){var i=n.search();o!==t&&r.historyUrl?(r.historyUrl.q==r.historyUrl.q&&r.historyUrl.isDirection==i.isDirection||a.$emit("setSearchFromUrl",null),r.historyUrl.fromDate!==i.fromDate||r.historyUrl.toDate!==i.toDate||r.historyUrl.fromTime!==i.fromTime||r.historyUrl.toTime!==i.toTime?(a.$emit("setRangeFromUrl",null),i.deviceId&&a.$emit("infoLocation",{id:i.deviceId,direction:i.direction})):!i.deviceId||r.historyUrl.deviceId===i.deviceId&&r.historyUrl.direction===i.direction?!i.deviceId&&r.historyUrl.deviceId&&(a.selectDevice=null,a.$emit("setDefaultMap",null)):(a.$emit("infoLocation",{id:i.deviceId,direction:i.direction}),a.$emit("activeMarker",{id:i.deviceId}))):i.deviceId&&a.$emit("infoLocation",{id:i.deviceId,direction:i.direction}),r.historyUrl=n.search()}),a.handleErrorResponse=function(e){var o=jQuery("#modalError");switch(e.status){case 400:console.log("API ERROR 400"),r.modalError={title:"Neplatný požadavek",body:"Požadavek nemůže být vyřízen, poněvadž byl syntakticky nesprávně zapsán.",button:"OK"},o.modal("show");break;case 401:r.modalError={title:"Platnost webové aplikace vypršela",body:"Pro obnovení platnosti stačí stisknout tlačítko <strong>Obnovit</strong>.",button:"Obnovit",clickButton:r.reloadApp},o.modal({backdrop:"static",keyboard:!1});break;case 404:console.log("API ERROR 404"),r.modalError={title:"Nenalezen",body:"Záznam nebyl nalezen.",button:"OK"},o.modal("show");break;case 500:console.log("API ERROR 500"),r.modalError={title:"Chyba",body:"Chyba serveru. Zopakujte akci později.",button:"OK"},o.modal("show");break;case-1:console.log("API NOT CONNECTED"),r.modalError={title:"Připojení k internetu",body:"Nejste připojeni k internetu. Zkontrolujte připojení.",button:"OK"},o.modal("show");break;default:console.log("API UNKNOWN ERROR"),r.modalError={title:"Neočekávaná chyba",body:"Nastala neočekávaná chyba.",button:"OK"},o.modal("show")}},r.reloadApp=function(){e.location.reload()}}]),angular.module("pvpk").controller("mapController",["$rootScope","$scope","config","Device",function(t,a,i,e){this.$onInit=function(){a.markers=[],a.map=new google.maps.Map(document.getElementById("map"),{center:i.DEFAULT_POSITION,zoom:i.DEFAULT_ZOOM,minZoom:i.DEFAULT_ZOOM_MIN,zoomControl:!0,mapTypeControl:!1,scaleControl:!1,streetViewControl:!1,rotateControl:!1,fullscreenControl:!1,mapTypeId:google.maps.MapTypeId.ROADMAP}),e.query({showDirection:0},function(e){for(var o,t=0;o=e[t];t++)a.createMarker(o)},function(e){console.log("Error api all Devices"),t.handleErrorResponse(e)})},a.createMarker=function(e){if(e.lat&&e.lng){var o=new google.maps.Marker({map:a.map,position:{lat:e.lat,lng:e.lng},title:e.name,infoWindow:new google.maps.InfoWindow({content:'<h6 class="mb-1">'+e.name+"</h6><address>"+e.street+", "+e.town+"</address>"}),id:e.id});o.addListener("click",function(){a.closeInfoWindows(),o.infoWindow.open(a.map,o),t.$emit("infoLocation",{id:e.id})}),a.markers.push(o)}},t.$on("activeMarker",function(e,o){for(var t,i=0;t=a.markers[i];i++)t.id&&t.id===o.id&&t.infoWindow?(a.map.setCenter(t.getPosition()),a.map.setZoom(12),t.infoWindow.open(a.map,t)):t.infoWindow.close()}),t.$on("setDefaultMap",function(e,o){a.map.setCenter(i.DEFAULT_POSITION),a.map.setZoom(i.DEFAULT_ZOOM),a.closeInfoWindows()}),a.closeInfoWindows=function(){for(var e,o=0;e=a.markers[o];o++)e.infoWindow.close()}}]),angular.module("pvpk").controller("searchController",["$rootScope","$scope","$location","config","Device",function(t,i,a,e,o){this.$onInit=function(){i.config=e,i.locations=[],i.showSearchLoading=!1,t.$emit("setSearchFromUrl",null)},i.searchLocations=function(){var e=a.search();e.q=i.search.q,e.isDirection=i.search.isDirection?1:null,a.search(e),!i.search.q||i.search.q.length<=1?i.locations=[]:(i.showSearchLoading=!0,o.query({address:i.search.q,showDirection:i.search.isDirection?1:0},function(e){i.locations=e,i.showSearchLoading=!1},function(e){i.showSearchLoading=!1,console.log("Error api all Devices"),t.handleErrorResponse(e)}))},t.$on("setSearchFromUrl",function(e,o){var t=a.search();i.search={q:t.q,isDirection:!!t.isDirection&&!!+t.isDirection},i.searchLocations()}),i.selectDevice=function(e,o){t.$emit("activeMarker",{id:e}),t.$emit("infoLocation",{id:e,direction:o})}}]),angular.module("pvpk").component("graphAverageSpeed",{template:'<div><canvas id="graphAverageSpeed" class="graphSize mb-5"></canvas></div>',controller:["$rootScope","$scope",function(e,i){e.$on("renderGraphAverageSpeed",function(e,o){var t=document.getElementById("graphAverageSpeed").getContext("2d");i.graphLine&&i.graphLine.destroy(),i.graphLine=new Chart(t,{type:"line",data:o.data,options:{responsive:!0,pointDot:!1,legend:{position:"bottom"},scales:{xAxes:[{ticks:{autoSkip:!0,maxTicksLimit:15}}],yAxes:[{scaleLabel:{display:!0,labelString:"km/h"},ticks:{beginAtZero:!0,suggestedMax:70}}]},tooltips:{mode:"index",intersect:!1,callbacks:{label:function(e){return e.yLabel+" km/h"}}}}})})}]}),angular.module("pvpk").component("graphNumberVehicles",{template:'<div><canvas id="graphNumberVehicles" class="graphSize mb-5"></canvas></div>',controller:["$rootScope","$scope",function(e,i){e.$on("renderGraphNumberVehicles",function(e,o){var t=document.getElementById("graphNumberVehicles").getContext("2d");i.graphNumberVehicles&&i.graphNumberVehicles.destroy(),i.graphNumberVehicles=new Chart(t,{type:"bar",data:o.data,options:{responsive:!0,onResize:function(e,o){e.options.legend.display=240<o.height,e.update()},legend:{position:"bottom"},scales:{xAxes:[{stacked:!0,ticks:{autoSkip:!0,maxTicksLimit:15}}],yAxes:[{scaleLabel:{display:!0,labelString:"počet vozidel"},stacked:!0}]},tooltips:{mode:"index",intersect:!1}}})})}]}),angular.module("pvpk").factory("Device",["$resource","config",function(e,o){return e(o.API_URL+"/devices/:id",{id:"@id",period:"@period"},{get:{url:o.API_URL+"/devices/:id/:period",method:"GET",headers:{"Content-Type":"application/json",Accept:"application/json",jwt:o.API_TOKEN}},query:{url:o.API_URL+"/devices",method:"GET",isArray:!0,headers:{"Content-Type":"application/json",Accept:"application/json",jwt:o.API_TOKEN}}})}]),angular.module("pvpk").factory("Vehicle",["$resource","config",function(e,o){return e(o.API_URL+"/vehicles",null,{query:{url:o.API_URL+"/vehicles",method:"GET",isArray:!0,headers:{"Content-Type":"application/json",Accept:"application/json",jwt:o.API_TOKEN}}})}]);
1
angular.module("pvpk",["ngResource"]),angular.module("pvpk").constant("config",{APP_NAME:"PVPK",APP_VERSION:"1.3.3",API_URL:API_URL,API_TOKEN:API_TOKEN,DEFAULT_POSITION:{lat:49.53,lng:13.3},DEFAULT_ZOOM:10,DEFAULT_ZOOM_MIN:7,DEFAULT_RANGE_DATE_DAY:{from:-30,to:-1},DEFAULT_RANGE_TIME_HOUR:{from:7,to:16}}),angular.module("pvpk").factory("Device",["$resource","config",function(e,o){return e(o.API_URL+"/devices/:id",{id:"@id",period:"@period"},{get:{url:o.API_URL+"/devices/:id/:period",method:"GET",headers:{"Content-Type":"application/json",Accept:"application/json",jwt:o.API_TOKEN}},query:{url:o.API_URL+"/devices",method:"GET",isArray:!0,headers:{"Content-Type":"application/json",Accept:"application/json",jwt:o.API_TOKEN}}})}]),angular.module("pvpk").factory("Range",["$resource","config",function(e,o){return e(o.API_URL+"/range",null,{get:{url:o.API_URL+"/range",method:"GET",headers:{"Content-Type":"application/json",Accept:"application/json",jwt:o.API_TOKEN}}})}]),angular.module("pvpk").factory("Vehicle",["$resource","config",function(e,o){return e(o.API_URL+"/vehicles",null,{query:{url:o.API_URL+"/vehicles",method:"GET",isArray:!0,headers:{"Content-Type":"application/json",Accept:"application/json",jwt:o.API_TOKEN}}})}]),angular.module("pvpk").controller("infoController",["$rootScope","$scope","$location","config","Device","Vehicle","Range",function(u,g,i,a,r,e,n){this.$onInit=function(){u.selectDevice=null,g.showInfoLoading=!1,g.vehicles=[],g.urlExportCsv=null,g.directions=[{id:void 0,name:"po směru i proti směru"},{id:1,name:"po směru"},{id:2,name:"proti směru"}],g.isLoadRange=!1,e.query(null,function(e){g.vehicles=e},function(e){u.graphShow=!1,console.log("Error api all Vehicles"),u.handleErrorResponse(e)}),u.$emit("setRangeFromUrl",null)},u.$on("setRangeFromUrl",function(e,o){var t=i.search();g.range={fromDate:moment(t.fromDate,"YYYY-MM-DD").isValid()?moment(t.fromDate).toDate():moment().add(a.DEFAULT_RANGE_DATE_DAY.from,"d").toDate(),toDate:moment(t.toDate,"YYYY-MM-DD").isValid()?moment(t.toDate).toDate():moment().add(a.DEFAULT_RANGE_DATE_DAY.to,"d").toDate(),fromTime:moment(t.fromTime,"HH:mm").isValid()?moment(t.fromTime,"HH:mm").toDate():moment({hour:a.DEFAULT_RANGE_TIME_HOUR.from}).toDate(),toTime:moment(t.toTime,"HH:mm").isValid()?moment(t.toTime,"HH:mm").toDate():moment({hour:a.DEFAULT_RANGE_TIME_HOUR.to}).toDate(),isTime:0!=t.isTime,maxDate:null==g.range?null:g.range.maxDate,minDate:null==g.range?null:g.range.minDate},g.isLoadRange||n.get(null,function(e){g.range.fromDate=moment.max(moment(e.last_date).add(a.DEFAULT_RANGE_DATE_DAY.from,"d"),moment(e.first_date)).toDate(),g.range.toDate=moment.min(moment(g.range.toDate),moment(e.last_date)).toDate(),g.range.maxDate=moment(e.last_date).toDate(),g.range.minDate=moment(e.first_date).toDate(),g.isLoadRange=!0},function(e){console.log("Error api get Range"),u.handleErrorResponse(e)})}),u.$on("infoLocation",function(e,o){g.showInfoLoading=!0;var t=i.search();t.deviceId=o.id,t.direction=o.direction,i.search(t);var a=g.getRange(),n={period:a.isTime?"time-period":"day-period",id:o.id,direction:o.direction,dateFrom:a.fromDate.format("YYYY-MM-DD"),dateTo:a.toDate.format("YYYY-MM-DD"),timeFrom:a.isTime?a.fromTime.format("HH:mm"):null,timeTo:a.isTime?a.toTime.format("HH:mm"):null};r.get(n,function(e){u.selectDevice=e,g.renderGraph(),g.urlExportCsv=g.generateUrlExportCsv(n),g.showInfoLoading=!1},function(e){u.selectDevice=null,g.showInfoLoading=!1,console.log("Error api get Devices"),u.handleErrorResponse(e)})}),g.generateUrlExportCsv=function(e){var o="/devices/:id/:period/csv?".replace(":id",e.id).replace(":period",e.period);delete e.id,delete e.period;var t=jQuery.param(e);return a.API_URL+o+t},g.changeRange=function(){if(g.range.fromDate>=g.range.toDate||g.range.isTime&&g.range.fromTime>=g.range.toTime)u.selectDevice.traffics=[];else if(g.range.fromDate>=g.range.minDate&&g.range.toDate<=g.range.maxDate&&g.range.toDate>=g.range.minDate&&g.range.fromDate<=g.range.maxDate){var e=g.getRange(),o=i.search();o.fromDate=e.fromDate.format("YYYY-MM-DD"),o.toDate=e.toDate.format("YYYY-MM-DD"),o.fromTime=e.isTime?e.fromTime.format("HH:mm"):null,o.toTime=e.isTime?e.toTime.format("HH:mm"):null,o.isTime=e.isTime?null:0,i.search(o),u.selectDevice&&u.$emit("infoLocation",{id:u.selectDevice.id,direction:u.selectDevice.direction})}else u.selectDevice.traffics=[]},g.changeDirection=function(){u.$emit("infoLocation",{id:u.selectDevice.id,direction:u.selectDevice.direction})},g.getRange=function(){return{fromDate:moment(g.range.fromDate).isValid()?moment(g.range.fromDate):moment().add(a.DEFAULT_RANGE_DATE_DAY.from,"d"),toDate:moment(g.range.toDate).isValid()?moment(g.range.toDate):moment().add(a.DEFAULT_RANGE_DATE_DAY.to,"d"),fromTime:moment(g.range.fromTime).isValid()?moment(g.range.fromTime):moment({hour:a.DEFAULT_RANGE_TIME_HOUR.from}),toTime:moment(g.range.toTime).isValid()?moment(g.range.toTime):moment({hour:a.DEFAULT_RANGE_TIME_HOUR.to}),isTime:!!g.range.isTime}},g.renderGraph=function(){for(var e,o=["rgba(158, 158, 158, #alpha)","rgba(213, 0, 0, #alpha)","rgba(0, 123, 255, #alpha)","rgba(170, 0, 255, #alpha)","rgba(0, 200, 83, #alpha)","rgba(255, 214, 0, #alpha)","rgba(255, 109, 0, #alpha)","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)"],t=jQuery.unique(u.selectDevice.traffics.map(function(e){return g.range.isTime?e.timeFrom:moment(e.date,"YYYY-MM-DD").format("D.M.YYYY")})),a=jQuery.unique(u.selectDevice.traffics.map(function(e){return e.typeVehicleId})),n=jQuery.grep(g.vehicles,function(e){return 0<=a.indexOf(e.id)}),i=[],r=[],l=0;e=n[l];l++){for(var c,s={label:e.name,backgroundColor:o[e.id].replace("#alpha","0.3"),borderColor:o[e.id].replace("#alpha","1"),borderWidth:2,data:[]},m={data:[],borderWidth:2,label:e.name,fill:!1,backgroundColor:o[e.id].replace("#alpha","0.3"),borderColor:o[e.id].replace("#alpha","1"),cubicInterpolationMode:"monotone",pointRadius:0},d=0,p=0;c=u.selectDevice.traffics[p];p++)(g.range.isTime&&t[d]!==c.timeFrom||!g.range.isTime&&t[d]!==moment(c.date,"YYYY-MM-DD").format("D.M.YYYY"))&&(d++,s.data.length<d&&(s.data.push(0),m.data.push(0))),c.typeVehicleId===e.id&&(s.data.push(g.range.isTime?c.numberVehicleAverage:c.numberVehicle),m.data.push(c.speedAverage<=0?0:c.speedAverage));i.push(s),r.push(m)}u.$emit("renderGraphNumberVehicles",{data:{labels:t,datasets:i}}),u.$emit("renderGraphAverageSpeed",{data:{labels:t,datasets:r}})},g.infoClose=function(){u.selectDevice=null;var e=i.search();e.deviceId=null,e.direction=null,i.search(e),u.$emit("setDefaultMap",null)}}]),angular.module("pvpk").controller("mainController",["$rootScope","$scope","$location","$window",function(n,i,r,e){this.$onInit=function(){i.showLoadingScreen=!0},e.onload=function(){var e=r.search();e.deviceId&&n.$emit("activeMarker",{id:e.deviceId}),i.$apply(function(){i.showLoadingScreen=!1})},n.$on("$locationChangeSuccess",function(e,o,t){var a=r.search();o!==t&&i.historyUrl?(i.historyUrl.q==i.historyUrl.q&&i.historyUrl.isDirection==a.isDirection||n.$emit("setSearchFromUrl",null),i.historyUrl.fromDate!==a.fromDate||i.historyUrl.toDate!==a.toDate||i.historyUrl.fromTime!==a.fromTime||i.historyUrl.toTime!==a.toTime?(n.$emit("setRangeFromUrl",null),a.deviceId&&n.$emit("infoLocation",{id:a.deviceId,direction:a.direction})):!a.deviceId||i.historyUrl.deviceId===a.deviceId&&i.historyUrl.direction===a.direction?!a.deviceId&&i.historyUrl.deviceId&&(n.selectDevice=null,n.$emit("setDefaultMap",null)):(n.$emit("infoLocation",{id:a.deviceId,direction:a.direction}),n.$emit("activeMarker",{id:a.deviceId}))):a.deviceId&&n.$emit("infoLocation",{id:a.deviceId,direction:a.direction}),i.historyUrl=r.search()}),n.handleErrorResponse=function(e){var o=jQuery("#modalError");switch(e.status){case 400:console.log("API ERROR 400"),i.modalError={title:"Neplatný požadavek",body:"Požadavek nemůže být vyřízen, poněvadž byl syntakticky nesprávně zapsán.",button:"OK"},o.modal("show");break;case 401:i.modalError={title:"Platnost webové aplikace vypršela",body:"Pro obnovení platnosti stačí stisknout tlačítko Obnovit.",button:"Obnovit",clickButton:i.reloadApp},o.modal({backdrop:"static",keyboard:!1});break;case 404:console.log("API ERROR 404"),i.modalError={title:"Nenalezen",body:"Záznam nebyl nalezen.",button:"OK"},o.modal("show");break;case 500:console.log("API ERROR 500"),i.modalError={title:"Chyba",body:"Chyba serveru. Zopakujte akci později.",button:"OK"},o.modal("show");break;case-1:console.log("API NOT CONNECTED"),i.modalError={title:"Připojení k internetu",body:"Nejste připojeni k internetu. Zkontrolujte připojení.",button:"OK"},o.modal("show");break;default:console.log("API UNKNOWN ERROR"),i.modalError={title:"Neočekávaná chyba",body:"Nastala neočekávaná chyba.",button:"OK"},o.modal("show")}},i.reloadApp=function(){e.location.reload()}}]),angular.module("pvpk").controller("mapController",["$rootScope","$scope","config","Device",function(t,n,a,e){this.$onInit=function(){n.markers=[],n.map=new google.maps.Map(document.getElementById("map"),{center:a.DEFAULT_POSITION,zoom:a.DEFAULT_ZOOM,minZoom:a.DEFAULT_ZOOM_MIN,zoomControl:!0,mapTypeControl:!1,scaleControl:!1,streetViewControl:!1,rotateControl:!1,fullscreenControl:!1,mapTypeId:google.maps.MapTypeId.ROADMAP}),e.query({showDirection:0},function(e){for(var o,t=0;o=e[t];t++)n.createMarker(o)},function(e){console.log("Error api all Devices"),t.handleErrorResponse(e)})},n.createMarker=function(e){if(e.lat&&e.lng){var o=new google.maps.Marker({map:n.map,position:{lat:e.lat,lng:e.lng},title:e.name,infoWindow:new google.maps.InfoWindow({content:'<h6 class="mb-1">'+e.name+"</h6><address>"+e.street+", "+e.town+"</address>"}),id:e.id});o.addListener("click",function(){n.closeInfoWindows(),o.infoWindow.open(n.map,o),t.$emit("infoLocation",{id:e.id})}),n.markers.push(o)}},t.$on("activeMarker",function(e,o){for(var t,a=0;t=n.markers[a];a++)t.id&&t.id===o.id&&t.infoWindow?(n.map.setCenter(t.getPosition()),n.map.setZoom(12),t.infoWindow.open(n.map,t)):t.infoWindow.close()}),t.$on("setDefaultMap",function(e,o){n.map.setCenter(a.DEFAULT_POSITION),n.map.setZoom(a.DEFAULT_ZOOM),n.closeInfoWindows()}),n.closeInfoWindows=function(){for(var e,o=0;e=n.markers[o];o++)e.infoWindow.close()}}]),angular.module("pvpk").controller("searchController",["$rootScope","$scope","$location","config","Device",function(t,a,n,e,o){this.$onInit=function(){a.config=e,a.locations=[],a.showSearchLoading=!1,t.$emit("setSearchFromUrl",null)},a.searchLocations=function(){var e=n.search();e.q=a.search.q,e.isDirection=a.search.isDirection?1:null,n.search(e),!a.search.q||a.search.q.length<=1?a.locations=[]:(a.showSearchLoading=!0,o.query({address:a.search.q,showDirection:a.search.isDirection?1:0},function(e){a.locations=e,a.showSearchLoading=!1},function(e){a.showSearchLoading=!1,console.log("Error api all Devices"),t.handleErrorResponse(e)}))},t.$on("setSearchFromUrl",function(e,o){var t=n.search();a.search={q:t.q,isDirection:!!t.isDirection&&!!+t.isDirection},a.searchLocations()}),a.selectDevice=function(e,o){t.$emit("activeMarker",{id:e}),t.$emit("infoLocation",{id:e,direction:o})}}]),angular.module("pvpk").component("graphAverageSpeed",{template:'<div><canvas id="graphAverageSpeed" class="graph-size mb-5"></canvas></div>',controller:["$rootScope","$scope",function(e,a){e.$on("renderGraphAverageSpeed",function(e,o){var t=document.getElementById("graphAverageSpeed").getContext("2d");a.graphLine&&a.graphLine.destroy(),a.graphLine=new Chart(t,{type:"line",data:o.data,options:{responsive:!0,pointDot:!1,legend:{position:"bottom"},scales:{xAxes:[{ticks:{autoSkip:!0,maxTicksLimit:15}}],yAxes:[{scaleLabel:{display:!0,labelString:"km/h"},ticks:{beginAtZero:!0,suggestedMax:70}}]},tooltips:{mode:"index",intersect:!1,callbacks:{label:function(e){return e.yLabel+" km/h"}}}}})})}]}),angular.module("pvpk").component("graphNumberVehicles",{template:'<div><canvas id="graphNumberVehicles" class="graph-size mb-5"></canvas></div>',controller:["$rootScope","$scope",function(e,a){e.$on("renderGraphNumberVehicles",function(e,o){var t=document.getElementById("graphNumberVehicles").getContext("2d");a.graphNumberVehicles&&a.graphNumberVehicles.destroy(),a.graphNumberVehicles=new Chart(t,{type:"bar",data:o.data,options:{responsive:!0,onResize:function(e,o){e.options.legend.display=240<o.height,e.update()},legend:{position:"bottom"},scales:{xAxes:[{stacked:!0,ticks:{autoSkip:!0,maxTicksLimit:15}}],yAxes:[{scaleLabel:{display:!0,labelString:"počet vozidel"},stacked:!0}]},tooltips:{mode:"index",intersect:!1}}})})}]});
2 2
//# sourceMappingURL=app.min.js.map
frontend/app.min.js.map
1
{"version":3,"sources":["app.module.js","app.config.js","infoController.js","mainController.js","mapController.js","searchController.js","graphAverageSpeed.js","graphNumberVehicles.js","DeviceService.js","VehicleService.js"],"names":["angular","module","constant","APP_NAME","APP_VERSION","API_URL","API_TOKEN","DEFAULT_POSITION","lat","lng","DEFAULT_ZOOM","DEFAULT_ZOOM_MIN","DEFAULT_RANGE_DATE_DAY","from","to","DEFAULT_RANGE_TIME_HOUR","controller","$rootScope","$scope","$location","config","Device","Vehicle","this","$onInit","selectDevice","showInfoLoading","vehicles","urlExportCsv","query","data","response","graphShow","console","log","handleErrorResponse","$emit","$on","event","args","params","search","range","fromDate","moment","isValid","toDate","add","fromTime","hour","toTime","isTime","deviceId","id","direction","getRange","period","dateFrom","format","dateTo","timeFrom","timeTo","get","renderGraph","generateUrlExportCsv","relativeUrl","replace","paramsUrl","jQuery","param","changeRange","traffics","vehicle","color","labels","unique","map","d","date","useVehiclesIds","typeVehicleId","filterVehicles","grep","n","indexOf","datasetsNumberVehicles","datasetsAverageSpeed","i","traffic","datasetNumberVehicles","label","name","backgroundColor","borderColor","borderWidth","datasetAverageSpeed","fill","cubicInterpolationMode","pointRadius","l","j","length","push","numberVehicleAverage","numberVehicle","speedAverage","datasets","infoClose","$window","showLoadingScreen","onload","$apply","newUrl","oldUrl","historyUrl","q","isDirection","modalError","status","title","body","button","modal","clickButton","reloadApp","backdrop","keyboard","location","reload","markers","google","maps","Map","document","getElementById","center","zoom","minZoom","zoomControl","mapTypeControl","scaleControl","streetViewControl","rotateControl","fullscreenControl","mapTypeId","MapTypeId","ROADMAP","showDirection","lctn","createMarker","marker","Marker","position","infoWindow","InfoWindow","content","street","town","addListener","closeInfoWindows","open","setCenter","getPosition","setZoom","close","locations","showSearchLoading","searchLocations","address","component","template","canvas","getContext","graphLine","destroy","Chart","type","options","responsive","pointDot","legend","scales","xAxes","ticks","autoSkip","maxTicksLimit","yAxes","scaleLabel","display","labelString","beginAtZero","suggestedMax","tooltips","mode","intersect","callbacks","tooltipItems","yLabel","canvasGraphNumberVehicles","graphNumberVehicles","onResize","chart","size","height","update","stacked","factory","$resource","url","method","headers","Content-Type","Accept","jwt","isArray"],"mappings":"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","file":"app.min.js","sourcesContent":["angular.module('pvpk', ['ngResource', 'ngSanitize']);","angular.module('pvpk')\r\n    .constant('config', {\r\n        APP_NAME: 'PVPK',\r\n        APP_VERSION: '1.3.0',\r\n        API_URL: API_URL,\r\n        API_TOKEN: API_TOKEN,\r\n        DEFAULT_POSITION: {lat: 49.53, lng: 13.3},\r\n        DEFAULT_ZOOM: 10,\r\n        DEFAULT_ZOOM_MIN: 7,\r\n        DEFAULT_RANGE_DATE_DAY: {from: -30, to: -1},\r\n        DEFAULT_RANGE_TIME_HOUR: {from: 7, to: 16}\r\n    });","angular.module('pvpk')\r\n    .controller('infoController', ['$rootScope', '$scope', '$location', 'config', 'Device', 'Vehicle', function ($rootScope, $scope, $location, config, Device, Vehicle) {\r\n\r\n        this.$onInit = function () {\r\n            $rootScope.selectDevice = null;\r\n            $scope.showInfoLoading = false;\r\n            $scope.vehicles = [];\r\n            $scope.urlExportCsv = null;\r\n\r\n            Vehicle.query(null, function (data) {\r\n                $scope.vehicles = data;\r\n            }, function (response) {\r\n                $rootScope.graphShow = false;\r\n                console.log('Error api all Vehicles');\r\n                $rootScope.handleErrorResponse(response);\r\n            });\r\n\r\n            $rootScope.$emit('setRangeFromUrl', null);\r\n        };\r\n\r\n        $rootScope.$on('setRangeFromUrl', function (event, args) {\r\n            var params = $location.search();\r\n            $scope.range = {\r\n                fromDate: moment(params.fromDate, 'YYYY-MM-DD').isValid() ? moment(params.fromDate).toDate() : moment().add(config.DEFAULT_RANGE_DATE_DAY.from, 'd').toDate(),\r\n                toDate: moment(params.toDate, 'YYYY-MM-DD').isValid() ? moment(params.toDate).toDate() : moment().add(config.DEFAULT_RANGE_DATE_DAY.to, 'd').toDate(),\r\n                fromTime: moment(params.fromTime, 'HH:mm').isValid() ? moment(params.fromTime, 'HH:mm').toDate() : moment({hour: config.DEFAULT_RANGE_TIME_HOUR.from}).toDate(),\r\n                toTime: moment(params.toTime, 'HH:mm').isValid() ? moment(params.toTime, 'HH:mm').toDate() : moment({hour: config.DEFAULT_RANGE_TIME_HOUR.to}).toDate(),\r\n                isTime: params.isTime == 0 ? false : true\r\n            };\r\n        });\r\n\r\n        $rootScope.$on('infoLocation', function (event, args) {\r\n            $scope.showInfoLoading = true;\r\n\r\n            var params = $location.search();\r\n            params.deviceId = args.id;\r\n            params.direction = args.direction;\r\n            $location.search(params);\r\n\r\n            var range = $scope.getRange();\r\n\r\n            var query = {\r\n                period: range.isTime ? 'time-period' : 'day-period',\r\n                id: args.id,\r\n                direction: args.direction,\r\n                dateFrom: range.fromDate.format('YYYY-MM-DD'),\r\n                dateTo: range.toDate.format('YYYY-MM-DD'),\r\n                timeFrom: range.isTime ? range.fromTime.format('HH:mm') : null,\r\n                timeTo: range.isTime ? range.toTime.format('HH:mm') : null\r\n            };\r\n\r\n            Device.get(query, function (data) {\r\n                $rootScope.selectDevice = data;\r\n                $scope.renderGraph();\r\n                $scope.urlExportCsv = $scope.generateUrlExportCsv(query);\r\n\r\n                $scope.showInfoLoading = false;\r\n            }, function (response) {\r\n                $rootScope.selectDevice = null;\r\n                $scope.showInfoLoading = false;\r\n                console.log('Error api get Devices');\r\n                $rootScope.handleErrorResponse(response);\r\n            });\r\n\r\n        });\r\n\r\n        $scope.generateUrlExportCsv = function (query) {\r\n            var relativeUrl = '/devices/:id/:period/csv?'.replace(':id', query.id).replace(':period', query.period);\r\n            delete query.id;\r\n            delete query.period;\r\n\r\n            var paramsUrl = jQuery.param(query);\r\n            return config.API_URL + relativeUrl + paramsUrl;\r\n        };\r\n\r\n        $scope.changeRange = function () {\r\n            if ($scope.range.fromDate >= $scope.range.toDate || ($scope.range.isTime && $scope.range.fromTime >= $scope.range.toTime)) {\r\n                $rootScope.selectDevice.traffics = [];\r\n                return;\r\n            }\r\n\r\n            var range = $scope.getRange();\r\n\r\n            var params = $location.search();\r\n            params.fromDate = range.fromDate.format('YYYY-MM-DD');\r\n            params.toDate = range.toDate.format('YYYY-MM-DD');\r\n            params.fromTime = range.isTime ? range.fromTime.format('HH:mm') : null;\r\n            params.toTime = range.isTime ? range.toTime.format('HH:mm') : null;\r\n            params.isTime = range.isTime ? null : 0;\r\n            $location.search(params);\r\n\r\n            if ($rootScope.selectDevice)\r\n                $rootScope.$emit('infoLocation', {\r\n                    id: $rootScope.selectDevice.id,\r\n                    direction: $rootScope.selectDevice.direction\r\n                });\r\n        };\r\n\r\n        $scope.getRange = function () {\r\n            return {\r\n                fromDate: moment($scope.range.fromDate).isValid() ? moment($scope.range.fromDate) : moment().add(config.DEFAULT_RANGE_DATE_DAY.from, 'd'),\r\n                toDate: moment($scope.range.toDate).isValid() ? moment($scope.range.toDate) : moment().add(config.DEFAULT_RANGE_DATE_DAY.to, 'd'),\r\n                fromTime: moment($scope.range.fromTime).isValid() ? moment($scope.range.fromTime) : moment({hour: config.DEFAULT_RANGE_TIME_HOUR.from}),\r\n                toTime: moment($scope.range.toTime).isValid() ? moment($scope.range.toTime) : moment({hour: config.DEFAULT_RANGE_TIME_HOUR.to}),\r\n                isTime: $scope.range.isTime ? true : false\r\n            };\r\n        };\r\n\r\n        $scope.renderGraph = function () {\r\n            var color = ['rgba(158, 158, 158, #alpha)', 'rgba(213, 0, 0, #alpha)', 'rgba(0, 123, 255, #alpha)', 'rgba(170, 0, 255, #alpha)',\r\n                'rgba(0, 200, 83, #alpha)', 'rgba(255, 214, 0, #alpha)', 'rgba(255, 109, 0, #alpha)',\r\n                '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)'];\r\n\r\n            var labels = jQuery.unique($rootScope.selectDevice.traffics.map(function (d) {\r\n                return $scope.range.isTime ? d.timeFrom : moment(d.date, 'YYYY-MM-DD').format('D.M.YYYY');\r\n            }));\r\n\r\n            var useVehiclesIds = jQuery.unique($rootScope.selectDevice.traffics.map(function (d) {\r\n                return d.typeVehicleId;\r\n            }));\r\n\r\n            var filterVehicles = jQuery.grep($scope.vehicles, function (n) {\r\n                return useVehiclesIds.indexOf(n.id) >= 0;\r\n            });\r\n\r\n            var datasetsNumberVehicles = [];\r\n            var datasetsAverageSpeed = [];\r\n\r\n            for (var i = 0, vehicle; vehicle = filterVehicles[i]; i++) {\r\n                var datasetNumberVehicles = {\r\n                    label: vehicle.name,\r\n                    backgroundColor: color[vehicle.id].replace(\"#alpha\", \"0.3\"),\r\n                    borderColor: color[vehicle.id].replace(\"#alpha\", \"1\"),\r\n                    borderWidth: 2,\r\n                    data: []\r\n                };\r\n\r\n                var datasetAverageSpeed = {\r\n                    data: [],\r\n                    borderWidth: 2,\r\n                    label: vehicle.name,\r\n                    fill: false,\r\n                    //fill: 'start',\r\n                    backgroundColor: color[vehicle.id].replace(\"#alpha\", \"0.3\"),\r\n                    borderColor: color[vehicle.id].replace(\"#alpha\", \"1\"),\r\n                    cubicInterpolationMode: 'monotone',\r\n                    pointRadius: 0\r\n                };\r\n\r\n                var l = 0;\r\n                for (var j = 0, traffic; traffic = $rootScope.selectDevice.traffics[j]; j++) {\r\n                    if (($scope.range.isTime && labels[l] !== traffic.timeFrom) || (!$scope.range.isTime && labels[l] !== moment(traffic.date, 'YYYY-MM-DD').format('D.M.YYYY'))) {\r\n                        l++;\r\n                        if (datasetNumberVehicles.data.length < l) {\r\n                            datasetNumberVehicles.data.push(0);\r\n                            datasetAverageSpeed.data.push(null);\r\n                        }\r\n                    }\r\n                    if (traffic.typeVehicleId === vehicle.id) {\r\n                        datasetNumberVehicles.data.push($scope.range.isTime ? traffic.numberVehicleAverage : traffic.numberVehicle);\r\n                        datasetAverageSpeed.data.push(traffic.speedAverage <= 0 ? null : traffic.speedAverage);\r\n                    }\r\n                }\r\n                datasetsNumberVehicles.push(datasetNumberVehicles);\r\n                datasetsAverageSpeed.push(datasetAverageSpeed);\r\n            }\r\n\r\n            $rootScope.$emit('renderGraphNumberVehicles', {\r\n                data: {\r\n                    labels: labels,\r\n                    datasets: datasetsNumberVehicles\r\n                }\r\n            });\r\n\r\n            $rootScope.$emit('renderGraphAverageSpeed', {\r\n                data: {\r\n                    labels: labels,\r\n                    datasets: datasetsAverageSpeed\r\n                }\r\n            });\r\n        };\r\n\r\n        $scope.infoClose = function () {\r\n            $rootScope.selectDevice = null;\r\n\r\n            var params = $location.search();\r\n            params.deviceId = null;\r\n            params.direction = null;\r\n            $location.search(params);\r\n\r\n            $rootScope.$emit('setDefaultMap', null);\r\n        };\r\n    }]);\r\n","angular.module('pvpk')\r\n    .controller('mainController', ['$rootScope', '$scope', '$location', '$window', function ($rootScope, $scope, $location, $window) {\r\n\r\n        this.$onInit = function () {\r\n            $scope.showLoadingScreen = true;\r\n        };\r\n\r\n        $window.onload = function () {\r\n            var params = $location.search();\r\n            if (params.deviceId) {\r\n                $rootScope.$emit('activeMarker', {id: params.deviceId});\r\n            }\r\n\r\n            $scope.$apply(function () {\r\n                $scope.showLoadingScreen = false;\r\n            });\r\n        };\r\n\r\n        $rootScope.$on('$locationChangeSuccess', function (event, newUrl, oldUrl) {\r\n            var params = $location.search();\r\n\r\n            if (newUrl !== oldUrl && $scope.historyUrl) {\r\n                if ($scope.historyUrl.q !== $scope.historyUrl.q || $scope.historyUrl.isDirection != params.isDirection) {\r\n                    $rootScope.$emit('setSearchFromUrl', null);\r\n                }\r\n\r\n                if ($scope.historyUrl.fromDate !== params.fromDate || $scope.historyUrl.toDate !== params.toDate ||\r\n                    $scope.historyUrl.fromTime !== params.fromTime || $scope.historyUrl.toTime !== params.toTime) {\r\n                    $rootScope.$emit('setRangeFromUrl', null);\r\n                    if (params.deviceId) {\r\n                        $rootScope.$emit('infoLocation', {id: params.deviceId, direction: params.direction});\r\n                    }\r\n                } else if (params.deviceId && ($scope.historyUrl.deviceId !== params.deviceId || $scope.historyUrl.direction !== params.direction)) {\r\n                    $rootScope.$emit('infoLocation', {id: params.deviceId, direction: params.direction});\r\n                    $rootScope.$emit('activeMarker', {id: params.deviceId});\r\n                } else if (!params.deviceId && $scope.historyUrl.deviceId) {\r\n                    $rootScope.selectDevice = null;\r\n                    $rootScope.$emit('setDefaultMap', null);\r\n                }\r\n            } else if (params.deviceId) {\r\n                $rootScope.$emit('infoLocation', {id: params.deviceId, direction: params.direction});\r\n            }\r\n\r\n            $scope.historyUrl = $location.search();\r\n        });\r\n\r\n        $rootScope.handleErrorResponse = function (response) {\r\n\r\n            var modalError = jQuery('#modalError');\r\n            switch (response.status) {\r\n                case 400:\r\n                    console.log('API ERROR 400');\r\n                    $scope.modalError = {\r\n                        title: 'Neplatný požadavek',\r\n                        body: 'Požadavek nemůže být vyřízen, poněvadž byl syntakticky nesprávně zapsán.',\r\n                        button: 'OK'\r\n                    };\r\n                    modalError.modal('show');\r\n                    break;\r\n                case 401:\r\n                    $scope.modalError = {\r\n                        title: 'Platnost webové aplikace vypršela',\r\n                        body: 'Pro obnovení platnosti stačí stisknout tlačítko <strong>Obnovit</strong>.',\r\n                        button: 'Obnovit',\r\n                        clickButton: $scope.reloadApp\r\n                    };\r\n                    modalError.modal({backdrop: 'static', keyboard: false});\r\n                    break;\r\n                case 404:\r\n                    console.log('API ERROR 404');\r\n                    $scope.modalError = {title: 'Nenalezen', body: 'Záznam nebyl nalezen.', button: 'OK'};\r\n                    modalError.modal('show');\r\n                    break;\r\n                case 500:\r\n                    console.log('API ERROR 500');\r\n                    $scope.modalError = {title: 'Chyba', body: 'Chyba serveru. Zopakujte akci později.', button: 'OK'};\r\n                    modalError.modal('show');\r\n                    break;\r\n                case -1:\r\n                    console.log('API NOT CONNECTED');\r\n                    $scope.modalError = {\r\n                        title: 'Připojení k internetu',\r\n                        body: 'Nejste připojeni k internetu. Zkontrolujte připojení.',\r\n                        button: 'OK'\r\n                    };\r\n                    modalError.modal('show');\r\n                    break;\r\n                default:\r\n                    console.log('API UNKNOWN ERROR');\r\n                    $scope.modalError = {title: 'Neočekávaná chyba', body: 'Nastala neočekávaná chyba.', button: 'OK'};\r\n                    modalError.modal('show');\r\n                    break;\r\n            }\r\n        };\r\n\r\n        $scope.reloadApp = function () {\r\n            $window.location.reload();\r\n        }\r\n    }]);","angular.module('pvpk')\r\n    .controller('mapController', ['$rootScope', '$scope', 'config', 'Device', function ($rootScope, $scope, config, Device) {\r\n\r\n        this.$onInit = function () {\r\n            $scope.markers = [];\r\n\r\n            $scope.map = new google.maps.Map(document.getElementById('map'), {\r\n                center: config.DEFAULT_POSITION,\r\n                zoom: config.DEFAULT_ZOOM,\r\n                minZoom: config.DEFAULT_ZOOM_MIN,\r\n                zoomControl: true,\r\n                mapTypeControl: false,\r\n                scaleControl: false,\r\n                streetViewControl: false,\r\n                rotateControl: false,\r\n                fullscreenControl: false,\r\n                mapTypeId: google.maps.MapTypeId.ROADMAP\r\n            });\r\n\r\n            Device.query({showDirection: 0}, function (data) {\r\n                for (var i = 0, lctn; lctn = data[i]; i++) {\r\n                    $scope.createMarker(lctn);\r\n                }\r\n            }, function (response) {\r\n                console.log('Error api all Devices');\r\n                $rootScope.handleErrorResponse(response);\r\n            });\r\n        };\r\n\r\n        $scope.createMarker = function (lctn) {\r\n            if (lctn.lat && lctn.lng) {\r\n                var marker = new google.maps.Marker({\r\n                    map: $scope.map,\r\n                    position: {lat: lctn.lat, lng: lctn.lng},\r\n                    title: lctn.name,\r\n                    infoWindow: new google.maps.InfoWindow({\r\n                        content: '<h6 class=\"mb-1\">' + lctn.name + '</h6>'\r\n                        + '<address>' + lctn.street + ', ' + lctn.town + '</address>'\r\n                    }),\r\n                    id: lctn.id\r\n                });\r\n\r\n                marker.addListener('click', function () {\r\n                    $scope.closeInfoWindows();\r\n                    marker.infoWindow.open($scope.map, marker);\r\n                    $rootScope.$emit('infoLocation', {id: lctn.id});\r\n                });\r\n\r\n                $scope.markers.push(marker);\r\n            }\r\n        };\r\n\r\n        $rootScope.$on('activeMarker', function (event, args) {\r\n            for (var i = 0, marker; marker = $scope.markers[i]; i++) {\r\n                if (marker.id && marker.id === args.id && marker.infoWindow) {\r\n                    $scope.map.setCenter(marker.getPosition());\r\n                    $scope.map.setZoom(12);\r\n                    marker.infoWindow.open($scope.map, marker);\r\n                } else {\r\n                    marker.infoWindow.close();\r\n                }\r\n            }\r\n        });\r\n\r\n        $rootScope.$on('setDefaultMap', function (event, args) {\r\n            $scope.map.setCenter(config.DEFAULT_POSITION);\r\n            $scope.map.setZoom(config.DEFAULT_ZOOM);\r\n            $scope.closeInfoWindows();\r\n        });\r\n\r\n        $scope.closeInfoWindows = function () {\r\n            for (var i = 0, marker; marker = $scope.markers[i]; i++) {\r\n                marker.infoWindow.close();\r\n            }\r\n        };\r\n    }]);","angular.module('pvpk')\r\n    .controller('searchController', ['$rootScope', '$scope', '$location', 'config', 'Device', function ($rootScope, $scope, $location, config, Device) {\r\n\r\n        this.$onInit = function () {\r\n            $scope.config = config;\r\n            $scope.locations = [];\r\n            $scope.showSearchLoading = false;\r\n\r\n            $rootScope.$emit('setSearchFromUrl', null);\r\n        };\r\n\r\n        $scope.searchLocations = function () {\r\n            var params = $location.search();\r\n            params.q = $scope.search.q;\r\n            params.isDirection = $scope.search.isDirection ? 1 : null;\r\n            $location.search(params);\r\n\r\n            if (!$scope.search.q || $scope.search.q.length <= 1) {\r\n                $scope.locations = [];\r\n                return;\r\n            }\r\n\r\n            $scope.showSearchLoading = true;\r\n\r\n            Device.query({\r\n                address: $scope.search.q,\r\n                showDirection: $scope.search.isDirection ? 1 : 0\r\n            }, function (data) {\r\n                $scope.locations = data;\r\n                $scope.showSearchLoading = false;\r\n            }, function (response) {\r\n                $scope.showSearchLoading = false;\r\n                console.log('Error api all Devices');\r\n                $rootScope.handleErrorResponse(response);\r\n            });\r\n        };\r\n\r\n        $rootScope.$on('setSearchFromUrl', function (event, args) {\r\n            var params = $location.search();\r\n            $scope.search = {\r\n                q: params.q,\r\n                isDirection: params.isDirection ? !!+params.isDirection : false\r\n            };\r\n            $scope.searchLocations();\r\n        });\r\n\r\n        $scope.selectDevice = function (id, direction) {\r\n            $rootScope.$emit('activeMarker', {id: id});\r\n            $rootScope.$emit('infoLocation', {id: id, direction: direction});\r\n        };\r\n\r\n    }]);","angular.module('pvpk')\r\n    .component('graphAverageSpeed', {\r\n        template: '<div><canvas id=\"graphAverageSpeed\" class=\"graphSize mb-5\"></canvas></div>',\r\n        controller: ['$rootScope', '$scope', function ($rootScope, $scope) {\r\n\r\n            $rootScope.$on('renderGraphAverageSpeed', function (event, args) {\r\n                var canvas = document.getElementById('graphAverageSpeed').getContext('2d');\r\n\r\n                if ($scope.graphLine)\r\n                    $scope.graphLine.destroy();\r\n\r\n                $scope.graphLine = new Chart(canvas, {\r\n                    type: 'line',\r\n                    data: args.data,\r\n                    options: {\r\n                        responsive: true,\r\n                        pointDot: false,\r\n                        legend: {\r\n                            position: 'bottom'\r\n                        },\r\n                        scales: {\r\n                            xAxes: [{\r\n                                ticks: {\r\n                                    autoSkip: true,\r\n                                    maxTicksLimit: 15\r\n                                }\r\n                            }],\r\n                            yAxes: [{\r\n                                scaleLabel: {\r\n                                    display: true,\r\n                                    labelString: 'km/h'\r\n                                },\r\n                                ticks: {\r\n                                    beginAtZero: true,\r\n                                    suggestedMax: 70\r\n                                }\r\n                            }]\r\n                        },\r\n                        tooltips: {\r\n                            mode: 'index',\r\n                            intersect: false,\r\n                            callbacks: {\r\n                                label: function (tooltipItems) {\r\n                                    return tooltipItems.yLabel + ' km/h';\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                });\r\n\r\n            });\r\n\r\n        }]\r\n    });","angular.module('pvpk')\r\n    .component('graphNumberVehicles', {\r\n        template: '<div><canvas id=\"graphNumberVehicles\" class=\"graphSize mb-5\"></canvas></div>',\r\n        controller: ['$rootScope', '$scope', function ($rootScope, $scope) {\r\n\r\n            $rootScope.$on('renderGraphNumberVehicles', function (event, args) {\r\n                var canvasGraphNumberVehicles = document.getElementById('graphNumberVehicles').getContext('2d');\r\n\r\n                if ($scope.graphNumberVehicles)\r\n                    $scope.graphNumberVehicles.destroy();\r\n\r\n                $scope.graphNumberVehicles = new Chart(canvasGraphNumberVehicles, {\r\n                    type: 'bar',\r\n                    data: args.data,\r\n                    options: {\r\n                        responsive: true,\r\n                        onResize: function (chart, size) {\r\n                            chart.options.legend.display = size.height > 240;\r\n                            chart.update();\r\n                        },\r\n                        legend: {\r\n                            position: 'bottom'\r\n                        },\r\n                        scales: {\r\n                            xAxes: [{\r\n                                stacked: true,\r\n                                ticks: {\r\n                                    autoSkip: true,\r\n                                    maxTicksLimit: 15\r\n                                }\r\n                            }],\r\n                            yAxes: [{\r\n                                scaleLabel: {\r\n                                    display: true,\r\n                                    labelString: \"počet vozidel\"\r\n                                },\r\n                                stacked: true\r\n                            }]\r\n                        },\r\n                        tooltips: {\r\n                            mode: 'index',\r\n                            intersect: false\r\n                        }\r\n                    }\r\n                });\r\n\r\n            });\r\n\r\n        }]\r\n    });","angular.module('pvpk')\r\n    .factory('Device', ['$resource', 'config', function ($resource, config) {\r\n        return $resource(config.API_URL + '/devices/:id', {id: '@id', period: '@period'}, {\r\n            'get': {\r\n                url: config.API_URL + '/devices/:id/:period',\r\n                method: 'GET',\r\n                headers: {\r\n                    'Content-Type': 'application/json',\r\n                    'Accept': 'application/json',\r\n                    'jwt': config.API_TOKEN\r\n                }\r\n            },\r\n            'query': {\r\n                url: config.API_URL + '/devices',\r\n                method: 'GET',\r\n                isArray: true,\r\n                headers: {\r\n                    'Content-Type': 'application/json',\r\n                    'Accept': 'application/json',\r\n                    'jwt': config.API_TOKEN\r\n                }\r\n            }\r\n        });\r\n    }]);","angular.module('pvpk')\r\n    .factory('Vehicle', ['$resource', 'config', function ($resource, config) {\r\n        return $resource(config.API_URL + '/vehicles', null, {\r\n            'query': {\r\n                url: config.API_URL + '/vehicles',\r\n                method: 'GET',\r\n                isArray: true,\r\n                headers: {\r\n                    'Content-Type': 'application/json',\r\n                    'Accept': 'application/json',\r\n                    'jwt': config.API_TOKEN\r\n                }\r\n            }\r\n        });\r\n    }]);"]}
1
{"version":3,"sources":["app.module.js","app.config.js","DeviceService.js","RangeService.js","VehicleService.js","infoController.js","mainController.js","mapController.js","searchController.js","graphAverageSpeed.js","graphNumberVehicles.js"],"names":["angular","module","constant","APP_NAME","APP_VERSION","API_URL","API_TOKEN","DEFAULT_POSITION","lat","lng","DEFAULT_ZOOM","DEFAULT_ZOOM_MIN","DEFAULT_RANGE_DATE_DAY","from","to","DEFAULT_RANGE_TIME_HOUR","factory","$resource","config","id","period","get","url","method","headers","Content-Type","Accept","jwt","query","isArray","controller","$rootScope","$scope","$location","Device","Vehicle","Range","this","$onInit","selectDevice","showInfoLoading","vehicles","urlExportCsv","directions","undefined","name","isLoadRange","data","response","graphShow","console","log","handleErrorResponse","$emit","$on","event","args","params","search","range","fromDate","moment","isValid","toDate","add","fromTime","hour","toTime","isTime","maxDate","minDate","max","last_date","first_date","min","deviceId","direction","getRange","dateFrom","format","dateTo","timeFrom","timeTo","renderGraph","generateUrlExportCsv","relativeUrl","replace","paramsUrl","jQuery","param","changeRange","traffics","changeDirection","vehicle","color","labels","unique","map","d","date","useVehiclesIds","typeVehicleId","filterVehicles","grep","n","indexOf","datasetsNumberVehicles","datasetsAverageSpeed","i","traffic","datasetNumberVehicles","label","backgroundColor","borderColor","borderWidth","datasetAverageSpeed","fill","cubicInterpolationMode","pointRadius","l","j","length","push","numberVehicleAverage","numberVehicle","speedAverage","datasets","infoClose","$window","showLoadingScreen","onload","$apply","newUrl","oldUrl","historyUrl","q","isDirection","modalError","status","title","body","button","modal","clickButton","reloadApp","backdrop","keyboard","location","reload","markers","google","maps","Map","document","getElementById","center","zoom","minZoom","zoomControl","mapTypeControl","scaleControl","streetViewControl","rotateControl","fullscreenControl","mapTypeId","MapTypeId","ROADMAP","showDirection","lctn","createMarker","marker","Marker","position","infoWindow","InfoWindow","content","street","town","addListener","closeInfoWindows","open","setCenter","getPosition","setZoom","close","locations","showSearchLoading","searchLocations","address","component","template","canvas","getContext","graphLine","destroy","Chart","type","options","responsive","pointDot","legend","scales","xAxes","ticks","autoSkip","maxTicksLimit","yAxes","scaleLabel","display","labelString","beginAtZero","suggestedMax","tooltips","mode","intersect","callbacks","tooltipItems","yLabel","canvasGraphNumberVehicles","graphNumberVehicles","onResize","chart","size","height","update","stacked"],"mappings":"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","file":"app.min.js","sourcesContent":["angular.module('pvpk', ['ngResource']);","angular.module('pvpk')\r\n    .constant('config', {\r\n        APP_NAME: 'PVPK',\r\n        APP_VERSION: '1.3.3',\r\n        API_URL: API_URL,\r\n        API_TOKEN: API_TOKEN,\r\n        DEFAULT_POSITION: {lat: 49.53, lng: 13.3},\r\n        DEFAULT_ZOOM: 10,\r\n        DEFAULT_ZOOM_MIN: 7,\r\n        DEFAULT_RANGE_DATE_DAY: {from: -30, to: -1},\r\n        DEFAULT_RANGE_TIME_HOUR: {from: 7, to: 16}\r\n    });","angular.module('pvpk')\r\n    .factory('Device', ['$resource', 'config', function ($resource, config) {\r\n        return $resource(config.API_URL + '/devices/:id', {id: '@id', period: '@period'}, {\r\n            'get': {\r\n                url: config.API_URL + '/devices/:id/:period',\r\n                method: 'GET',\r\n                headers: {\r\n                    'Content-Type': 'application/json',\r\n                    'Accept': 'application/json',\r\n                    'jwt': config.API_TOKEN\r\n                }\r\n            },\r\n            'query': {\r\n                url: config.API_URL + '/devices',\r\n                method: 'GET',\r\n                isArray: true,\r\n                headers: {\r\n                    'Content-Type': 'application/json',\r\n                    'Accept': 'application/json',\r\n                    'jwt': config.API_TOKEN\r\n                }\r\n            }\r\n        });\r\n    }]);","angular.module('pvpk')\r\n    .factory('Range', ['$resource', 'config', function ($resource, config) {\r\n        return $resource(config.API_URL + '/range', null, {\r\n            'get': {\r\n                url: config.API_URL + '/range',\r\n                method: 'GET',\r\n                headers: {\r\n                    'Content-Type': 'application/json',\r\n                    'Accept': 'application/json',\r\n                    'jwt': config.API_TOKEN\r\n                }\r\n            }\r\n        });\r\n    }]);","angular.module('pvpk')\r\n    .factory('Vehicle', ['$resource', 'config', function ($resource, config) {\r\n        return $resource(config.API_URL + '/vehicles', null, {\r\n            'query': {\r\n                url: config.API_URL + '/vehicles',\r\n                method: 'GET',\r\n                isArray: true,\r\n                headers: {\r\n                    'Content-Type': 'application/json',\r\n                    'Accept': 'application/json',\r\n                    'jwt': config.API_TOKEN\r\n                }\r\n            }\r\n        });\r\n    }]);","angular.module('pvpk')\r\n    .controller('infoController', ['$rootScope', '$scope', '$location', 'config', 'Device', 'Vehicle', 'Range', function ($rootScope, $scope, $location, config, Device, Vehicle, Range) {\r\n\r\n        this.$onInit = function () {\r\n            $rootScope.selectDevice = null;\r\n            $scope.showInfoLoading = false;\r\n            $scope.vehicles = [];\r\n            $scope.urlExportCsv = null;\r\n            $scope.directions = [\r\n                {id: undefined, name: 'po směru i proti směru'},\r\n                {id: 1, name: 'po směru'},\r\n                {id: 2, name: 'proti směru'}];\r\n            $scope.isLoadRange = false;\r\n\r\n            Vehicle.query(null, function (data) {\r\n                $scope.vehicles = data;\r\n            }, function (response) {\r\n                $rootScope.graphShow = false;\r\n                console.log('Error api all Vehicles');\r\n                $rootScope.handleErrorResponse(response);\r\n            });\r\n\r\n            $rootScope.$emit('setRangeFromUrl', null);\r\n        };\r\n\r\n        $rootScope.$on('setRangeFromUrl', function (event, args) {\r\n            var params = $location.search();\r\n\r\n            $scope.range = {\r\n                fromDate: moment(params.fromDate, 'YYYY-MM-DD').isValid() ? moment(params.fromDate).toDate() : moment().add(config.DEFAULT_RANGE_DATE_DAY.from, 'd').toDate(),\r\n                toDate: moment(params.toDate, 'YYYY-MM-DD').isValid() ? moment(params.toDate).toDate() : moment().add(config.DEFAULT_RANGE_DATE_DAY.to, 'd').toDate(),\r\n                fromTime: moment(params.fromTime, 'HH:mm').isValid() ? moment(params.fromTime, 'HH:mm').toDate() : moment({hour: config.DEFAULT_RANGE_TIME_HOUR.from}).toDate(),\r\n                toTime: moment(params.toTime, 'HH:mm').isValid() ? moment(params.toTime, 'HH:mm').toDate() : moment({hour: config.DEFAULT_RANGE_TIME_HOUR.to}).toDate(),\r\n                isTime: params.isTime == 0 ? false : true,\r\n                maxDate: $scope.range == null ? null : $scope.range.maxDate,\r\n                minDate: $scope.range == null ? null : $scope.range.minDate\r\n            };\r\n\r\n            if (!$scope.isLoadRange) {\r\n                Range.get(null, function (data) {\r\n                    $scope.range.fromDate = moment.max(moment(data.last_date).add(config.DEFAULT_RANGE_DATE_DAY.from, 'd'), moment(data.first_date)).toDate();\r\n                    $scope.range.toDate = moment.min(moment($scope.range.toDate), moment(data.last_date)).toDate();\r\n                    $scope.range.maxDate = moment(data.last_date).toDate();\r\n                    $scope.range.minDate = moment(data.first_date).toDate();\r\n                    $scope.isLoadRange = true;\r\n                }, function (response) {\r\n                    console.log('Error api get Range');\r\n                    $rootScope.handleErrorResponse(response);\r\n                });\r\n            }\r\n        });\r\n\r\n        $rootScope.$on('infoLocation', function (event, args) {\r\n            $scope.showInfoLoading = true;\r\n\r\n            var params = $location.search();\r\n            params.deviceId = args.id;\r\n            params.direction = args.direction;\r\n            $location.search(params);\r\n\r\n            var range = $scope.getRange();\r\n\r\n            var query = {\r\n                period: range.isTime ? 'time-period' : 'day-period',\r\n                id: args.id,\r\n                direction: args.direction,\r\n                dateFrom: range.fromDate.format('YYYY-MM-DD'),\r\n                dateTo: range.toDate.format('YYYY-MM-DD'),\r\n                timeFrom: range.isTime ? range.fromTime.format('HH:mm') : null,\r\n                timeTo: range.isTime ? range.toTime.format('HH:mm') : null\r\n            };\r\n\r\n            Device.get(query, function (data) {\r\n                $rootScope.selectDevice = data;\r\n                $scope.renderGraph();\r\n                $scope.urlExportCsv = $scope.generateUrlExportCsv(query);\r\n\r\n                $scope.showInfoLoading = false;\r\n            }, function (response) {\r\n                $rootScope.selectDevice = null;\r\n                $scope.showInfoLoading = false;\r\n                console.log('Error api get Devices');\r\n                $rootScope.handleErrorResponse(response);\r\n            });\r\n\r\n        });\r\n\r\n        $scope.generateUrlExportCsv = function (query) {\r\n            var relativeUrl = '/devices/:id/:period/csv?'.replace(':id', query.id).replace(':period', query.period);\r\n            delete query.id;\r\n            delete query.period;\r\n\r\n            var paramsUrl = jQuery.param(query);\r\n            return config.API_URL + relativeUrl + paramsUrl;\r\n        };\r\n\r\n        $scope.changeRange = function () {\r\n            if ($scope.range.fromDate >= $scope.range.toDate || ($scope.range.isTime && $scope.range.fromTime >= $scope.range.toTime)) {\r\n                $rootScope.selectDevice.traffics = [];\r\n                return;\r\n            }\r\n\r\n            if (!($scope.range.fromDate >= $scope.range.minDate && $scope.range.toDate <= $scope.range.maxDate\r\n                && $scope.range.toDate >= $scope.range.minDate && $scope.range.fromDate <= $scope.range.maxDate)) {\r\n                $rootScope.selectDevice.traffics = [];\r\n                return;\r\n            }\r\n\r\n\r\n            var range = $scope.getRange();\r\n\r\n            var params = $location.search();\r\n            params.fromDate = range.fromDate.format('YYYY-MM-DD');\r\n            params.toDate = range.toDate.format('YYYY-MM-DD');\r\n            params.fromTime = range.isTime ? range.fromTime.format('HH:mm') : null;\r\n            params.toTime = range.isTime ? range.toTime.format('HH:mm') : null;\r\n            params.isTime = range.isTime ? null : 0;\r\n            $location.search(params);\r\n\r\n            if ($rootScope.selectDevice)\r\n                $rootScope.$emit('infoLocation', {\r\n                    id: $rootScope.selectDevice.id,\r\n                    direction: $rootScope.selectDevice.direction\r\n                });\r\n        };\r\n\r\n        $scope.changeDirection = function () {\r\n\r\n            $rootScope.$emit('infoLocation', {\r\n                id: $rootScope.selectDevice.id,\r\n                direction: $rootScope.selectDevice.direction\r\n            });\r\n        };\r\n\r\n        $scope.getRange = function () {\r\n            return {\r\n                fromDate: moment($scope.range.fromDate).isValid() ? moment($scope.range.fromDate) : moment().add(config.DEFAULT_RANGE_DATE_DAY.from, 'd'),\r\n                toDate: moment($scope.range.toDate).isValid() ? moment($scope.range.toDate) : moment().add(config.DEFAULT_RANGE_DATE_DAY.to, 'd'),\r\n                fromTime: moment($scope.range.fromTime).isValid() ? moment($scope.range.fromTime) : moment({hour: config.DEFAULT_RANGE_TIME_HOUR.from}),\r\n                toTime: moment($scope.range.toTime).isValid() ? moment($scope.range.toTime) : moment({hour: config.DEFAULT_RANGE_TIME_HOUR.to}),\r\n                isTime: $scope.range.isTime ? true : false\r\n            };\r\n        };\r\n\r\n        $scope.renderGraph = function () {\r\n            var color = ['rgba(158, 158, 158, #alpha)', 'rgba(213, 0, 0, #alpha)', 'rgba(0, 123, 255, #alpha)', 'rgba(170, 0, 255, #alpha)',\r\n                'rgba(0, 200, 83, #alpha)', 'rgba(255, 214, 0, #alpha)', 'rgba(255, 109, 0, #alpha)',\r\n                '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)'];\r\n\r\n            var labels = jQuery.unique($rootScope.selectDevice.traffics.map(function (d) {\r\n                return $scope.range.isTime ? d.timeFrom : moment(d.date, 'YYYY-MM-DD').format('D.M.YYYY');\r\n            }));\r\n\r\n            var useVehiclesIds = jQuery.unique($rootScope.selectDevice.traffics.map(function (d) {\r\n                return d.typeVehicleId;\r\n            }));\r\n\r\n            var filterVehicles = jQuery.grep($scope.vehicles, function (n) {\r\n                return useVehiclesIds.indexOf(n.id) >= 0;\r\n            });\r\n\r\n            var datasetsNumberVehicles = [];\r\n            var datasetsAverageSpeed = [];\r\n\r\n            for (var i = 0, vehicle; vehicle = filterVehicles[i]; i++) {\r\n                var datasetNumberVehicles = {\r\n                    label: vehicle.name,\r\n                    backgroundColor: color[vehicle.id].replace(\"#alpha\", \"0.3\"),\r\n                    borderColor: color[vehicle.id].replace(\"#alpha\", \"1\"),\r\n                    borderWidth: 2,\r\n                    data: []\r\n                };\r\n\r\n                var datasetAverageSpeed = {\r\n                    data: [],\r\n                    borderWidth: 2,\r\n                    label: vehicle.name,\r\n                    fill: false,\r\n                    backgroundColor: color[vehicle.id].replace(\"#alpha\", \"0.3\"),\r\n                    borderColor: color[vehicle.id].replace(\"#alpha\", \"1\"),\r\n                    cubicInterpolationMode: 'monotone',\r\n                    pointRadius: 0\r\n                };\r\n\r\n                var l = 0;\r\n                for (var j = 0, traffic; traffic = $rootScope.selectDevice.traffics[j]; j++) {\r\n                    if (($scope.range.isTime && labels[l] !== traffic.timeFrom) || (!$scope.range.isTime && labels[l] !== moment(traffic.date, 'YYYY-MM-DD').format('D.M.YYYY'))) {\r\n                        l++;\r\n                        if (datasetNumberVehicles.data.length < l) {\r\n                            datasetNumberVehicles.data.push(0);\r\n                            datasetAverageSpeed.data.push(0);\r\n                        }\r\n                    }\r\n                    if (traffic.typeVehicleId === vehicle.id) {\r\n                        datasetNumberVehicles.data.push($scope.range.isTime ? traffic.numberVehicleAverage : traffic.numberVehicle);\r\n                        datasetAverageSpeed.data.push(traffic.speedAverage <= 0 ? 0 : traffic.speedAverage);\r\n                    }\r\n                }\r\n                datasetsNumberVehicles.push(datasetNumberVehicles);\r\n                datasetsAverageSpeed.push(datasetAverageSpeed);\r\n            }\r\n\r\n            $rootScope.$emit('renderGraphNumberVehicles', {\r\n                data: {\r\n                    labels: labels,\r\n                    datasets: datasetsNumberVehicles\r\n                }\r\n            });\r\n\r\n            $rootScope.$emit('renderGraphAverageSpeed', {\r\n                data: {\r\n                    labels: labels,\r\n                    datasets: datasetsAverageSpeed\r\n                }\r\n            });\r\n        };\r\n\r\n        $scope.infoClose = function () {\r\n            $rootScope.selectDevice = null;\r\n\r\n            var params = $location.search();\r\n            params.deviceId = null;\r\n            params.direction = null;\r\n            $location.search(params);\r\n\r\n            $rootScope.$emit('setDefaultMap', null);\r\n        };\r\n    }]);\r\n","angular.module('pvpk')\r\n    .controller('mainController', ['$rootScope', '$scope', '$location', '$window', function ($rootScope, $scope, $location, $window) {\r\n\r\n        this.$onInit = function () {\r\n            $scope.showLoadingScreen = true;\r\n        };\r\n\r\n        $window.onload = function () {\r\n            var params = $location.search();\r\n            if (params.deviceId) {\r\n                $rootScope.$emit('activeMarker', {id: params.deviceId});\r\n            }\r\n\r\n            $scope.$apply(function () {\r\n                $scope.showLoadingScreen = false;\r\n            });\r\n        };\r\n\r\n        $rootScope.$on('$locationChangeSuccess', function (event, newUrl, oldUrl) {\r\n            var params = $location.search();\r\n\r\n            if (newUrl !== oldUrl && $scope.historyUrl) {\r\n                if ($scope.historyUrl.q !== $scope.historyUrl.q || $scope.historyUrl.isDirection != params.isDirection) {\r\n                    $rootScope.$emit('setSearchFromUrl', null);\r\n                }\r\n\r\n                if ($scope.historyUrl.fromDate !== params.fromDate || $scope.historyUrl.toDate !== params.toDate ||\r\n                    $scope.historyUrl.fromTime !== params.fromTime || $scope.historyUrl.toTime !== params.toTime) {\r\n                    $rootScope.$emit('setRangeFromUrl', null);\r\n                    if (params.deviceId) {\r\n                        $rootScope.$emit('infoLocation', {id: params.deviceId, direction: params.direction});\r\n                    }\r\n                } else if (params.deviceId && ($scope.historyUrl.deviceId !== params.deviceId || $scope.historyUrl.direction !== params.direction)) {\r\n                    $rootScope.$emit('infoLocation', {id: params.deviceId, direction: params.direction});\r\n                    $rootScope.$emit('activeMarker', {id: params.deviceId});\r\n                } else if (!params.deviceId && $scope.historyUrl.deviceId) {\r\n                    $rootScope.selectDevice = null;\r\n                    $rootScope.$emit('setDefaultMap', null);\r\n                }\r\n            } else if (params.deviceId) {\r\n                $rootScope.$emit('infoLocation', {id: params.deviceId, direction: params.direction});\r\n            }\r\n\r\n            $scope.historyUrl = $location.search();\r\n        });\r\n\r\n        $rootScope.handleErrorResponse = function (response) {\r\n\r\n            var modalError = jQuery('#modalError');\r\n            switch (response.status) {\r\n                case 400:\r\n                    console.log('API ERROR 400');\r\n                    $scope.modalError = {\r\n                        title: 'Neplatný požadavek',\r\n                        body: 'Požadavek nemůže být vyřízen, poněvadž byl syntakticky nesprávně zapsán.',\r\n                        button: 'OK'\r\n                    };\r\n                    modalError.modal('show');\r\n                    break;\r\n                case 401:\r\n                    $scope.modalError = {\r\n                        title: 'Platnost webové aplikace vypršela',\r\n                        body: 'Pro obnovení platnosti stačí stisknout tlačítko Obnovit.',\r\n                        button: 'Obnovit',\r\n                        clickButton: $scope.reloadApp\r\n                    };\r\n                    modalError.modal({backdrop: 'static', keyboard: false});\r\n                    break;\r\n                case 404:\r\n                    console.log('API ERROR 404');\r\n                    $scope.modalError = {title: 'Nenalezen', body: 'Záznam nebyl nalezen.', button: 'OK'};\r\n                    modalError.modal('show');\r\n                    break;\r\n                case 500:\r\n                    console.log('API ERROR 500');\r\n                    $scope.modalError = {title: 'Chyba', body: 'Chyba serveru. Zopakujte akci později.', button: 'OK'};\r\n                    modalError.modal('show');\r\n                    break;\r\n                case -1:\r\n                    console.log('API NOT CONNECTED');\r\n                    $scope.modalError = {\r\n                        title: 'Připojení k internetu',\r\n                        body: 'Nejste připojeni k internetu. Zkontrolujte připojení.',\r\n                        button: 'OK'\r\n                    };\r\n                    modalError.modal('show');\r\n                    break;\r\n                default:\r\n                    console.log('API UNKNOWN ERROR');\r\n                    $scope.modalError = {title: 'Neočekávaná chyba', body: 'Nastala neočekávaná chyba.', button: 'OK'};\r\n                    modalError.modal('show');\r\n                    break;\r\n            }\r\n        };\r\n\r\n        $scope.reloadApp = function () {\r\n            $window.location.reload();\r\n        }\r\n    }]);","angular.module('pvpk')\r\n    .controller('mapController', ['$rootScope', '$scope', 'config', 'Device', function ($rootScope, $scope, config, Device) {\r\n\r\n        this.$onInit = function () {\r\n            $scope.markers = [];\r\n\r\n            $scope.map = new google.maps.Map(document.getElementById('map'), {\r\n                center: config.DEFAULT_POSITION,\r\n                zoom: config.DEFAULT_ZOOM,\r\n                minZoom: config.DEFAULT_ZOOM_MIN,\r\n                zoomControl: true,\r\n                mapTypeControl: false,\r\n                scaleControl: false,\r\n                streetViewControl: false,\r\n                rotateControl: false,\r\n                fullscreenControl: false,\r\n                mapTypeId: google.maps.MapTypeId.ROADMAP\r\n            });\r\n\r\n            Device.query({showDirection: 0}, function (data) {\r\n                for (var i = 0, lctn; lctn = data[i]; i++) {\r\n                    $scope.createMarker(lctn);\r\n                }\r\n            }, function (response) {\r\n                console.log('Error api all Devices');\r\n                $rootScope.handleErrorResponse(response);\r\n            });\r\n        };\r\n\r\n        $scope.createMarker = function (lctn) {\r\n            if (lctn.lat && lctn.lng) {\r\n                var marker = new google.maps.Marker({\r\n                    map: $scope.map,\r\n                    position: {lat: lctn.lat, lng: lctn.lng},\r\n                    title: lctn.name,\r\n                    infoWindow: new google.maps.InfoWindow({\r\n                        content: '<h6 class=\"mb-1\">' + lctn.name + '</h6>'\r\n                        + '<address>' + lctn.street + ', ' + lctn.town + '</address>'\r\n                    }),\r\n                    id: lctn.id\r\n                });\r\n\r\n                marker.addListener('click', function () {\r\n                    $scope.closeInfoWindows();\r\n                    marker.infoWindow.open($scope.map, marker);\r\n                    $rootScope.$emit('infoLocation', {id: lctn.id});\r\n                });\r\n\r\n                $scope.markers.push(marker);\r\n            }\r\n        };\r\n\r\n        $rootScope.$on('activeMarker', function (event, args) {\r\n            for (var i = 0, marker; marker = $scope.markers[i]; i++) {\r\n                if (marker.id && marker.id === args.id && marker.infoWindow) {\r\n                    $scope.map.setCenter(marker.getPosition());\r\n                    $scope.map.setZoom(12);\r\n                    marker.infoWindow.open($scope.map, marker);\r\n                } else {\r\n                    marker.infoWindow.close();\r\n                }\r\n            }\r\n        });\r\n\r\n        $rootScope.$on('setDefaultMap', function (event, args) {\r\n            $scope.map.setCenter(config.DEFAULT_POSITION);\r\n            $scope.map.setZoom(config.DEFAULT_ZOOM);\r\n            $scope.closeInfoWindows();\r\n        });\r\n\r\n        $scope.closeInfoWindows = function () {\r\n            for (var i = 0, marker; marker = $scope.markers[i]; i++) {\r\n                marker.infoWindow.close();\r\n            }\r\n        };\r\n    }]);","angular.module('pvpk')\r\n    .controller('searchController', ['$rootScope', '$scope', '$location', 'config', 'Device', function ($rootScope, $scope, $location, config, Device) {\r\n\r\n        this.$onInit = function () {\r\n            $scope.config = config;\r\n            $scope.locations = [];\r\n            $scope.showSearchLoading = false;\r\n\r\n            $rootScope.$emit('setSearchFromUrl', null);\r\n        };\r\n\r\n        $scope.searchLocations = function () {\r\n            var params = $location.search();\r\n            params.q = $scope.search.q;\r\n            params.isDirection = $scope.search.isDirection ? 1 : null;\r\n            $location.search(params);\r\n\r\n            if (!$scope.search.q || $scope.search.q.length <= 1) {\r\n                $scope.locations = [];\r\n                return;\r\n            }\r\n\r\n            $scope.showSearchLoading = true;\r\n\r\n            Device.query({\r\n                address: $scope.search.q,\r\n                showDirection: $scope.search.isDirection ? 1 : 0\r\n            }, function (data) {\r\n                $scope.locations = data;\r\n                $scope.showSearchLoading = false;\r\n            }, function (response) {\r\n                $scope.showSearchLoading = false;\r\n                console.log('Error api all Devices');\r\n                $rootScope.handleErrorResponse(response);\r\n            });\r\n        };\r\n\r\n        $rootScope.$on('setSearchFromUrl', function (event, args) {\r\n            var params = $location.search();\r\n            $scope.search = {\r\n                q: params.q,\r\n                isDirection: params.isDirection ? !!+params.isDirection : false\r\n            };\r\n            $scope.searchLocations();\r\n        });\r\n\r\n        $scope.selectDevice = function (id, direction) {\r\n            $rootScope.$emit('activeMarker', {id: id});\r\n            $rootScope.$emit('infoLocation', {id: id, direction: direction});\r\n        };\r\n\r\n    }]);","angular.module('pvpk')\r\n    .component('graphAverageSpeed', {\r\n        template: '<div><canvas id=\"graphAverageSpeed\" class=\"graph-size mb-5\"></canvas></div>',\r\n        controller: ['$rootScope', '$scope', function ($rootScope, $scope) {\r\n\r\n            $rootScope.$on('renderGraphAverageSpeed', function (event, args) {\r\n                var canvas = document.getElementById('graphAverageSpeed').getContext('2d');\r\n\r\n                if ($scope.graphLine)\r\n                    $scope.graphLine.destroy();\r\n\r\n                $scope.graphLine = new Chart(canvas, {\r\n                    type: 'line',\r\n                    data: args.data,\r\n                    options: {\r\n                        responsive: true,\r\n                        pointDot: false,\r\n                        legend: {\r\n                            position: 'bottom'\r\n                        },\r\n                        scales: {\r\n                            xAxes: [{\r\n                                ticks: {\r\n                                    autoSkip: true,\r\n                                    maxTicksLimit: 15\r\n                                }\r\n                            }],\r\n                            yAxes: [{\r\n                                scaleLabel: {\r\n                                    display: true,\r\n                                    labelString: 'km/h'\r\n                                },\r\n                                ticks: {\r\n                                    beginAtZero: true,\r\n                                    suggestedMax: 70\r\n                                }\r\n                            }]\r\n                        },\r\n                        tooltips: {\r\n                            mode: 'index',\r\n                            intersect: false,\r\n                            callbacks: {\r\n                                label: function (tooltipItems) {\r\n                                    return tooltipItems.yLabel + ' km/h';\r\n                                }\r\n                            }\r\n                        }\r\n                    }\r\n                });\r\n\r\n            });\r\n\r\n        }]\r\n    });","angular.module('pvpk')\r\n    .component('graphNumberVehicles', {\r\n        template: '<div><canvas id=\"graphNumberVehicles\" class=\"graph-size mb-5\"></canvas></div>',\r\n        controller: ['$rootScope', '$scope', function ($rootScope, $scope) {\r\n\r\n            $rootScope.$on('renderGraphNumberVehicles', function (event, args) {\r\n                var canvasGraphNumberVehicles = document.getElementById('graphNumberVehicles').getContext('2d');\r\n\r\n                if ($scope.graphNumberVehicles)\r\n                    $scope.graphNumberVehicles.destroy();\r\n\r\n                $scope.graphNumberVehicles = new Chart(canvasGraphNumberVehicles, {\r\n                    type: 'bar',\r\n                    data: args.data,\r\n                    options: {\r\n                        responsive: true,\r\n                        onResize: function (chart, size) {\r\n                            chart.options.legend.display = size.height > 240;\r\n                            chart.update();\r\n                        },\r\n                        legend: {\r\n                            position: 'bottom'\r\n                        },\r\n                        scales: {\r\n                            xAxes: [{\r\n                                stacked: true,\r\n                                ticks: {\r\n                                    autoSkip: true,\r\n                                    maxTicksLimit: 15\r\n                                }\r\n                            }],\r\n                            yAxes: [{\r\n                                scaleLabel: {\r\n                                    display: true,\r\n                                    labelString: \"počet vozidel\"\r\n                                },\r\n                                stacked: true\r\n                            }]\r\n                        },\r\n                        tooltips: {\r\n                            mode: 'index',\r\n                            intersect: false\r\n                        }\r\n                    }\r\n                });\r\n\r\n            });\r\n\r\n        }]\r\n    });"]}
frontend/app.webmanifest
1
{
2
  "name": "Průjezd vozidel - Plzeňský kraj",
3
  "short_name": "PVPK",
4
  "start_url": ".",
5
  "display": "standalone",
6
  "background_color": "#fff",
7
  "description": "Zobrazení dat o průjezdu vozidel pro Plzeňský kraj.",
8
  "icons": [{
9
    "src": "./assets/img/favicon.png",
10
    "sizes": "20x18",
11
    "type": "image/png"
12
  }]
13
}
frontend/app/app.config.js
1 1
angular.module('pvpk')
2 2
    .constant('config', {
3 3
        APP_NAME: 'PVPK',
4
        APP_VERSION: '1.3.0',
4
        APP_VERSION: '1.3.3',
5 5
        API_URL: API_URL,
6 6
        API_TOKEN: API_TOKEN,
7 7
        DEFAULT_POSITION: {lat: 49.53, lng: 13.3},
frontend/app/app.module.js
1
angular.module('pvpk', ['ngResource', 'ngSanitize']);
1
angular.module('pvpk', ['ngResource']);
frontend/app/controllers/infoController.js
1 1
angular.module('pvpk')
2
    .controller('infoController', ['$rootScope', '$scope', '$location', 'config', 'Device', 'Vehicle', function ($rootScope, $scope, $location, config, Device, Vehicle) {
2
    .controller('infoController', ['$rootScope', '$scope', '$location', 'config', 'Device', 'Vehicle', 'Range', function ($rootScope, $scope, $location, config, Device, Vehicle, Range) {
3 3

  
4 4
        this.$onInit = function () {
5 5
            $rootScope.selectDevice = null;
6 6
            $scope.showInfoLoading = false;
7 7
            $scope.vehicles = [];
8 8
            $scope.urlExportCsv = null;
9
            $scope.directions = [
10
                {id: undefined, name: 'po směru i proti směru'},
11
                {id: 1, name: 'po směru'},
12
                {id: 2, name: 'proti směru'}];
13
            $scope.isLoadRange = false;
9 14

  
10 15
            Vehicle.query(null, function (data) {
11 16
                $scope.vehicles = data;
......
20 25

  
21 26
        $rootScope.$on('setRangeFromUrl', function (event, args) {
22 27
            var params = $location.search();
28

  
23 29
            $scope.range = {
24 30
                fromDate: moment(params.fromDate, 'YYYY-MM-DD').isValid() ? moment(params.fromDate).toDate() : moment().add(config.DEFAULT_RANGE_DATE_DAY.from, 'd').toDate(),
25 31
                toDate: moment(params.toDate, 'YYYY-MM-DD').isValid() ? moment(params.toDate).toDate() : moment().add(config.DEFAULT_RANGE_DATE_DAY.to, 'd').toDate(),
26 32
                fromTime: moment(params.fromTime, 'HH:mm').isValid() ? moment(params.fromTime, 'HH:mm').toDate() : moment({hour: config.DEFAULT_RANGE_TIME_HOUR.from}).toDate(),
27 33
                toTime: moment(params.toTime, 'HH:mm').isValid() ? moment(params.toTime, 'HH:mm').toDate() : moment({hour: config.DEFAULT_RANGE_TIME_HOUR.to}).toDate(),
28
                isTime: params.isTime == 0 ? false : true
34
                isTime: params.isTime == 0 ? false : true,
35
                maxDate: $scope.range == null ? null : $scope.range.maxDate,
36
                minDate: $scope.range == null ? null : $scope.range.minDate
29 37
            };
38

  
39
            if (!$scope.isLoadRange) {
40
                Range.get(null, function (data) {
41
                    $scope.range.fromDate = moment.max(moment(data.last_date).add(config.DEFAULT_RANGE_DATE_DAY.from, 'd'), moment(data.first_date)).toDate();
42
                    $scope.range.toDate = moment.min(moment($scope.range.toDate), moment(data.last_date)).toDate();
43
                    $scope.range.maxDate = moment(data.last_date).toDate();
44
                    $scope.range.minDate = moment(data.first_date).toDate();
45
                    $scope.isLoadRange = true;
46
                }, function (response) {
47
                    console.log('Error api get Range');
48
                    $rootScope.handleErrorResponse(response);
49
                });
50
            }
30 51
        });
31 52

  
32 53
        $rootScope.$on('infoLocation', function (event, args) {
......
79 100
                return;
80 101
            }
81 102

  
103
            if (!($scope.range.fromDate >= $scope.range.minDate && $scope.range.toDate <= $scope.range.maxDate
104
                && $scope.range.toDate >= $scope.range.minDate && $scope.range.fromDate <= $scope.range.maxDate)) {
105
                $rootScope.selectDevice.traffics = [];
106
                return;
107
            }
108

  
109

  
82 110
            var range = $scope.getRange();
83 111

  
84 112
            var params = $location.search();
......
96 124
                });
97 125
        };
98 126

  
127
        $scope.changeDirection = function () {
128

  
129
            $rootScope.$emit('infoLocation', {
130
                id: $rootScope.selectDevice.id,
131
                direction: $rootScope.selectDevice.direction
132
            });
133
        };
134

  
99 135
        $scope.getRange = function () {
100 136
            return {
101 137
                fromDate: moment($scope.range.fromDate).isValid() ? moment($scope.range.fromDate) : moment().add(config.DEFAULT_RANGE_DATE_DAY.from, 'd'),
......
140 176
                    borderWidth: 2,
141 177
                    label: vehicle.name,
142 178
                    fill: false,
143
                    //fill: 'start',
144 179
                    backgroundColor: color[vehicle.id].replace("#alpha", "0.3"),
145 180
                    borderColor: color[vehicle.id].replace("#alpha", "1"),
146 181
                    cubicInterpolationMode: 'monotone',
......
153 188
                        l++;
154 189
                        if (datasetNumberVehicles.data.length < l) {
155 190
                            datasetNumberVehicles.data.push(0);
156
                            datasetAverageSpeed.data.push(null);
191
                            datasetAverageSpeed.data.push(0);
157 192
                        }
158 193
                    }
159 194
                    if (traffic.typeVehicleId === vehicle.id) {
160 195
                        datasetNumberVehicles.data.push($scope.range.isTime ? traffic.numberVehicleAverage : traffic.numberVehicle);
161
                        datasetAverageSpeed.data.push(traffic.speedAverage <= 0 ? null : traffic.speedAverage);
196
                        datasetAverageSpeed.data.push(traffic.speedAverage <= 0 ? 0 : traffic.speedAverage);
162 197
                    }
163 198
                }
164 199
                datasetsNumberVehicles.push(datasetNumberVehicles);
frontend/app/controllers/mainController.js
60 60
                case 401:
61 61
                    $scope.modalError = {
62 62
                        title: 'Platnost webové aplikace vypršela',
63
                        body: 'Pro obnovení platnosti stačí stisknout tlačítko <strong>Obnovit</strong>.',
63
                        body: 'Pro obnovení platnosti stačí stisknout tlačítko Obnovit.',
64 64
                        button: 'Obnovit',
65 65
                        clickButton: $scope.reloadApp
66 66
                    };
frontend/app/directives/graphAverageSpeed.js
1 1
angular.module('pvpk')
2 2
    .component('graphAverageSpeed', {
3
        template: '<div><canvas id="graphAverageSpeed" class="graphSize mb-5"></canvas></div>',
3
        template: '<div><canvas id="graphAverageSpeed" class="graph-size mb-5"></canvas></div>',
4 4
        controller: ['$rootScope', '$scope', function ($rootScope, $scope) {
5 5

  
6 6
            $rootScope.$on('renderGraphAverageSpeed', function (event, args) {
frontend/app/directives/graphNumberVehicles.js
1 1
angular.module('pvpk')
2 2
    .component('graphNumberVehicles', {
3
        template: '<div><canvas id="graphNumberVehicles" class="graphSize mb-5"></canvas></div>',
3
        template: '<div><canvas id="graphNumberVehicles" class="graph-size mb-5"></canvas></div>',
4 4
        controller: ['$rootScope', '$scope', function ($rootScope, $scope) {
5 5

  
6 6
            $rootScope.$on('renderGraphNumberVehicles', function (event, args) {
frontend/app/services/RangeService.js
1
angular.module('pvpk')
2
    .factory('Range', ['$resource', 'config', function ($resource, config) {
3
        return $resource(config.API_URL + '/range', null, {
4
            'get': {
5
                url: config.API_URL + '/range',
6
                method: 'GET',
7
                headers: {
8
                    'Content-Type': 'application/json',
9
                    'Accept': 'application/json',
10
                    'jwt': config.API_TOKEN
11
                }
12
            }
13
        });
14
    }]);
frontend/assets/css/styles.min.css
1
*{margin:0;padding:0}html,body{width:100%;height:100%;min-height:100% !important;margin:0;padding:0}#search{z-index:20;float:left;min-height:100%;max-height:100%;overflow:auto;background-color:#cfd8dc;box-shadow:0 0 10px 0 rgba(50,50,50,0.75)}#search header h1{font-weight:bold;font-size:1rem;line-height:1rem}#search footer{float:left}.searchWrapper{float:left;min-height:calc(100% - 40px)}.searchWrapper .custom-control-label::before{background-color:white}#info{z-index:10;min-height:100%;max-height:100%;overflow:auto;box-shadow:0 0 10px 0 rgba(50,50,50,0.75)}#info header address{margin:0}@media (max-width: 991.98px){#info,#search{height:auto;min-height:auto;max-height:none;overflow:hidden;box-shadow:none}}#map{min-height:100%;max-height:100%;margin:0;padding:0;overflow:hidden}.loading{width:50px;height:50px;margin:0 auto;border:6px solid #fff;border-top:6px solid #007bff;border-radius:50%;animation:spin 2s linear infinite}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}#loadingScreen{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;width:100%;height:100%;background-color:#cfd8dc}#loadingScreen .loading{position:fixed;top:0;right:0;bottom:0;left:0;width:100px;height:100px;margin:auto auto;border:12px solid #fff;border-top:12px solid #007bff;border-radius:50%;animation:spin 2s linear infinite}#loadingScreen #logo{position:fixed;top:-160px;right:0;bottom:0;left:0;width:100%;height:50px;margin:auto 0;font-size:1.4rem;text-align:center}#loadingScreen #noscript{position:fixed;top:0;right:0;bottom:0;left:0;width:100%;height:110px;margin:auto 0;font-size:1rem;text-align:center;background-color:#cfd8dc}.graphSize{width:100%}::-webkit-scrollbar-track{background-color:#f5f5f5}::-webkit-scrollbar{width:8px;background-color:#f5f5f5}::-webkit-scrollbar-thumb{background-color:rgba(0,123,255,0.75)}
1
*{margin:0;padding:0}html,body{width:100%;height:100%;min-height:100% !important;margin:0;padding:0}#search{z-index:20;float:left;min-height:100%;max-height:100%;overflow:auto;background-color:#cfd8dc;box-shadow:0 0 10px 0 rgba(50,50,50,0.75)}#search header h1{font-weight:bold;font-size:1rem;line-height:1rem}#search footer{float:left}.searchWrapper{float:left;min-height:calc(100% - 40px)}.searchWrapper .custom-control-label::before{background-color:white}#info{z-index:10;min-height:100%;max-height:100%;overflow:auto;box-shadow:0 0 10px 0 rgba(50,50,50,0.75)}#info header address{margin:0}#info .source-link{color:#212529;text-decoration:underline}#info .source-link:hover{text-decoration:none}@media (max-width: 991.98px){#info,#search{height:auto;min-height:auto;max-height:none;overflow:hidden;box-shadow:none}}#map{min-height:100%;max-height:100%;margin:0;padding:0;overflow:hidden}.loading{width:50px;height:50px;margin:0 auto;border:6px solid #fff;border-top:6px solid #007bff;border-radius:50%;animation:spin 2s linear infinite}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}#loadingScreen{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;width:100%;height:100%;background-color:#cfd8dc}#loadingScreen .loading{position:fixed;top:0;right:0;bottom:0;left:0;width:100px;height:100px;margin:auto auto;border:12px solid #fff;border-top:12px solid #007bff;border-radius:50%;animation:spin 2s linear infinite}#loadingScreen #logo{position:fixed;top:-160px;right:0;bottom:0;left:0;width:100%;height:50px;margin:auto 0;font-size:1.4rem;text-align:center}#loadingScreen #noscript{position:fixed;top:0;right:0;bottom:0;left:0;width:100%;height:110px;margin:auto 0;font-size:1rem;text-align:center;background-color:#cfd8dc}.graph-size{width:100%}::-webkit-scrollbar-track{background-color:#f5f5f5}::-webkit-scrollbar{width:8px;background-color:#f5f5f5}::-webkit-scrollbar-thumb{background-color:rgba(0,123,255,0.75)}
2 2

  
3 3
/*# sourceMappingURL=styles.min.css.map */
frontend/assets/css/styles.min.css.map
1
{"version":3,"file":"styles.min.css","sources":["styles.scss","_variables.scss"],"sourcesContent":["@import './variables';\r\n\r\n* {\r\n  margin: 0;\r\n  padding: 0;\r\n}\r\n\r\nhtml,\r\nbody {\r\n  width: 100%;\r\n  height: 100%;\r\n  min-height: 100% !important;\r\n  margin: 0;\r\n  padding: 0;\r\n}\r\n\r\n#search {\r\n  z-index: 20;\r\n  float: left;\r\n  min-height: 100%;\r\n  max-height: 100%;\r\n  overflow: auto;\r\n  background-color: $primary-background-color;\r\n  box-shadow: 0 0 10px 0 rgba(50, 50, 50, 0.75);\r\n\r\n  header h1 {\r\n    font-weight: bold;\r\n    font-size: 1rem;\r\n    line-height: 1rem;\r\n  }\r\n\r\n  footer {\r\n    float: left;\r\n  }\r\n}\r\n\r\n.searchWrapper {\r\n  float: left;\r\n  min-height: calc(100% - 40px);\r\n\r\n  .custom-control-label::before {\r\n    background-color: white;\r\n  }\r\n}\r\n\r\n#info {\r\n  z-index: 10;\r\n  min-height: 100%;\r\n  max-height: 100%;\r\n  overflow: auto;\r\n  box-shadow: 0 0 10px 0 rgba(50, 50, 50, 0.75);\r\n\r\n  header address {\r\n    margin: 0;\r\n  }\r\n}\r\n\r\n@media (max-width: 991.98px) {\r\n  #info,\r\n  #search {\r\n    height: auto;\r\n    min-height: auto;\r\n    max-height: none;\r\n    overflow: hidden;\r\n    box-shadow: none;\r\n  }\r\n}\r\n\r\n#map {\r\n  min-height: 100%;\r\n  max-height: 100%;\r\n  margin: 0;\r\n  padding: 0;\r\n  overflow: hidden;\r\n}\r\n\r\n/* LOADING */\r\n.loading {\r\n  width: 50px;\r\n  height: 50px;\r\n  margin: 0 auto;\r\n  border: 6px solid $loading-second-color;\r\n  border-top: 6px solid $loading-first-color;\r\n  border-radius: 50%;\r\n  animation: spin 2s linear infinite;\r\n}\r\n\r\n@keyframes spin {\r\n  0% {\r\n    transform: rotate(0deg);\r\n  }\r\n\r\n  100% {\r\n    transform: rotate(360deg);\r\n  }\r\n}\r\n\r\n#loadingScreen {\r\n  position: fixed;\r\n  top: 0;\r\n  right: 0;\r\n  bottom: 0;\r\n  left: 0;\r\n  z-index: 1000;\r\n  width: 100%;\r\n  height: 100%;\r\n  background-color: $primary-background-color;\r\n\r\n  .loading {\r\n    position: fixed;\r\n    top: 0;\r\n    right: 0;\r\n    bottom: 0;\r\n    left: 0;\r\n    width: 100px;\r\n    height: 100px;\r\n    margin: auto auto;\r\n    border: 12px solid $loading-second-color;\r\n    border-top: 12px solid $loading-first-color;\r\n    border-radius: 50%;\r\n    animation: spin 2s linear infinite;\r\n  }\r\n\r\n  #logo {\r\n    position: fixed;\r\n    top: -160px;\r\n    right: 0;\r\n    bottom: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 50px;\r\n    margin: auto 0;\r\n    font-size: 1.4rem;\r\n    text-align: center;\r\n  }\r\n\r\n  #noscript {\r\n    position: fixed;\r\n    top: 0;\r\n    right: 0;\r\n    bottom: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 110px;\r\n    margin: auto 0;\r\n    font-size: 1rem;\r\n    text-align: center;\r\n    background-color: $primary-background-color;\r\n  }\r\n}\r\n\r\n/* GRAPH */\r\n\r\n.graphSize {\r\n  width: 100%;\r\n}\r\n\r\n/* SCROLLBAR */\r\n\r\n::-webkit-scrollbar-track {\r\n  background-color: $scrollbar-background-color;\r\n}\r\n\r\n::-webkit-scrollbar {\r\n  width: 8px;\r\n  background-color: $scrollbar-background-color;\r\n}\r\n\r\n::-webkit-scrollbar-thumb {\r\n  background-color: rgba($scrollbar-color, 0.75);\r\n}\r\n\r\n","$primary-background-color: #cfd8dc;\r\n\r\n$loading-first-color: #007bff;\r\n$loading-second-color: white;\r\n\r\n$scrollbar-background-color: whitesmoke;\r\n$scrollbar-color: #007bff;\r\n"],"names":[],"mappings":"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"}
1
{"version":3,"file":"styles.min.css","sources":["styles.scss","_variables.scss"],"sourcesContent":["@import './variables';\r\n\r\n* {\r\n  margin: 0;\r\n  padding: 0;\r\n}\r\n\r\nhtml,\r\nbody {\r\n  width: 100%;\r\n  height: 100%;\r\n  min-height: 100% !important;\r\n  margin: 0;\r\n  padding: 0;\r\n}\r\n\r\n#search {\r\n  z-index: 20;\r\n  float: left;\r\n  min-height: 100%;\r\n  max-height: 100%;\r\n  overflow: auto;\r\n  background-color: $primary-background-color;\r\n  box-shadow: 0 0 10px 0 rgba(50, 50, 50, 0.75);\r\n\r\n  header h1 {\r\n    font-weight: bold;\r\n    font-size: 1rem;\r\n    line-height: 1rem;\r\n  }\r\n\r\n  footer {\r\n    float: left;\r\n  }\r\n}\r\n\r\n.searchWrapper {\r\n  float: left;\r\n  min-height: calc(100% - 40px);\r\n\r\n  .custom-control-label::before {\r\n    background-color: white;\r\n  }\r\n}\r\n\r\n#info {\r\n  z-index: 10;\r\n  min-height: 100%;\r\n  max-height: 100%;\r\n  overflow: auto;\r\n  box-shadow: 0 0 10px 0 rgba(50, 50, 50, 0.75);\r\n\r\n  header address {\r\n    margin: 0;\r\n  }\r\n\r\n  .source-link {\r\n    color: $color-black;\r\n    text-decoration: underline;\r\n\r\n    &:hover {\r\n      text-decoration: none;\r\n    }\r\n  }\r\n}\r\n\r\n@media (max-width: 991.98px) {\r\n  #info,\r\n  #search {\r\n    height: auto;\r\n    min-height: auto;\r\n    max-height: none;\r\n    overflow: hidden;\r\n    box-shadow: none;\r\n  }\r\n}\r\n\r\n#map {\r\n  min-height: 100%;\r\n  max-height: 100%;\r\n  margin: 0;\r\n  padding: 0;\r\n  overflow: hidden;\r\n}\r\n\r\n/* LOADING */\r\n.loading {\r\n  width: 50px;\r\n  height: 50px;\r\n  margin: 0 auto;\r\n  border: 6px solid $loading-second-color;\r\n  border-top: 6px solid $loading-first-color;\r\n  border-radius: 50%;\r\n  animation: spin 2s linear infinite;\r\n}\r\n\r\n@keyframes spin {\r\n  0% {\r\n    transform: rotate(0deg);\r\n  }\r\n\r\n  100% {\r\n    transform: rotate(360deg);\r\n  }\r\n}\r\n\r\n#loadingScreen {\r\n  position: fixed;\r\n  top: 0;\r\n  right: 0;\r\n  bottom: 0;\r\n  left: 0;\r\n  z-index: 1000;\r\n  width: 100%;\r\n  height: 100%;\r\n  background-color: $primary-background-color;\r\n\r\n  .loading {\r\n    position: fixed;\r\n    top: 0;\r\n    right: 0;\r\n    bottom: 0;\r\n    left: 0;\r\n    width: 100px;\r\n    height: 100px;\r\n    margin: auto auto;\r\n    border: 12px solid $loading-second-color;\r\n    border-top: 12px solid $loading-first-color;\r\n    border-radius: 50%;\r\n    animation: spin 2s linear infinite;\r\n  }\r\n\r\n  #logo {\r\n    position: fixed;\r\n    top: -160px;\r\n    right: 0;\r\n    bottom: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 50px;\r\n    margin: auto 0;\r\n    font-size: 1.4rem;\r\n    text-align: center;\r\n  }\r\n\r\n  #noscript {\r\n    position: fixed;\r\n    top: 0;\r\n    right: 0;\r\n    bottom: 0;\r\n    left: 0;\r\n    width: 100%;\r\n    height: 110px;\r\n    margin: auto 0;\r\n    font-size: 1rem;\r\n    text-align: center;\r\n    background-color: $primary-background-color;\r\n  }\r\n}\r\n\r\n/* GRAPH */\r\n\r\n.graph-size {\r\n  width: 100%;\r\n}\r\n\r\n/* SCROLLBAR */\r\n\r\n::-webkit-scrollbar-track {\r\n  background-color: $scrollbar-background-color;\r\n}\r\n\r\n::-webkit-scrollbar {\r\n  width: 8px;\r\n  background-color: $scrollbar-background-color;\r\n}\r\n\r\n::-webkit-scrollbar-thumb {\r\n  background-color: rgba($scrollbar-color, 0.75);\r\n}\r\n\r\n","$primary-background-color: #cfd8dc;\r\n\r\n$loading-first-color: #007bff;\r\n$loading-second-color: white;\r\n\r\n$scrollbar-background-color: whitesmoke;\r\n$scrollbar-color: #007bff;\r\n\r\n$color-black: #212529;\r\n"],"names":[],"mappings":"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"}
frontend/assets/sass/_variables.scss
5 5

  
6 6
$scrollbar-background-color: whitesmoke;
7 7
$scrollbar-color: #007bff;
8

  
9
$color-black: #212529;
frontend/assets/sass/styles.scss
53 53
  header address {
54 54
    margin: 0;
55 55
  }
56

  
57
  .source-link {
58
    color: $color-black;
59
    text-decoration: underline;
60

  
61
    &:hover {
62
      text-decoration: none;
63
    }
64
  }
56 65
}
57 66

  
58 67
@media (max-width: 991.98px) {
......
151 160

  
152 161
/* GRAPH */
153 162

  
154
.graphSize {
163
.graph-size {
155 164
  width: 100%;
156 165
}
157 166

  
frontend/gulpfile.js
41 41
    return gulp.src([
42 42
        './app/app.module.js',
43 43
        './app/app.config.js',
44
        './app/services/*.js',
44 45
        './app/controllers/*.js',
45
        './app/directives/*.js',
46
        './app/services/*.js'
46
        './app/directives/*.js'
47 47
    ])
48 48
        .pipe(sourcemaps.init())
49 49
        .pipe(concat('app.js'))
......
58 58
        .pipe(gulp.dest('./'));
59 59
});
60 60

  
61
gulp.task('build-sass', gulp.series('fix-sass', 'sass'));
61
gulp.task('build-sass', gulp.series('lint-sass', 'sass'));
62 62

  
63 63
gulp.task('build', gulp.parallel('build-sass', 'build-js'));
64 64

  
frontend/index.php
8 8
    <meta name="description" content="Zobrazení dat o průjezdu vozidel pro Plzeňský kraj">
9 9
    <meta name="viewport" content="width=device-width, initial-scale=1">
10 10

  
11
    <link rel="manifest" href="app.webmanifest">
12

  
11 13
    <link rel="apple-touch-icon" href="./assets/img/favicon.png">
12 14
    <link rel="icon" href="./assets/img/favicon.png">
13 15

  
14
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css"
15
          integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
16
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
17
          integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
16 18
    <link rel="stylesheet" media="screen" href="./assets/css/styles.min.css">
17 19

  
18
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.0/angular.min.js"></script>
19
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.0/angular-resource.min.js"></script>
20
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.0/angular-sanitize.min.js"></script>
20
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>
21
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular-resource.min.js"></script>
22
    <!--    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular-sanitize.min.js"></script>-->
21 23

  
22 24
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
23 25
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
......
42 44
<div id="loadingScreen" ng-show="showLoadingScreen">
43 45
    <h1 id="logo">
44 46
        <img src="./assets/img/favicon.png" alt="logo"> Průjezd vozidel
45
        <small class="text-muted">Plzeňský kraj</small>
47
        <small>Plzeňský kraj</small>
46 48
    </h1>
47 49
    <div class="loading"></div>
48 50
    <noscript id="noscript">Aplikace vyžaduje Javascript. Aktivujte Javascript a znovu načtěte tuto stránku.
......
58 60
            <header class="mt-2">
59 61
                <h1>
60 62
                    <img src="./assets/img/favicon.png" alt="logo"> Průjezd vozidel
61
                    <small class="text-muted">Plzeňský kraj</small>
63
                    <small>Plzeňský kraj</small>
62 64
                </h1>
63 65
            </header>
64 66

  
65
            <form class="mb-4 mt-4">
67
            <div class="mb-4 mt-4">
66 68
                <div class="form-group">
67 69
                    <label for="searchLocation" class="h5">Hledání - lokalit</label>
68 70
                    <input type="search" id="searchLocation" name="location"
......
79 81
                           ng-model-options="{debounce: 600}">
80 82
                    <label for="searchIsDirection" class="custom-control-label">Rozlišovat směr</label>
81 83
                </div>
82
            </form>
84
            </div>
83 85

  
84 86
            <div class="result-locations mb-4 mt-4">
85 87
                <h5>Lokality</h5>
......
96 98
                            <small ng-show="search.isDirection">{{location.direction ==1 ? 'po směru': 'proti směru' }}
97 99
                            </small>
98 100
                        </div>
99
                        <small>
100
                            <address>{{location.street}}, {{location.town}}</address>
101
                        </small>
101
                        <address class="small">{{location.street}}, {{location.town}}</address>
102

  
102 103
                    </a>
103 104
                </div>
104 105

  
105
                <div ng-show="locations.length==0 && !showSearchLoading">
106
                    <small class="form-text text-muted text-center">Žádná lokalita</small>
106
                <div class="form-text text-center small" ng-show="locations.length==0 && !showSearchLoading">
107
                    Žádná lokalita
107 108
                </div>
108 109

  
109 110
                <div class="loading" ng-show="showSearchLoading"></div>
110 111
            </div>
111 112
        </div>
112
        <footer class="text-center mb-2 mt-2 w-100">
113
            <small class="text-muted">© 2018 FAV, ZČU • version: {{ config.APP_VERSION }}</small>
113
        <footer class="text-center text-muted mb-2 mt-2 w-100 small">
114
            © 2018 FAV, ZČU • version: {{ config.APP_VERSION }}
114 115
        </footer>
115 116
    </section>
116 117

  
......
125 126
                    <span aria-hidden="true">&times;</span>
126 127
                </button>
127 128
            </h4>
128
            <small>
129
                <address>{{$root.selectDevice.street}}, {{$root.selectDevice.town}}</address>
130
                <span>Směr: <strong>{{$root.selectDevice.direction  ? ($root.selectDevice.direction ==1 ? 'po směru': 'proti směru') : 'po směru i proti směru'}}</strong></span>
131
            </small>
129
            <address>{{$root.selectDevice.street}}, {{$root.selectDevice.town}}</address>
132 130
        </header>
133 131

  
132
        <div class="form-inline mb-4 mt-2">
133
            <label for="selectDeviceDirection" class="=hidden"></label>
134
            <select id="selectDeviceDirection" class="custom-select custom-select-sm"
135
                    ng-model="$root.selectDevice.direction"
136
                    ng-change="changeDirection(direction.id)"
137
                    ng-options="direction.id as direction.name for direction in directions"
138
                    ng-model-options="{updateOn: 'default', allowInvalid: true, debounce: 600}">
139
            </select>
140
        </div>
141

  
142

  
143
        <div class="alert alert-warning" role="alert"
144
             ng-show="!(range.fromDate >= range.minDate && range.toDate <= range.maxDate && range.toDate >= range.minDate && range.fromDate <= range.maxDate)">
145

  
146
            Data jsou k dispozici jen v rosahu {{range.minDate | date:"dd.MM.yyyy"}} - {{range.maxDate| date:"dd.MM.yyyy"}}
147

  
148
        </div>
149

  
150

  
134 151
        <div class="mb-4 mt-4" ng-form="rangeForm">
135 152
            <div class="form-row">
136 153
                <div class="form-group col">
......
157 174
                    </div>
158 175
                </div>
159 176
            </div>
160

  
161 177
            <div class="form-row">
162 178
                <div class="form-group col">
163 179
                    <label for="rangeFromTime">
......
199 215
        <div class="loading" ng-show="showInfoLoading"></div>
200 216

  
201 217
        <div id="graphs" ng-show="$root.selectDevice!=null && $root.selectDevice.traffics.length>0 && !showInfoLoading">
202
            <h4 class="mt-4">Průměrná rychlost</h4>
218
            <h4 class="mt-4">{{range.isTime ? "Průměrná rychlost za den" : "Průměrná rychlost za jednotlivé dny"}}</h4>
203 219
            <graph-average-speed></graph-average-speed>
204 220

  
205
            <h4 class="mt-4">Počet vozidel</h4>
221
            <h4 class="mt-4">{{range.isTime ? "Počet vozidel za den" : "Průměrná rychlost za jednotlivé dny"}}</h4>
206 222
            <graph-number-vehicles></graph-number-vehicles>
207 223

  
208 224
            <div class="text-center">
209 225
                <a class="btn btn-dark" href="{{ urlExportCsv }}" role="button">Export CSV</a>
210 226
            </div>
211 227

  
212
            <div class="text-center mb-2 mt-2 w-100">
213
                <small class="text-muted">zdroj dat: <a target="_blank" href="https://doprava.plzensky-kraj.cz">doprava.plzensky-kraj.cz</a>
214
                </small>
228
            <div class="text-center mb-2 mt-2 w-100 small">
229
                zdroj dat: <a class="source-link" target="_blank" rel="noopener"
230
                              href="https://doprava.plzensky-kraj.cz">doprava.plzensky-kraj.cz</a>
231

  
215 232
            </div>
216 233
        </div>
217 234

  
218
        <div ng-show="$root.selectDevice && $root.selectDevice.traffics.length==0 && !showInfoLoading">
219
            <small class="form-text text-muted text-center">Data nejsou k dispozici</small>
235
        <div class="form-text text-center small"
236
             ng-show="$root.selectDevice && $root.selectDevice.traffics.length==0 && !showInfoLoading">
237
            Data nejsou k dispozici
220 238
        </div>
221 239
    </section>
222 240

  
......
234 252
                <h5 class="modal-title">{{modalError.title}}</h5>
235 253
            </div>
236 254
            <div class="modal-body">
237
                <p ng-bind-html="modalError.body"></p>
255
                <p>{{modalError.body}}</p>
238 256
            </div>
239 257
            <div class="modal-footer">
240 258
                <button type="button" class="btn btn-primary" data-dismiss="{{modalError.clickButton ? '' : 'modal'}}"
......
249 267
        integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
250 268
        crossorigin="anonymous"></script>
251 269

  
252
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"
253
        integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T"
270
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"
271
        integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
254 272
        crossorigin="anonymous"></script>
255 273

  
256 274
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCSx7hyAzQiG5uocJTeZgf1Z3lpDy4kpEk"
frontend/package.json
1 1
{
2 2
  "name": "PVPK",
3
  "version": "1.2.0",
3
  "version": "1.3.3",
4 4
  "dependencies": {
5 5
    "gulp": "^4.0.0",
6 6
    "gulp-sass": "^4.0.1",
7 7
    "gulp-sourcemaps": "^2.6.4",
8 8
    "gulp-stylelint": "^7.0.0",
9
    "gulp-rename": "^1.2.3",
9
    "gulp-rename": "^1.4.0",
10 10
    "gulp-clean": "^0.4.0",
11 11
    "gulp-util": "^3.0.8",
12 12
    "gulp-concat": "^2.6.1",
13
    "gulp-uglify": "^3.0.0",
14
    "stylelint": "^9.2.1",
15
    "stylelint-order": "^0.8.1",
13
    "gulp-uglify": "^3.0.1",
14
    "stylelint": "^9.5.0",
15
    "stylelint-order": "^1.0.0",
16 16
    "stylelint-config-rational-order": "^0.0.2",
17 17
    "stylelint-config-standard": "^18.2.0",
18 18
    "stylelint-config-recommended-scss": "^3.2.0"

Také k dispozici: Unified diff