", { "class": "ganttview-block-container" }));
}
return blocksDiv;
};
// Render bars
Gantt.prototype.addBlocks = function(slider, start) {
var rows = jQuery("div.ganttview-blocks div.ganttview-block-container", slider);
var rowIdx = 0;
for (var i = 0; i < this.data.length; i++) {
var series = this.data[i];
var size = this.daysBetween(series.start, series.end) + 1;
var offset = this.daysBetween(start, series.start);
var text = jQuery("
", {"class": "ganttview-block-text"});
var block = jQuery("
", {
"class": "ganttview-block tooltip",
"title": this.getBarTooltip(this.data[i]),
"css": {
"width": ((size * this.options.cellWidth) - 9) + "px",
"margin-left": (offset * this.options.cellWidth) + "px"
}
}).append(text);
if (size >= 2) {
text.append(this.data[i].progress);
}
block.data("task", this.data[i]);
this.setTaskColor(block, this.data[i]);
jQuery(rows[rowIdx]).append(block);
rowIdx = rowIdx + 1;
}
};
// Get tooltip for task bars
Gantt.prototype.getBarTooltip = function(task) {
if (task.not_defined) {
return $(this.options.container).data("label-not-defined");
}
return "" + task.progress + "
" +
$(this.options.container).data("label-assignee") + " " + (task.assignee ? task.assignee : '') + "
" +
$(this.options.container).data("label-start-date") + " " + $.datepicker.formatDate('yy-mm-dd', task.start) + "
" +
$(this.options.container).data("label-end-date") + " " + $.datepicker.formatDate('yy-mm-dd', task.end);
};
// Set task color
Gantt.prototype.setTaskColor = function(block, task) {
if (task.not_defined) {
block.addClass("ganttview-block-not-defined");
}
else {
block.css("background-color", task.color.background);
block.css("border-color", task.color.border);
}
};
// Setup jquery-ui resizable
Gantt.prototype.listenForBlockResize = function(startDate) {
var self = this;
jQuery("div.ganttview-block", this.options.container).resizable({
grid: this.options.cellWidth,
handles: "e,w",
stop: function() {
var block = jQuery(this);
self.updateDataAndPosition(block, startDate);
self.saveTask(block.data("task"));
}
});
};
// Setup jquery-ui drag and drop
Gantt.prototype.listenForBlockDrag = function(startDate) {
var self = this;
jQuery("div.ganttview-block", this.options.container).draggable({
axis: "x",
grid: [this.options.cellWidth, this.options.cellWidth],
stop: function() {
var block = jQuery(this);
self.updateDataAndPosition(block, startDate);
self.saveTask(block.data("task"));
}
});
};
// Update the task data and the position on the chart
Gantt.prototype.updateDataAndPosition = function(block, startDate) {
var container = jQuery("div.ganttview-slide-container", this.options.container);
var scroll = container.scrollLeft();
var offset = block.offset().left - container.offset().left - 1 + scroll;
var task = block.data("task");
// Restore color for defined block
task.not_defined = false;
this.setTaskColor(block, task);
// Set new start date
var daysFromStart = Math.round(offset / this.options.cellWidth);
var newStart = this.addDays(this.cloneDate(startDate), daysFromStart);
task.start = newStart;
// Set new end date
var width = block.outerWidth();
var numberOfDays = Math.round(width / this.options.cellWidth) - 1;
task.end = this.addDays(this.cloneDate(newStart), numberOfDays);
if (numberOfDays > 0) {
jQuery("div.ganttview-block-text", block).text(task.progress);
}
// Update tooltip
block.attr("title", this.getBarTooltip(task));
block.data("task", task);
// Remove top and left properties to avoid incorrect block positioning,
// set position to relative to keep blocks relative to scrollbar when scrolling
block
.css("top", "")
.css("left", "")
.css("position", "relative")
.css("margin-left", offset + "px");
};
// Creates a 3 dimensional array [year][month][day] of every day
// between the given start and end dates
Gantt.prototype.getDates = function(start, end) {
var dates = [];
dates[start.getFullYear()] = [];
dates[start.getFullYear()][start.getMonth()] = [start];
var last = start;
while (this.compareDate(last, end) == -1) {
var next = this.addDays(this.cloneDate(last), 1);
if (! dates[next.getFullYear()]) {
dates[next.getFullYear()] = [];
}
if (! dates[next.getFullYear()][next.getMonth()]) {
dates[next.getFullYear()][next.getMonth()] = [];
}
dates[next.getFullYear()][next.getMonth()].push(next);
last = next;
}
return dates;
};
// Convert data to Date object
Gantt.prototype.prepareData = function(data) {
for (var i = 0; i < data.length; i++) {
var start = new Date(data[i].start[0], data[i].start[1] - 1, data[i].start[2], 0, 0, 0, 0);
data[i].start = start;
var end = new Date(data[i].end[0], data[i].end[1] - 1, data[i].end[2], 0, 0, 0, 0);
data[i].end = end;
}
return data;
};
// Get the start and end date from the data provided
Gantt.prototype.getDateRange = function(minDays) {
var minStart = new Date();
var maxEnd = new Date();
for (var i = 0; i < this.data.length; i++) {
var start = new Date();
start.setTime(Date.parse(this.data[i].start));
var end = new Date();
end.setTime(Date.parse(this.data[i].end));
if (i == 0) {
minStart = start;
maxEnd = end;
}
if (this.compareDate(minStart, start) == 1) {
minStart = start;
}
if (this.compareDate(maxEnd, end) == -1) {
maxEnd = end;
}
}
// Insure that the width of the chart is at least the slide width to avoid empty
// whitespace to the right of the grid
if (this.daysBetween(minStart, maxEnd) < minDays) {
maxEnd = this.addDays(this.cloneDate(minStart), minDays);
}
// Always start one day before the minStart
minStart.setDate(minStart.getDate() - 1);
return [minStart, maxEnd];
};
// Returns the number of day between 2 dates
Gantt.prototype.daysBetween = function(start, end) {
if (! start || ! end) {
return 0;
}
var count = 0, date = this.cloneDate(start);
while (this.compareDate(date, end) == -1) {
count = count + 1;
this.addDays(date, 1);
}
return count;
};
// Return true if it's the weekend
Gantt.prototype.isWeekend = function(date) {
return date.getDay() % 6 == 0;
};
// Clone Date object
Gantt.prototype.cloneDate = function(date) {
return new Date(date.getTime());
};
// Add days to a Date object
Gantt.prototype.addDays = function(date, value) {
date.setDate(date.getDate() + value * 1);
return date;
};
/**
* Compares the first date to the second date and returns an number indication of their relative values.
*
* -1 = date1 is lessthan date2
* 0 = values are equal
* 1 = date1 is greaterthan date2.
*/
Gantt.prototype.compareDate = function(date1, date2) {
if (isNaN(date1) || isNaN(date2)) {
throw new Error(date1 + " - " + date2);
} else if (date1 instanceof Date && date2 instanceof Date) {
return (date1 < date2) ? -1 : (date1 > date2) ? 1 : 0;
} else {
throw new TypeError(date1 + " - " + date2);
}
};