You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

gantt.js 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /* Redmine - project management software
  2. Copyright (C) 2006-2015 Jean-Philippe Lang */
  3. var draw_gantt = null;
  4. var draw_top;
  5. var draw_right;
  6. var draw_left;
  7. var rels_stroke_width = 2;
  8. function setDrawArea() {
  9. draw_top = $("#gantt_draw_area").position().top;
  10. draw_right = $("#gantt_draw_area").width();
  11. draw_left = $("#gantt_area").scrollLeft();
  12. }
  13. function getRelationsArray() {
  14. var arr = new Array();
  15. $.each($('div.task_todo[data-rels]'), function(index_div, element) {
  16. var element_id = $(element).attr("id");
  17. if (element_id != null) {
  18. var issue_id = element_id.replace("task-todo-issue-", "");
  19. var data_rels = $(element).data("rels");
  20. for (rel_type_key in data_rels) {
  21. $.each(data_rels[rel_type_key], function(index_issue, element_issue) {
  22. arr.push({issue_from: issue_id, issue_to: element_issue,
  23. rel_type: rel_type_key});
  24. });
  25. }
  26. }
  27. });
  28. return arr;
  29. }
  30. function drawRelations() {
  31. var arr = getRelationsArray();
  32. $.each(arr, function(index_issue, element_issue) {
  33. var issue_from = $("#task-todo-issue-" + element_issue["issue_from"]);
  34. var issue_to = $("#task-todo-issue-" + element_issue["issue_to"]);
  35. if (issue_from.size() == 0 || issue_to.size() == 0) {
  36. return;
  37. }
  38. var issue_height = issue_from.height();
  39. var issue_from_top = issue_from.position().top + (issue_height / 2) - draw_top;
  40. var issue_from_right = issue_from.position().left + issue_from.width();
  41. var issue_to_top = issue_to.position().top + (issue_height / 2) - draw_top;
  42. var issue_to_left = issue_to.position().left;
  43. var color = issue_relation_type[element_issue["rel_type"]]["color"];
  44. var landscape_margin = issue_relation_type[element_issue["rel_type"]]["landscape_margin"];
  45. var issue_from_right_rel = issue_from_right + landscape_margin;
  46. var issue_to_left_rel = issue_to_left - landscape_margin;
  47. draw_gantt.path(["M", issue_from_right + draw_left, issue_from_top,
  48. "L", issue_from_right_rel + draw_left, issue_from_top])
  49. .attr({stroke: color,
  50. "stroke-width": rels_stroke_width
  51. });
  52. if (issue_from_right_rel < issue_to_left_rel) {
  53. draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_from_top,
  54. "L", issue_from_right_rel + draw_left, issue_to_top])
  55. .attr({stroke: color,
  56. "stroke-width": rels_stroke_width
  57. });
  58. draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_to_top,
  59. "L", issue_to_left + draw_left, issue_to_top])
  60. .attr({stroke: color,
  61. "stroke-width": rels_stroke_width
  62. });
  63. } else {
  64. var issue_middle_top = issue_to_top +
  65. (issue_height *
  66. ((issue_from_top > issue_to_top) ? 1 : -1));
  67. draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_from_top,
  68. "L", issue_from_right_rel + draw_left, issue_middle_top])
  69. .attr({stroke: color,
  70. "stroke-width": rels_stroke_width
  71. });
  72. draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_middle_top,
  73. "L", issue_to_left_rel + draw_left, issue_middle_top])
  74. .attr({stroke: color,
  75. "stroke-width": rels_stroke_width
  76. });
  77. draw_gantt.path(["M", issue_to_left_rel + draw_left, issue_middle_top,
  78. "L", issue_to_left_rel + draw_left, issue_to_top])
  79. .attr({stroke: color,
  80. "stroke-width": rels_stroke_width
  81. });
  82. draw_gantt.path(["M", issue_to_left_rel + draw_left, issue_to_top,
  83. "L", issue_to_left + draw_left, issue_to_top])
  84. .attr({stroke: color,
  85. "stroke-width": rels_stroke_width
  86. });
  87. }
  88. draw_gantt.path(["M", issue_to_left + draw_left, issue_to_top,
  89. "l", -4 * rels_stroke_width, -2 * rels_stroke_width,
  90. "l", 0, 4 * rels_stroke_width, "z"])
  91. .attr({stroke: "none",
  92. fill: color,
  93. "stroke-linecap": "butt",
  94. "stroke-linejoin": "miter"
  95. });
  96. });
  97. }
  98. function getProgressLinesArray() {
  99. var arr = new Array();
  100. var today_left = $('#today_line').position().left;
  101. arr.push({left: today_left, top: 0});
  102. $.each($('div.issue-subject, div.version-name'), function(index, element) {
  103. var t = $(element).position().top - draw_top ;
  104. var h = ($(element).height() / 9);
  105. var element_top_upper = t - h;
  106. var element_top_center = t + (h * 3);
  107. var element_top_lower = t + (h * 8);
  108. var issue_closed = $(element).children('span').hasClass('issue-closed');
  109. var version_closed = $(element).children('span').hasClass('version-closed');
  110. if (issue_closed || version_closed) {
  111. arr.push({left: today_left, top: element_top_center});
  112. } else {
  113. var issue_done = $("#task-done-" + $(element).attr("id"));
  114. var is_behind_start = $(element).children('span').hasClass('behind-start-date');
  115. var is_over_end = $(element).children('span').hasClass('over-end-date');
  116. if (is_over_end) {
  117. arr.push({left: draw_right, top: element_top_upper, is_right_edge: true});
  118. arr.push({left: draw_right, top: element_top_lower, is_right_edge: true, none_stroke: true});
  119. } else if (issue_done.size() > 0) {
  120. var done_left = issue_done.first().position().left +
  121. issue_done.first().width();
  122. arr.push({left: done_left, top: element_top_center});
  123. } else if (is_behind_start) {
  124. arr.push({left: 0 , top: element_top_upper, is_left_edge: true});
  125. arr.push({left: 0 , top: element_top_lower, is_left_edge: true, none_stroke: true});
  126. } else {
  127. var todo_left = today_left;
  128. var issue_todo = $("#task-todo-" + $(element).attr("id"));
  129. if (issue_todo.size() > 0){
  130. todo_left = issue_todo.first().position().left;
  131. }
  132. arr.push({left: Math.min(today_left, todo_left), top: element_top_center});
  133. }
  134. }
  135. });
  136. return arr;
  137. }
  138. function drawGanttProgressLines() {
  139. var arr = getProgressLinesArray();
  140. var color = $("#today_line")
  141. .css("border-left-color");
  142. var i;
  143. for(i = 1 ; i < arr.length ; i++) {
  144. if (!("none_stroke" in arr[i]) &&
  145. (!("is_right_edge" in arr[i - 1] && "is_right_edge" in arr[i]) &&
  146. !("is_left_edge" in arr[i - 1] && "is_left_edge" in arr[i]))
  147. ) {
  148. var x1 = (arr[i - 1].left == 0) ? 0 : arr[i - 1].left + draw_left;
  149. var x2 = (arr[i].left == 0) ? 0 : arr[i].left + draw_left;
  150. draw_gantt.path(["M", x1, arr[i - 1].top,
  151. "L", x2, arr[i].top])
  152. .attr({stroke: color, "stroke-width": 2});
  153. }
  154. }
  155. }
  156. function drawGanttHandler() {
  157. var folder = document.getElementById('gantt_draw_area');
  158. if(draw_gantt != null)
  159. draw_gantt.clear();
  160. else
  161. draw_gantt = Raphael(folder);
  162. setDrawArea();
  163. if ($("#draw_progress_line").prop('checked'))
  164. drawGanttProgressLines();
  165. if ($("#draw_relations").prop('checked'))
  166. drawRelations();
  167. }