Feature #12122 » gantt-progress-line-html-r11137.diff
app/views/gantts/show.html.erb | ||
---|---|---|
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 |
<label> |
|
19 |
<%= check_box_tag "draw_progress_line", 0, params[:draw_progress_line] %> |
|
20 |
<%= l(:label_gantt_progress_line) %> |
|
21 |
</label> |
|
22 |
</div> |
|
23 |
</fieldset> |
|
15 | 24 | |
16 | 25 |
<p class="contextual"> |
17 | 26 |
<%= gantt_zoom_link(@gantt, :in) %> |
... | ... | |
229 | 238 |
style += "width:10px;" |
230 | 239 |
style += "border-left: 1px dashed red;" |
231 | 240 |
%> |
232 |
<%= content_tag(:div, ' '.html_safe, :style => style) %> |
|
241 |
<%= content_tag(:div, ' '.html_safe, :style => style, :id => 'today_line') %>
|
|
233 | 242 |
<% end %> |
234 | 243 |
<% |
235 | 244 |
style = "" |
... | ... | |
279 | 288 |
var issue_relation_type = <%= raw Redmine::Helpers::Gantt::DRAW_TYPES.to_json %>; |
280 | 289 |
$(document).ready(drawGanttHandler); |
281 | 290 |
$(window).resize(drawGanttHandler); |
291 |
$(function() { |
|
292 |
$("#draw_progress_line").change(drawGanttHandler); |
|
293 |
}); |
|
282 | 294 |
<% end %> |
config/locales/en.yml | ||
---|---|---|
883 | 883 |
label_cross_project_tree: With project tree |
884 | 884 |
label_cross_project_hierarchy: With project hierarchy |
885 | 885 |
label_cross_project_system: With all projects |
886 |
label_gantt_progress_line: Progress line |
|
886 | 887 | |
887 | 888 |
button_login: Login |
888 | 889 |
button_submit: Submit |
config/locales/ja.yml | ||
---|---|---|
834 | 834 |
label_git_report_last_commit: ファイルとディレクトリの最新コミットを表示する |
835 | 835 |
label_parent_revision: 親 |
836 | 836 |
label_child_revision: 子 |
837 |
label_gantt_progress_line: イナズマ線 |
|
837 | 838 | |
838 | 839 |
button_login: ログイン |
839 | 840 |
button_submit: 送信 |
lib/redmine/helpers/gantt.rb | ||
---|---|---|
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 | 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", :label => label, :markers => true) |
|
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 | 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 | 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 | 644 |
coords[:bar_end] = self.date_to - self.date_from + 1 |
629 | 645 |
end |
630 | 646 |
if progress |
631 |
progress_date = start_date + (end_date - start_date + 1) * (progress / 100.0)
|
|
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 | 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 | 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('div', subject,
|
|
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 | 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 | 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 |
public/javascripts/gantt.js | ||
---|---|---|
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 | 165 |
else |
106 | 166 |
draw_gantt = Raphael(folder); |
107 | 167 |
setDrawArea(); |
168 |
if ($("#draw_progress_line").attr('checked')) |
|
169 |
drawGanttProgressLines(); |
|
108 | 170 |
drawRelations(); |
109 | 171 |
} |