144 lines
5.4 KiB
JavaScript
144 lines
5.4 KiB
JavaScript
$(function()
|
|
{
|
|
if(ganttPlans)
|
|
{
|
|
$('#ganttPlans .gantt-plan, #ganttContainer .gantt-row').remove();
|
|
initWaterfallGanttBlock();
|
|
}
|
|
$('#ganttContainer').off('scroll').on('scroll', function(e) {
|
|
$('#ganttPlans')[0].scrollTop = e.target.scrollTop;
|
|
});
|
|
});
|
|
|
|
window.initWaterfallGanttBlock = function()
|
|
{
|
|
var ganttData = ganttPlans;
|
|
if(!ganttData) return;
|
|
|
|
var plans = [];
|
|
var tasks = [];
|
|
var plansMap = {};
|
|
var startDatetime = Number.MAX_SAFE_INTEGER;
|
|
var endDatetime = 0;
|
|
var minTimeGap = Number.MAX_SAFE_INTEGER;
|
|
var $gantt = $('#' + waterfallGanttID);
|
|
var ONE_DAY = 24 * 3600 * 1000;
|
|
var TIME_GAP_STEP = 7;
|
|
var MIN_COL_WIDTH = 60;
|
|
|
|
$.each(ganttData, function(index, item)
|
|
{
|
|
plansMap[item.id] = item;
|
|
if(item.type == 'plan' && item.parent == '0')
|
|
{
|
|
item.startDatetime = createDatetime(item.start_date);
|
|
item.endDatetime = createDatetime(item.deadline);
|
|
startDatetime = Math.min(startDatetime, item.startDatetime);
|
|
endDatetime = Math.max(endDatetime, item.endDatetime);
|
|
minTimeGap = Math.min(minTimeGap, endDatetime - startDatetime);
|
|
item.tasks = [];
|
|
item.completeTasks = [];
|
|
item.progress = Number.parseFloat(item.taskProgress.replace('%', ''), 10);
|
|
plans.push(item);
|
|
}
|
|
else if(item.type === 'task')
|
|
{
|
|
item.progress = Number.parseFloat(item.taskProgress.replace('%', ''), 10);
|
|
tasks.push(item);
|
|
}
|
|
});
|
|
|
|
$.each(tasks, function(index, task)
|
|
{
|
|
var plan = plansMap[task.parent];
|
|
if(typeof(plan) == 'undefined') return;
|
|
while(plan.parent > 0)
|
|
{
|
|
plan = plansMap[plan.parent];
|
|
if(typeof(plan) != 'object') return;
|
|
}
|
|
if(task.progress === 100) plan.completeTasks.push(task);
|
|
plan.tasks.push(task);
|
|
});
|
|
|
|
var $plans = $gantt.find('.gantt-plans');
|
|
var $ganttContainer = $gantt.find('.gantt-container');
|
|
var $ganttCanvas = $gantt.find('.gantt-canvas');
|
|
var themeColor = 'rgb(46, 127, 255)';
|
|
var canvasHeight = plans.length * 50 + 10;
|
|
|
|
var days = Math.ceil((endDatetime - startDatetime) / ONE_DAY);
|
|
minTimeGap = Math.max(1, Math.ceil(minTimeGap / ONE_DAY));
|
|
|
|
/* Update gantt plans and bars */
|
|
$.each(plans, function(index, plan)
|
|
{
|
|
var $plan = $('<div class="gantt-plan"></div>');
|
|
$plan.append('<div class="strong flex" title="' + plan.name + '"><div class="text-ellipsis">' + plan.name + '</div>' + (plan.milestonecode == '1' ? '<icon class="icon icon-flag icon-sm red center"></icon>' : '') + '</div>');
|
|
$plans.append($plan);
|
|
|
|
var $bar = $('<div class="gantt-bar"></div>');
|
|
$('<div class="gantt-bar-progress bg-primary"></div>').css(
|
|
{
|
|
width: plan.progress + '%',
|
|
background: themeColor,
|
|
}).appendTo($bar);
|
|
$bar.append('<div class="gantt-task-info text-muted small">' + progressLang + ' ' + plan.taskProgress + '</div>').attr('title', zui.formatDate(plan.startDatetime, 'yyyy-MM-dd') + '~' + zui.formatDate(plan.endDatetime, 'yyyy-MM-dd'));
|
|
var $row = $('<div class="gantt-row" data-id="' + plan.id + '"></div>').append($bar);
|
|
$ganttCanvas.append($row);
|
|
});
|
|
|
|
/* Layout gantt container */
|
|
$ganttContainer.css('left', $plans.width() + 15);
|
|
$ganttCanvas.css('height', canvasHeight);
|
|
|
|
/* Layout gantt */
|
|
var minWidth = $ganttContainer.width();
|
|
var timeGap = minTimeGap < TIME_GAP_STEP ? minTimeGap : Math.floor(minTimeGap / TIME_GAP_STEP) * TIME_GAP_STEP;
|
|
var colsCount = Math.ceil(days / timeGap);
|
|
var canvasWidth = Math.max(minWidth, colsCount * MIN_COL_WIDTH);
|
|
var colWidth = Math.floor(canvasWidth / colsCount);
|
|
var pxPerMs = colWidth / (timeGap * ONE_DAY);
|
|
$ganttCanvas.css('width', canvasWidth).find('.gantt-col').remove();
|
|
for (var i = 0; i < colsCount; ++i)
|
|
{
|
|
var $col = $('<div class="gantt-col"></div>');
|
|
$col.css(
|
|
{
|
|
left: i * colWidth,
|
|
width: colWidth,
|
|
height: canvasHeight
|
|
});
|
|
var colTime = startDatetime + i * timeGap * ONE_DAY;
|
|
$col.append('<div class="gantt-col-time text-muted small">' + zui.formatDate(colTime, 'MM/dd') + '</div>');
|
|
$ganttCanvas.append($col);
|
|
}
|
|
|
|
$.each(plans, function(index, plan)
|
|
{
|
|
var $planRow = $gantt.find('.gantt-row[data-id="' + plan.id + '"]');
|
|
$planRow.find('.gantt-bar').css(
|
|
{
|
|
left: Math.floor((plan.startDatetime - startDatetime) * pxPerMs),
|
|
width: Math.floor((plan.endDatetime - plan.startDatetime) * pxPerMs)
|
|
});
|
|
});
|
|
|
|
$gantt.find('.gantt-today').css('left', (Date.now() - startDatetime) * pxPerMs);
|
|
|
|
/**
|
|
* Create date from string
|
|
*
|
|
* @param {String} dateStr like '2020-08-02'
|
|
* @return {Number} Date timestramp
|
|
*/
|
|
function createDatetime(dateStr)
|
|
{
|
|
dateStr = dateStr.split('-');
|
|
var year = Number.parseInt(dateStr[0].length > 3 ? dateStr[0] : dateStr[2], 10);
|
|
var month = Number.parseInt(dateStr[1], 10);
|
|
var day = Number.parseInt(dateStr[2].length > 3 ? dateStr[0] : dateStr[2], 10);
|
|
return new Date(year, month - 1, day).getTime();
|
|
}
|
|
}
|