waterfallganttblock.ui.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. $(function()
  2. {
  3. if(ganttPlans)
  4. {
  5. $('#ganttPlans .gantt-plan, #ganttContainer .gantt-row').remove();
  6. initWaterfallGanttBlock();
  7. }
  8. $('#ganttContainer').off('scroll').on('scroll', function(e) {
  9. $('#ganttPlans')[0].scrollTop = e.target.scrollTop;
  10. });
  11. });
  12. window.initWaterfallGanttBlock = function()
  13. {
  14. var ganttData = ganttPlans;
  15. if(!ganttData) return;
  16. var plans = [];
  17. var tasks = [];
  18. var plansMap = {};
  19. var startDatetime = Number.MAX_SAFE_INTEGER;
  20. var endDatetime = 0;
  21. var minTimeGap = Number.MAX_SAFE_INTEGER;
  22. var $gantt = $('#' + waterfallGanttID);
  23. var ONE_DAY = 24 * 3600 * 1000;
  24. var TIME_GAP_STEP = 7;
  25. var MIN_COL_WIDTH = 60;
  26. $.each(ganttData, function(index, item)
  27. {
  28. plansMap[item.id] = item;
  29. if(item.type == 'plan' && item.parent == '0')
  30. {
  31. item.startDatetime = createDatetime(item.start_date);
  32. item.endDatetime = createDatetime(item.deadline);
  33. startDatetime = Math.min(startDatetime, item.startDatetime);
  34. endDatetime = Math.max(endDatetime, item.endDatetime);
  35. minTimeGap = Math.min(minTimeGap, endDatetime - startDatetime);
  36. item.tasks = [];
  37. item.completeTasks = [];
  38. item.progress = Number.parseFloat(item.taskProgress.replace('%', ''), 10);
  39. plans.push(item);
  40. }
  41. else if(item.type === 'task')
  42. {
  43. item.progress = Number.parseFloat(item.taskProgress.replace('%', ''), 10);
  44. tasks.push(item);
  45. }
  46. });
  47. $.each(tasks, function(index, task)
  48. {
  49. var plan = plansMap[task.parent];
  50. if(typeof(plan) == 'undefined') return;
  51. while(plan.parent > 0)
  52. {
  53. plan = plansMap[plan.parent];
  54. if(typeof(plan) != 'object') return;
  55. }
  56. if(task.progress === 100) plan.completeTasks.push(task);
  57. plan.tasks.push(task);
  58. });
  59. var $plans = $gantt.find('.gantt-plans');
  60. var $ganttContainer = $gantt.find('.gantt-container');
  61. var $ganttCanvas = $gantt.find('.gantt-canvas');
  62. var themeColor = 'rgb(46, 127, 255)';
  63. var canvasHeight = plans.length * 50 + 10;
  64. var days = Math.ceil((endDatetime - startDatetime) / ONE_DAY);
  65. minTimeGap = Math.max(1, Math.ceil(minTimeGap / ONE_DAY));
  66. /* Update gantt plans and bars */
  67. $.each(plans, function(index, plan)
  68. {
  69. var $plan = $('<div class="gantt-plan"></div>');
  70. $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>');
  71. $plans.append($plan);
  72. var $bar = $('<div class="gantt-bar"></div>');
  73. $('<div class="gantt-bar-progress bg-primary"></div>').css(
  74. {
  75. width: plan.progress + '%',
  76. background: themeColor,
  77. }).appendTo($bar);
  78. $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'));
  79. var $row = $('<div class="gantt-row" data-id="' + plan.id + '"></div>').append($bar);
  80. $ganttCanvas.append($row);
  81. });
  82. /* Layout gantt container */
  83. $ganttContainer.css('left', $plans.width() + 15);
  84. $ganttCanvas.css('height', canvasHeight);
  85. /* Layout gantt */
  86. var minWidth = $ganttContainer.width();
  87. var timeGap = minTimeGap < TIME_GAP_STEP ? minTimeGap : Math.floor(minTimeGap / TIME_GAP_STEP) * TIME_GAP_STEP;
  88. var colsCount = Math.ceil(days / timeGap);
  89. var canvasWidth = Math.max(minWidth, colsCount * MIN_COL_WIDTH);
  90. var colWidth = Math.floor(canvasWidth / colsCount);
  91. var pxPerMs = colWidth / (timeGap * ONE_DAY);
  92. $ganttCanvas.css('width', canvasWidth).find('.gantt-col').remove();
  93. for (var i = 0; i < colsCount; ++i)
  94. {
  95. var $col = $('<div class="gantt-col"></div>');
  96. $col.css(
  97. {
  98. left: i * colWidth,
  99. width: colWidth,
  100. height: canvasHeight
  101. });
  102. var colTime = startDatetime + i * timeGap * ONE_DAY;
  103. $col.append('<div class="gantt-col-time text-muted small">' + zui.formatDate(colTime, 'MM/dd') + '</div>');
  104. $ganttCanvas.append($col);
  105. }
  106. $.each(plans, function(index, plan)
  107. {
  108. var $planRow = $gantt.find('.gantt-row[data-id="' + plan.id + '"]');
  109. $planRow.find('.gantt-bar').css(
  110. {
  111. left: Math.floor((plan.startDatetime - startDatetime) * pxPerMs),
  112. width: Math.floor((plan.endDatetime - plan.startDatetime) * pxPerMs)
  113. });
  114. });
  115. $gantt.find('.gantt-today').css('left', (Date.now() - startDatetime) * pxPerMs);
  116. /**
  117. * Create date from string
  118. *
  119. * @param {String} dateStr like '2020-08-02'
  120. * @return {Number} Date timestramp
  121. */
  122. function createDatetime(dateStr)
  123. {
  124. dateStr = dateStr.split('-');
  125. var year = Number.parseInt(dateStr[0].length > 3 ? dateStr[0] : dateStr[2], 10);
  126. var month = Number.parseInt(dateStr[1], 10);
  127. var day = Number.parseInt(dateStr[2].length > 3 ? dateStr[0] : dateStr[2], 10);
  128. return new Date(year, month - 1, day).getTime();
  129. }
  130. }