angular.module("zoneShootingChoroplethViewer", ['mixpanelAPI', 'videoPlayer', 'eventTypeFilterGroup', 'errorStatusCheck', 'reportSettings']) .directive('zoneShootingChoroplethViewer', function() { return { restrict: 'E', replace: true, scope: { slId: '=', loadEvent: '=', apiEndpoint: '=', zone: '=', player: '=', season: '=', canViewClips: '=', permissions: "=", reportType: '=' }, templateUrl: 'views/zoneShootingChoroplethViewer.html', controller: function ($rootScope, $scope, $timeout, $http, $filter, mixpanelAPI, errorStatusCheck, playlistCreator) { $scope.$watch('player', function(newValue) { if (newValue) { $scope.viewContext = { "view": $scope.slId, "playerName": newValue.firstName + " " + newValue.lastName, "zone": $scope.zone, } } }); $scope.$watch('season', function(newValue) { if(!newValue) { return; } var today = new Date(); var dd = today.getDate(); var mm = today.getMonth()+1; //January is 0! var yyyy = today.getFullYear(); if(dd<10) { dd='0'+dd } if(mm<10) { mm='0'+mm } today = yyyy+'-'+mm+'-'+dd; $scope.today=today; $scope.filterSet['maxDate'] = today; $scope.filterSet['minDate'] = newValue.startDate; $scope.context.dateFrom = newValue.startDate; $scope.context.dateTo = today; if (typeof $scope.player !== 'undetermined') { $scope.getPlayerEventsLocationData($scope.player, function () {}, $scope.filterSet); } }); $scope.blurMe = function ($event) { $event.target.blur(); } $scope.playlistCreator = playlistCreator; $scope.flip = false; if ($scope.zone == 'dz') { $scope.flip = true; } $scope.filterSet={}; var today = new Date(); var dd = today.getDate(); var mm = today.getMonth()+1; //January is 0! var yyyy = today.getFullYear(); if(dd<10) { dd='0'+dd } if(mm<10) { mm='0'+mm } today = yyyy+'-'+mm+'-'+dd; $scope.today=today; $scope.filterSet['maxDate'] = today; $scope.filterSet['minDate'] = $scope.season.startDate; // Neutral Zone view includes carry plays which can be either OZ or DZ if ($scope.zone != 'nz') { $scope.filterSet['zone'] = $scope.zone; } $scope.getPrimaryPositionText = function (position) { var primaryPositionText = "Forward"; if (position == 'D') { primaryPositionText = "Defenceman"; } else if (position == 'G') { primaryPositionText = "Goaltender"; } return primaryPositionText; } $scope.isAccuracyDisabled = function (accuracyType) { var returnFlag = false; if ($scope.context.breakdownType == 'goals') { returnFlag = true; } else if ($scope.context.breakdownType == 'shotsonnet' && accuracyType == 'shotsonnet') { returnFlag = true; } return returnFlag; } $scope.decorateDetailsWithZoneContext = function (detailsObject) { detailsObject.reportType = $scope.reportType; detailsObject.fromDate = $scope.context.dateFrom; detailsObject.toDate = $scope.context.dateTo; detailsObject.manpowerSituation = $scope.context.manpowerSituation; detailsObject.periodType = $scope.context.periodType; detailsObject.breakdownType = $scope.context.breakdownType; detailsObject.accuracyType = $scope.context.accuracyType; detailsObject.distancePercentile = $scope.context.distancePercentile; detailsObject.showEvents = $scope.showEvents; return detailsObject; } $scope.$watch('context.dateFrom + context.dateTo', function () { if($scope.context.dateFrom <= $scope.context.dateTo){ $scope.finalizeUpdateChoroplethView(function(){}); if ($scope.player) { mixpanelAPI.send('setFilterDate', mixpanelAPI.decorateDetailsWithPlayerInfo( $scope.decorateDetailsWithZoneContext({}), $scope.player )); } } }); $scope.dataContextsEqual = function (dataContext1, dataContext2) { var areContextsConsistent = true; // Contexts are always consistent when dealing with a single player.. /* if ( ) { areContextsConsistent = false; } */ return areContextsConsistent; } $scope.getViewerDataContextSnapshot = function () { var dataContext = { dateFrom : $scope.context.dateFrom, dateTo : $scope.context.dateTo, manpowerSituation : $scope.context.manpowerSituation, periodType : $scope.context.periodType, breakdownType : $scope.context.breakdownType, accuracyType : $scope.context.accuracyType, distancePercentile : $scope.context.distancePercentile } return dataContext; } $scope.incrementShowLoadingCounter = function () { if ($scope.context.showLoadingCount == 0) { $scope.context.showLoading = true; } $scope.context.showLoadingCount += 1; } $scope.decrementShowLoadingCounter = function () { $scope.context.showLoadingCount -= 1; if ($scope.context.showLoadingCount <= 0) { $scope.context.showLoadingCount = 0; $scope.context.showLoading = false; } } $scope.context = { showLoading : false, periodType : 'regular', manpowerSituation : 'all', breakdownType : 'shots', accuracyType : 'off', distancePercentile : 100, dateFrom : $scope.filterSet['minDate'], dateTo : $scope.filterSet['maxDate'] } $scope.showAccuracy = false; $scope.accuracyLabel = ''; $scope.showDistance = false; $scope.viewerOkToLoad = false; $scope.reportContext = ""; $scope.data = {}; $scope.$on($scope.loadEvent, function (event, callback) { if ($scope.viewerOkToLoad == false) { $scope.showEvents = false; $scope.fromCalendar = Calendar.setup({ dateField : 'dateFrom', dateFormat: '%Y-%m-%d', triggerElement : $scope.slId + '-calendar-from', date: $scope.context.dateFrom, selectHandler:function(date){ var j=date.date.print(this.dateFormat); $scope.$apply(function () { $scope.context.dateFrom = j; }); } }); $scope.toCalendar = Calendar.setup({ dateField : 'dateTo', dateFormat: '%Y-%m-%d', triggerElement : $scope.slId + '-calendar-to', date:$scope.context.dateTo, selectHandler:function(date){ var j=date.date.print(this.dateFormat); $scope.$apply(function () { $scope.context.dateTo = j; }); } }); } $scope.viewerOkToLoad = true; $scope.context.showLoading = false; $scope.context.showLoadingCount = 0; $scope.getPlayerEventsLocationData($scope.player, callback, $scope.filterSet); }); function isEmpty(obj){ return (Object.getOwnPropertyNames(obj).length === 0); } $scope.getPlayerEventsLocationData = function(player, finalizeFunction, filterset) { if(!$scope.season) { return; } if ($scope.viewerOkToLoad) { if (!filterset) { var filterset = {}; } var url = $scope.apiEndpoint + 'players/' + player.id + '/eventlocations/shot,goal/season/' + $scope.season.id + '/context/all/all'; var sep = '?'; if (!isEmpty(filterset)) { var k; for (k in filterset) { url = url + sep + k + "=" + filterset[k]; if(sep == '?') sep = '&'; } } $scope.incrementShowLoadingCounter(); var fetchContext = $scope.getViewerDataContextSnapshot(); $http.get(url) .success(function (data) { $scope.decrementShowLoadingCounter(); if ($scope.dataContextsEqual(fetchContext, $scope.context)) { var shotsData = []; var goalsData = []; angular.forEach(data, function (value) { if (value.eventname == 'shot') { value.primaryColor = "0099FF"; value.secondaryColor = "0066FF"; shotsData.push(value); } else { value.primaryColor = "FF3300"; value.secondaryColor = "FF9900"; goalsData.push(value); } }); // Put shots data first, then goals data, so goals data ends up on top of shots in view $scope.data.full = shotsData.concat(goalsData); $scope.$broadcast('loadChoroplethData', $scope.data.full); $scope.finalizeUpdateChoroplethView(finalizeFunction); } }) .error(function (data, status) { $scope.decrementShowLoadingCounter(); var message = 'Could not get ' + $scope.context.eventsSelection.groupName + ' event locations for ' + player.id; errorStatusCheck.checkErrorStatus(data, status, message); }); } } $scope.finalizeUpdateChoroplethView = function (finalizeFunction) { $scope.data.filtered = $scope.data.full; angular.forEach($scope.data.filtered, function (value) { value.toBin = false; value.hide = true; value.accuracyNumerator = false; if (($scope.context.manpowerSituation == 'all' || $scope.context.manpowerSituation == value.manpowerSituation) && ($scope.context.periodType == 'all' || ($scope.context.periodType == 'regular' && value.period <= 3) || ($scope.context.periodType == 'overTime' && value.period > 3 )) && value.date >= $scope.context.dateFrom && value.date < $scope.context.dateTo) { if ($scope.context.breakdownType == 'shots') { if (value.eventname == 'shot') { value.toBin = true; value.hide = false; } } else if ($scope.context.breakdownType == 'unblockedshots') { if (value.eventname == 'shot' && value.type.indexOf('blocked') < 0) { value.toBin = true; value.hide = false; } } else if ($scope.context.breakdownType == 'shotsonnet') { if (value.eventname == 'shot' && value.outcome == 'successful') { value.toBin = true; value.hide = false; } } else if ($scope.context.breakdownType == 'goals') { if (value.eventname == 'goal') { value.toBin = true; } } if ($scope.context.accuracyType == 'shotsonnet') { if (value.eventname == 'shot' && value.outcome == 'successful') { value.accuracyNumerator = true; } } if ($scope.context.accuracyType == 'goals') { if (value.eventname == 'goal') { value.accuracyNumerator = true; } } if (value.eventname == 'goal') { value.hide = false; } } $rootScope.$broadcast('eventSelection::Reset'); }); $scope.reportContext = $scope.getEventContextString(); $scope.$broadcast('updateChoroplethView', { points: $scope.data.filtered, showDistance: $scope.showDistance, accuracyLabel: $scope.accuracyLabel, distancePercentile: $scope.context.distancePercentile }); finalizeFunction(); } $scope.setPeriodType=function(periodType){ $scope.context.periodType = periodType; $scope.finalizeUpdateChoroplethView(function(){}); mixpanelAPI.send('setPeriodType', mixpanelAPI.decorateDetailsWithPlayerInfo( $scope.decorateDetailsWithZoneContext({}), $scope.player)); } $scope.setManpowerSituation = function(manpowerSituation) { $scope.context.manpowerSituation = manpowerSituation; $scope.finalizeUpdateChoroplethView(function(){}); mixpanelAPI.send('setManpowerSituation', mixpanelAPI.decorateDetailsWithPlayerInfo( $scope.decorateDetailsWithZoneContext({}), $scope.player)); } $scope.syncAccuracySettingsToAccuracyType = function () { if ($scope.context.accuracyType != 'off') { $scope.showAccuracy = true; if ($scope.context.accuracyType == 'shotsonnet') { if ($scope.context.breakdownType == 'shots') { $scope.accuracyLabel = 'SoN'; } else if ($scope.context.breakdownType == 'unblockedshots') { $scope.accuracyLabel = 'USoN'; } } else if ($scope.context.accuracyType == 'goals') { if ($scope.context.breakdownType == 'shots') { $scope.accuracyLabel = 'TSP'; } else if ($scope.context.breakdownType == 'unblockedshots') { $scope.accuracyLabel = 'USP'; } else if ($scope.context.breakdownType == 'shotsonnet') { $scope.accuracyLabel = 'SP'; } } } else { $scope.showAccuracy = false; $scope.accuracyLabel = ''; } } $scope.setBreakdownType = function(breakdownType) { $scope.context.breakdownType = breakdownType; if ($scope.context.breakdownType == 'goals') { $scope.context.accuracyType = 'off'; } else if ($scope.context.breakdownType == 'shotsonnet') { if ($scope.context.accuracyType != 'off' && $scope.context.accuracyType != 'goals') { $scope.context.accuracyType = 'off'; } } $scope.syncAccuracySettingsToAccuracyType(); $scope.finalizeUpdateChoroplethView(function(){}); mixpanelAPI.send('setBreakdownType', mixpanelAPI.decorateDetailsWithPlayerInfo( $scope.decorateDetailsWithZoneContext({}), $scope.player)); } $scope.setAccuracyType = function(accuracyType) { if (!$scope.isAccuracyDisabled(accuracyType)) { $scope.context.accuracyType = accuracyType; $scope.syncAccuracySettingsToAccuracyType(); $scope.finalizeUpdateChoroplethView(function(){}); mixpanelAPI.send('setAccuracyType', mixpanelAPI.decorateDetailsWithPlayerInfo( $scope.decorateDetailsWithZoneContext({}), $scope.player)); } } $scope.setDistancePercentile = function(distancePercentile) { $scope.context.distancePercentile = distancePercentile; if (distancePercentile != 100) { $scope.showDistance = true; } else { $scope.showDistance = false; } $scope.finalizeUpdateChoroplethView(function(){}); mixpanelAPI.send('setDistancePercentile', mixpanelAPI.decorateDetailsWithPlayerInfo( $scope.decorateDetailsWithZoneContext({}), $scope.player)); } $scope.toggleShowEvents = function() { if ($scope.showEvents == true) { $scope.showEvents = false; } else { $scope.showEvents = true; } mixpanelAPI.send('toggleShowEvents', mixpanelAPI.decorateDetailsWithPlayerInfo( $scope.decorateDetailsWithZoneContext({}), $scope.player)); } String.prototype.capitalize = function() { return this.charAt(0).toUpperCase() + this.slice(1); } $scope.getEventContextString = function() { var returnString = ""; if ($scope.context.breakdownType == 'shots') { returnString = "All shot attempts"; } else if ($scope.context.breakdownType == 'unblockedshots') { returnString = "Unblocked shot attempts"; } else if ($scope.context.breakdownType == 'shotsonnet') { returnString = "Shots on net"; } else if ($scope.context.breakdownType == 'goals') { returnString = "Goals"; } if ($scope.context.manpowerSituation == 'evenStrength') { returnString += ", at even strength"; } else if ($scope.context.manpowerSituation == 'powerPlay') { returnString += ", in power play"; } else if ($scope.context.manpowerSituation == 'shortHanded') { returnString += ", short handed"; } if ($scope.context.periodType != 'all') { if ($scope.context.periodType == 'regular') { returnString += ", regular time"; } else if ($scope.context.periodType == 'overTime') { returnString += ", overtime "; } } var today = new Date(); var dd = today.getDate(); var mm = today.getMonth()+1; //January is 0! var yyyy = today.getFullYear(); if(dd<10) { dd='0'+dd } if(mm<10) { mm='0'+mm } today = yyyy+'-'+mm+'-'+dd; $scope.today=today; var startDate = $scope.season ? $scope.season.startDate : $scope.filterSet['minDate']; if($scope.filterSet['maxDate']== $scope.today&&$scope.filterSet['minDate']!=startDate){ returnString += ', since ' + $scope.filterSet['minDate'] ; } else if($scope.filterSet['maxDate']!= $scope.today&&$scope.filterSet['minDate']==startDate){ returnString += ', up to ' + $scope.filterSet['maxDate'] ; } else if ($scope.filterSet['maxDate']!= $scope.today&&$scope.filterSet['minDate']!=startDate) { returnString += ', from ' + $scope.filterSet['minDate'] ; returnString += ' to ' + $scope.filterSet['maxDate'] ; } return returnString; } $scope.deactivateVideo = function () { // Deactivate video for single event playback $scope.eventPlaybackContext.isVideoPlayerActive = false; $scope.eventPlaybackContext.playbackHandlers.deactivateVideo(); // Deactivate video for event playlist playback $scope.playlistPlaybackContext.isVideoPlayerActive = false; $scope.playlistPlaybackContext.playbackHandlers.deactivateVideo(); } $scope.playlistPlaybackContext = {}; $scope.playlistPlaybackContext.isVideoPlayerActive = false; $scope.playlistPlaybackContext.list = null; $scope.playlistPlaybackContext.playbackHandlers = null; $scope.eventPlaybackContext = {}; $scope.eventPlaybackContext.isVideoPlayerActive = false; $scope.eventPlaybackContext.event = null; $scope.eventPlaybackContext.playbackHandlers = null; $scope.registerVideoPlayer = function (id, handlers) { if (id == $scope.slId + '-event-video-player') { $scope.eventPlaybackContext.playbackHandlers = handlers; } else if (id == $scope.slId + '-playlist-video-player') { $scope.playlistPlaybackContext.playbackHandlers = handlers; } else if (id == $scope.slId + '-period-video-player') { $scope.periodViewContext.playbackHandlers = handlers; } } $scope.restartPlaylist = function () { $scope.playlistPlaybackContext.playbackHandlers.deactivateVideo(); $scope.playbackPlaylistInternal(); if ($scope.player) { mixpanelAPI.send('restartPlaylist', mixpanelAPI.decorateDetailsWithPlayerInfo( $scope.decorateDetailsWithZoneContext({}), $scope.player )); } } // This function runs the choropleth events as a playlist $scope.playbackPlaylistInternal = function () { $rootScope.$broadcast('eventSelection::Reset'); }; $scope.playbackEvent = function (event) { //alert('playback ' + event); $scope.onEventPlaybackStart = function (id, event) { mixpanelAPI.send('playbackStart', mixpanelAPI.decorateDetailsWithPlayerInfo( mixpanelAPI.decorateDetailsWithGameInfo( mixpanelAPI.decorateDetailsWithTeamInfo ({ "view": $scope.slId, "event": event.id, "eventName": event.name, "shorthand": event.shorthand, "period": event.period, "toFrame": event.frame }, $scope.player.team), event.game), $scope.player )); } $scope.onTogglePlayPause = function () { mixpanelAPI.send('togglePlayPause', mixpanelAPI.decorateDetailsWithPlayerInfo({ "view": $scope.slId }, $scope.player )); } $scope.onSkipFwd = function () { mixpanelAPI.send('skipFwd', mixpanelAPI.decorateDetailsWithPlayerInfo({ "view": $scope.slId }, $scope.player )); } $scope.onSkipBack = function () { mixpanelAPI.send('skipBack', mixpanelAPI.decorateDetailsWithPlayerInfo({ "view": $scope.slId }, $scope.player )); } $scope.onSetSpeed = function (id, newSpeed) { $scope.eventPlaybackContext.playbackHandlers.setSpeed(newSpeed); mixpanelAPI.send('setSpeed', mixpanelAPI.decorateDetailsWithPlayerInfo({ "view": $scope.slId, "speed": newSpeed }, $scope.player )); } } } // end of controller }; // end of directoive factory });