diff options
Diffstat (limited to 'www/js/TimelineCtrl.js')
| -rw-r--r-- | www/js/TimelineCtrl.js | 2705 |
1 files changed, 1266 insertions, 1439 deletions
diff --git a/www/js/TimelineCtrl.js b/www/js/TimelineCtrl.js index 5795d0a4..d69cfd24 100644 --- a/www/js/TimelineCtrl.js +++ b/www/js/TimelineCtrl.js @@ -12,1664 +12,1491 @@ // FIXME: too much redundant code between EventCtrl and Timeline // Move to ModalCtrl and see if it works -angular.module('zmApp.controllers').controller('zmApp.TimelineCtrl', ['$ionicPlatform', '$scope', 'zm', 'NVRDataModel', '$ionicSideMenuDelegate', '$rootScope', '$http', '$q', 'message', '$state', '$ionicLoading', '$ionicPopover', '$ionicScrollDelegate', '$ionicModal', '$timeout', '$ionicContentBanner', '$ionicHistory', '$sce', '$stateParams', '$translate', '$ionicPopup', '$interval', function($ionicPlatform, $scope, zm, NVRDataModel, $ionicSideMenuDelegate, $rootScope, $http, $q, message, $state, $ionicLoading, $ionicPopover, $ionicScrollDelegate, $ionicModal, $timeout, $ionicContentBanner, $ionicHistory, $sce, $stateParams, $translate, $ionicPopup, $interval) -{ - var broadcastHandles = []; +angular.module('zmApp.controllers').controller('zmApp.TimelineCtrl', ['$ionicPlatform', '$scope', 'zm', 'NVRDataModel', '$ionicSideMenuDelegate', '$rootScope', '$http', '$q', 'message', '$state', '$ionicLoading', '$ionicPopover', '$ionicScrollDelegate', '$ionicModal', '$timeout', '$ionicContentBanner', '$ionicHistory', '$sce', '$stateParams', '$translate', '$ionicPopup', '$interval', function ($ionicPlatform, $scope, zm, NVRDataModel, $ionicSideMenuDelegate, $rootScope, $http, $q, message, $state, $ionicLoading, $ionicPopover, $ionicScrollDelegate, $ionicModal, $timeout, $ionicContentBanner, $ionicHistory, $sce, $stateParams, $translate, $ionicPopup, $interval) { + var broadcastHandles = []; + + //console.log("Inside Timeline controller"); + $scope.openMenu = function () { + $ionicSideMenuDelegate.toggleLeft(); + }; + + //---------------------------------------f------------------------- + // Alarm notification handling + //---------------------------------------------------------------- + $scope.handleAlarms = function () { + $rootScope.isAlarm = !$rootScope.isAlarm; + if (!$rootScope.isAlarm) { + $rootScope.alarmCount = "0"; + $ionicHistory.nextViewOptions({ + disableBack: true + }); + $state.go("app.events", { + "id": 0, + "playEvent": false + }, { + reload: true + }); + return; + } + }; - //console.log("Inside Timeline controller"); - $scope.openMenu = function() - { - $ionicSideMenuDelegate.toggleLeft(); - }; + $scope.leftButtons = [{ + type: 'button-icon icon ion-navicon', + tap: function (e) { + $scope.toggleMenu(); + } + }]; + + //----------------------------------------------------------- + // Used to display date range for timeline + //----------------------------------------------------------- + $scope.prettify = function (str) { + if (NVRDataModel.getLogin().useLocalTimeZone) + return moment.tz(str, NVRDataModel.getTimeZoneNow()).tz(moment.tz.guess()).format('MMMM Do YYYY, ' + NVRDataModel.getTimeFormat()); + else + return moment(str).format('MMMM Do YYYY, ' + NVRDataModel.getTimeFormat()); + }; + + //----------------------------------------------------------- + // used for playback when you tap on a timeline event + //----------------------------------------------------------- + $scope.calcMsTimer = function (frames, len) { + var myframes, mylen; + myframes = parseFloat(frames); + mylen = parseFloat(len); + // console.log ("frames " + myframes + "length " + mylen); + // console.log ("*** MS COUNT " + (1000.0/(myframes/mylen))); + return (Math.round(1000 / (myframes / mylen))); + }; + + $scope.toggleMinAlarmFrameCount = function () { + // console.log("Toggling"); - //---------------------------------------f------------------------- - // Alarm notification handling - //---------------------------------------------------------------- - $scope.handleAlarms = function() - { - $rootScope.isAlarm = !$rootScope.isAlarm; - if (!$rootScope.isAlarm) - { - $rootScope.alarmCount = "0"; - $ionicHistory.nextViewOptions( - { - disableBack: true - }); - $state.go("app.events", - { - "id": 0, - "playEvent": false - }, - { - reload: true - }); - return; - } - }; + var ld = NVRDataModel.getLogin(); + ld.enableAlarmCount = !ld.enableAlarmCount; - $scope.leftButtons = [ - { - type: 'button-icon icon ion-navicon', - tap: function(e) - { - $scope.toggleMenu(); - } - }]; + NVRDataModel.setLogin(ld); + $scope.loginData = ld; - //----------------------------------------------------------- - // Used to display date range for timeline - //----------------------------------------------------------- - $scope.prettify = function(str) - { - if (NVRDataModel.getLogin().useLocalTimeZone) - return moment.tz(str, NVRDataModel.getTimeZoneNow()).tz(moment.tz.guess()).format('MMMM Do YYYY, ' + NVRDataModel.getTimeFormat()); - else - return moment(str).format('MMMM Do YYYY, ' + NVRDataModel.getTimeFormat()); - }; + drawGraph(curFromDate, curToDate, curCount); - //----------------------------------------------------------- - // used for playback when you tap on a timeline event - //----------------------------------------------------------- - $scope.calcMsTimer = function(frames, len) - { - var myframes, mylen; - myframes = parseFloat(frames); - mylen = parseFloat(len); - // console.log ("frames " + myframes + "length " + mylen); - // console.log ("*** MS COUNT " + (1000.0/(myframes/mylen))); - return (Math.round(1000 / (myframes / mylen))); - }; + }; - $scope.toggleMinAlarmFrameCount = function() - { - // console.log("Toggling"); + //----------------------------------------------------------- + // Move/Zoom are used to move the timeline around + //----------------------------------------------------------- + function move(percentage) { + var range = timeline.getWindow(); + var interval = range.end - range.start; - var ld = NVRDataModel.getLogin(); - ld.enableAlarmCount = !ld.enableAlarmCount; + timeline.setWindow({ + start: range.start.valueOf() - interval * percentage, + end: range.end.valueOf() - interval * percentage + }); + } - NVRDataModel.setLogin(ld); - $scope.loginData = ld; + // helps to navigate to current time quickly + // after a night of heavy navigation + $scope.gotoNow = function () { + timeline.moveTo(timeline.getCurrentTime()); + }; - drawGraph(curFromDate, curToDate, curCount); + $scope.move = function (percentage) { + move(percentage); - }; + }; - //----------------------------------------------------------- - // Move/Zoom are used to move the timeline around - //----------------------------------------------------------- - function move(percentage) - { - var range = timeline.getWindow(); - var interval = range.end - range.start; + //----------------------------------------- + // Move by X days + //----------------------------------------- + $scope.moveDays = function (d) { + var range = timeline.getWindow(); + var ds = moment(range.start); + if (d > 0) + ds.add(d, 'days'); + else + ds.subtract(Math.abs(d), 'days'); - timeline.setWindow( - { - start: range.start.valueOf() - interval * percentage, - end: range.end.valueOf() - interval * percentage - }); - } + var es = moment(ds); // clone it! + es.add(1, 'day'); - // helps to navigate to current time quickly - // after a night of heavy navigation - $scope.gotoNow = function() - { - timeline.moveTo(timeline.getCurrentTime()); - }; + fromDate = ds.format("YYYY-MM-DD HH:mm:ss"); + toDate = es.format("YYYY-MM-DD HH:mm:ss"); - $scope.move = function(percentage) - { - move(percentage); + $scope.fromDate = fromDate; + $scope.toDate = toDate; + $rootScope.customTimelineRange = false; + NVRDataModel.log("moving by " + d + " day to " + fromDate + " upto " + toDate); + drawGraph(fromDate, toDate, maxItems); + + }; + + function eventDetails(ev) { + $scope.event = ev; + $ionicModal.fromTemplateUrl('templates/timeline-modal.html', { + scope: $scope, // give ModalCtrl access to this scope + animation: 'slide-in-up', + id: 'analyze', + + }) + .then(function (modal) { + $scope.modal = modal; + + $scope.modal.show(); + + }); + } + + //-------------------------------------------------------- + // To show a modal dialog with the event tapped on in timeline + // FIXME : code repeat from Events + //-------------------------------------------------------- + function openModal(event) { + + if ($scope.modalFromTimelineIsOpen == true) { + // don't know why but some conflict from angular to timeline lib + // results in double modals at times + NVRDataModel.log(">>-- duplicate modal detected, preventing"); + } - }; + $scope.modalFromTimelineIsOpen = true; + NVRDataModel.setAwake(NVRDataModel.getKeepAwake()); - //----------------------------------------- - // Move by X days - //----------------------------------------- - $scope.moveDays = function(d) - { - var range = timeline.getWindow(); - var ds = moment(range.start); - if (d > 0) - ds.add(d, 'days'); - else - ds.subtract(Math.abs(d), 'days'); + // pass this event to ModalCtrl + $scope.currentEvent = event; - var es = moment(ds); // clone it! - es.add(1, 'day'); + $scope.event = event; + // in Timeline view, make sure events stick to same monitor + $scope.followSameMonitor = "1"; - fromDate = ds.format("YYYY-MM-DD HH:mm:ss"); - toDate = es.format("YYYY-MM-DD HH:mm:ss"); + //prepareModalEvent(event.Event.Id); - $scope.fromDate = fromDate; - $scope.toDate = toDate; - $rootScope.customTimelineRange = false; - NVRDataModel.log("moving by " + d + " day to " + fromDate + " upto " + toDate); - drawGraph(fromDate, toDate, maxItems); + var ld = NVRDataModel.getLogin(); + var sl = 'disabled'; + if (ld.showLiveForInProgressEvents) { + sl = 'enabled'; + } + $scope.modalData = { + doRefresh: false }; + $ionicModal.fromTemplateUrl('templates/events-modal.html', { + scope: $scope, // give ModalCtrl access to this scope + animation: 'slide-in-up', + id: 'footage', + showLive: sl + }) + .then(function (modal) { + $scope.modal = modal; + + $ionicLoading.show({ + template: $translate.instant('kPleaseWait') + "...", + noBackdrop: true, + duration: 10000, - function eventDetails(ev) - { - $scope.event = ev; - $ionicModal.fromTemplateUrl('templates/timeline-modal.html', - { - scope: $scope, // give ModalCtrl access to this scope - animation: 'slide-in-up', - id: 'analyze', + }); - }) - .then(function(modal) - { - $scope.modal = modal; + $scope.modal.show(); - $scope.modal.show(); + var ld = NVRDataModel.getLogin(); - }); + }); + + } + + //-------------------------------------------------------- + //We need to destroy because we are instantiating + // it on open + //-------------------------------------------------------- + $scope.closeModal = function () { + $scope.modalFromTimelineIsOpen = false; + // $interval.cancel(eventsInterval); + //$interval.cancel(segmentHandle); + NVRDataModel.debug("TimelineCtrl:Close & Destroy Modal"); + NVRDataModel.stopNetwork("TimelineCtrl: closeModal"); + NVRDataModel.setAwake(false); + if ($scope.modal !== undefined) { + $scope.modal.remove(); } - //-------------------------------------------------------- - // To show a modal dialog with the event tapped on in timeline - // FIXME : code repeat from Events - //-------------------------------------------------------- - function openModal(event) - { + if ($scope.modalData.doRefresh) { - if ($scope.modalFromTimelineIsOpen == true) + $timeout(function () { + drawGraph($scope.fromDate, $scope.toDate, maxItems); + }, 500); + + } + + }; + + /* $scope.toggleGapless = function() { - // don't know why but some conflict from angular to timeline lib - // results in double modals at times - NVRDataModel.log(">>-- duplicate modal detected, preventing"); - } + console.log ("GAPLESS TOGGLE"); + $scope.loginData.gapless = !$scope.loginData.gapless; + NVRDataModel.setLogin($scope.loginData); + + };*/ - $scope.modalFromTimelineIsOpen = true; - NVRDataModel.setAwake(NVRDataModel.getKeepAwake()); + //------------------------------------------------------------------------- + // called when user switches to background + //------------------------------------------------------------------------- + function onPause() { + NVRDataModel.debug("TimelineCtrl:onpause called"); + $interval.cancel(updateInterval); + // console.log("*** Moving to Background ***"); // Handle the pause event - // pass this event to ModalCtrl - $scope.currentEvent = event; + if ($scope.popover) $scope.popover.remove(); - $scope.event = event; - // in Timeline view, make sure events stick to same monitor - $scope.followSameMonitor = "1"; + } - //prepareModalEvent(event.Event.Id); + //-------------------------------------------------------- + // This function is called by the graph ontapped function + // which in turn calls openModal + //-------------------------------------------------------- - var ld = NVRDataModel.getLogin(); - var sl = 'disabled'; - if (ld.showLiveForInProgressEvents) { - sl = 'enabled'; - } + function showEvent(event) { - $scope.modalData = {doRefresh:false}; - $ionicModal.fromTemplateUrl('templates/events-modal.html', - { - scope: $scope, // give ModalCtrl access to this scope - animation: 'slide-in-up', - id: 'footage', - showLive:sl - }) - .then(function(modal) - { - $scope.modal = modal; - - $ionicLoading.show( - { - template: $translate.instant('kPleaseWait') + "...", - noBackdrop: true, - duration: 10000, + // in context of angular - }); + $timeout(function () { + openModal(event); + }); - $scope.modal.show(); + } - var ld = NVRDataModel.getLogin(); + var tzu = $scope.$on('tz-updated', function () { + $scope.tzAbbr = NVRDataModel.getTimeZoneNow(); + NVRDataModel.debug("Timezone API updated timezone to " + NVRDataModel.getTimeZoneNow()); + }); + broadcastHandles.push(tzu); - }); + //------------------------------------------------- + // Make sure we delete the timeline + // This may be redundant as the root view gets + // destroyed but no harm + //------------------------------------------------- + $scope.$on('$ionicView.leave', function () { + NVRDataModel.debug("Timeline: Deregistering broadcast handles"); + for (var i = 0; i < broadcastHandles.length; i++) { + // broadcastHandles[i](); } + broadcastHandles = []; - //-------------------------------------------------------- - //We need to destroy because we are instantiating - // it on open - //-------------------------------------------------------- - $scope.closeModal = function() - { - $scope.modalFromTimelineIsOpen = false; - // $interval.cancel(eventsInterval); - //$interval.cancel(segmentHandle); - NVRDataModel.debug("TimelineCtrl:Close & Destroy Modal"); - NVRDataModel.stopNetwork("TimelineCtrl: closeModal"); - NVRDataModel.setAwake(false); - if ($scope.modal !== undefined) - { - $scope.modal.remove(); - } + if (timeline) { + $interval.cancel(updateInterval); + timeline.destroy(); + //console.log("**Destroying Timeline"); - if ($scope.modalData.doRefresh) { + } + }); - $timeout (function() {drawGraph ($scope.fromDate, $scope.toDate, maxItems );},500); - - } + /*$scope.$on('$ionicView.enter', function() { - }; - /* $scope.toggleGapless = function() - { - console.log ("GAPLESS TOGGLE"); - $scope.loginData.gapless = !$scope.loginData.gapless; - NVRDataModel.setLogin($scope.loginData); - - };*/ - - //------------------------------------------------------------------------- - // called when user switches to background - //------------------------------------------------------------------------- - function onPause() - { - NVRDataModel.debug("TimelineCtrl:onpause called"); - $interval.cancel(updateInterval); - // console.log("*** Moving to Background ***"); // Handle the pause event - if ($scope.popover) $scope.popover.remove(); + + });*/ - } + $scope.$on('$ionicView.beforeEnter', function () { - //-------------------------------------------------------- - // This function is called by the graph ontapped function - // which in turn calls openModal - //-------------------------------------------------------- + //$ionicHistory.clearCache(); + //$ionicHistory.clearHistory(); + timeline = ''; + $scope.newEvents = ''; - function showEvent(event) - { + }); - // in context of angular + //------------------------------------------- + // Entire reason for existence: + // double tap doesn't reliably work + // when paired with tap on mobiles + //------------------------------------------- - $timeout(function() - { - openModal(event); - }); + $scope.toggleTap = function () { + + if ($scope.onTap == $translate.instant('kTimelineEvent')) { + $scope.onDTap = $translate.instant('kTimelineEvent'); + $scope.onTap = $translate.instant('kTimelineGraph'); + } else { + $scope.onTap = $translate.instant('kTimelineEvent'); + $scope.onDTap = $translate.instant('kTimelineGraph'); } + $scope.timelineControls = $translate.instant('kTimelineTap') + ':' + $scope.onTap + " / " + $translate.instant('kTimelineDTap') + ':' + $scope.onDTap; - var tzu = $scope.$on('tz-updated', function() - { - $scope.tzAbbr = NVRDataModel.getTimeZoneNow(); - NVRDataModel.debug("Timezone API updated timezone to " + NVRDataModel.getTimeZoneNow()); - }); - broadcastHandles.push(tzu); - - //------------------------------------------------- - // Make sure we delete the timeline - // This may be redundant as the root view gets - // destroyed but no harm - //------------------------------------------------- - $scope.$on('$ionicView.leave', function() - { + }; - NVRDataModel.debug ("Timeline: Deregistering broadcast handles"); - for (var i=0; i < broadcastHandles.length; i++) { - // broadcastHandles[i](); - } - broadcastHandles = []; - if (timeline) - { - $interval.cancel(updateInterval); - timeline.destroy(); - //console.log("**Destroying Timeline"); + //------------------------------------------------- + // FIXME: shitty hackery -- Im using a rootScope + // to know if you just went to custom range + // and back. Fix this, really. + // So anyway, if you did select a custom range + // then we "go back" to timeline, which is when + // we come here - so make sure we update the + // graph range + //------------------------------------------------- - } - }); - /*$scope.$on('$ionicView.enter', function() { + $scope.$on('$ionicView.afterEnter', function () { + $scope.monitors = message; + $scope.onTap = $translate.instant('kTimelineEvent'); + $scope.onDTap = $translate.instant('kTimelineGraph'); + $scope.timelineControls = $translate.instant('kTimelineTap') + ':' + $scope.onTap + " / " + $translate.instant('kTimelineDTap') + ':' + $scope.onDTap; - - });*/ + //console.log("***AFTER ENTER"); - $scope.$on('$ionicView.beforeEnter', function() - { + $scope.follow = { + 'time': NVRDataModel.getLogin().followTimeLine + }; - //$ionicHistory.clearCache(); - //$ionicHistory.clearHistory(); - timeline = ''; - $scope.newEvents = ''; + $interval.cancel(updateInterval); - }); + // Make sure sliding for menu is disabled so it + // does not interfere with graph panning + $ionicSideMenuDelegate.canDragContent(false); + var ld = NVRDataModel.getLogin(); + maxItemsConf = ($rootScope.platformOS == 'desktop') ? zm.graphDesktopItemMax : zm.graphItemMax; + maxItems = ld.graphSize || maxItemsConf; + NVRDataModel.log("Graph items to draw is " + maxItems); + $scope.maxItems = maxItems; + $scope.translationData = { + maxItemsVal: maxItems + }; - //------------------------------------------- - // Entire reason for existence: - // double tap doesn't reliably work - // when paired with tap on mobiles - //------------------------------------------- + $scope.graphLoaded = false; + NVRDataModel.debug("TimelineCtrl/drawGraph: graphLoaded is " + $scope.graphLoaded); - $scope.toggleTap = function() { + //latestDateDrawn = moment().locale('en').format("YYYY-MM-DD HH:mm:ss"); + $scope.modalFromTimelineIsOpen = false; + //var tempMon = message; - if ($scope.onTap == $translate.instant('kTimelineEvent')) { - $scope.onDTap = $translate.instant('kTimelineEvent'); - $scope.onTap = $translate.instant('kTimelineGraph'); + // lets timeline.onget the abbreviated version of TZ to display + if (NVRDataModel.getLogin().useLocalTimeZone) { + $scope.tzAbbr = moment().tz(moment.tz.guess()).zoneAbbr(); + } else { + $scope.tzAbbr = moment().tz(NVRDataModel.getTimeZoneNow()).zoneAbbr(); + } + //console.log ("TIMELINE MONITORS: " + JSON.stringify(message)); + //var ld = NVRDataModel.getLogin(); + $scope.loginData = NVRDataModel.getLogin(); + + /* if (ld.persistMontageOrder) { + var iMon = NVRDataModel.applyMontageMonitorPrefs(tempMon, 2); + $scope.monitors = iMon[0]; + } else*/ + + //console.log ("MONITORS:"+JSON.stringify($scope.monitors)); + + if ($rootScope.customTimelineRange) { + $scope.currentMode = 'custom'; + //console.log("***** CUSTOM RANGE"); + if (moment($rootScope.fromString).isValid() && + moment($rootScope.toString).isValid()) { + // console.log("FROM & TO IS CUSTOM"); + fromDate = $rootScope.fromString; + toDate = $rootScope.toString; + $scope.fromDate = fromDate; + $scope.toDate = toDate; + drawGraph(fromDate, toDate, maxItems); + } else { + //console.log("From:" + $rootScope.fromString + " To:" + $rootScope.toString); + //console.log("FROM & TO IS CUSTOM INVALID"); + + if (NVRDataModel.getLogin().useLocalTimeZone) { + fromDate = moment().startOf('day').format("YYYY-MM-DD HH:mm:ss"); + toDate = moment().endOf('day').format("YYYY-MM-DD HH:mm:ss"); + } else { + fromDate = moment().tz(NVRDataModel.getTimeZoneNow()).startOf('day').format("YYYY-MM-DD HH:mm:ss"); + toDate = moment().tz(NVRDataModel.getTimeZoneNow()).endOf('day').format("YYYY-MM-DD HH:mm:ss"); } - else { - $scope.onTap = $translate.instant('kTimelineEvent'); - $scope.onDTap = $translate.instant('kTimelineGraph'); + + drawGraph(fromDate, toDate, maxItems); + } + } else { + $scope.currentMode = 'day'; + + if (NVRDataModel.getLogin().useLocalTimeZone) { + fromDate = moment().startOf('day').format("YYYY-MM-DD HH:mm:ss"); + toDate = moment().endOf('day').format("YYYY-MM-DD HH:mm:ss"); + } else { + fromDate = moment().tz(NVRDataModel.getTimeZoneNow()).startOf('day').format("YYYY-MM-DD HH:mm:ss"); + toDate = moment().tz(NVRDataModel.getTimeZoneNow()).endOf('day').format("YYYY-MM-DD HH:mm:ss"); + } + drawGraph(fromDate, toDate, maxItems); + } + + $ionicPopover.fromTemplateUrl('templates/timeline-popover.html', { + scope: $scope, + }).then(function (popover) { + $scope.popover = popover; + }); + + // -------------------------------------------------------- + // Handling of back button in case modal is open should + // close the modal + // -------------------------------------------------------- + + $ionicPlatform.registerBackButtonAction(function (e) { + e.preventDefault(); + if ($scope.modal != undefined && $scope.modal.isShown()) { + // switch off awake, as liveview is finished + NVRDataModel.debug("Modal is open, closing it"); + NVRDataModel.setAwake(false); + $scope.modal.remove(); + } else { + NVRDataModel.debug("Modal is closed, so toggling or exiting"); + if (!$ionicSideMenuDelegate.isOpenLeft()) { + $ionicSideMenuDelegate.toggleLeft(); + + } else { + navigator.app.exitApp(); } - $scope.timelineControls = $translate.instant('kTimelineTap')+':'+$scope.onTap+" / "+$translate.instant('kTimelineDTap')+':'+$scope.onDTap; - }; + } + }, 1000); - //------------------------------------------------- - // FIXME: shitty hackery -- Im using a rootScope - // to know if you just went to custom range - // and back. Fix this, really. - // So anyway, if you did select a custom range - // then we "go back" to timeline, which is when - // we come here - so make sure we update the - // graph range - //------------------------------------------------- - + }); - $scope.$on('$ionicView.afterEnter', function() - { + //------------------------------------------------- + // Controller main + //------------------------------------------------- - $scope.monitors = message; + var graphIndex; + var updateInterval; + var lastTimeForEvent; + var groups, graphData; + var isProcessNewEventsWaiting = false; + var options; + var dblclick = false; - $scope.onTap = $translate.instant('kTimelineEvent'); - $scope.onDTap = $translate.instant('kTimelineGraph'); - $scope.timelineControls = $translate.instant('kTimelineTap')+':'+$scope.onTap+" / "+$translate.instant('kTimelineDTap')+':'+$scope.onDTap; - - //console.log("***AFTER ENTER"); + $scope.mycarousel = { + index: 0 + }; + $scope.ionRange = { + index: 1 + }; - $scope.follow = { - 'time': NVRDataModel.getLogin().followTimeLine - }; + var curFromDate, curToDate, curCount; - $interval.cancel(updateInterval); + document.addEventListener("pause", onPause, false); - // Make sure sliding for menu is disabled so it - // does not interfere with graph panning - $ionicSideMenuDelegate.canDragContent(false); - var ld = NVRDataModel.getLogin(); - maxItemsConf = ($rootScope.platformOS == 'desktop') ? zm.graphDesktopItemMax : zm.graphItemMax; - maxItems = ld.graphSize || maxItemsConf; - NVRDataModel.log("Graph items to draw is " + maxItems); - $scope.maxItems = maxItems; - $scope.translationData = { - maxItemsVal: maxItems - }; - - $scope.graphLoaded = false; - NVRDataModel.debug("TimelineCtrl/drawGraph: graphLoaded is " + $scope.graphLoaded); - - //latestDateDrawn = moment().locale('en').format("YYYY-MM-DD HH:mm:ss"); - $scope.modalFromTimelineIsOpen = false; - //var tempMon = message; - - // lets timeline.onget the abbreviated version of TZ to display - if (NVRDataModel.getLogin().useLocalTimeZone) - { - $scope.tzAbbr = moment().tz(moment.tz.guess()).zoneAbbr(); - } - else - { - $scope.tzAbbr = moment().tz(NVRDataModel.getTimeZoneNow()).zoneAbbr(); - } + // FIXME: Timeline awake to avoid graph redrawing + NVRDataModel.setAwake(NVRDataModel.getKeepAwake()); - //console.log ("TIMELINE MONITORS: " + JSON.stringify(message)); - //var ld = NVRDataModel.getLogin(); - $scope.loginData = NVRDataModel.getLogin(); + // fromDate and toDate will be used to plot the range for the graph + // We start in day mode + // + var fromDate, toDate; - /* if (ld.persistMontageOrder) { - var iMon = NVRDataModel.applyMontageMonitorPrefs(tempMon, 2); - $scope.monitors = iMon[0]; - } else*/ + fromDate = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()).startOf('day').format("YYYY-MM-DD HH:mm:ss"); + toDate = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()).endOf('day').format("YYYY-MM-DD HH:mm:ss"); - //console.log ("MONITORS:"+JSON.stringify($scope.monitors)); + $scope.fromDate = fromDate; + $scope.toDate = toDate; - if ($rootScope.customTimelineRange) - { - $scope.currentMode = 'custom'; - //console.log("***** CUSTOM RANGE"); - if (moment($rootScope.fromString).isValid() && - moment($rootScope.toString).isValid()) - { - // console.log("FROM & TO IS CUSTOM"); - fromDate = $rootScope.fromString; - toDate = $rootScope.toString; - $scope.fromDate = fromDate; - $scope.toDate = toDate; - drawGraph(fromDate, toDate, maxItems); - } - else - { - //console.log("From:" + $rootScope.fromString + " To:" + $rootScope.toString); - //console.log("FROM & TO IS CUSTOM INVALID"); + // maxItems will be ignored during timeline draw if its desktop + var maxItemsConf; - if (NVRDataModel.getLogin().useLocalTimeZone) - { - fromDate = moment().startOf('day').format("YYYY-MM-DD HH:mm:ss"); - toDate = moment().endOf('day').format("YYYY-MM-DD HH:mm:ss"); - } - else - { - fromDate = moment().tz(NVRDataModel.getTimeZoneNow()).startOf('day').format("YYYY-MM-DD HH:mm:ss"); - toDate = moment().tz(NVRDataModel.getTimeZoneNow()).endOf('day').format("YYYY-MM-DD HH:mm:ss"); - } + var ld = NVRDataModel.getLogin(); + var maxItems; - drawGraph(fromDate, toDate, maxItems); - } - } - else - { - $scope.currentMode = 'day'; + //flat colors for graph - https://flatuicolors.com http://www.flatuicolorpicker.com + var colors = ['#3498db', '#E57373', '#EB974E', '#95A5A6', '#e74c3c', '#03C9A9', ]; - if (NVRDataModel.getLogin().useLocalTimeZone) - { - fromDate = moment().startOf('day').format("YYYY-MM-DD HH:mm:ss"); - toDate = moment().endOf('day').format("YYYY-MM-DD HH:mm:ss"); - } - else - { - fromDate = moment().tz(NVRDataModel.getTimeZoneNow()).startOf('day').format("YYYY-MM-DD HH:mm:ss"); - toDate = moment().tz(NVRDataModel.getTimeZoneNow()).endOf('day').format("YYYY-MM-DD HH:mm:ss"); - } - drawGraph(fromDate, toDate, maxItems); - } + var container; + container = angular.element(document.getElementById('visualization')); + var timeline; - $ionicPopover.fromTemplateUrl('templates/timeline-popover.html', - { - scope: $scope, - }).then(function(popover) - { - $scope.popover = popover; - }); + //console.log ("RETURNING MONITORS " + JSON.stringify($scope.monitors)); + //$scope.monitors = message; - // -------------------------------------------------------- - // Handling of back button in case modal is open should - // close the modal - // -------------------------------------------------------- + //console.log ("MONITOR DATA AFTER APPLYING : " + JSON.stringify($scope.monitors)); - $ionicPlatform.registerBackButtonAction(function(e) - { - e.preventDefault(); - if ($scope.modal != undefined && $scope.modal.isShown()) - { - // switch off awake, as liveview is finished - NVRDataModel.debug("Modal is open, closing it"); - NVRDataModel.setAwake(false); - $scope.modal.remove(); - } - else - { - NVRDataModel.debug("Modal is closed, so toggling or exiting"); - if (!$ionicSideMenuDelegate.isOpenLeft()) - { - $ionicSideMenuDelegate.toggleLeft(); + $scope.navControls = false; + var navControls = false; - } - else - { - navigator.app.exitApp(); - } + //drawGraph(fromDate, toDate, maxItems); + //dummyDrawGraph(fromDate, toDate,maxItems); - } + //------------------------------------------------- + // Rest graph to sane state after you went + // wild zooming and panning :-) + //------------------------------------------------- + $scope.fit = function () { + timeline.fit(); + }; - }, 1000); + $scope.toggleNav = function () { + if (navControls == true) { + navControls = !navControls; + // $scope.navControls = navControls; + // give out animation time + $timeout(function () { + $scope.navControls = navControls; + }, 2000); + } else { + navControls = !navControls; + $scope.navControls = navControls; + } + var element = angular.element(document.getElementById("timeline-ctrl")); + + if (navControls) { + element.removeClass("animated bounceOutLeft"); + element.addClass("animated bounceInRight"); + } else { + element.removeClass("animated bounceInRight"); + element.addClass("animated bounceOutLeft"); + } - }); + }; - //------------------------------------------------- - // Controller main - //------------------------------------------------- + function shortenTime(str) { + if (NVRDataModel.getLogin().useLocalTimeZone) + return moment.tz(str, NVRDataModel.getTimeZoneNow()).tz(moment.tz.guess()).format(NVRDataModel.getTimeFormat()); + else + return moment(str).format(NVRDataModel.getTimeFormat()); + } - var graphIndex; - var updateInterval; - var lastTimeForEvent; - var groups, graphData; - var isProcessNewEventsWaiting = false; - var options; - var dblclick = false; + $scope.toggleFollowTime = function () { + /*if ($scope.currentMode != 'day') { + $rootScope.zmPopup = $ionicPopup.alert({ + title: $translate.instant('kError'), + template: $translate.instant('kFollowError') + }); + return; + }*/ + $scope.follow.time = !$scope.follow.time; + var loginData = NVRDataModel.getLogin(); + loginData.followTimeLine = $scope.follow.time; + NVRDataModel.setLogin(loginData); + }; + //------------------------------------------------- + // Called with day/week/month + // so we can redraw the graph + //------------------------------------------------- + + $scope.buttonClicked = function (index) { + //console.log (index); + if (index == 0) //month + { + $scope.follow.time = NVRDataModel.getLogin().followTimeLine; + $scope.currentMode = "month"; + NVRDataModel.log("Month view"); + $rootScope.customTimelineRange = false; + + toDate = moment().format("YYYY-MM-DD HH:mm:ss"); + fromDate = moment().subtract(1, 'month').startOf('day').format("YYYY-MM-DD HH:mm:ss"); + $scope.fromDate = fromDate; + $scope.toDate = toDate; + drawGraph(fromDate, toDate, maxItems); + } else if (index == 1) //week + { + $scope.follow.time = NVRDataModel.getLogin().followTimeLine; + $scope.currentMode = "week"; + $rootScope.customTimelineRange = false; + NVRDataModel.log("Week view"); + toDate = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()).format("YYYY-MM-DD HH:mm:ss"); + fromDate = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()).subtract(1, 'week').startOf('day').format("YYYY-MM-DD HH:mm:ss"); + $scope.fromDate = fromDate; + $scope.toDate = toDate; + drawGraph(fromDate, toDate, maxItems); + } else if (index == 2) //day + { - $scope.mycarousel = { - index: 0 - }; - $scope.ionRange = { - index: 1 - }; + $scope.currentMode = "day"; + $rootScope.customTimelineRange = false; + NVRDataModel.log("Day view"); + //toDate = moment().format("YYYY-MM-DD HH:mm:ss"); + fromDate = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()).startOf('day').format("YYYY-MM-DD HH:mm:ss"); + toDate = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()).endOf('day').format("YYYY-MM-DD HH:mm:ss"); + $scope.fromDate = fromDate; + $scope.toDate = toDate; + drawGraph(fromDate, toDate, maxItems); + } else // custom + { + $scope.follow.time = NVRDataModel.getLogin().followTimeLine; + $scope.currentMode = "custom"; + $rootScope.customTimelineRange = true; + $state.go('app.events-date-time-filter'); + return; + } - var curFromDate, curToDate, curCount; + }; - document.addEventListener("pause", onPause, false); + /** + * [processNewEvents is called every X seconds when dynamic update is on. X = 10 for now] + * @return {[type]} + */ + function processNewEvents() { - // FIXME: Timeline awake to avoid graph redrawing - NVRDataModel.setAwake(NVRDataModel.getKeepAwake()); + //safeguard in the event http calls are still going on + if (!$scope.follow.time || isProcessNewEventsWaiting) return; + + var ld = NVRDataModel.getLogin(); - // fromDate and toDate will be used to plot the range for the graph - // We start in day mode + // check for last 2 minutes to account for late DB updates and what not. 5 mins was likely enough // - var fromDate, toDate; - fromDate = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()).startOf('day').format("YYYY-MM-DD HH:mm:ss"); - toDate = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()).endOf('day').format("YYYY-MM-DD HH:mm:ss"); + // make sure these are server time + var from = moment(lastTimeForEvent).tz(NVRDataModel.getTimeZoneNow()); + from = from.subtract(2, 'minutes').locale('en').format("YYYY-MM-DD HH:mm:ss"); - $scope.fromDate = fromDate; - $scope.toDate = toDate; + var to = moment(lastTimeForEvent).tz(NVRDataModel.getTimeZoneNow()); + to = to.locale('en').format("YYYY-MM-DD HH:mm:ss"); - // maxItems will be ignored during timeline draw if its desktop - var maxItemsConf; + lastTimeForEvent = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()); - var ld = NVRDataModel.getLogin(); - var maxItems; + // FIXME: totally ignoring event pages - hoping it wont be more than 100 or 150 whatever + // the events per page limit is. Why? laziness. + // + var completedEvents = ld.apiurl + '/events/index/EndTime >=:' + from; + // we can add alarmCount as this is really for completed events + //completedEvents = completedEvents + "/AlarmFrames >=:" + (ld.enableAlarmCount ? ld.minAlarmCount : 0); - //flat colors for graph - https://flatuicolors.com http://www.flatuicolorpicker.com - var colors = ['#3498db', '#E57373', '#EB974E', '#95A5A6', '#e74c3c', '#03C9A9', ]; + completedEvents = completedEvents + ".json"; - var container; - container = angular.element(document.getElementById('visualization')); - var timeline; + // now get currently ongoing events + // as it turns out various events get stored withn null and never recover + // so, lets limiy to 15 m + // - //console.log ("RETURNING MONITORS " + JSON.stringify($scope.monitors)); - //$scope.monitors = message; + var st = moment(lastTimeForEvent).tz(NVRDataModel.getTimeZoneNow()); + st = st.subtract(10, 'minutes').locale('en').format("YYYY-MM-DD HH:mm:ss"); + var ongoingEvents = ld.apiurl + '/events/index/StartTime >=:' + st + '/EndTime =:.json'; + //NVRDataModel.debug("Getting incremental events using: " + completedEvents); - //console.log ("MONITOR DATA AFTER APPLYING : " + JSON.stringify($scope.monitors)); + NVRDataModel.debug("Completed events API:" + completedEvents); + NVRDataModel.debug("Ongoing events API:+" + ongoingEvents); - $scope.navControls = false; - var navControls = false; + isProcessNewEventsWaiting = true; - //drawGraph(fromDate, toDate, maxItems); - //dummyDrawGraph(fromDate, toDate,maxItems); + var $httpApi = $http.get(completedEvents); + var $httpOngoing = $http.get(ongoingEvents); - //------------------------------------------------- - // Rest graph to sane state after you went - // wild zooming and panning :-) - //------------------------------------------------- - $scope.fit = function() - { - timeline.fit(); - }; + $q.all([$httpApi, $httpOngoing]) + .then(function (dataarray) { - $scope.toggleNav = function() - { - if (navControls == true) - { - navControls = !navControls; - // $scope.navControls = navControls; - // give out animation time - $timeout(function() - { - $scope.navControls = navControls; - }, 2000); - } - else - { - navControls = !navControls; - $scope.navControls = navControls; - } - var element = angular.element(document.getElementById("timeline-ctrl")); + var myevents = dataarray[0].data.events; - if (navControls) - { - element.removeClass("animated bounceOutLeft"); - element.addClass("animated bounceInRight"); - } - else - { - element.removeClass("animated bounceInRight"); - element.addClass("animated bounceOutLeft"); - } + if (dataarray.length > 1) { + myevents = myevents.concat(dataarray[1].data.events); - }; + } - function shortenTime(str) - { - if (NVRDataModel.getLogin().useLocalTimeZone) - return moment.tz(str, NVRDataModel.getTimeZoneNow()).tz(moment.tz.guess()).format(NVRDataModel.getTimeFormat()); - else - return moment(str).format(NVRDataModel.getTimeFormat()); - } + $scope.newEvents = ''; + var localNewEvents = ''; + //console.log ("GOT "+JSON.stringify(data)); - $scope.toggleFollowTime = function() - { - /*if ($scope.currentMode != 'day') { - $rootScope.zmPopup = $ionicPopup.alert({ - title: $translate.instant('kError'), - template: $translate.instant('kFollowError') - }); - return; - }*/ - $scope.follow.time = !$scope.follow.time; - var loginData = NVRDataModel.getLogin(); - loginData.followTimeLine = $scope.follow.time; - NVRDataModel.setLogin(loginData); - }; - //------------------------------------------------- - // Called with day/week/month - // so we can redraw the graph - //------------------------------------------------- + for (var j = 0; j < myevents.length; j++) { - $scope.buttonClicked = function(index) - { - //console.log (index); - if (index == 0) //month - { - $scope.follow.time = NVRDataModel.getLogin().followTimeLine; - $scope.currentMode = "month"; - NVRDataModel.log("Month view"); - $rootScope.customTimelineRange = false; - - toDate = moment().format("YYYY-MM-DD HH:mm:ss"); - fromDate = moment().subtract(1, 'month').startOf('day').format("YYYY-MM-DD HH:mm:ss"); - $scope.fromDate = fromDate; - $scope.toDate = toDate; - drawGraph(fromDate, toDate, maxItems); - } - else if (index == 1) //week - { - $scope.follow.time = NVRDataModel.getLogin().followTimeLine; - $scope.currentMode = "week"; - $rootScope.customTimelineRange = false; - NVRDataModel.log("Week view"); - toDate = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()).format("YYYY-MM-DD HH:mm:ss"); - fromDate = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()).subtract(1, 'week').startOf('day').format("YYYY-MM-DD HH:mm:ss"); - $scope.fromDate = fromDate; - $scope.toDate = toDate; - drawGraph(fromDate, toDate, maxItems); - } - else if (index == 2) //day - { + // these are all in server timezone but no TZ - $scope.currentMode = "day"; - $rootScope.customTimelineRange = false; - NVRDataModel.log("Day view"); - //toDate = moment().format("YYYY-MM-DD HH:mm:ss"); - fromDate = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()).startOf('day').format("YYYY-MM-DD HH:mm:ss"); - toDate = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()).endOf('day').format("YYYY-MM-DD HH:mm:ss"); - $scope.fromDate = fromDate; - $scope.toDate = toDate; - drawGraph(fromDate, toDate, maxItems); - } - else // custom - { - $scope.follow.time = NVRDataModel.getLogin().followTimeLine; - $scope.currentMode = "custom"; - $rootScope.customTimelineRange = true; - $state.go('app.events-date-time-filter'); - return; - } + myevents[j].Event.StartTime = moment.tz(myevents[j].Event.StartTime, NVRDataModel.getTimeZoneNow()).format('YYYY-MM-DD HH:mm:ss'); - }; + myevents[j].Event.EndTime = moment.tz(myevents[j].Event.EndTime, NVRDataModel.getTimeZoneNow()).format('YYYY-MM-DD HH:mm:ss'); - /** - * [processNewEvents is called every X seconds when dynamic update is on. X = 10 for now] - * @return {[type]} - */ - function processNewEvents() - { + var itm = graphData.get(myevents[j].Event.Id); + if (itm) { + // console.log(myevents[j].Event.Id + " already exists, updating params"); - //safeguard in the event http calls are still going on - if (!$scope.follow.time || isProcessNewEventsWaiting) return; + var content = "<span class='my-vis-font'>" + "(" + myevents[j].Event.Id + ")" + myevents[j].Event.Notes + " " + $translate.instant('kRecordingProgress') + "</span>"; - var ld = NVRDataModel.getLogin(); + var style; + var recordingInProgress = false; - // check for last 2 minutes to account for late DB updates and what not. 5 mins was likely enough - // + if (moment(myevents[j].Event.EndTime).isValid()) // recording over + { + //console.log ("EVENT "+myevents[j].Event.Id+" emded at "+myevents[j].Event.EndTime); - // make sure these are server time - var from = moment(lastTimeForEvent).tz(NVRDataModel.getTimeZoneNow()); - from = from.subtract(2, 'minutes').locale('en').format("YYYY-MM-DD HH:mm:ss"); + content = "<span class='my-vis-font'>" + "( <i class='ion-android-notifications'></i>" + myevents[j].Event.AlarmFrames + ") " + " (" + myevents[j].Event.Id + ") " + myevents[j].Event.Notes + "</span>"; - var to = moment(lastTimeForEvent).tz(NVRDataModel.getTimeZoneNow()); - to = to.locale('en').format("YYYY-MM-DD HH:mm:ss"); + style = "background-color:" + colors[parseInt(myevents[j].Event.MonitorId) % colors.length] + + ";border-color:" + colors[parseInt(myevents[j].Event.MonitorId) % colors.length]; + } else // still recording + { - lastTimeForEvent = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()); + var tze; + tze = moment().tz(NVRDataModel.getTimeZoneNow()); - // FIXME: totally ignoring event pages - hoping it wont be more than 100 or 150 whatever - // the events per page limit is. Why? laziness. - // - var completedEvents = ld.apiurl + '/events/index/EndTime >=:' + from; - // we can add alarmCount as this is really for completed events - //completedEvents = completedEvents + "/AlarmFrames >=:" + (ld.enableAlarmCount ? ld.minAlarmCount : 0); + myevents[j].Event.EndTime = tze.format('YYYY-MM-DD HH:mm:ss'); - completedEvents = completedEvents + ".json"; + //console.log ("END TIME = "+ myevents[j].Event.EndTime); - // now get currently ongoing events - // as it turns out various events get stored withn null and never recover - // so, lets limiy to 15 m - // + style = "background-color:orange"; + recordingInProgress = true; - var st = moment(lastTimeForEvent).tz(NVRDataModel.getTimeZoneNow()); - st = st.subtract(10, 'minutes').locale('en').format("YYYY-MM-DD HH:mm:ss"); - var ongoingEvents = ld.apiurl + '/events/index/StartTime >=:' + st + '/EndTime =:.json'; - //NVRDataModel.debug("Getting incremental events using: " + completedEvents); + } - NVRDataModel.debug("Completed events API:" + completedEvents); - NVRDataModel.debug("Ongoing events API:+" + ongoingEvents); + // right at this point we need to decide if we keep or remove this event + // - isProcessNewEventsWaiting = true; + if (ld.enableAlarmCount && ld.minAlarmCount > myevents[j].Event.AlarmFrames && !recordingInProgress) { + // remove + NVRDataModel.debug("Removing Event:" + myevents[j].Event.Id + "as it doesn't have " + myevents[j].Event.AlarmFrames + " alarm frames"); + // var old = timeline.getWindow(); + graphData.remove(myevents[j].Event.Id); + // timeline.setWindow (old.start, old.end); + } else { - var $httpApi = $http.get(completedEvents); - var $httpOngoing = $http.get(ongoingEvents); + var tzs1, tze1; + if (NVRDataModel.getLogin().useLocalTimeZone) { + tzs1 = moment.tz(myevents[j].Event.StartTime, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); + tze1 = moment.tz(myevents[j].Event.EndTime, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); + } else { + tzs1 = moment.tz(myevents[j].Event.StartTime, NVRDataModel.getTimeZoneNow()); + tze1 = moment.tz(myevents[j].Event.EndTime, NVRDataModel.getTimeZoneNow()); + } - $q.all([$httpApi, $httpOngoing]) - .then(function(dataarray) - { + //tzs1 = tzs1.format("YYYY-MM-DD HH:mm:ss"); + //tze1 = tze1.format("YYYY-MM-DD HH:mm:ss"); + + NVRDataModel.debug("Updating Event:" + myevents[j].Event.Id + "StartTime:" + tzs1.format() + " EndTime:" + tze1.format()); + graphData.update({ + id: myevents[j].Event.Id, + content: content, + start: tzs1, + // start: myevents[j].Event.StartTime, + // end: myevents[j].Event.EndTime, + end: tze1, + //group: myevents[j].Event.MonitorId, + //type: "range", + style: style, + myframes: myevents[j].Event.Frames, + mydur: myevents[j].Event.Length, + myeid: myevents[j].Event.Id, + myename: myevents[j].Event.Name, + myvideo: myevents[j].Event.DefaultVideo, + myevent: myevents[j] + + }); - var myevents = dataarray[0].data.events; + //timeline.focus(myevents[j].Event.Id); + // + timeline.moveTo(timeline.getCurrentTime()); + //console.log ("Focus EID="+myevents[j].Event.Id); + localNewEvents = localNewEvents + NVRDataModel.getMonitorName(myevents[j].Event.MonitorId) + '@' + shortenTime(myevents[j].Event.StartTime) + ' (' + myevents[j].Event.Id + '),'; - if (dataarray.length > 1) - { - myevents = myevents.concat(dataarray[1].data.events); + } - } + } else { // event is new - $scope.newEvents = ''; - var localNewEvents = ''; - //console.log ("GOT "+JSON.stringify(data)); - - for (var j = 0; j < myevents.length; j++) - { - - // these are all in server timezone but no TZ - - myevents[j].Event.StartTime = moment.tz(myevents[j].Event.StartTime, NVRDataModel.getTimeZoneNow()).format('YYYY-MM-DD HH:mm:ss'); - - myevents[j].Event.EndTime = moment.tz(myevents[j].Event.EndTime, NVRDataModel.getTimeZoneNow()).format('YYYY-MM-DD HH:mm:ss'); - - var itm = graphData.get(myevents[j].Event.Id); - if (itm) - { - // console.log(myevents[j].Event.Id + " already exists, updating params"); - - var content = "<span class='my-vis-font'>" + "(" + myevents[j].Event.Id + ")" + myevents[j].Event.Notes + " " + $translate.instant('kRecordingProgress') + "</span>"; - - var style; - var recordingInProgress = false; - - if (moment(myevents[j].Event.EndTime).isValid()) // recording over - { - //console.log ("EVENT "+myevents[j].Event.Id+" emded at "+myevents[j].Event.EndTime); - - content = "<span class='my-vis-font'>" + "( <i class='ion-android-notifications'></i>" + myevents[j].Event.AlarmFrames + ") " + " (" + myevents[j].Event.Id + ") " + myevents[j].Event.Notes + "</span>"; - - style = "background-color:" + colors[parseInt(myevents[j].Event.MonitorId) % colors.length] + - ";border-color:" + colors[parseInt(myevents[j].Event.MonitorId) % colors.length]; - } - else // still recording - { - - var tze; - tze = moment().tz(NVRDataModel.getTimeZoneNow()); - - myevents[j].Event.EndTime = tze.format('YYYY-MM-DD HH:mm:ss'); - - //console.log ("END TIME = "+ myevents[j].Event.EndTime); - - style = "background-color:orange"; - recordingInProgress = true; - - } - - // right at this point we need to decide if we keep or remove this event - // - - if (ld.enableAlarmCount && ld.minAlarmCount > myevents[j].Event.AlarmFrames && !recordingInProgress) - { - // remove - NVRDataModel.debug("Removing Event:" + myevents[j].Event.Id + "as it doesn't have " + myevents[j].Event.AlarmFrames + " alarm frames"); - // var old = timeline.getWindow(); - graphData.remove(myevents[j].Event.Id); - // timeline.setWindow (old.start, old.end); - } - else - { - - var tzs1, tze1; - if (NVRDataModel.getLogin().useLocalTimeZone) - { - tzs1 = moment.tz(myevents[j].Event.StartTime, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); - tze1 = moment.tz(myevents[j].Event.EndTime, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); - } - else - { - tzs1 = moment.tz(myevents[j].Event.StartTime, NVRDataModel.getTimeZoneNow()); - tze1 = moment.tz(myevents[j].Event.EndTime, NVRDataModel.getTimeZoneNow()); - } - - //tzs1 = tzs1.format("YYYY-MM-DD HH:mm:ss"); - //tze1 = tze1.format("YYYY-MM-DD HH:mm:ss"); - - NVRDataModel.debug("Updating Event:" + myevents[j].Event.Id + "StartTime:" + tzs1.format() + " EndTime:" + tze1.format()); - graphData.update( - { - id: myevents[j].Event.Id, - content: content, - start: tzs1, - // start: myevents[j].Event.StartTime, - // end: myevents[j].Event.EndTime, - end: tze1, - //group: myevents[j].Event.MonitorId, - //type: "range", - style: style, - myframes: myevents[j].Event.Frames, - mydur: myevents[j].Event.Length, - myeid: myevents[j].Event.Id, - myename: myevents[j].Event.Name, - myvideo: myevents[j].Event.DefaultVideo, - myevent: myevents[j] - - }); - - //timeline.focus(myevents[j].Event.Id); - // - timeline.moveTo(timeline.getCurrentTime()); - //console.log ("Focus EID="+myevents[j].Event.Id); - localNewEvents = localNewEvents + NVRDataModel.getMonitorName(myevents[j].Event.MonitorId) + '@' + shortenTime(myevents[j].Event.StartTime) + ' (' + myevents[j].Event.Id + '),'; - - } - - } - else - { // event is new - - var isBeingRecorded = false; - var idfound = false; - for (var ii = 0; ii < $scope.monitors.length; ii++) - { - if ($scope.monitors[ii].Monitor.Id == myevents[j].Event.MonitorId && NVRDataModel.isNotHidden(myevents[j].Event.MonitorId)) - { - idfound = true; - break; - } - } - - if (idfound) - { - - myevents[j].Event.MonitorName = NVRDataModel.getMonitorName(myevents[j].Event.MonitorId); - - myevents[j].Event.streamingURL = NVRDataModel.getStreamingURL(myevents[j].Event.MonitorId); - myevents[j].Event.baseURL = NVRDataModel.getBaseURL(myevents[j].Event.MonitorId); - myevents[j].Event.imageMode = NVRDataModel.getImageMode(myevents[j].Event.MonitorId); - if (NVRDataModel.getLogin().url != myevents[j].Event.baseURL) - { - - myevents[j].Event.baseURL = NVRDataModel.getLogin().url; - } - - if (typeof myevents[j].Event.DefaultVideo === 'undefined') - // console.log (JSON.stringify(myevents[j])); - myevents[j].Event.DefaultVideo = ""; - - // now lets make sure we don't infinitely increase - - if (graphIndex >= curCount) - //if (1) - { - var mv = graphData.min('id'); - //console.log("MIN="+JSON.stringify(mv)); - if (mv) - { - graphData.remove(mv.id); - graphIndex--; - NVRDataModel.debug("Removed Event " + mv.id + " to make space"); - } - - } - - // since this is a new add its possible dates are not defined - if (!moment(myevents[j].Event.StartTime).isValid()) - { - NVRDataModel.log("Event:" + myevents[j].Event.Id + "-Invalid Start time - this should really not happen "); - - } - - if (!moment(myevents[j].Event.EndTime).isValid()) - { - var t1 = moment().tz(NVRDataModel.getTimeZoneNow()); - - myevents[j].Event.EndTime = t1.format('YYYY-MM-DD HH:mm:ss'); - - NVRDataModel.debug("Event:" + myevents[j].Event.Id + "-End time is invalid, setting to current time"); - - isBeingRecorded = true; - - } - - // if range doesn't allow for current time, we need to fix that - /*if (moment(options.max).isBefore(moment())) { - // console.log("Adjusting Range to fit in new event"); - options.max = moment().add('1', 'hours').locale('en').format("YYYY-MM-DD HH:mm:ss"); - timeline.setOptions(options); - }*/ - - var eventText = "<span class='my-vis-font'>" + "( <i class='ion-android-notifications'></i>" + (myevents[j].Event.AlarmFrames || ' unknown ') + ") " + myevents[j].Event.Notes + "</span>"; - - if (isBeingRecorded) - { - eventText = "<span class='my-vis-font'>" + "(" + myevents[j].Event.Id + ") " + myevents[j].Event.Notes + " " + $translate.instant('kRecordingProgress') + "</span>"; - } - - // since we concated, its possible events may be repeated - if (!graphData.get(myevents[j].Event.Id)) - { - - localNewEvents = localNewEvents + NVRDataModel.getMonitorName(myevents[j].Event.MonitorId) + '@' + shortenTime(myevents[j].Event.StartTime) + ' (' + myevents[j].Event.Id + '),'; - - var tzs2, tze2; - if (NVRDataModel.getLogin().useLocalTimeZone) - { - tzs2 = moment.tz(myevents[j].Event.StartTime, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); - tze2 = moment.tz(myevents[j].Event.EndTime, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); - } - else - { - tzs2 = moment.tz(myevents[j].Event.StartTime, NVRDataModel.getTimeZoneNow()); - tze2 = moment.tz(myevents[j].Event.EndTime, NVRDataModel.getTimeZoneNow()); - } - - //tzs2 = tzs2.format("YYYY-MM-DD HH:mm:ss"); - //tze2 = tze2.format("YYYY-MM-DD HH:mm:ss"); - - NVRDataModel.debug(">>> " + myevents[j].Event.Id + " New event updating graph " + " from:" + tzs2.format() + " to:" + tze2.format()); - - graphData.add( - { - - id: myevents[j].Event.Id, - content: eventText, - start: tzs2, - //start: myevents[j].Event.StartTime, - // end: myevents[j].Event.EndTime, - end: tze2, - group: myevents[j].Event.MonitorId, - style: "background-color:orange", - //type: "range", - - myframes: myevents[j].Event.Frames, - mydur: myevents[j].Event.Length, - myeid: myevents[j].Event.Id, - myename: myevents[j].Event.Name, - myvideo: myevents[j].Event.DefaultVideo, - myevent: myevents[j] - - }); - graphIndex++; - //timeline.focus(myevents[j].Event.Id); - timeline.moveTo(timeline.getCurrentTime()); - } - - //options.max = moment(fromDate).locale('en').format("YYYY-MM-DD HH:mm:ss"); - - } //idfound - - } // new event - - } // for j - - // At this stage, see if we need to display new events - if (localNewEvents.length > 0) - { - localNewEvents = $translate.instant('kLatestEvents') + ':' + localNewEvents; - localNewEvents = localNewEvents.slice(0, -1); - $scope.newEvents = localNewEvents; - } - isProcessNewEventsWaiting = false; + var isBeingRecorded = false; + var idfound = false; + for (var ii = 0; ii < $scope.monitors.length; ii++) { + if ($scope.monitors[ii].Monitor.Id == myevents[j].Event.MonitorId && NVRDataModel.isNotHidden(myevents[j].Event.MonitorId)) { + idfound = true; + break; + } + } + + if (idfound) { + + myevents[j].Event.MonitorName = NVRDataModel.getMonitorName(myevents[j].Event.MonitorId); + + myevents[j].Event.streamingURL = NVRDataModel.getStreamingURL(myevents[j].Event.MonitorId); + myevents[j].Event.baseURL = NVRDataModel.getBaseURL(myevents[j].Event.MonitorId); + myevents[j].Event.imageMode = NVRDataModel.getImageMode(myevents[j].Event.MonitorId); + if (NVRDataModel.getLogin().url != myevents[j].Event.baseURL) { + + myevents[j].Event.baseURL = NVRDataModel.getLogin().url; + } - }, - function(err) + if (typeof myevents[j].Event.DefaultVideo === 'undefined') + // console.log (JSON.stringify(myevents[j])); + myevents[j].Event.DefaultVideo = ""; + + // now lets make sure we don't infinitely increase + + if (graphIndex >= curCount) + //if (1) { - NVRDataModel.debug("Error getting incremental timeline data"); - isProcessNewEventsWaiting = false; + var mv = graphData.min('id'); + //console.log("MIN="+JSON.stringify(mv)); + if (mv) { + graphData.remove(mv.id); + graphIndex--; + NVRDataModel.debug("Removed Event " + mv.id + " to make space"); + } - }); + } - // check all events that started 10+10 seconds ago + // since this is a new add its possible dates are not defined + if (!moment(myevents[j].Event.StartTime).isValid()) { + NVRDataModel.log("Event:" + myevents[j].Event.Id + "-Invalid Start time - this should really not happen "); - } + } - //------------------------------------------------- - // This function draws the graph - //------------------------------------------------- + if (!moment(myevents[j].Event.EndTime).isValid()) { + var t1 = moment().tz(NVRDataModel.getTimeZoneNow()); - function drawGraph(fromDate, toDate, count) - { + myevents[j].Event.EndTime = t1.format('YYYY-MM-DD HH:mm:ss'); - // console.log("INSIDE DRAW"); + NVRDataModel.debug("Event:" + myevents[j].Event.Id + "-End time is invalid, setting to current time"); - $scope.newEvents = ""; - // we only need this for day mode - $interval.cancel(updateInterval); + isBeingRecorded = true; - curFromDate = fromDate; - curToDate = toDate; - curCount = count; + } - var isFirstItem = true; + // if range doesn't allow for current time, we need to fix that + /*if (moment(options.max).isBefore(moment())) { + // console.log("Adjusting Range to fit in new event"); + options.max = moment().add('1', 'hours').locale('en').format("YYYY-MM-DD HH:mm:ss"); + timeline.setOptions(options); + }*/ - var fromDateNoLang = moment(fromDate).locale('en').format("YYYY-MM-DD HH:mm:ss"); - var toDateNoLang = moment(toDate).locale('en').format("YYYY-MM-DD HH:mm:ss"); + var eventText = "<span class='my-vis-font'>" + "( <i class='ion-android-notifications'></i>" + (myevents[j].Event.AlarmFrames || ' unknown ') + ") " + myevents[j].Event.Notes + "</span>"; - //latestDateDrawn =toDateNoLang; + if (isBeingRecorded) { + eventText = "<span class='my-vis-font'>" + "(" + myevents[j].Event.Id + ") " + myevents[j].Event.Notes + " " + $translate.instant('kRecordingProgress') + "</span>"; + } + + // since we concated, its possible events may be repeated + if (!graphData.get(myevents[j].Event.Id)) { + + localNewEvents = localNewEvents + NVRDataModel.getMonitorName(myevents[j].Event.MonitorId) + '@' + shortenTime(myevents[j].Event.StartTime) + ' (' + myevents[j].Event.Id + '),'; + + var tzs2, tze2; + if (NVRDataModel.getLogin().useLocalTimeZone) { + tzs2 = moment.tz(myevents[j].Event.StartTime, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); + tze2 = moment.tz(myevents[j].Event.EndTime, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); + } else { + tzs2 = moment.tz(myevents[j].Event.StartTime, NVRDataModel.getTimeZoneNow()); + tze2 = moment.tz(myevents[j].Event.EndTime, NVRDataModel.getTimeZoneNow()); + } + + //tzs2 = tzs2.format("YYYY-MM-DD HH:mm:ss"); + //tze2 = tze2.format("YYYY-MM-DD HH:mm:ss"); + + NVRDataModel.debug(">>> " + myevents[j].Event.Id + " New event updating graph " + " from:" + tzs2.format() + " to:" + tze2.format()); + + graphData.add({ + + id: myevents[j].Event.Id, + content: eventText, + start: tzs2, + //start: myevents[j].Event.StartTime, + // end: myevents[j].Event.EndTime, + end: tze2, + group: myevents[j].Event.MonitorId, + style: "background-color:orange", + //type: "range", + + myframes: myevents[j].Event.Frames, + mydur: myevents[j].Event.Length, + myeid: myevents[j].Event.Id, + myename: myevents[j].Event.Name, + myvideo: myevents[j].Event.DefaultVideo, + myevent: myevents[j] + + }); + graphIndex++; + //timeline.focus(myevents[j].Event.Id); + timeline.moveTo(timeline.getCurrentTime()); + } + + //options.max = moment(fromDate).locale('en').format("YYYY-MM-DD HH:mm:ss"); + + } //idfound + + } // new event + + } // for j + + // At this stage, see if we need to display new events + if (localNewEvents.length > 0) { + localNewEvents = $translate.instant('kLatestEvents') + ':' + localNewEvents; + localNewEvents = localNewEvents.slice(0, -1); + $scope.newEvents = localNewEvents; + } + isProcessNewEventsWaiting = false; + + }, + function (err) { + NVRDataModel.debug("Error getting incremental timeline data"); + isProcessNewEventsWaiting = false; - $ionicLoading.show( - { - template: $translate.instant('kLoadingGraph') + "...", - animation: 'fade-in', - showBackdrop: true, - maxWidth: 200, - showDelay: 0, - duration: zm.loadingTimeout, //specifically for Android - http seems to get stuck at times }); - NVRDataModel.log("TimelineCtrl/drawgraph: from->" + fromDateNoLang + " to->" + toDateNoLang + " count:" + count); - $scope.graphLoaded = false; - NVRDataModel.debug("TimelineCtrl/drawgraph: graphLoaded:" + $scope.graphLoaded); + // check all events that started 10+10 seconds ago - if (timeline) - { - NVRDataModel.debug("TimelineCtrl/drawgraph: destroying timeline as it exists"); - timeline.destroy(); - } + } + + //------------------------------------------------- + // This function draws the graph + //------------------------------------------------- + + function drawGraph(fromDate, toDate, count) { + + // console.log("INSIDE DRAW"); + + $scope.newEvents = ""; + // we only need this for day mode + $interval.cancel(updateInterval); + + curFromDate = fromDate; + curToDate = toDate; + curCount = count; + + var isFirstItem = true; + + var fromDateNoLang = moment(fromDate).locale('en').format("YYYY-MM-DD HH:mm:ss"); + var toDateNoLang = moment(toDate).locale('en').format("YYYY-MM-DD HH:mm:ss"); + + //latestDateDrawn =toDateNoLang; + + $ionicLoading.show({ + template: $translate.instant('kLoadingGraph') + "...", + animation: 'fade-in', + showBackdrop: true, + maxWidth: 200, + showDelay: 0, + duration: zm.loadingTimeout, //specifically for Android - http seems to get stuck at times + }); + + NVRDataModel.log("TimelineCtrl/drawgraph: from->" + fromDateNoLang + " to->" + toDateNoLang + " count:" + count); + $scope.graphLoaded = false; + NVRDataModel.debug("TimelineCtrl/drawgraph: graphLoaded:" + $scope.graphLoaded); + + if (timeline) { + NVRDataModel.debug("TimelineCtrl/drawgraph: destroying timeline as it exists"); + timeline.destroy(); + } - groups = new vis.DataSet(); - graphData = new vis.DataSet(); - //console.log ("AFTER VIS"); + groups = new vis.DataSet(); + graphData = new vis.DataSet(); + //console.log ("AFTER VIS"); - var tzs, tze; + var tzs, tze; - // lets scope the time graph to either local or remote time zone + // lets scope the time graph to either local or remote time zone + if (NVRDataModel.getLogin().useLocalTimeZone) { + tzs = moment.tz(fromDate, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); + tze = moment.tz(toDate, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); + } else { + tzs = moment.tz(fromDate, NVRDataModel.getTimeZoneNow()); + tze = moment.tz(toDate, NVRDataModel.getTimeZoneNow()); + } + + //tzs = tzs.format("YYYY-MM-DD HH:mm:ss"); + //tze = tze.format("YYYY-MM-DD HH:mm:ss"); + + options = { + + showCurrentTime: true, + editable: false, + moment: function (date) { + + //var t; if (NVRDataModel.getLogin().useLocalTimeZone) - { - tzs = moment.tz(fromDate, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); - tze = moment.tz(toDate, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); - } + //if (0) + return moment.tz(date, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); else - { - tzs = moment.tz(fromDate, NVRDataModel.getTimeZoneNow()); - tze = moment.tz(toDate, NVRDataModel.getTimeZoneNow()); + // typecast to server time zone - its in server time anyway + return moment.tz(date, NVRDataModel.getTimeZoneNow()); + }, + //throttleRedraw: 100, + moveable: true, + zoomable: true, + selectable: true, + start: tzs, + end: tze, + orientation: 'top', + min: tzs, + //max: tze, + zoomMin: 5 * 60 * 1000, // 1 min + stack: false, + format: { + minorLabels: { + minute: NVRDataModel.getTimeFormat(), + hour: NVRDataModel.getTimeFormat(), + second: 's', + }, + majorLabels: { + second: "D MMM " + NVRDataModel.getTimeFormat(), } + }, - //tzs = tzs.format("YYYY-MM-DD HH:mm:ss"); - //tze = tze.format("YYYY-MM-DD HH:mm:ss"); + }; - options = { + graphIndex = 1; // will be used for graph ID - showCurrentTime: true, - editable: false, - moment: function(date) - { + //console.log ("**NOLANG" + fromDateNoLang + " " + toDateNoLang); - //var t; - if (NVRDataModel.getLogin().useLocalTimeZone) - //if (0) - return moment.tz(date, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); - else - // typecast to server time zone - its in server time anyway - return moment.tz(date, NVRDataModel.getTimeZoneNow()); - }, - //throttleRedraw: 100, - moveable: true, - zoomable: true, - selectable: true, - start: tzs, - end: tze, - orientation: 'top', - min: tzs, - //max: tze, - zoomMin: 5 * 60 * 1000, // 1 min - stack: false, - format: - { - minorLabels: - { - minute: NVRDataModel.getTimeFormat(), - hour: NVRDataModel.getTimeFormat(), - second: 's', - }, - majorLabels: - { - second: "D MMM " + NVRDataModel.getTimeFormat(), - } - }, + NVRDataModel.getEventsPages(0, fromDateNoLang, toDateNoLang) + .then(function (data) { + var pages = data.pageCount || 1; + var itemsPerPage = parseInt(data.limit); + var iterCount; - }; + // So iterCount is the # of HTTP calls I need to make + iterCount = Math.max(Math.round(count / itemsPerPage), 1); + NVRDataModel.debug("TimelineCtrl/drawGraph: pages of data: " + pages + " items per page: " + itemsPerPage); + NVRDataModel.debug("TimelineCtrl/drawGraph: I will make " + iterCount + " HTTP Requests to get all graph data"); - graphIndex = 1; // will be used for graph ID + // I've restructured this part. I was initially using vis DataSets + // for dynamic binding which was easier, but due to performance reasons + // I am waiting for the full data to load before I draw + var promises = []; + while ((pages > 0) && (iterCount > 0)) { + var promise = NVRDataModel.getEvents(0, pages, "none", fromDateNoLang, toDateNoLang); + promises.push(promise); + pages--; + iterCount--; - //console.log ("**NOLANG" + fromDateNoLang + " " + toDateNoLang); + } - NVRDataModel.getEventsPages(0, fromDateNoLang, toDateNoLang) - .then(function(data) - { - var pages = data.pageCount || 1; - var itemsPerPage = parseInt(data.limit); - var iterCount; + $q.all(promises) + .then(function (data) { + NVRDataModel.debug("TimelineCtrl/drawgraph: all pages of graph data received"); + graphIndex = 0; + NVRDataModel.log("Creating " + $scope.monitors.length + " groups for the graph"); + // create groups + for (var g = 0; g < $scope.monitors.length; g++) { + groups.add({ + id: $scope.monitors[g].Monitor.Id, + //mid: $scope.monitors[g].Monitor.Id, + content: NVRDataModel.getMonitorName($scope.monitors[g].Monitor.Id), + order: $scope.monitors[g].Monitor.Sequence + }); + NVRDataModel.debug("TimelineCtrl/drawgraph:Adding group " + + NVRDataModel.getMonitorName($scope.monitors[g].Monitor.Id)); + } - // So iterCount is the # of HTTP calls I need to make - iterCount = Math.max(Math.round(count / itemsPerPage), 1); - NVRDataModel.debug("TimelineCtrl/drawGraph: pages of data: " + pages + " items per page: " + itemsPerPage); - NVRDataModel.debug("TimelineCtrl/drawGraph: I will make " + iterCount + " HTTP Requests to get all graph data"); + for (var j = 0; j < data.length; j++) { + var myevents = data[j]; - // I've restructured this part. I was initially using vis DataSets - // for dynamic binding which was easier, but due to performance reasons - // I am waiting for the full data to load before I draw - var promises = []; - while ((pages > 0) && (iterCount > 0)) - { - var promise = NVRDataModel.getEvents(0, pages, "none", fromDateNoLang, toDateNoLang); - promises.push(promise); - pages--; - iterCount--; + if (graphIndex > count) { + NVRDataModel.log("Exiting page count graph - reached limit of " + count); + break; } - $q.all(promises) - .then(function(data) - { - NVRDataModel.debug("TimelineCtrl/drawgraph: all pages of graph data received"); - graphIndex = 0; - NVRDataModel.log("Creating " + $scope.monitors.length + " groups for the graph"); - // create groups - for (var g = 0; g < $scope.monitors.length; g++) - { - groups.add( - { - id: $scope.monitors[g].Monitor.Id, - //mid: $scope.monitors[g].Monitor.Id, - content: NVRDataModel.getMonitorName($scope.monitors[g].Monitor.Id), - order: $scope.monitors[g].Monitor.Sequence - }); - NVRDataModel.debug("TimelineCtrl/drawgraph:Adding group " + - NVRDataModel.getMonitorName($scope.monitors[g].Monitor.Id)); - } - - for (var j = 0; j < data.length; j++) - { - var myevents = data[j]; - - if (graphIndex > count) - { - NVRDataModel.log("Exiting page count graph - reached limit of " + count); - break; - - } - - for (var i = 0; i < myevents.length; i++) - { - - // make sure group id exists before adding - var idfound = true; - var ld = NVRDataModel.getLogin(); - - if (ld.persistMontageOrder) - { - - idfound = false; - for (var ii = 0; ii < $scope.monitors.length; ii++) - { - if ($scope.monitors[ii].Monitor.Id == myevents[i].Event.MonitorId && NVRDataModel.isNotHidden(myevents[i].Event.MonitorId)) - { - idfound = true; - //console.log ("****************** ID MATCH " + graphIndex); - - break; - } - } - } - - myevents[i].Event.MonitorName = NVRDataModel.getMonitorName(myevents[i].Event.MonitorId); - // now construct base path - - myevents[i].Event.streamingURL = NVRDataModel.getStreamingURL(myevents[i].Event.MonitorId); - myevents[i].Event.baseURL = NVRDataModel.getBaseURL(myevents[i].Event.MonitorId); - myevents[i].Event.imageMode = NVRDataModel.getImageMode(myevents[i].Event.MonitorId); - if (NVRDataModel.getLogin().url != myevents[i].Event.baseURL) - { - //NVRDataModel.debug ("Multi server, changing base"); - myevents[i].Event.baseURL = NVRDataModel.getLogin().url; - - } - // console.log ("***** MULTISERVER STREAMING URL FOR EVENTS " + myevents[i].Event.streamingURL); - - // console.log ("***** MULTISERVER BASE URL FOR EVENTS " + myevents[i].Event.baseURL); - - if (idfound) - { - - if (typeof myevents[i].Event.DefaultVideo === 'undefined') - // console.log (JSON.stringify(myevents[i])); - myevents[i].Event.DefaultVideo = ""; - - //console.log ("ADDING "+myevents[i].Event.StartTime+"->"+myevents[i].Event.EndTime); - - var tzs, tze; - if (NVRDataModel.getLogin().useLocalTimeZone) - { - tzs = moment.tz(myevents[i].Event.StartTime, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); - tze = moment.tz(myevents[i].Event.EndTime, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); - } - else - { - tzs = moment.tz(myevents[i].Event.StartTime, NVRDataModel.getTimeZoneNow()); - tze = moment.tz(myevents[i].Event.EndTime, NVRDataModel.getTimeZoneNow()); - } - - //console.log ("ADDED "+tzs+" " +tze); - graphData.add( - { - //id: graphIndex, - id: myevents[i].Event.Id, - content: "<span class='my-vis-font'>" + "( <i class='ion-android-notifications'></i>" + myevents[i].Event.AlarmFrames + ") " + "(" + myevents[j].Event.Id + ") " + myevents[i].Event.Notes + "</span>", - - start: tzs, - //start: myevents[i].Event.StartTime, - //end: myevents[i].Event.EndTime, - end: tze, - group: myevents[i].Event.MonitorId, - //type: "range", - style: "background-color:" + colors[parseInt(myevents[i].Event.MonitorId) % colors.length] + - ";border-color:" + colors[parseInt(myevents[i].Event.MonitorId) % colors.length], - myframes: myevents[i].Event.Frames, - mydur: myevents[i].Event.Length, - myeid: myevents[i].Event.Id, - myename: myevents[i].Event.Name, - myvideo: myevents[i].Event.DefaultVideo, - myevent: myevents[i] - - }); - graphIndex++; - } - else - { - //console.log ("SKIPPED GRAPH ID " + graphIndex); - } - - if (graphIndex > count) - { - NVRDataModel.log("Exiting event graph - reached limit of " + count); - break; - - } - - } - } - - // console.log(">>>>> CREATING NEW TIMELINE with " + JSON.stringify(options)); - timeline = new vis.Timeline(container[0], null, options); - // console.log ("GRAPH DATA"); - timeline.setItems(graphData); - // console.log ("GROUPS"); - timeline.setGroups(groups); - - if (NVRDataModel.getLogin().timelineScale == -1) - - { - // console.log ("SCALE NOT FOUND"); - - timeline.fit(); - } - else - { - timeline.fit(); - - /*var d = NVRDataModel.getLogin().timelineScale; - console.log ("SCALE FOUND "+d+" SECONDS"); - var w = timeline.getWindow(); - console.log ("Original s="+w.start+" e="+w.end); - - - var s = moment.tz(w.end, NVRDataModel.getTimeZoneNow()).subtract(d,'seconds').tz(moment.tz.guess()); - - //var s = moment(w.start).format("YYYY-MM-DD HH:mm:ss"); - // - //var e = moment(w.start).add(d,'seconds').format("YYYY-MM-DD HH:mm:ss"); - - var e = moment.tz(w.end, NVRDataModel.getTimeZoneNow()).tz(moment.tz.guess()); - - console.log ("Start="+s+" End="+e); - $timeout (function() {timeline.setWindow(s,e);},1000);*/ - - } - - lastTimeForEvent = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()); - updateInterval = $interval(function() - { - processNewEvents(); - }.bind(this), 10 * 1000); - - $ionicLoading.hide(); - $scope.graphLoaded = true; - NVRDataModel.debug("graph loaded: " + $scope.graphLoaded); - $scope.navControls = false; - dblclick = false; - - // we don't really need this anymore - as we have an interval timer - // ticking away - - // this is called for each tick the bar moves - // speed moves depending on zoom factor - // - /* timeline.on('currentTimeTick', function() { - - if ($scope.follow.time) { - - } - - - });*/ - - timeline.on('rangechanged', function(s) - { - ///console.log ("Range Changed:"+JSON.stringify(s)); - if (s.byUser) - { - - var w = timeline.getWindow(); - //console.log ("start:"+w.start+" end:"+w.end); - var a = moment(w.start); - var b = moment(w.end); - var d = b.diff(a, 'seconds'); - var ld = NVRDataModel.getLogin(); - ld.timelineScale = d; - NVRDataModel.setLogin(ld); - //console.log ("Stored user scale of "+d+" seconds"); - } + for (var i = 0; i < myevents.length; i++) { - }); - - timeline.on('click', function(prop) - { - //console.log ("CLICK"); - if ($scope.onTap==$translate.instant('kTimelineGraph')) - timelineAnalyzeFrames(prop); - else - timelineShowEvent(prop); + // make sure group id exists before adding + var idfound = true; + var ld = NVRDataModel.getLogin(); + if (ld.persistMontageOrder) { - }); + idfound = false; + for (var ii = 0; ii < $scope.monitors.length; ii++) { + if ($scope.monitors[ii].Monitor.Id == myevents[i].Event.MonitorId && NVRDataModel.isNotHidden(myevents[i].Event.MonitorId)) { + idfound = true; + //console.log ("****************** ID MATCH " + graphIndex); - timeline.on('doubleClick', function(prop) - { - if ($scope.onDTap==$translate.instant('kTimelineGraph')) - timelineAnalyzeFrames(prop); - else - timelineShowEvent(prop); + break; + } + } + } - }); - }, - function(error) - { - NVRDataModel.displayBanner('error', 'Timeline error', 'Please try again'); + myevents[i].Event.MonitorName = NVRDataModel.getMonitorName(myevents[i].Event.MonitorId); + // now construct base path - } + myevents[i].Event.streamingURL = NVRDataModel.getStreamingURL(myevents[i].Event.MonitorId); + myevents[i].Event.baseURL = NVRDataModel.getBaseURL(myevents[i].Event.MonitorId); + myevents[i].Event.imageMode = NVRDataModel.getImageMode(myevents[i].Event.MonitorId); + if (NVRDataModel.getLogin().url != myevents[i].Event.baseURL) { + //NVRDataModel.debug ("Multi server, changing base"); + myevents[i].Event.baseURL = NVRDataModel.getLogin().url; - ); // get Events - }); - } + } + // console.log ("***** MULTISERVER STREAMING URL FOR EVENTS " + myevents[i].Event.streamingURL); - function timelineShowEvent(prop) { - $timeout(function() - { - if (dblclick) - { - //console.log ("IGNORING CLICK AS DBL CLICK"); - $timeout(function() - { - dblclick = false; - }, 400); - return; - } - //console.log ("CLICK"); - //console.log ("I GOT " + JSON.stringify(prop)); - // console.log ("EVENT IS " + JSON.stringify(properties.event)); - //var properties = timeline.getEventProperties(prop); - // console.log ( "I GOT " + properties); - var itm = prop.item; - //console.log ("ITEM CLICKED " + itm); - if (itm && !isNaN(itm)) - { - NVRDataModel.debug("TimelineCtrl/drawGraph:You clicked on item " + itm); - var item = graphData.get(itm); - NVRDataModel.debug("TimelineCtrl/drawGraph: clicked item details:" + JSON.stringify(item)); - showEvent(item.myevent); + // console.log ("***** MULTISERVER BASE URL FOR EVENTS " + myevents[i].Event.baseURL); - } - else - { - NVRDataModel.debug("exact match not found, guessing item with co-ordinates X=" + prop.x + " group=" + prop.group); - if (prop.group) - { - var visible = timeline.getVisibleItems(); - NVRDataModel.debug("Visible items=" + JSON.stringify(visible)); - var closestItem = null; - var minDist = 99999; - var _item; - for (var x = 0; x < visible.length; x++) - { - _item = timeline.itemSet.items[x]; - if (_item.data.group == prop.group) - { - if (Math.abs(_item.left - prop.x) < minDist) - { - closestItem = _item; - minDist = Math.abs(_item.left - prop.x); - NVRDataModel.debug("Temporary closest " + _item.left); - //console.log (_item); - } - } + if (idfound) { - } + if (typeof myevents[i].Event.DefaultVideo === 'undefined') + // console.log (JSON.stringify(myevents[i])); + myevents[i].Event.DefaultVideo = ""; - if (closestItem != null) - { - NVRDataModel.log("Closest item " + closestItem.left + " group: " + closestItem.data.group); - showEvent(closestItem.data.myevent); - } - else - { - NVRDataModel.log("Did not find a visible item match"); + //console.log ("ADDING "+myevents[i].Event.StartTime+"->"+myevents[i].Event.EndTime); + + var tzs, tze; + if (NVRDataModel.getLogin().useLocalTimeZone) { + tzs = moment.tz(myevents[i].Event.StartTime, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); + tze = moment.tz(myevents[i].Event.EndTime, NVRDataModel.getTimeZoneNow()).tz(NVRDataModel.getLocalTimeZoneNow()); + } else { + tzs = moment.tz(myevents[i].Event.StartTime, NVRDataModel.getTimeZoneNow()); + tze = moment.tz(myevents[i].Event.EndTime, NVRDataModel.getTimeZoneNow()); } - } - else // no group row tapped, do nothing - { - /*$ionicLoading.show({ - template: "", - animation: 'fade-in', - showBackdrop: true, - maxWidth: 200, - showDelay: 0, - duration: 1500, - });*/ + //console.log ("ADDED "+tzs+" " +tze); + graphData.add({ + //id: graphIndex, + id: myevents[i].Event.Id, + content: "<span class='my-vis-font'>" + "( <i class='ion-android-notifications'></i>" + myevents[i].Event.AlarmFrames + ") " + "(" + myevents[j].Event.Id + ") " + myevents[i].Event.Notes + "</span>", + + start: tzs, + //start: myevents[i].Event.StartTime, + //end: myevents[i].Event.EndTime, + end: tze, + group: myevents[i].Event.MonitorId, + //type: "range", + style: "background-color:" + colors[parseInt(myevents[i].Event.MonitorId) % colors.length] + + ";border-color:" + colors[parseInt(myevents[i].Event.MonitorId) % colors.length], + myframes: myevents[i].Event.Frames, + mydur: myevents[i].Event.Length, + myeid: myevents[i].Event.Id, + myename: myevents[i].Event.Name, + myvideo: myevents[i].Event.DefaultVideo, + myevent: myevents[i] + + }); + graphIndex++; + } else { + //console.log ("SKIPPED GRAPH ID " + graphIndex); + } + + if (graphIndex > count) { + NVRDataModel.log("Exiting event graph - reached limit of " + count); + break; + + } + } - // console.log("Zoomed out too far to playback events"); - } - }, 400); - } + } - function timelineAnalyzeFrames(prop) { - // console.log ("DOUBLE"); - dblclick = true; - var itm = prop.item; - //console.log ("ITEM CLICKED " + itm); - if (itm && !isNaN(itm)) - { - NVRDataModel.debug("TimelineCtrl/drawGraph:You clicked on item " + itm); - var item = graphData.get(itm); - NVRDataModel.debug("TimelineCtrl/drawGraph: clicked item details:" + JSON.stringify(item)); - eventDetails(item.myevent); + // console.log(">>>>> CREATING NEW TIMELINE with " + JSON.stringify(options)); + timeline = new vis.Timeline(container[0], null, options); + // console.log ("GRAPH DATA"); + timeline.setItems(graphData); + // console.log ("GROUPS"); + timeline.setGroups(groups); - } - else - { + if (NVRDataModel.getLogin().timelineScale == -1) - NVRDataModel.debug("exact match not found, guessing item with co-ordinates X=" + prop.x + " group=" + prop.group); - if (prop.group) - { - var visible = timeline.getVisibleItems(); - NVRDataModel.debug("Visible items=" + JSON.stringify(visible)); - var closestItem = null; - var minDist = 99999; - var _item; - for (var x = 0; x < visible.length; x++) - { - _item = timeline.itemSet.items[x]; - if (_item.data.group == prop.group) - { - if (Math.abs(_item.left - prop.x) < minDist) - { - closestItem = _item; - minDist = Math.abs(_item.left - prop.x); - NVRDataModel.debug("Temporary closest " + _item.left); - //console.log (_item); - } - } + { + // console.log ("SCALE NOT FOUND"); + timeline.fit(); + } else { + timeline.fit(); + + /*var d = NVRDataModel.getLogin().timelineScale; + console.log ("SCALE FOUND "+d+" SECONDS"); + var w = timeline.getWindow(); + console.log ("Original s="+w.start+" e="+w.end); + + + var s = moment.tz(w.end, NVRDataModel.getTimeZoneNow()).subtract(d,'seconds').tz(moment.tz.guess()); + + //var s = moment(w.start).format("YYYY-MM-DD HH:mm:ss"); + // + //var e = moment(w.start).add(d,'seconds').format("YYYY-MM-DD HH:mm:ss"); + + var e = moment.tz(w.end, NVRDataModel.getTimeZoneNow()).tz(moment.tz.guess()); + + console.log ("Start="+s+" End="+e); + $timeout (function() {timeline.setWindow(s,e);},1000);*/ + + } + + lastTimeForEvent = moment().tz(NVRDataModel.getLogin().useLocalTimeZone ? NVRDataModel.getLocalTimeZoneNow() : NVRDataModel.getTimeZoneNow()); + updateInterval = $interval(function () { + processNewEvents(); + }.bind(this), 10 * 1000); + + $ionicLoading.hide(); + $scope.graphLoaded = true; + NVRDataModel.debug("graph loaded: " + $scope.graphLoaded); + $scope.navControls = false; + dblclick = false; + + // we don't really need this anymore - as we have an interval timer + // ticking away + + // this is called for each tick the bar moves + // speed moves depending on zoom factor + // + /* timeline.on('currentTimeTick', function() { + + if ($scope.follow.time) { + + } + + + });*/ + + timeline.on('rangechanged', function (s) { + ///console.log ("Range Changed:"+JSON.stringify(s)); + if (s.byUser) { + + var w = timeline.getWindow(); + //console.log ("start:"+w.start+" end:"+w.end); + var a = moment(w.start); + var b = moment(w.end); + var d = b.diff(a, 'seconds'); + var ld = NVRDataModel.getLogin(); + ld.timelineScale = d; + NVRDataModel.setLogin(ld); + //console.log ("Stored user scale of "+d+" seconds"); } - NVRDataModel.log("Closest item " + closestItem.left + " group: " + closestItem.data.group); - if (closestItem != null) - { - NVRDataModel.log("Closest item " + closestItem.left + " group: " + closestItem.data.group); - showEvent(closestItem.data.myevent); - } + + }); + + timeline.on('click', function (prop) { + //console.log ("CLICK"); + if ($scope.onTap == $translate.instant('kTimelineGraph')) + timelineAnalyzeFrames(prop); else - { - NVRDataModel.log("Did not find a visible item match"); - } + timelineShowEvent(prop); + + + }); + + timeline.on('doubleClick', function (prop) { + if ($scope.onDTap == $translate.instant('kTimelineGraph')) + timelineAnalyzeFrames(prop); + else + timelineShowEvent(prop); + + }); + }, + function (error) { + NVRDataModel.displayBanner('error', 'Timeline error', 'Please try again'); + } - // console.log("Zoomed out too far to playback events"); - } - } + ); // get Events + }); + } - $scope.radialMenuOptions = { - content: '', - //size: 'small', + function timelineShowEvent(prop) { + $timeout(function () { + if (dblclick) { + //console.log ("IGNORING CLICK AS DBL CLICK"); + $timeout(function () { + dblclick = false; + }, 400); + return; + } + //console.log ("CLICK"); + //console.log ("I GOT " + JSON.stringify(prop)); + // console.log ("EVENT IS " + JSON.stringify(properties.event)); + //var properties = timeline.getEventProperties(prop); + // console.log ( "I GOT " + properties); + var itm = prop.item; + //console.log ("ITEM CLICKED " + itm); + if (itm && !isNaN(itm)) { + NVRDataModel.debug("TimelineCtrl/drawGraph:You clicked on item " + itm); + var item = graphData.get(itm); + NVRDataModel.debug("TimelineCtrl/drawGraph: clicked item details:" + JSON.stringify(item)); + showEvent(item.myevent); + + } else { + NVRDataModel.debug("exact match not found, guessing item with co-ordinates X=" + prop.x + " group=" + prop.group); + if (prop.group) { + var visible = timeline.getVisibleItems(); + NVRDataModel.debug("Visible items=" + JSON.stringify(visible)); + var closestItem = null; + var minDist = 99999; + var _item; + for (var x = 0; x < visible.length; x++) { + _item = timeline.itemSet.items[x]; + if (_item.data.group == prop.group) { + if (Math.abs(_item.left - prop.x) < minDist) { + closestItem = _item; + minDist = Math.abs(_item.left - prop.x); + NVRDataModel.debug("Temporary closest " + _item.left); + //console.log (_item); + } + } + + } - background: '#982112', - isOpen: true, - toggleOnClick: false, - button: + if (closestItem != null) { + NVRDataModel.log("Closest item " + closestItem.left + " group: " + closestItem.data.group); + showEvent(closestItem.data.myevent); + } else { + NVRDataModel.log("Did not find a visible item match"); + } + } else // no group row tapped, do nothing { - cssClass: 'fa fa-compress fa-2x', - size: 'small', - onclick: function() - { - //console.log("fitting"); - timeline.fit(); + + /*$ionicLoading.show({ + template: "", + animation: 'fade-in', + showBackdrop: true, + maxWidth: 200, + showDelay: 0, + duration: 1500, + });*/ + } + // console.log("Zoomed out too far to playback events"); + } + }, 400); + } + + function timelineAnalyzeFrames(prop) { + // console.log ("DOUBLE"); + dblclick = true; + var itm = prop.item; + //console.log ("ITEM CLICKED " + itm); + if (itm && !isNaN(itm)) { + NVRDataModel.debug("TimelineCtrl/drawGraph:You clicked on item " + itm); + var item = graphData.get(itm); + NVRDataModel.debug("TimelineCtrl/drawGraph: clicked item details:" + JSON.stringify(item)); + eventDetails(item.myevent); + + } else { + + NVRDataModel.debug("exact match not found, guessing item with co-ordinates X=" + prop.x + " group=" + prop.group); + if (prop.group) { + var visible = timeline.getVisibleItems(); + NVRDataModel.debug("Visible items=" + JSON.stringify(visible)); + var closestItem = null; + var minDist = 99999; + var _item; + for (var x = 0; x < visible.length; x++) { + _item = timeline.itemSet.items[x]; + if (_item.data.group == prop.group) { + if (Math.abs(_item.left - prop.x) < minDist) { + closestItem = _item; + minDist = Math.abs(_item.left - prop.x); + NVRDataModel.debug("Temporary closest " + _item.left); + //console.log (_item); } - }, - items: [ - { - content: '', - cssClass: 'fa fa-minus-circle', - empty: false, - onclick: function() - { - //zoom(0.2); - timeline.zoomOut(0.2); - } - }, + } - { - content: '', - cssClass: 'fa fa-chevron-circle-up', - empty: true, - onclick: function() { + } + NVRDataModel.log("Closest item " + closestItem.left + " group: " + closestItem.data.group); + if (closestItem != null) { + NVRDataModel.log("Closest item " + closestItem.left + " group: " + closestItem.data.group); + showEvent(closestItem.data.myevent); + } else { + NVRDataModel.log("Did not find a visible item match"); + } + } - } - }, + // console.log("Zoomed out too far to playback events"); + } + } + + $scope.radialMenuOptions = { + content: '', + //size: 'small', + + background: '#982112', + isOpen: true, + toggleOnClick: false, + button: { + cssClass: 'fa fa-compress fa-2x', + size: 'small', + onclick: function () { + //console.log("fitting"); + timeline.fit(); + } + }, + items: [{ + content: '', + cssClass: 'fa fa-minus-circle', + empty: false, + onclick: function () { + //zoom(0.2); + timeline.zoomOut(0.2); + } + }, - { - content: '', - cssClass: 'fa fa-chevron-circle-up', - empty: false, + { + content: '', + cssClass: 'fa fa-chevron-circle-up', + empty: true, + onclick: function () { - onclick: function() - { + } + }, - move(0.2); - } - }, - { - content: 'D', - empty: true, + { + content: '', + cssClass: 'fa fa-chevron-circle-up', + empty: false, - onclick: function() - { - // console.log('About'); - } - }, + onclick: function () { - { - content: '', - cssClass: 'fa fa-chevron-circle-up', - empty: true, - onclick: function() { + move(0.2); + } + }, + { + content: 'D', + empty: true, - } - }, + onclick: function () { + // console.log('About'); + } + }, - { - content: '', - cssClass: 'fa fa-plus-circle', - empty: false, - onclick: function() - { + { + content: '', + cssClass: 'fa fa-chevron-circle-up', + empty: true, + onclick: function () { - //zoom(-0.2); - timeline.zoomIn(0.2); - } - }, + } + }, - { - content: '', - cssClass: 'fa fa-chevron-circle-up', - empty: true, - onclick: function() { + { + content: '', + cssClass: 'fa fa-plus-circle', + empty: false, + onclick: function () { - } - }, + //zoom(-0.2); + timeline.zoomIn(0.2); + } + }, - { - content: 'H', - empty: true, - onclick: function() - { - // console.log('About'); - } - }, + { + content: '', + cssClass: 'fa fa-chevron-circle-up', + empty: true, + onclick: function () { - { - content: '', - cssClass: 'fa fa-chevron-circle-up', - empty: false, - onclick: function() - { - move(-0.2); - } - }, + } + }, - { - content: '', - cssClass: 'fa fa-chevron-circle-up', - empty: true, - onclick: function() { + { + content: 'H', + empty: true, + onclick: function () { + // console.log('About'); + } + }, - } - }, + { + content: '', + cssClass: 'fa fa-chevron-circle-up', + empty: false, + onclick: function () { + move(-0.2); + } + }, - { - content: 'K', - empty: true, - onclick: function() - { - //console.log('About'); - } - }, - ] - }; + { + content: '', + cssClass: 'fa fa-chevron-circle-up', + empty: true, + onclick: function () { + + } + }, + + { + content: 'K', + empty: true, + onclick: function () { + //console.log('About'); + } + }, + ] + }; }]); |
