", { "class": "ganttview-block-container" }));
}
}
div.append(blocksDiv);
}
function addBlocks(div, data, cellWidth, start) {
var rows = jQuery("div.ganttview-blocks div.ganttview-block-container", div);
var rowIdx = 0;
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].series.length; j++) {
var series = data[i].series[j];
var size = DateUtils.daysBetween(series.start, series.end) + 1;
var offset = DateUtils.daysBetween(start, series.start);
var block = jQuery("
", {
"class": "ganttview-block",
"title": series.name + ", " + size + " days \n"+ series.start +" to "+ series.end,
"css": {
"width": ((size * cellWidth) - 7) + "px",
"margin-left": ((offset * cellWidth) + 3) + "px"
}
});
addBlockData(block, data[i], series);
if (data[i].series[j].color) {
block.css("background-color", data[i].series[j].color);
}
block.append(jQuery("
", { "class": "ganttview-block-text" }).text(size));
jQuery(rows[rowIdx]).append(block);
rowIdx = rowIdx + 1;
}
}
}
function addBlockData(block, data, series) {
// This allows custom attributes to be added to the series data objects
// and makes them available to the 'data' argument of click, resize, and drag handlers
var blockData = { id: data.id, name: data.name };
jQuery.extend(blockData, series);
block.data("block-data", blockData);
}
function applyLastClass(div) {
jQuery("div.ganttview-grid-row div.ganttview-grid-row-cell:last-child", div).addClass("last");
jQuery("div.ganttview-hzheader-days div.ganttview-hzheader-day:last-child", div).addClass("last");
jQuery("div.ganttview-hzheader-months div.ganttview-hzheader-month:last-child", div).addClass("last");
}
return {
render: render
};
}
var Behavior = function (div, opts) {
function apply() {
if (opts.behavior.clickable) {
bindBlockClick(div, opts.behavior.onClick);
}
if (opts.behavior.resizable) {
bindBlockResize(div, opts.cellWidth, opts.start, opts.behavior.onResize);
}
if (opts.behavior.draggable) {
bindBlockDrag(div, opts.cellWidth, opts.start, opts.behavior.onDrag);
}
}
function bindBlockClick(div, callback) {
jQuery("div.ganttview-block", div).on("click", function () {
if (callback) { callback(jQuery(this).data("block-data")); }
});
}
function bindBlockResize(div, cellWidth, startDate, callback) {
jQuery("div.ganttview-block", div).resizable({
grid: cellWidth,
handles: "e,w",
stop: function () {
var block = jQuery(this);
updateDataAndPosition(div, block, cellWidth, startDate);
if (callback) { callback(block.data("block-data")); }
}
});
}
function bindBlockDrag(div, cellWidth, startDate, callback) {
jQuery("div.ganttview-block", div).draggable({
axis: "x",
grid: [cellWidth, cellWidth],
stop: function () {
var block = jQuery(this);
updateDataAndPosition(div, block, cellWidth, startDate);
if (callback) { callback(block.data("block-data")); }
}
});
}
function updateDataAndPosition(div, block, cellWidth, startDate) {
var container = jQuery("div.ganttview-slide-container", div);
var scroll = container.scrollLeft();
var offset = block.offset().left - container.offset().left - 1 + scroll;
// Set new start date
var daysFromStart = Math.round(offset / cellWidth);
var newStart = startDate.clone().addDays(daysFromStart);
block.data("block-data").start = newStart;
// Set new end date
var width = block.outerWidth();
var numberOfDays = Math.round(width / cellWidth) - 1;
block.data("block-data").end = newStart.clone().addDays(numberOfDays);
jQuery("div.ganttview-block-text", block).text(numberOfDays + 1);
// 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");
}
return {
apply: apply
};
}
var ArrayUtils = {
contains: function (arr, obj) {
var has = false;
for (var i = 0; i < arr.length; i++) { if (arr[i] == obj) { has = true; } }
return has;
}
};
var DateUtils = {
daysBetween: function (start, end) {
if (!start || !end) { return 0; }
start = Date.parse(start); end = Date.parse(end);
if (start.getYear() == 1901 || end.getYear() == 8099) { return 0; }
var count = 0, date = start.clone();
while (date.compareTo(end) == -1) { count = count + 1; date.addDays(1); }
return count;
},
isWeekend: function (date) {
return date.getDay() % 6 == 0;
},
isToday: function (date) {
return date.isToday();
},
getBoundaryDatesFromData: function (data, minDays) {
var minStart = new Date(); maxEnd = new Date();
for (var i = 0; i < data.length; i++) {
for (var j = 0; j < data[i].series.length; j++) {
var start = Date.parse(data[i].series[j].start);
var end = Date.parse(data[i].series[j].end)
if (i == 0 && j == 0) { minStart = start; maxEnd = end; }
if (minStart.compareTo(start) == 1) { minStart = start; }
if (maxEnd.compareTo(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 (DateUtils.daysBetween(minStart, maxEnd) < minDays) {
maxEnd = minStart.clone().addDays(minDays);
}
return [minStart, maxEnd];
}
};
})(jQuery);