angular-gantt
Version:
Gantt chart component for AngularJS
300 lines (256 loc) • 12.6 kB
JavaScript
/*
Project: angular-gantt v1.2.9 - Gantt chart component for AngularJS
Authors: Marco Schweighauser, Rémi Alvergnat
License: MIT
Homepage: https://www.angular-gantt.com
Github: https://github.com/angular-gantt/angular-gantt.git
*/
(function(){
'use strict';
angular.module('gantt.tooltips', ['gantt', 'gantt.tooltips.templates']).directive('ganttTooltips', ['$compile', '$document', function($compile, $document) {
return {
restrict: 'E',
require: '^gantt',
scope: {
enabled: '=?',
dateFormat: '=?',
content: '=?',
delay: '=?'
},
link: function(scope, element, attrs, ganttCtrl) {
var api = ganttCtrl.gantt.api;
// Load options from global options attribute.
if (scope.options && typeof(scope.options.tooltips) === 'object') {
for (var option in scope.options.tooltips) {
scope[option] = scope.options[option];
}
}
if (scope.enabled === undefined) {
scope.enabled = true;
}
if (scope.dateFormat === undefined) {
scope.dateFormat = 'MMM DD, HH:mm';
}
if (scope.delay === undefined) {
scope.delay = 500;
}
if (scope.content === undefined) {
scope.content = '{{task.model.name}}</br>'+
'<small>'+
'{{task.isMilestone() === true && getFromLabel() || getFromLabel() + \' - \' + getToLabel()}}'+
'</small>';
}
scope.api = api;
api.directives.on.new(scope, function(directiveName, taskScope, taskElement) {
if (directiveName === 'ganttTask') {
var tooltipScope = taskScope.$new();
tooltipScope.pluginScope = scope;
var ifElement = $document[0].createElement('div');
angular.element(ifElement).attr('data-ng-if', 'pluginScope.enabled');
var tooltipElement = $document[0].createElement('gantt-tooltip');
if (attrs.templateUrl !== undefined) {
angular.element(tooltipElement).attr('data-template-url', attrs.templateUrl);
}
if (attrs.template !== undefined) {
angular.element(tooltipElement).attr('data-template', attrs.template);
}
angular.element(ifElement).append(tooltipElement);
taskElement.append($compile(ifElement)(tooltipScope));
}
});
}
};
}]);
}());
(function() {
'use strict';
angular.module('gantt.tooltips').directive('ganttTooltip', ['$log','$timeout', '$compile', '$document', '$templateCache', 'ganttDebounce', 'ganttSmartEvent', function($log, $timeout, $compile, $document, $templateCache, debounce, smartEvent) {
// This tooltip displays more information about a task
return {
restrict: 'E',
templateUrl: function(tElement, tAttrs) {
var templateUrl;
if (tAttrs.templateUrl === undefined) {
templateUrl = 'plugins/tooltips/tooltip.tmpl.html';
} else {
templateUrl = tAttrs.templateUrl;
}
if (tAttrs.template !== undefined) {
$templateCache.put(templateUrl, tAttrs.template);
}
return templateUrl;
},
scope: true,
replace: true,
controller: ['$scope', '$element', 'ganttUtils', function($scope, $element, utils) {
var bodyElement = angular.element($document[0].body);
var parentElement = $scope.task.$element;
var showTooltipPromise;
var visible = false;
var mouseEnterX;
$scope.getFromLabel = function() {
var taskTooltips = $scope.task.model.tooltips;
var rowTooltips = $scope.task.row.model.tooltips;
if (typeof(taskTooltips) === 'boolean') {
taskTooltips = {enabled: taskTooltips};
}
if (typeof(rowTooltips) === 'boolean') {
rowTooltips = {enabled: rowTooltips};
}
var dateFormat = utils.firstProperty([taskTooltips, rowTooltips], 'dateFormat', $scope.pluginScope.dateFormat);
return $scope.task.model.from.format(dateFormat);
};
$scope.getToLabel = function() {
var taskTooltips = $scope.task.model.tooltips;
var rowTooltips = $scope.task.row.model.tooltips;
if (typeof(taskTooltips) === 'boolean') {
taskTooltips = {enabled: taskTooltips};
}
if (typeof(rowTooltips) === 'boolean') {
rowTooltips = {enabled: rowTooltips};
}
var dateFormat = utils.firstProperty([taskTooltips, rowTooltips], 'dateFormat', $scope.pluginScope.dateFormat);
return $scope.task.model.to.format(dateFormat);
};
var mouseMoveHandler = smartEvent($scope, bodyElement, 'mousemove', debounce(function(e) {
if (!visible) {
mouseEnterX = e.clientX;
displayTooltip(true, false);
} else {
// check if mouse goes outside the parent
if(
!$scope.taskRect ||
e.clientX < $scope.taskRect.left ||
e.clientX > $scope.taskRect.right ||
e.clientY > $scope.taskRect.bottom ||
e.clientY < $scope.taskRect.top
) {
displayTooltip(false, false);
}
updateTooltip(e.clientX);
}
}, 5, false));
$scope.task.getContentElement().bind('mousemove', function(evt) {
mouseEnterX = evt.clientX;
});
$scope.task.getContentElement().bind('mouseenter', function(evt) {
mouseEnterX = evt.clientX;
displayTooltip(true, true);
});
$scope.task.getContentElement().bind('mouseleave', function() {
displayTooltip(false);
});
if ($scope.pluginScope.api.tasks.on.moveBegin) {
$scope.pluginScope.api.tasks.on.moveBegin($scope, function(task) {
if (task === $scope.task) {
displayTooltip(true);
}
});
$scope.pluginScope.api.tasks.on.moveEnd($scope, function(task) {
if (task === $scope.task) {
displayTooltip(false);
}
});
$scope.pluginScope.api.tasks.on.resizeBegin($scope, function(task) {
if (task === $scope.task) {
displayTooltip(true);
}
});
$scope.pluginScope.api.tasks.on.resizeEnd($scope, function(task) {
if (task === $scope.task) {
displayTooltip(false);
}
});
}
var displayTooltip = function(newValue, showDelayed) {
if (showTooltipPromise) {
$timeout.cancel(showTooltipPromise);
}
var taskTooltips = $scope.task.model.tooltips;
var rowTooltips = $scope.task.row.model.tooltips;
if (typeof(taskTooltips) === 'boolean') {
taskTooltips = {enabled: taskTooltips};
}
if (typeof(rowTooltips) === 'boolean') {
rowTooltips = {enabled: rowTooltips};
}
var enabled = utils.firstProperty([taskTooltips, rowTooltips], 'enabled', $scope.pluginScope.enabled);
if (enabled && !visible && mouseEnterX !== undefined && newValue) {
if (showDelayed) {
showTooltipPromise = $timeout(function() {
showTooltip(mouseEnterX);
}, $scope.pluginScope.delay, false);
} else {
showTooltip(mouseEnterX);
}
} else if (!newValue) {
if (!$scope.task.active) {
hideTooltip();
}
}
};
var showTooltip = function(x) {
visible = true;
mouseMoveHandler.bind();
$scope.displayed = true;
$scope.$evalAsync(function() {
var restoreNgHide;
if ($element.hasClass('ng-hide')) {
$element.removeClass('ng-hide');
restoreNgHide = true;
}
$scope.elementHeight = $element[0].offsetHeight;
if (restoreNgHide) {
$element.addClass('ng-hide');
}
$scope.taskRect = parentElement[0].getBoundingClientRect();
updateTooltip(x);
});
};
var getViewPortWidth = function() {
var d = $document[0];
return d.documentElement.clientWidth || d.documentElement.getElementById('body')[0].clientWidth;
};
var updateTooltip = function(x) {
// Check if info is overlapping with view port
if (x + $element[0].offsetWidth > getViewPortWidth()) {
$element.css('left', (x + 20 - $element[0].offsetWidth) + 'px');
$scope.isRightAligned = true;
} else {
$element.css('left', (x - 20) + 'px');
$scope.isRightAligned = false;
}
};
var hideTooltip = function() {
visible = false;
mouseMoveHandler.unbind();
$scope.$evalAsync(function() {
$scope.displayed = false;
});
};
if ($scope.task.isMoving) {
// Display tooltip because task has been moved to a new row
displayTooltip(true, false);
}
$scope.gantt.api.directives.raise.new('ganttTooltip', $scope, $element);
$scope.$on('$destroy', function() {
$scope.gantt.api.directives.raise.destroy('ganttTooltip', $scope, $element);
});
}]
};
}]);
}());
angular.module('gantt.tooltips.templates', []).run(['$templateCache', function($templateCache) {
$templateCache.put('plugins/tooltips/tooltip.tmpl.html',
'<div ng-cloak\n' +
' class="gantt-task-info"\n' +
' ng-show="displayed"\n' +
' ng-class="isRightAligned ? \'gantt-task-infoArrowR\' : \'gantt-task-infoArrow\'"\n' +
' ng-style="{top: taskRect.top + \'px\', marginTop: -elementHeight - 8 + \'px\'}">\n' +
' <div class="gantt-task-info-content">\n' +
' <div gantt-bind-compile-html="pluginScope.content"></div>\n' +
' </div>\n' +
'</div>\n' +
'');
}]);
//# sourceMappingURL=angular-gantt-tooltips-plugin.js.map