@@ -12,6 +12,39 | |||
|
12 | 12 | <%= render :partial => 'queries/filters', :locals => {:query => @query} %> |
|
13 | 13 | </div> |
|
14 | 14 | </fieldset> |
|
15 | <fieldset id="filters" class="collapsible"> | |
|
16 | <legend onclick="toggleFieldset(this);"><%= l(:label_display) %></legend> | |
|
17 | <div> | |
|
18 | <table> | |
|
19 | <tr> | |
|
20 | <td> | |
|
21 | <fieldset> | |
|
22 | <legend><%= l(:label_related_issues) %></legend> | |
|
23 | <label> | |
|
24 | <%= check_box_tag "draw_rels", params["draw_rels"], true %> | |
|
25 | <% rels = [IssueRelation::TYPE_BLOCKS, IssueRelation::TYPE_PRECEDES] %> | |
|
26 | <% rels.each do |rel| %> | |
|
27 | <% color = Redmine::Helpers::Gantt::DRAW_TYPES[rel][:color] %> | |
|
28 | <%= content_tag(:span, ' '.html_safe, | |
|
29 | :style => "background-color: #{color}") %> | |
|
30 | <%= l(IssueRelation::TYPES[rel][:name]) %> | |
|
31 | <% end %> | |
|
32 | </label> | |
|
33 | </fieldset> | |
|
34 | </td> | |
|
35 | <td> | |
|
36 | <fieldset> | |
|
37 | <legend><%= l(:label_gantt_progress_line) %></legend> | |
|
38 | <label> | |
|
39 | <%= check_box_tag "draw_progress_line", params[:draw_progress_line], false %> | |
|
40 | <%= l(:label_display) %> | |
|
41 | </label> | |
|
42 | </fieldset> | |
|
43 | </td> | |
|
44 | </tr> | |
|
45 | </table> | |
|
46 | </div> | |
|
47 | </fieldset> | |
|
15 | 48 | |
|
16 | 49 | <p class="contextual"> |
|
17 | 50 | <%= gantt_zoom_link(@gantt, :in) %> |
@@ -229,7 +262,7 | |||
|
229 | 262 | style += "width:10px;" |
|
230 | 263 | style += "border-left: 1px dashed red;" |
|
231 | 264 | %> |
|
232 | <%= content_tag(:div, ' '.html_safe, :style => style) %> | |
|
265 | <%= content_tag(:div, ' '.html_safe, :style => style, :id => 'today_line') %> | |
|
233 | 266 | <% end %> |
|
234 | 267 | <% |
|
235 | 268 | style = "" |
@@ -279,4 +312,8 | |||
|
279 | 312 | var issue_relation_type = <%= raw Redmine::Helpers::Gantt::DRAW_TYPES.to_json %>; |
|
280 | 313 | $(document).ready(drawGanttHandler); |
|
281 | 314 | $(window).resize(drawGanttHandler); |
|
315 | $(function() { | |
|
316 | $("#draw_rels").change(drawGanttHandler); | |
|
317 | $("#draw_progress_line").change(drawGanttHandler); | |
|
318 | }); | |
|
282 | 319 | <% end %> |
@@ -886,6 +886,7 en: | |||
|
886 | 886 | label_cross_project_tree: With project tree |
|
887 | 887 | label_cross_project_hierarchy: With project hierarchy |
|
888 | 888 | label_cross_project_system: With all projects |
|
889 | label_gantt_progress_line: Progress line | |
|
889 | 890 | |
|
890 | 891 | button_login: Login |
|
891 | 892 | button_submit: Submit |
@@ -833,6 +833,7 ja: | |||
|
833 | 833 | label_git_report_last_commit: ファイルとディレクトリの最新コミットを表示する |
|
834 | 834 | label_parent_revision: 親 |
|
835 | 835 | label_child_revision: 子 |
|
836 | label_gantt_progress_line: イナズマ線 | |
|
836 | 837 | |
|
837 | 838 | button_login: ログイン |
|
838 | 839 | button_submit: 送信 |
@@ -308,10 +308,18 module Redmine | |||
|
308 | 308 | html_class << 'icon icon-package ' |
|
309 | 309 | html_class << (version.behind_schedule? ? 'version-behind-schedule' : '') << " " |
|
310 | 310 | html_class << (version.overdue? ? 'version-overdue' : '') |
|
311 | html_class << ' version-closed' unless version.open? | |
|
312 | if version.start_date && version.due_date && version.completed_pourcent | |
|
313 | progress_date = calc_progress_date(version.start_date, | |
|
314 | version.due_date, version.completed_pourcent) | |
|
315 | html_class << ' behind-start-date' if progress_date < self.date_from | |
|
316 | html_class << ' over-end-date' if progress_date > self.date_to | |
|
317 | end | |
|
311 | 318 | s = view.link_to_version(version).html_safe |
|
312 | 319 | subject = view.content_tag(:span, s, |
|
313 | 320 | :class => html_class).html_safe |
|
314 |
html_subject(options, subject, :css => "version-name" |
|
|
321 | html_subject(options, subject, :css => "version-name", | |
|
322 | :id => "version-#{version.id}") | |
|
315 | 323 | when :image |
|
316 | 324 | image_subject(options, version.to_s_with_project) |
|
317 | 325 | when :pdf |
@@ -332,7 +340,8 module Redmine | |||
|
332 | 340 | label = h("#{version.project} -") + label unless @project && @project == version.project |
|
333 | 341 | case options[:format] |
|
334 | 342 | when :html |
|
335 |
html_task(options, coords, :css => "version task", |
|
|
343 | html_task(options, coords, :css => "version task", | |
|
344 | :label => label, :markers => true, :version => version) | |
|
336 | 345 | when :image |
|
337 | 346 | image_task(options, coords, :label => label, :markers => true, :height => 3) |
|
338 | 347 | when :pdf |
@@ -354,6 +363,13 module Redmine | |||
|
354 | 363 | css_classes << ' issue-overdue' if issue.overdue? |
|
355 | 364 | css_classes << ' issue-behind-schedule' if issue.behind_schedule? |
|
356 | 365 | css_classes << ' icon icon-issue' unless Setting.gravatar_enabled? && issue.assigned_to |
|
366 | css_classes << ' issue-closed' if issue.closed? | |
|
367 | if issue.start_date && issue.due_before && issue.done_ratio | |
|
368 | progress_date = calc_progress_date(issue.start_date, | |
|
369 | issue.due_before, issue.done_ratio) | |
|
370 | css_classes << ' behind-start-date' if progress_date < self.date_from | |
|
371 | css_classes << ' over-end-date' if progress_date > self.date_to | |
|
372 | end | |
|
357 | 373 | s = "".html_safe |
|
358 | 374 | if issue.assigned_to.present? |
|
359 | 375 | assigned_string = l(:field_assigned_to) + ": " + issue.assigned_to.name |
@@ -365,7 +381,7 module Redmine | |||
|
365 | 381 | s << view.link_to_issue(issue).html_safe |
|
366 | 382 | subject = view.content_tag(:span, s, :class => css_classes).html_safe |
|
367 | 383 | html_subject(options, subject, :css => "issue-subject", |
|
368 | :title => issue.subject) + "\n" | |
|
384 | :title => issue.subject, :id => "issue-#{issue.id}") + "\n" | |
|
369 | 385 | when :image |
|
370 | 386 | image_subject(options, issue.subject) |
|
371 | 387 | when :pdf |
@@ -628,7 +644,7 module Redmine | |||
|
628 | 644 | coords[:bar_end] = self.date_to - self.date_from + 1 |
|
629 | 645 | end |
|
630 | 646 | if progress |
|
631 |
progress_date = start_date |
|
|
647 | progress_date = calc_progress_date(start_date, end_date, progress) | |
|
632 | 648 | if progress_date > self.date_from && progress_date > start_date |
|
633 | 649 | if progress_date < self.date_to |
|
634 | 650 | coords[:bar_progress_end] = progress_date - self.date_from |
@@ -655,6 +671,10 module Redmine | |||
|
655 | 671 | coords |
|
656 | 672 | end |
|
657 | 673 | |
|
674 | def calc_progress_date(start_date, end_date, progress) | |
|
675 | start_date + (end_date - start_date + 1) * (progress / 100.0) | |
|
676 | end | |
|
677 | ||
|
658 | 678 | # Sorts a collection of issues by start_date, due_date, id for gantt rendering |
|
659 | 679 | def sort_issues!(issues) |
|
660 | 680 | issues.sort! { |a, b| gantt_issue_compare(a, b) } |
@@ -695,9 +715,10 module Redmine | |||
|
695 | 715 | def html_subject(params, subject, options={}) |
|
696 | 716 | style = "position: absolute;top:#{params[:top]}px;left:#{params[:indent]}px;" |
|
697 | 717 | style << "width:#{params[:subject_width] - params[:indent]}px;" if params[:subject_width] |
|
698 |
output = view.content_tag( |
|
|
718 | output = view.content_tag(:div, subject, | |
|
699 | 719 | :class => options[:css], :style => style, |
|
700 |
:title => options[:title] |
|
|
720 | :title => options[:title], | |
|
721 | :id => options[:id]) | |
|
701 | 722 | @subjects << output |
|
702 | 723 | output |
|
703 | 724 | end |
@@ -742,6 +763,7 module Redmine | |||
|
742 | 763 | style << "left:#{coords[:bar_start]}px;" |
|
743 | 764 | style << "width:#{width}px;" |
|
744 | 765 | html_id = "task-todo-issue-#{options[:issue].id}" if options[:issue] |
|
766 | html_id = "task-todo-version-#{options[:version].id}" if options[:version] | |
|
745 | 767 | content_opt = {:style => style, |
|
746 | 768 | :class => "#{options[:css]} task_todo", |
|
747 | 769 | :id => html_id} |
@@ -768,9 +790,12 module Redmine | |||
|
768 | 790 | style << "top:#{params[:top]}px;" |
|
769 | 791 | style << "left:#{coords[:bar_start]}px;" |
|
770 | 792 | style << "width:#{width}px;" |
|
793 | html_id = "task-done-issue-#{options[:issue].id}" if options[:issue] | |
|
794 | html_id = "task-done-version-#{options[:version].id}" if options[:version] | |
|
771 | 795 | output << view.content_tag(:div, ' '.html_safe, |
|
772 | 796 | :style => style, |
|
773 |
:class => "#{options[:css]} task_done" |
|
|
797 | :class => "#{options[:css]} task_done", | |
|
798 | :id => html_id) | |
|
774 | 799 | end |
|
775 | 800 | end |
|
776 | 801 | # Renders the markers |
@@ -98,6 +98,66 function drawRelations() { | |||
|
98 | 98 | }); |
|
99 | 99 | } |
|
100 | 100 | |
|
101 | function getProgressLinesArray() { | |
|
102 | var arr = new Array(); | |
|
103 | var today_left = $('#today_line').position().left; | |
|
104 | arr.push({left: today_left, top: 0}); | |
|
105 | $.each($('div.issue-subject, div.version-name'), function(index, element) { | |
|
106 | var t = $(element).position().top - draw_top ; | |
|
107 | var h = ($(element).height() / 9); | |
|
108 | var element_top_upper = t - h; | |
|
109 | var element_top_center = t + (h * 3); | |
|
110 | var element_top_lower = t + (h * 8); | |
|
111 | var issue_closed = $(element).children('span').hasClass('issue-closed'); | |
|
112 | var version_closed = $(element).children('span').hasClass('version-closed'); | |
|
113 | if (issue_closed || version_closed) { | |
|
114 | arr.push({left: today_left, top: element_top_center}); | |
|
115 | } else { | |
|
116 | var issue_done = $("#task-done-" + $(element).attr("id")); | |
|
117 | var is_behind_start = $(element).children('span').hasClass('behind-start-date'); | |
|
118 | var is_over_end = $(element).children('span').hasClass('over-end-date'); | |
|
119 | if (is_over_end) { | |
|
120 | arr.push({left: draw_right, top: element_top_upper, is_right_edge: true}); | |
|
121 | arr.push({left: draw_right, top: element_top_lower, is_right_edge: true, none_stroke: true}); | |
|
122 | } else if (issue_done.size() > 0) { | |
|
123 | var done_left = issue_done.first().position().left + | |
|
124 | issue_done.first().width(); | |
|
125 | arr.push({left: done_left, top: element_top_center}); | |
|
126 | } else if (is_behind_start) { | |
|
127 | arr.push({left: 0 , top: element_top_upper, is_left_edge: true}); | |
|
128 | arr.push({left: 0 , top: element_top_lower, is_left_edge: true, none_stroke: true}); | |
|
129 | } else { | |
|
130 | var todo_left = today_left; | |
|
131 | var issue_todo = $("#task-todo-" + $(element).attr("id")); | |
|
132 | if (issue_todo.size() > 0){ | |
|
133 | todo_left = issue_todo.first().position().left; | |
|
134 | } | |
|
135 | arr.push({left: Math.min(today_left, todo_left), top: element_top_center}); | |
|
136 | } | |
|
137 | } | |
|
138 | }); | |
|
139 | return arr; | |
|
140 | } | |
|
141 | ||
|
142 | function drawGanttProgressLines() { | |
|
143 | var arr = getProgressLinesArray(); | |
|
144 | var color = $("#today_line") | |
|
145 | .css("border-left-color"); | |
|
146 | var i; | |
|
147 | for(i = 1 ; i < arr.length ; i++) { | |
|
148 | if (!("none_stroke" in arr[i]) && | |
|
149 | (!("is_right_edge" in arr[i - 1] && "is_right_edge" in arr[i]) && | |
|
150 | !("is_left_edge" in arr[i - 1] && "is_left_edge" in arr[i])) | |
|
151 | ) { | |
|
152 | var x1 = (arr[i - 1].left == 0) ? 0 : arr[i - 1].left + draw_left; | |
|
153 | var x2 = (arr[i].left == 0) ? 0 : arr[i].left + draw_left; | |
|
154 | draw_gantt.path(["M", x1, arr[i - 1].top, | |
|
155 | "L", x2, arr[i].top]) | |
|
156 | .attr({stroke: color, "stroke-width": 2}); | |
|
157 | } | |
|
158 | } | |
|
159 | } | |
|
160 | ||
|
101 | 161 | function drawGanttHandler() { |
|
102 | 162 | var folder = document.getElementById('gantt_draw_area'); |
|
103 | 163 | if(draw_gantt != null) |
@@ -105,5 +165,8 function drawGanttHandler() { | |||
|
105 | 165 | else |
|
106 | 166 | draw_gantt = Raphael(folder); |
|
107 | 167 | setDrawArea(); |
|
168 | if ($("#draw_progress_line").attr('checked')) | |
|
169 | drawGanttProgressLines(); | |
|
170 | if ($("#draw_rels").attr('checked')) | |
|
108 | 171 | drawRelations(); |
|
109 | 172 | } |
General Comments 0
You need to be logged in to leave comments.
Login now