diff options
author | Frederic Guillot <fred@kanboard.net> | 2017-04-01 17:04:18 -0400 |
---|---|---|
committer | Frederic Guillot <fred@kanboard.net> | 2017-04-01 17:04:18 -0400 |
commit | 5cc488947305eea5b9762997222c84d6007761c8 (patch) | |
tree | 5f602bb06ade363aa40eda99b4fe9a61f592609f /assets/js/src | |
parent | 253d5a9331e4b4775066ec8cb9664da9a2aa6ac9 (diff) |
Move Gantt charts to external plugin
Diffstat (limited to 'assets/js/src')
-rw-r--r-- | assets/js/src/Gantt.js | 489 |
1 files changed, 0 insertions, 489 deletions
diff --git a/assets/js/src/Gantt.js b/assets/js/src/Gantt.js deleted file mode 100644 index cd6cac00..00000000 --- a/assets/js/src/Gantt.js +++ /dev/null @@ -1,489 +0,0 @@ -// Based on jQuery.ganttView v.0.8.8 Copyright (c) 2010 JC Grubbs - jc.grubbs@devmynd.com - MIT License -Kanboard.Gantt = function(app) { - this.app = app; - this.data = []; - - this.options = { - container: "#gantt-chart", - showWeekends: true, - allowMoves: true, - allowResizes: true, - cellWidth: 21, - cellHeight: 31, - slideWidth: 1000, - vHeaderWidth: 200 - }; -}; - -Kanboard.Gantt.prototype.execute = function() { - if (this.app.hasId("gantt-chart")) { - this.show(); - } -}; - -// Save record after a resize or move -Kanboard.Gantt.prototype.saveRecord = function(record) { - this.app.showLoadingIcon(); - - $.ajax({ - cache: false, - url: $(this.options.container).data("save-url"), - contentType: "application/json", - type: "POST", - processData: false, - data: JSON.stringify(record), - complete: this.app.hideLoadingIcon.bind(this) - }); -}; - -// Build the Gantt chart -Kanboard.Gantt.prototype.show = function() { - this.data = this.prepareData($(this.options.container).data('records')); - - var minDays = Math.floor((this.options.slideWidth / this.options.cellWidth) + 5); - var range = this.getDateRange(minDays); - var startDate = range[0]; - var endDate = range[1]; - var container = $(this.options.container); - var chart = jQuery("<div>", { "class": "ganttview" }); - - chart.append(this.renderVerticalHeader()); - chart.append(this.renderSlider(startDate, endDate)); - container.append(chart); - - jQuery("div.ganttview-grid-row div.ganttview-grid-row-cell:last-child", container).addClass("last"); - jQuery("div.ganttview-hzheader-days div.ganttview-hzheader-day:last-child", container).addClass("last"); - jQuery("div.ganttview-hzheader-months div.ganttview-hzheader-month:last-child", container).addClass("last"); - - if (! $(this.options.container).data('readonly')) { - this.listenForBlockResize(startDate); - this.listenForBlockMove(startDate); - } - else { - this.options.allowResizes = false; - this.options.allowMoves = false; - } -}; - -// Render record list on the left -Kanboard.Gantt.prototype.renderVerticalHeader = function() { - var headerDiv = jQuery("<div>", { "class": "ganttview-vtheader" }); - var itemDiv = jQuery("<div>", { "class": "ganttview-vtheader-item" }); - var seriesDiv = jQuery("<div>", { "class": "ganttview-vtheader-series" }); - - for (var i = 0; i < this.data.length; i++) { - var content = jQuery("<span>") - .append(jQuery("<i>", {"class": "fa fa-info-circle tooltip", "title": this.getVerticalHeaderTooltip(this.data[i])})) - .append(" "); - - if (this.data[i].type == "task") { - content.append(jQuery("<a>", {"href": this.data[i].link, "title": this.data[i].title}).text(this.data[i].title)); - } - else { - content - .append(jQuery("<a>", {"href": this.data[i].board_link, "title": $(this.options.container).data("label-board-link")}).append('<i class="fa fa-th"></i>')) - .append(" ") - .append(jQuery("<a>", {"href": this.data[i].gantt_link, "title": $(this.options.container).data("label-gantt-link")}).append('<i class="fa fa-sliders"></i>')) - .append(" ") - .append(jQuery("<a>", {"href": this.data[i].link}).text(this.data[i].title)); - } - - seriesDiv.append(jQuery("<div>", {"class": "ganttview-vtheader-series-name"}).append(content)); - } - - itemDiv.append(seriesDiv); - headerDiv.append(itemDiv); - - return headerDiv; -}; - -// Render right part of the chart (top header + grid + bars) -Kanboard.Gantt.prototype.renderSlider = function(startDate, endDate) { - var slideDiv = jQuery("<div>", {"class": "ganttview-slide-container"}); - var dates = this.getDates(startDate, endDate); - - slideDiv.append(this.renderHorizontalHeader(dates)); - slideDiv.append(this.renderGrid(dates)); - slideDiv.append(this.addBlockContainers()); - this.addBlocks(slideDiv, startDate); - - return slideDiv; -}; - -// Render top header (days) -Kanboard.Gantt.prototype.renderHorizontalHeader = function(dates) { - var headerDiv = jQuery("<div>", { "class": "ganttview-hzheader" }); - var monthsDiv = jQuery("<div>", { "class": "ganttview-hzheader-months" }); - var daysDiv = jQuery("<div>", { "class": "ganttview-hzheader-days" }); - var totalW = 0; - - for (var y in dates) { - for (var m in dates[y]) { - var w = dates[y][m].length * this.options.cellWidth; - totalW = totalW + w; - - monthsDiv.append(jQuery("<div>", { - "class": "ganttview-hzheader-month", - "css": { "width": (w - 1) + "px" } - }).append($.datepicker.regional[$("body").data('js-lang')].monthNames[m] + " " + y)); - - for (var d in dates[y][m]) { - daysDiv.append(jQuery("<div>", { "class": "ganttview-hzheader-day" }).append(dates[y][m][d].getDate())); - } - } - } - - monthsDiv.css("width", totalW + "px"); - daysDiv.css("width", totalW + "px"); - headerDiv.append(monthsDiv).append(daysDiv); - - return headerDiv; -}; - -// Render grid -Kanboard.Gantt.prototype.renderGrid = function(dates) { - var gridDiv = jQuery("<div>", { "class": "ganttview-grid" }); - var rowDiv = jQuery("<div>", { "class": "ganttview-grid-row" }); - - for (var y in dates) { - for (var m in dates[y]) { - for (var d in dates[y][m]) { - var cellDiv = jQuery("<div>", { "class": "ganttview-grid-row-cell" }); - if (this.options.showWeekends && this.isWeekend(dates[y][m][d])) { - cellDiv.addClass("ganttview-weekend"); - } - rowDiv.append(cellDiv); - } - } - } - var w = jQuery("div.ganttview-grid-row-cell", rowDiv).length * this.options.cellWidth; - rowDiv.css("width", w + "px"); - gridDiv.css("width", w + "px"); - - for (var i = 0; i < this.data.length; i++) { - gridDiv.append(rowDiv.clone()); - } - - return gridDiv; -}; - -// Render bar containers -Kanboard.Gantt.prototype.addBlockContainers = function() { - var blocksDiv = jQuery("<div>", { "class": "ganttview-blocks" }); - - for (var i = 0; i < this.data.length; i++) { - blocksDiv.append(jQuery("<div>", { "class": "ganttview-block-container" })); - } - - return blocksDiv; -}; - -// Render bars -Kanboard.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("<div>", {"class": "ganttview-block-text"}); - - var block = jQuery("<div>", { - "class": "ganttview-block tooltip" + (this.options.allowMoves ? " ganttview-block-movable" : ""), - "title": this.getBarTooltip(series), - "css": { - "width": ((size * this.options.cellWidth) - 9) + "px", - "margin-left": (offset * this.options.cellWidth) + "px" - } - }).append(text); - - if (size >= 2) { - text.append(series.progress); - } - - block.data("record", series); - this.setBarColor(block, series); - - jQuery(rows[rowIdx]).append(block); - rowIdx = rowIdx + 1; - } -}; - -// Get tooltip for vertical header -Kanboard.Gantt.prototype.getVerticalHeaderTooltip = function(record) { - var tooltip = ""; - - if (record.type == "task") { - tooltip = jQuery("<span>") - .append(jQuery("<strong>").text(record.column_title)) - .append(document.createTextNode(' (' + record.progress + ')')) - .append(jQuery("<br>")) - .append(document.createTextNode(record.title)).prop('outerHTML'); - } - else { - var types = ["project-manager", "project-member"]; - - for (var index in types) { - var type = types[index]; - if (! jQuery.isEmptyObject(record.users[type])) { - var list = jQuery("<ul>"); - - for (var user_id in record.users[type]) { - if (user_id) { - list.append(jQuery("<li>").text(record.users[type][user_id])); - } - } - - tooltip += "<p><strong>" + $(this.options.container).data("label-" + type) + "</strong></p>" + list.prop('outerHTML'); - } - } - } - - return tooltip; -}; - -// Get tooltip for bars -Kanboard.Gantt.prototype.getBarTooltip = function(record) { - var tooltip = ""; - - if (record.not_defined) { - tooltip = $(this.options.container).data("label-not-defined"); - } - else { - if (record.type == "task") { - var assigneeLabel = $(this.options.container).data("label-assignee"); - tooltip += jQuery("<strong>").text(record.progress).prop('outerHTML'); - tooltip += "<br>"; - tooltip += jQuery('<span>').append(document.createTextNode(assigneeLabel + " " + (record.assignee ? record.assignee : ''))).prop('outerHTML'); - tooltip += "<br>"; - } - - tooltip += $(this.options.container).data("label-start-date") + " " + $.datepicker.formatDate('yy-mm-dd', record.start) + "<br/>"; - tooltip += $(this.options.container).data("label-end-date") + " " + $.datepicker.formatDate('yy-mm-dd', record.end); - } - - return tooltip; -}; - -// Set bar color -Kanboard.Gantt.prototype.setBarColor = function(block, record) { - if (record.not_defined) { - block.addClass("ganttview-block-not-defined"); - } - else { - block.css("background-color", record.color.background); - block.css("border-color", record.color.border); - - if (record.progress != "0%") { - block.append(jQuery("<div>", { - "css": { - "z-index": 0, - "position": "absolute", - "top": 0, - "bottom": 0, - "background-color": record.color.border, - "width": record.progress, - "opacity": 0.4 - } - })); - } - } -}; - -// Setup jquery-ui resizable -Kanboard.Gantt.prototype.listenForBlockResize = function(startDate) { - var self = this; - - jQuery("div.ganttview-block", this.options.container).resizable({ - grid: this.options.cellWidth, - handles: "e,w", - delay: 300, - stop: function() { - var block = jQuery(this); - self.updateDataAndPosition(block, startDate); - self.saveRecord(block.data("record")); - } - }); -}; - -// Setup jquery-ui drag and drop -Kanboard.Gantt.prototype.listenForBlockMove = function(startDate) { - var self = this; - - jQuery("div.ganttview-block", this.options.container).draggable({ - axis: "x", - delay: 300, - grid: [this.options.cellWidth, this.options.cellWidth], - stop: function() { - var block = jQuery(this); - self.updateDataAndPosition(block, startDate); - self.saveRecord(block.data("record")); - } - }); -}; - -// Update the record data and the position on the chart -Kanboard.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 record = block.data("record"); - - // Restore color for defined block - record.not_defined = false; - this.setBarColor(block, record); - - // Set new start date - var daysFromStart = Math.round(offset / this.options.cellWidth); - var newStart = this.addDays(this.cloneDate(startDate), daysFromStart); - record.start = newStart; - - // Set new end date - var width = block.outerWidth(); - var numberOfDays = Math.round(width / this.options.cellWidth) - 1; - record.end = this.addDays(this.cloneDate(newStart), numberOfDays); - - if (record.type === "task" && numberOfDays > 0) { - jQuery("div.ganttview-block-text", block).text(record.progress); - } - - // Update tooltip - block.attr("title", this.getBarTooltip(record)); - - block.data("record", record); - - // 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 -Kanboard.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 -Kanboard.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 -Kanboard.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 -Kanboard.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 -Kanboard.Gantt.prototype.isWeekend = function(date) { - return date.getDay() % 6 == 0; -}; - -// Clone Date object -Kanboard.Gantt.prototype.cloneDate = function(date) { - return new Date(date.getTime()); -}; - -// Add days to a Date object -Kanboard.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. - */ -Kanboard.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); - } -}; |