@@ -12,6 +12,39 | |||||
12 | <%= render :partial => 'queries/filters', :locals => {:query => @query} %> |
|
12 | <%= render :partial => 'queries/filters', :locals => {:query => @query} %> | |
13 | </div> |
|
13 | </div> | |
14 | </fieldset> |
|
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 | <p class="contextual"> |
|
49 | <p class="contextual"> | |
17 | <%= gantt_zoom_link(@gantt, :in) %> |
|
50 | <%= gantt_zoom_link(@gantt, :in) %> | |
@@ -229,7 +262,7 | |||||
229 | style += "width:10px;" |
|
262 | style += "width:10px;" | |
230 | style += "border-left: 1px dashed red;" |
|
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 | <% end %> |
|
266 | <% end %> | |
234 | <% |
|
267 | <% | |
235 | style = "" |
|
268 | style = "" | |
@@ -279,4 +312,8 | |||||
279 | var issue_relation_type = <%= raw Redmine::Helpers::Gantt::DRAW_TYPES.to_json %>; |
|
312 | var issue_relation_type = <%= raw Redmine::Helpers::Gantt::DRAW_TYPES.to_json %>; | |
280 | $(document).ready(drawGanttHandler); |
|
313 | $(document).ready(drawGanttHandler); | |
281 | $(window).resize(drawGanttHandler); |
|
314 | $(window).resize(drawGanttHandler); | |
|
315 | $(function() { | |||
|
316 | $("#draw_rels").change(drawGanttHandler); | |||
|
317 | $("#draw_progress_line").change(drawGanttHandler); | |||
|
318 | }); | |||
282 | <% end %> |
|
319 | <% end %> |
@@ -886,6 +886,7 en: | |||||
886 | label_cross_project_tree: With project tree |
|
886 | label_cross_project_tree: With project tree | |
887 | label_cross_project_hierarchy: With project hierarchy |
|
887 | label_cross_project_hierarchy: With project hierarchy | |
888 | label_cross_project_system: With all projects |
|
888 | label_cross_project_system: With all projects | |
|
889 | label_gantt_progress_line: Progress line | |||
889 |
|
890 | |||
890 | button_login: Login |
|
891 | button_login: Login | |
891 | button_submit: Submit |
|
892 | button_submit: Submit |
@@ -833,6 +833,7 ja: | |||||
833 | label_git_report_last_commit: ファイルとディレクトリの最新コミットを表示する |
|
833 | label_git_report_last_commit: ファイルとディレクトリの最新コミットを表示する | |
834 | label_parent_revision: 親 |
|
834 | label_parent_revision: 親 | |
835 | label_child_revision: 子 |
|
835 | label_child_revision: 子 | |
|
836 | label_gantt_progress_line: イナズマ線 | |||
836 |
|
837 | |||
837 | button_login: ログイン |
|
838 | button_login: ログイン | |
838 | button_submit: 送信 |
|
839 | button_submit: 送信 |
@@ -308,10 +308,18 module Redmine | |||||
308 | html_class << 'icon icon-package ' |
|
308 | html_class << 'icon icon-package ' | |
309 | html_class << (version.behind_schedule? ? 'version-behind-schedule' : '') << " " |
|
309 | html_class << (version.behind_schedule? ? 'version-behind-schedule' : '') << " " | |
310 | html_class << (version.overdue? ? 'version-overdue' : '') |
|
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 | s = view.link_to_version(version).html_safe |
|
318 | s = view.link_to_version(version).html_safe | |
312 | subject = view.content_tag(:span, s, |
|
319 | subject = view.content_tag(:span, s, | |
313 | :class => html_class).html_safe |
|
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 | when :image |
|
323 | when :image | |
316 | image_subject(options, version.to_s_with_project) |
|
324 | image_subject(options, version.to_s_with_project) | |
317 | when :pdf |
|
325 | when :pdf | |
@@ -332,7 +340,8 module Redmine | |||||
332 | label = h("#{version.project} -") + label unless @project && @project == version.project |
|
340 | label = h("#{version.project} -") + label unless @project && @project == version.project | |
333 | case options[:format] |
|
341 | case options[:format] | |
334 | when :html |
|
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 | when :image |
|
345 | when :image | |
337 | image_task(options, coords, :label => label, :markers => true, :height => 3) |
|
346 | image_task(options, coords, :label => label, :markers => true, :height => 3) | |
338 | when :pdf |
|
347 | when :pdf | |
@@ -354,6 +363,13 module Redmine | |||||
354 | css_classes << ' issue-overdue' if issue.overdue? |
|
363 | css_classes << ' issue-overdue' if issue.overdue? | |
355 | css_classes << ' issue-behind-schedule' if issue.behind_schedule? |
|
364 | css_classes << ' issue-behind-schedule' if issue.behind_schedule? | |
356 | css_classes << ' icon icon-issue' unless Setting.gravatar_enabled? && issue.assigned_to |
|
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 | s = "".html_safe |
|
373 | s = "".html_safe | |
358 | if issue.assigned_to.present? |
|
374 | if issue.assigned_to.present? | |
359 | assigned_string = l(:field_assigned_to) + ": " + issue.assigned_to.name |
|
375 | assigned_string = l(:field_assigned_to) + ": " + issue.assigned_to.name | |
@@ -365,7 +381,7 module Redmine | |||||
365 | s << view.link_to_issue(issue).html_safe |
|
381 | s << view.link_to_issue(issue).html_safe | |
366 | subject = view.content_tag(:span, s, :class => css_classes).html_safe |
|
382 | subject = view.content_tag(:span, s, :class => css_classes).html_safe | |
367 | html_subject(options, subject, :css => "issue-subject", |
|
383 | html_subject(options, subject, :css => "issue-subject", | |
368 | :title => issue.subject) + "\n" |
|
384 | :title => issue.subject, :id => "issue-#{issue.id}") + "\n" | |
369 | when :image |
|
385 | when :image | |
370 | image_subject(options, issue.subject) |
|
386 | image_subject(options, issue.subject) | |
371 | when :pdf |
|
387 | when :pdf | |
@@ -628,7 +644,7 module Redmine | |||||
628 | coords[:bar_end] = self.date_to - self.date_from + 1 |
|
644 | coords[:bar_end] = self.date_to - self.date_from + 1 | |
629 | end |
|
645 | end | |
630 | if progress |
|
646 | if progress | |
631 |
progress_date = start_date |
|
647 | progress_date = calc_progress_date(start_date, end_date, progress) | |
632 | if progress_date > self.date_from && progress_date > start_date |
|
648 | if progress_date > self.date_from && progress_date > start_date | |
633 | if progress_date < self.date_to |
|
649 | if progress_date < self.date_to | |
634 | coords[:bar_progress_end] = progress_date - self.date_from |
|
650 | coords[:bar_progress_end] = progress_date - self.date_from | |
@@ -655,6 +671,10 module Redmine | |||||
655 | coords |
|
671 | coords | |
656 | end |
|
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 | # Sorts a collection of issues by start_date, due_date, id for gantt rendering |
|
678 | # Sorts a collection of issues by start_date, due_date, id for gantt rendering | |
659 | def sort_issues!(issues) |
|
679 | def sort_issues!(issues) | |
660 | issues.sort! { |a, b| gantt_issue_compare(a, b) } |
|
680 | issues.sort! { |a, b| gantt_issue_compare(a, b) } | |
@@ -695,9 +715,10 module Redmine | |||||
695 | def html_subject(params, subject, options={}) |
|
715 | def html_subject(params, subject, options={}) | |
696 | style = "position: absolute;top:#{params[:top]}px;left:#{params[:indent]}px;" |
|
716 | style = "position: absolute;top:#{params[:top]}px;left:#{params[:indent]}px;" | |
697 | style << "width:#{params[:subject_width] - params[:indent]}px;" if params[:subject_width] |
|
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 | :class => options[:css], :style => style, |
|
719 | :class => options[:css], :style => style, | |
700 |
:title => options[:title] |
|
720 | :title => options[:title], | |
|
721 | :id => options[:id]) | |||
701 | @subjects << output |
|
722 | @subjects << output | |
702 | output |
|
723 | output | |
703 | end |
|
724 | end | |
@@ -742,6 +763,7 module Redmine | |||||
742 | style << "left:#{coords[:bar_start]}px;" |
|
763 | style << "left:#{coords[:bar_start]}px;" | |
743 | style << "width:#{width}px;" |
|
764 | style << "width:#{width}px;" | |
744 | html_id = "task-todo-issue-#{options[:issue].id}" if options[:issue] |
|
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 | content_opt = {:style => style, |
|
767 | content_opt = {:style => style, | |
746 | :class => "#{options[:css]} task_todo", |
|
768 | :class => "#{options[:css]} task_todo", | |
747 | :id => html_id} |
|
769 | :id => html_id} | |
@@ -768,9 +790,12 module Redmine | |||||
768 | style << "top:#{params[:top]}px;" |
|
790 | style << "top:#{params[:top]}px;" | |
769 | style << "left:#{coords[:bar_start]}px;" |
|
791 | style << "left:#{coords[:bar_start]}px;" | |
770 | style << "width:#{width}px;" |
|
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 | output << view.content_tag(:div, ' '.html_safe, |
|
795 | output << view.content_tag(:div, ' '.html_safe, | |
772 | :style => style, |
|
796 | :style => style, | |
773 |
:class => "#{options[:css]} task_done" |
|
797 | :class => "#{options[:css]} task_done", | |
|
798 | :id => html_id) | |||
774 | end |
|
799 | end | |
775 | end |
|
800 | end | |
776 | # Renders the markers |
|
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 | function drawGanttHandler() { |
|
161 | function drawGanttHandler() { | |
102 | var folder = document.getElementById('gantt_draw_area'); |
|
162 | var folder = document.getElementById('gantt_draw_area'); | |
103 | if(draw_gantt != null) |
|
163 | if(draw_gantt != null) | |
@@ -105,5 +165,8 function drawGanttHandler() { | |||||
105 | else |
|
165 | else | |
106 | draw_gantt = Raphael(folder); |
|
166 | draw_gantt = Raphael(folder); | |
107 | setDrawArea(); |
|
167 | setDrawArea(); | |
108 | drawRelations(); |
|
168 | if ($("#draw_progress_line").attr('checked')) | |
|
169 | drawGanttProgressLines(); | |||
|
170 | if ($("#draw_rels").attr('checked')) | |||
|
171 | drawRelations(); | |||
109 | } |
|
172 | } |
General Comments 0
You need to be logged in to leave comments.
Login now