<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script type='text/javascript' src="http://cdn.jsdelivr.net/momentjs/latest/moment-with-locales.min.js"></script>
<script type='text/javascript' src="http://cdn.jsdelivr.net/angular.moment/latest/angular-moment.min.js"></script>
<script type='text/javascript' src="http://rawgit.com/JimLiu/angular-ui-tree/master/dist/angular-ui-tree.js"></script>
<link rel="stylesheet" type="text/css" href="http://rawgit.com/angular-ui-tree/angular-ui-tree/master/dist/angular-ui-tree.min.css">
<link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.2/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="http://cdn.jsdelivr.net/bootstrap/latest/css/bootstrap.css">
<link rel="stylesheet" type="text/css" href="style.css">
<script type='text/javascript' src="http://rawgit.com/angular-gantt/angular-gantt/master/assets/angular-gantt.js"></script>
<script type='text/javascript' src="http://rawgit.com/angular-gantt/angular-gantt/master/assets/angular-gantt-plugins.js"></script>
<link rel="stylesheet" type="text/css" href="http://rawgit.com/angular-gantt/angular-gantt/master/assets/angular-gantt.css">
<link rel="stylesheet" type="text/css" href="http://rawgit.com/angular-gantt/angular-gantt/master/assets/angular-gantt-plugins.css">
<script type='text/javascript' src="script.js"></script>
</head>
<body>
<div ng-app="plnkrGanttMaster" ng-controller="Ctrl">
<div class="container-content" ng-cloak="true">
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<div class="panel-group" bs-collapse>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a href="" bs-collapse-toggle>Options</a>
</h4>
</div>
<div class="panel-collapse" bs-collapse-target>
<div class="panel-body">
<div class="container-fluid">
<div class="row">
<div class="form-inline">
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-search"></i> Scale</label><br>
<button type="button" style="width: 5em; text-align: left" class="btn btn-default" ng-model="options.scale" ng-options="s for s in ['minute', '5 minutes', 'hour', '3 hours', 'day', 'week', '2 weeks', 'month', 'quarter', '6 months', 'year']" bs-select></button>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-sort"></i> Sort</label><br>
<button type="button" style="width: 6em; text-align: left" class="btn btn-default" ng-model="options.sortMode" ng-options="m.value as m.label for m in [{label: 'disabled', value: undefined}, {label: 'name', value: 'model.name'}, {label: 'from', value: 'from'}, {label: 'to', value: 'to'}]" bs-select></button>
</div>
<div class="form-group input-append text-center">
<label class="control-label"><i class="fa fa-filter"></i> Filter Tasks</label><br>
<input type="text" class="form-control" style="width: 8em; text-align: left" ng-model="options.filterTask">
</div>
<div class="form-group input-append text-center">
<label class="control-label"><i class="fa fa-filter"></i> Filter Rows</label><br>
<input type="text" class="form-control" style="width: 8em; text-align: left" ng-model="options.filterRow">
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-clock-o"></i> Today</label><br>
<button type="button" style="width: 6em; text-align: left" class="btn btn-default" ng-model="options.currentDate" ng-options="d for d in ['none', 'line', 'column']" bs-select></button>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-expand"></i> Expand</label><br>
<button type="button" style="width: 6em; text-align: left" class="btn btn-default" ng-model="options.autoExpand" ng-options="e for e in ['none', 'both', 'left', 'right']" bs-select></button>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-scissors"></i> Out of range</label><br>
<button type="button" style="width: 8em; text-align: left" class="btn btn-default" ng-model="options.taskOutOfRange" ng-options="e for e in ['expand', 'truncate']" bs-select></button>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-pencil-square-o"></i> Edit</label><br>
<button type="button" class="btn btn-default" ng-model="options.draw" bs-checkbox>Draw</button>
<button type="button" class="btn btn-default" ng-model="options.readOnly" bs-checkbox>Read Only</button>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-magnet"></i> Magnet</label><br>
<button type="button" style="width: 8em; text-align: left" class="btn btn-default" ng-model="options.columnMagnet" ng-options="m for m in ['column', '1 second', '1 minute', '5 minutes', '15 minutes', '1 hour', '1 day', '5 days']" bs-select></button>
<button type="button" class="btn btn-default" ng-model="options.daily" bs-checkbox>Daily</button>
<button type="button" class="btn btn-default" ng-model="options.timeFramesMagnet" bs-checkbox>TimeFrames</button>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-bars"></i> Side</label><br>
<div class="btn-group" bs-checkbox-group>
<button type="button" style="width: 8em; text-align: left" class="btn btn-default" ng-model="options.sideMode" ng-options="s for s in ['Tree', 'Table', 'TreeTable', 'Disabled']" bs-select></button>
</div>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-gear"></i> Groups</label><br>
<div class="btn-group" bs-checkbox-group>
<button type="button" style="width: 8em; text-align: left" class="btn btn-default" ng-model="options.groupDisplayMode" ng-options="s for s in ['group', 'overview', 'promote', 'Disabled']" bs-select></button>
</div>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-crop"></i> Layout</label><br>
<div class="btn-group" bs-checkbox-group>
<button type="button" class="btn btn-default" ng-model="options.maxHeight" bs-checkbox>Height</button>
<button ng-disabled="!canAutoWidth(options.scale)" type="button" class="btn btn-default" ng-model="options.width" bs-checkbox>Width</button>
</div>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-search"></i> Zoom</label><br>
<input ng-disabled="!options.width" type="number" ng-model="options.zoom" step="0.1" min="0.1" max="5" class="form-control" />
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-text-width"></i> Labels</label><br>
<div class="btn-group" bs-checkbox-group>
<button type="button" class="btn btn-default" ng-model="options.labelsEnabled" bs-checkbox>Show</button>
<button type="button" class="btn btn-default" ng-model="options.allowSideResizing" bs-checkbox>Resizable</button>
</div>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-code"></i> Content</label><br>
<div class="btn-group" bs-checkbox-group>
<button type="button" class="btn btn-default" ng-model="options.rowContentEnabled" bs-checkbox>Rows</button>
<button type="button" class="btn btn-default" ng-model="options.taskContentEnabled" bs-checkbox>Tasks</button>
</div>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-calendar"></i> <i class="fa fa-arrows-h"></i> <i class="fa fa-calendar"></i> Date range</label><br>
<div class="form-group">
<input type="text" class="form-control" ng-model="options.fromDate" max-date="{{options.toDate}}" start-date="{{options.currentDateValue.toString()}}" start-week="1" placeholder="From" bs-datepicker>
</div>
<div class="form-group">
<input type="text" class="form-control" ng-model="options.toDate" min-date="{{options.fromDate}}" start-date="{{options.currentDateValue.toString()}}" start-week="1" placeholder="To" bs-datepicker>
</div>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-sign-out"></i> Non-working</label><br>
<button type="button" style="width: 8em; text-align: left" class="btn btn-default" ng-model="options.timeFramesNonWorkingMode" ng-options="e for e in ['visible', 'hidden', 'cropped']" bs-select></button>
</div>
<div class="form-group text-center">
<label class="control-label"><i class="fa fa-database"></i> Data actions</label><br>
<div class="btn-group">
<button class="btn btn-default" ng-click="reload()">Reload</button>
<button class="btn btn-default" ng-click="remove()">Remove</button>
<button class="btn btn-default" ng-click="clear()">Clear</button>
</div>
</div>
<div ng-if="options.sideMode === 'Tree' || options.sideMode === 'TreeTable'" class="form-group text-center">
<label class="control-label"><i class="fa fa fa-chevron-circle-right"></i> Tree actions</label><br>
<div class="btn-group">
<button class="btn btn-default" ng-click="expandAll()">Expand all</button>
<button class="btn btn-default" ng-click="collapseAll()">Collapse all</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row top-buffer">
<div class="col-md-12">
<div class="panel-group" bs-collapse>
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a href="" bs-collapse-toggle>Gantt</a>
</h4>
</div>
<div class="panel-collapse" bs-collapse-target>
<div class="panel-body">
<div gantt
data="data"
timespans="timespans"
show-side="options.labelsEnabled"
daily="options.daily"
filter-task="{'name': options.filterTask}"
filter-row="{'name': options.filterRow}"
sort-mode="options.sortMode"
view-scale="options.scale"
column-width="getColumnWidth(options.width, options.scale, options.zoom)"
auto-expand="options.autoExpand"
task-out-of-range="options.taskOutOfRange"
from-date = "options.fromDate"
to-date = "options.toDate"
allow-side-resizing = "options.allowSideResizing"
task-content = "options.taskContentEnabled ? options.taskContent : undefined"
row-content = "options.rowContentEnabled ? options.rowContent : undefined"
current-date="options.currentDate"
current-date-value="options.currentDateValue"
headers="options.width && options.shortHeaders || options.longHeaders"
max-height="options.maxHeight && 300 || 0"
time-frames="options.timeFrames"
date-frames="options.dateFrames"
time-frames-non-working-mode="options.timeFramesNonWorkingMode"
time-frames-magnet="options.timeFramesMagnet"
api="options.api"
column-magnet="options.columnMagnet">
<gantt-tree enabled="options.sideMode === 'Tree' || options.sideMode === 'TreeTable'"
header-content="options.treeHeaderContent"
keep-ancestor-on-filter-row="true">
</gantt-tree>
<gantt-table enabled="options.sideMode === 'Table' || options.sideMode === 'TreeTable'"
columns="options.sideMode === 'TreeTable' ? options.treeTableColumns : options.columns"
headers="options.columnsHeaders"
classes="options.columnsClasses"
formatters="options.columnsFormatters"
contents="options.columnsContents"
header-contents="options.columnsHeaderContents">
</gantt-table>
<gantt-groups enabled="options.groupDisplayMode === 'group' || options.groupDisplayMode === 'overview' || options.groupDisplayMode === 'promote'" display="options.groupDisplayMode"></gantt-groups>
<gantt-tooltips></gantt-tooltips>
<gantt-bounds></gantt-bounds>
<gantt-progress></gantt-progress>
<gantt-sortable></gantt-sortable>
<gantt-movable enabled="!options.readOnly"></gantt-movable>
<gantt-draw-task
enabled="options.canDraw"
move-threshold="2"
task-factory="options.drawTaskFactory">
</gantt-draw-task>
<gantt-overlap></gantt-overlap>
<gantt-resize-sensor></gantt-resize-sensor>
</div>
</div>
<div class="panel-body">
<div class="live-table">
<div class="live-cell" ng-show="live.row.tasks.length > 0">
<h4><button type="button" style="text-align: left" class="btn btn-default" ng-model="live.task" ng-options="t as t.name for t in live.row.tasks" bs-select></button> (Task object)</h4>
<textarea class="live-task" ng-model="live.taskJson"></textarea>
</div>
<div class="live-cell" ng-show="data.length > 0">
<h4><button type="button" style="text-align: left" class="btn btn-default" ng-model="live.row" ng-options="r as r.name for r in data" bs-select></button> (Row object)</h4>
<textarea class="live-row" ng-model="live.rowJson"></textarea>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
angular.module('plnkrGanttMaster', [
'gantt', // angular-gantt.
'gantt.sortable',
'gantt.movable',
'gantt.drawtask',
'gantt.tooltips',
'gantt.bounds',
'gantt.progress',
'gantt.table',
'gantt.tree',
'gantt.groups',
'gantt.overlap',
'gantt.resizeSensor'
]).config(['$compileProvider', function ($compileProvider) {
$compileProvider.debugInfoEnabled(true); // Remove debug info (angularJS >= 1.3)
}]).controller('Ctrl', ['$scope', '$timeout', '$log', 'ganttUtils', 'GanttObjectModel', 'Sample', 'ganttMouseOffset', 'ganttDebounce', 'moment', function ($scope, $timeout, $log, utils, ObjectModel, Sample, mouseOffset, debounce, moment) {
var objectModel;
var dataToRemove;
$scope.options = {
mode: 'custom',
scale: 'day',
sortMode: undefined,
sideMode: 'TreeTable',
daily: false,
maxHeight: false,
width: false,
zoom: 1,
columns: ['model.name', 'from', 'to'],
treeTableColumns: ['from', 'to'],
columnsHeaders: { 'model.name': 'Name', 'from': 'From', 'to': 'To' },
columnsClasses: { 'model.name': 'gantt-column-name', 'from': 'gantt-column-from', 'to': 'gantt-column-to' },
columnsFormatters: {
'from': function (from) {
return from !== undefined ? from.format('lll') : undefined;
},
'to': function (to) {
return to !== undefined ? to.format('lll') : undefined;
}
},
treeHeaderContent: '<i class="fa fa-align-justify"></i> {{getHeader()}}',
columnsHeaderContents: {
'model.name': '<i class="fa fa-align-justify"></i> {{getHeader()}}',
'from': '<i class="fa fa-calendar"></i> {{getHeader()}}',
'to': '<i class="fa fa-calendar"></i> {{getHeader()}}'
},
autoExpand: 'none',
taskOutOfRange: 'truncate',
fromDate: moment(null),
toDate: undefined,
rowContent: '<i class="fa fa-align-justify"></i> {{row.model.name}}',
taskContent: '<i class="fa fa-tasks"></i> {{task.model.name}}',
allowSideResizing: true,
labelsEnabled: true,
currentDate: 'line',
currentDateValue: new Date(2013, 9, 23, 11, 20, 0),
draw: false,
readOnly: false,
groupDisplayMode: 'group',
filterTask: '',
filterRow: '',
timeFrames: {
'day': {
start: moment('8:00', 'HH:mm'),
end: moment('20:00', 'HH:mm'),
working: true,
default: true
},
'noon': {
start: moment('12:00', 'HH:mm'),
end: moment('13:30', 'HH:mm'),
working: false,
default: true
},
'weekend': {
working: false
},
'holiday': {
working: false,
color: 'red',
classes: ['gantt-timeframe-holiday']
}
},
dateFrames: {
'weekend': {
evaluator: function (date) {
return date.isoWeekday() === 6 || date.isoWeekday() === 7;
},
targets: ['weekend']
},
'11-november': {
evaluator: function (date) {
return date.month() === 10 && date.date() === 11;
},
targets: ['holiday']
}
},
timeFramesNonWorkingMode: 'visible',
columnMagnet: '15 minutes',
timeFramesMagnet: true,
canDraw: function (event) {
var isLeftMouseButton = event.button === 0 || event.button === 1;
return $scope.options.draw && !$scope.options.readOnly && isLeftMouseButton;
},
drawTaskFactory: function () {
return {
id: utils.randomUuid(), // Unique id of the task.
name: 'Drawn task', // Name shown on top of each task.
color: '#AA8833' // Color of the task in HEX format (Optional).
};
},
api: function (api) {
// API Object is used to control methods and events from angular-gantt.
$scope.api = api;
api.core.on.ready($scope, function () {
// Log various events to console
api.scroll.on.scroll($scope, logScrollEvent);
api.core.on.ready($scope, logReadyEvent);
api.data.on.remove($scope, addEventName('data.on.remove', logDataEvent));
api.data.on.load($scope, addEventName('data.on.load', logDataEvent));
api.data.on.clear($scope, addEventName('data.on.clear', logDataEvent));
api.tasks.on.add($scope, addEventName('tasks.on.add', logTaskEvent));
api.tasks.on.change($scope, addEventName('tasks.on.change', logTaskEvent));
api.tasks.on.rowChange($scope, addEventName('tasks.on.rowChange', logTaskEvent));
api.tasks.on.remove($scope, addEventName('tasks.on.remove', logTaskEvent));
if (api.tasks.on.moveBegin) {
api.tasks.on.moveBegin($scope, addEventName('tasks.on.moveBegin', logTaskEvent));
//api.tasks.on.move($scope, addEventName('tasks.on.move', logTaskEvent));
api.tasks.on.moveEnd($scope, addEventName('tasks.on.moveEnd', logTaskEvent));
api.tasks.on.resizeBegin($scope, addEventName('tasks.on.resizeBegin', logTaskEvent));
//api.tasks.on.resize($scope, addEventName('tasks.on.resize', logTaskEvent));
api.tasks.on.resizeEnd($scope, addEventName('tasks.on.resizeEnd', logTaskEvent));
}
api.rows.on.add($scope, addEventName('rows.on.add', logRowEvent));
api.rows.on.change($scope, addEventName('rows.on.change', logRowEvent));
api.rows.on.move($scope, addEventName('rows.on.move', logRowEvent));
api.rows.on.remove($scope, addEventName('rows.on.remove', logRowEvent));
api.side.on.resizeBegin($scope, addEventName('labels.on.resizeBegin', logLabelsEvent));
//api.side.on.resize($scope, addEventName('labels.on.resize', logLabelsEvent));
api.side.on.resizeEnd($scope, addEventName('labels.on.resizeEnd', logLabelsEvent));
api.timespans.on.add($scope, addEventName('timespans.on.add', logTimespanEvent));
api.columns.on.generate($scope, logColumnsGenerateEvent);
api.rows.on.filter($scope, logRowsFilterEvent);
api.tasks.on.filter($scope, logTasksFilterEvent);
// When gantt is ready, load data.
// `data` attribute could have been used too.
$scope.load();
// Add some DOM events
api.directives.on.new($scope, function (directiveName, directiveScope, element) {
if (directiveName === 'ganttTask') {
element.bind('click', function (event) {
event.stopPropagation();
logTaskEvent('task-click', directiveScope.task);
});
element.bind('mousedown touchstart', function (event) {
event.stopPropagation();
$scope.live.row = directiveScope.task.row.model;
if (directiveScope.task.originalModel !== undefined) {
$scope.live.task = directiveScope.task.originalModel;
} else {
$scope.live.task = directiveScope.task.model;
}
$scope.$digest();
});
} else if (directiveName === 'ganttRow') {
element.bind('click', function (event) {
event.stopPropagation();
logRowEvent('row-click', directiveScope.row);
});
element.bind('mousedown touchstart', function (event) {
event.stopPropagation();
$scope.live.row = directiveScope.row.model;
$scope.$digest();
});
} else if (directiveName === 'ganttRowLabel') {
element.bind('click', function () {
logRowEvent('row-label-click', directiveScope.row);
});
element.bind('mousedown touchstart', function () {
$scope.live.row = directiveScope.row.model;
$scope.$digest();
});
}
});
api.tasks.on.rowChange($scope, function (task) {
$scope.live.row = task.row.model;
});
objectModel = new ObjectModel(api);
});
}
};
$scope.handleTaskIconClick = function (taskModel) {
alert('Icon from ' + taskModel.name + ' task has been clicked.');
};
$scope.handleRowIconClick = function (rowModel) {
alert('Icon from ' + rowModel.name + ' row has been clicked.');
};
$scope.expandAll = function () {
$scope.api.tree.expandAll();
};
$scope.collapseAll = function () {
$scope.api.tree.collapseAll();
};
$scope.$watch('options.sideMode', function (newValue, oldValue) {
if (newValue !== oldValue) {
$scope.api.side.setWidth(undefined);
$timeout(function () {
$scope.api.columns.refresh();
});
}
});
$scope.canAutoWidth = function (scale) {
if (scale.match(/.*?hour.*?/) || scale.match(/.*?minute.*?/)) {
return false;
}
return true;
};
$scope.getColumnWidth = function (widthEnabled, scale, zoom) {
if (!widthEnabled && $scope.canAutoWidth(scale)) {
return undefined;
}
if (scale.match(/.*?week.*?/)) {
return 150 * zoom;
}
if (scale.match(/.*?month.*?/)) {
return 300 * zoom;
}
if (scale.match(/.*?quarter.*?/)) {
return 500 * zoom;
}
if (scale.match(/.*?year.*?/)) {
return 800 * zoom;
}
return 40 * zoom;
};
// Reload data action
$scope.load = function () {
$scope.data = Sample.getSampleData();
dataToRemove = undefined;
$scope.timespans = Sample.getSampleTimespans();
};
$scope.reload = function () {
$scope.load();
};
// Remove data action
$scope.remove = function () {
$scope.api.data.remove(dataToRemove);
};
// Clear data action
$scope.clear = function () {
$scope.data = [];
};
// Visual two way binding.
$scope.live = {};
var debounceValue = 1000;
var listenTaskJson = debounce(function (taskJson) {
if (taskJson !== undefined) {
var task = angular.fromJson(taskJson);
objectModel.cleanTask(task);
var model = $scope.live.task;
angular.extend(model, task);
}
}, debounceValue);
$scope.$watch('live.taskJson', listenTaskJson);
var listenRowJson = debounce(function (rowJson) {
if (rowJson !== undefined) {
var row = angular.fromJson(rowJson);
objectModel.cleanRow(row);
var tasks = row.tasks;
delete row.tasks;
var rowModel = $scope.live.row;
angular.extend(rowModel, row);
var newTasks = {};
var i, l;
if (tasks !== undefined) {
for (i = 0, l = tasks.length; i < l; i++) {
objectModel.cleanTask(tasks[i]);
}
for (i = 0, l = tasks.length; i < l; i++) {
newTasks[tasks[i].id] = tasks[i];
}
if (rowModel.tasks === undefined) {
rowModel.tasks = [];
}
for (i = rowModel.tasks.length - 1; i >= 0; i--) {
var existingTask = rowModel.tasks[i];
var newTask = newTasks[existingTask.id];
if (newTask === undefined) {
rowModel.tasks.splice(i, 1);
} else {
objectModel.cleanTask(newTask);
angular.extend(existingTask, newTask);
delete newTasks[existingTask.id];
}
}
} else {
delete rowModel.tasks;
}
angular.forEach(newTasks, function (newTask) {
rowModel.tasks.push(newTask);
});
}
}, debounceValue);
$scope.$watch('live.rowJson', listenRowJson);
$scope.$watchCollection('live.task', function (task) {
$scope.live.taskJson = angular.toJson(task, true);
$scope.live.rowJson = angular.toJson($scope.live.row, true);
});
$scope.$watchCollection('live.row', function (row) {
$scope.live.rowJson = angular.toJson(row, true);
if (row !== undefined && row.tasks !== undefined && row.tasks.indexOf($scope.live.task) < 0) {
$scope.live.task = row.tasks[0];
}
});
$scope.$watchCollection('live.row.tasks', function () {
$scope.live.rowJson = angular.toJson($scope.live.row, true);
});
// Event handler
var logScrollEvent = function (left, date, direction) {
if (date !== undefined) {
$log.info('[Event] api.on.scroll: ' + left + ', ' + (date === undefined ? 'undefined' : date.format()) + ', ' + direction);
}
};
// Event handler
var logDataEvent = function (eventName) {
$log.info('[Event] ' + eventName);
};
// Event handler
var logTaskEvent = function (eventName, task) {
$log.info('[Event] ' + eventName + ': ' + task.model.name);
};
// Event handler
var logRowEvent = function (eventName, row) {
$log.info('[Event] ' + eventName + ': ' + row.model.name);
};
// Event handler
var logTimespanEvent = function (eventName, timespan) {
$log.info('[Event] ' + eventName + ': ' + timespan.model.name);
};
// Event handler
var logLabelsEvent = function (eventName, width) {
$log.info('[Event] ' + eventName + ': ' + width);
};
// Event handler
var logColumnsGenerateEvent = function (columns, headers) {
$log.info('[Event] ' + 'columns.on.generate' + ': ' + columns.length + ' column(s), ' + headers.length + ' header(s)');
};
// Event handler
var logRowsFilterEvent = function (rows, filteredRows) {
$log.info('[Event] rows.on.filter: ' + filteredRows.length + '/' + rows.length + ' rows displayed.');
};
// Event handler
var logTasksFilterEvent = function (tasks, filteredTasks) {
$log.info('[Event] tasks.on.filter: ' + filteredTasks.length + '/' + tasks.length + ' tasks displayed.');
};
// Event handler
var logReadyEvent = function () {
$log.info('[Event] core.on.ready');
};
// Event utility function
var addEventName = function (eventName, func) {
return function (data) {
return func(eventName, data);
};
};
}])
.service('Sample', function Sample() {
return {
getSampleData: function () {
return [
// Order is optional. If not specified it will be assigned automatically
{
name: 'Milestones', height: '3em', sortable: false, classes: 'gantt-row-milestone', color: '#45607D', tasks: [
// Dates can be specified as string, timestamp or javascript date object. The data attribute can be used to attach a custom object
{ name: 'Kickoff', color: '#93C47D', from: '2013-10-07T09:00:00', to: '2013-10-07T10:00:00', data: 'Can contain any custom data or object' },
{ name: 'Concept approval', color: '#93C47D', from: new Date(2013, 9, 18, 18, 0, 0), to: new Date(2013, 9, 18, 18, 0, 0), est: new Date(2013, 9, 16, 7, 0, 0), lct: new Date(2013, 9, 19, 0, 0, 0) },
{ name: 'Development finished', color: '#93C47D', from: new Date(2013, 10, 15, 18, 0, 0), to: new Date(2013, 10, 15, 18, 0, 0) },
{ name: 'Shop is running', color: '#93C47D', from: new Date(2013, 10, 22, 12, 0, 0), to: new Date(2013, 10, 22, 12, 0, 0) },
{ name: 'Go-live', color: '#93C47D', from: new Date(2013, 10, 29, 16, 0, 0), to: new Date(2013, 10, 29, 16, 0, 0) }
], data: 'Can contain any custom data or object'
},
{
name: 'Status meetings', tasks: [
{ name: 'Demo #1', color: '#9FC5F8', from: new Date(2013, 9, 25, 15, 0, 0), to: new Date(2013, 9, 25, 18, 30, 0) },
{ name: 'Demo #2', color: '#9FC5F8', from: new Date(2013, 10, 1, 15, 0, 0), to: new Date(2013, 10, 1, 18, 0, 0) },
{ name: 'Demo #3', color: '#9FC5F8', from: new Date(2013, 10, 8, 15, 0, 0), to: new Date(2013, 10, 8, 18, 0, 0) },
{ name: 'Demo #4', color: '#9FC5F8', from: new Date(2013, 10, 15, 15, 0, 0), to: new Date(2013, 10, 15, 18, 0, 0) },
{ name: 'Demo #5', color: '#9FC5F8', from: new Date(2013, 10, 24, 9, 0, 0), to: new Date(2013, 10, 24, 10, 0, 0) }
]
},
{
name: 'Kickoff', movable: { allowResizing: false }, tasks: [
{
name: 'Day 1', color: '#9FC5F8', from: new Date(2013, 9, 7, 9, 0, 0), to: new Date(2013, 9, 7, 17, 0, 0),
progress: { percent: 100, color: '#3C8CF8' }, movable: false
},
{
name: 'Day 2', color: '#9FC5F8', from: new Date(2013, 9, 8, 9, 0, 0), to: new Date(2013, 9, 8, 17, 0, 0),
progress: { percent: 100, color: '#3C8CF8' }
},
{
name: 'Day 3', color: '#9FC5F8', from: new Date(2013, 9, 9, 8, 30, 0), to: new Date(2013, 9, 9, 12, 0, 0),
progress: { percent: 100, color: '#3C8CF8' }
}
]
},
{
name: 'Create concept', tasks: [
{
name: 'Create concept', content: '<i class="fa fa-cog" ng-click="scope.handleTaskIconClick(task.model)"></i> {{task.model.name}}', color: '#F1C232', from: new Date(2013, 9, 10, 8, 0, 0), to: new Date(2013, 9, 16, 18, 0, 0), est: new Date(2013, 9, 8, 8, 0, 0), lct: new Date(2013, 9, 18, 20, 0, 0),
progress: 100
}
]
},
{
name: 'Finalize concept', tasks: [
{
name: 'Finalize concept', color: '#F1C232', from: new Date(2013, 9, 17, 8, 0, 0), to: new Date(2013, 9, 18, 18, 0, 0),
progress: 100
}
]
},
{ name: 'Development', children: ['Sprint 1', 'Sprint 2', 'Sprint 3', 'Sprint 4'], content: '<i class="fa fa-file-code-o" ng-click="scope.handleRowIconClick(row.model)"></i> {{row.model.name}}' },
{
name: 'Sprint 1', tooltips: false, tasks: [
{
name: 'Product list view', color: '#F1C232', from: new Date(2013, 9, 21, 8, 0, 0), to: new Date(2013, 9, 25, 15, 0, 0),
progress: 25
}
]
},
{
name: 'Sprint 2', tasks: [
{ name: 'Order basket', color: '#F1C232', from: new Date(2013, 9, 28, 8, 0, 0), to: new Date(2013, 10, 1, 15, 0, 0) }
]
},
{
name: 'Sprint 3', tasks: [
{ name: 'Checkout', color: '#F1C232', from: new Date(2013, 10, 4, 8, 0, 0), to: new Date(2013, 10, 8, 15, 0, 0) }
]
},
{
name: 'Sprint 4', tasks: [
{ name: 'Login & Signup & Admin Views', color: '#F1C232', from: new Date(2013, 10, 11, 8, 0, 0), to: new Date(2013, 10, 15, 15, 0, 0) }
]
},
{ name: 'Hosting' },
{
name: 'Setup', tasks: [
{ name: 'HW', color: '#F1C232', from: new Date(2013, 10, 18, 8, 0, 0), to: new Date(2013, 10, 18, 12, 0, 0) }
]
},
{
name: 'Config', tasks: [
{ name: 'SW / DNS/ Backups', color: '#F1C232', from: new Date(2013, 10, 18, 12, 0, 0), to: new Date(2013, 10, 21, 18, 0, 0) }
]
},
{ name: 'Server', parent: 'Hosting', children: ['Setup', 'Config'] },
{
name: 'Deployment', parent: 'Hosting', tasks: [
{ name: 'Depl. & Final testing', color: '#F1C232', from: new Date(2013, 10, 21, 8, 0, 0), to: new Date(2013, 10, 22, 12, 0, 0), 'classes': 'gantt-task-deployment' }
]
},
{
name: 'Workshop', tasks: [
{ name: 'On-side education', color: '#F1C232', from: new Date(2013, 10, 24, 9, 0, 0), to: new Date(2013, 10, 25, 15, 0, 0) }
]
},
{
name: 'Content', tasks: [
{ name: 'Supervise content creation', color: '#F1C232', from: new Date(2013, 10, 26, 9, 0, 0), to: new Date(2013, 10, 29, 16, 0, 0) }
]
},
{
name: 'Documentation', tasks: [
{ name: 'Technical/User documentation', color: '#F1C232', from: new Date(2013, 10, 26, 8, 0, 0), to: new Date(2013, 10, 28, 18, 0, 0) }
]
}
];
},
getSampleTimespans: function () {
return [
{
from: new Date(2013, 9, 21, 8, 0, 0),
to: new Date(2013, 9, 25, 15, 0, 0),
name: 'Sprint 1 Timespan'
//priority: undefined,
//classes: [],
//data: undefined
}
];
}
};
})
;
.gantt-row-milestone {
font-weight: bold;
vertical-align: middle;
color: white;
}
[angular-gantt](http://www.angular-gantt.com) master branch