Project

General

Profile

Feature #3436 » gantt-relations-r10943.diff

Toshi MARUYAMA, 2012-12-05 11:49

View differences:

app/views/gantts/show.html.erb
1
<% content_for :header_tags do %>
2
  <%= javascript_include_tag 'raphael' %>
3
  <%= javascript_include_tag 'gantt' %>
4
<% end %>
5
<%= javascript_tag do %>
6
  $(document).ready(drawGanttHandler);
7
  $(window).resize(drawGanttHandler);
8
<% end %>
1 9
<% @gantt.view = self %>
2 10
<h2><%= @query.new_record? ? l(:label_gantt) : h(@query.name) %></h2>
3 11

  
......
102 110
</td>
103 111

  
104 112
<td>
105
<div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;">
113
<div style="position:relative;height:<%= t_height + 24 %>px;overflow:auto;" id="gantt_area">
106 114
<%
107 115
  style  = ""
108 116
  style += "width: #{g_width - 1}px;"
......
231 239
  %>
232 240
  <%= content_tag(:div, '&nbsp;'.html_safe, :style => style) %>
233 241
<% end %>
234

  
242
<%
243
  style  = ""
244
  style += "position: absolute;"
245
  style += "height: #{g_height}px;"
246
  style += "top: #{headers_height + 1}px;"
247
  style += "left: 0px;"
248
  style += "width: #{g_width - 1}px;"
249
%>
250
<%= content_tag(:div, '', :style => style, :id => "gantt_draw_area") %>
235 251
</div>
236 252
</td>
237 253
</tr>
public/javascripts/gantt.js
1
var draw_gantt = null;
2
var draw_top;
3
var draw_right;
4
var draw_left;
5

  
6
function setDrawArea() {
7
  draw_top   = $("#gantt_draw_area").position().top;
8
  draw_right = $("#gantt_draw_area").width();
9
  draw_left  = $("#gantt_area").scrollLeft();
10
}
11

  
12
function drawGanttHandler() {
13
  var folder = document.getElementById('gantt_draw_area');
14
  if(draw_gantt != null)
15
    draw_gantt.clear();
16
  else
17
    draw_gantt = Raphael(folder);
18
  setDrawArea();
19
}
app/views/gantts/show.html.erb
3 3
  <%= javascript_include_tag 'gantt' %>
4 4
<% end %>
5 5
<%= javascript_tag do %>
6
  var issue_relation_type = <%= IssueRelation::TYPES.to_json.html_safe %>;
6 7
  $(document).ready(drawGanttHandler);
7 8
  $(window).resize(drawGanttHandler);
9
  $(function() {
10
    $.each($("#draw_rels").children("label").children("input"), function(index, element) {
11
      $(element).change(drawGanttHandler);
12
    });
13
  });
8 14
<% end %>
9 15
<% @gantt.view = self %>
10 16
<h2><%= @query.new_record? ? l(:label_gantt) : h(@query.name) %></h2>
......
20 26
    <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
21 27
  </div>
22 28
</fieldset>
29
<fieldset id="filters" class="collapsible">
30
  <legend onclick="toggleFieldset(this);"><%= l(:label_display) %></legend>
31
  <div>
32
    <table>
33
      <tr>
34
        <td>
35
          <fieldset id = "draw_rels">
36
            <legend><%= l(:label_related_issues) %></legend>
37
            <%
38
              rels = IssueRelation::TYPES.to_a.select {|rel|
39
                rel[1][:reverse].nil?
40
              }
41
              rels_sorted = rels.sort {|x, y|
42
                              x[1][:order] <=> y[1][:order]
43
                            }.collect{|v| [v[0], l(v[1][:name])]}
44
            %>
45
            <% rels_sorted.each do |rel| %>
46
              <label>
47
                <%= check_box_tag "draw_#{rel[0]}", 0, params["draw_#{rel[0]}"] %>
48
                <%= content_tag(:span, '&nbsp;&nbsp;&nbsp;'.html_safe,
49
                                :id => "gantt_draw_rel_color_#{rel[0]}") %>
50
                <%= rel[1] %>
51
              </label>
52
            <% end %>
53
          </fieldset>
54
      </tr>
55
    </table>
56
  </div>
57
</fieldset>
23 58

  
24 59
<p class="contextual">
25 60
  <%= gantt_zoom_link(@gantt, :in) %>
lib/redmine/helpers/gantt.rb
705 705
        params[:image].text(params[:indent], params[:top] + 2, subject)
706 706
      end
707 707

  
708
      def issue_relations(issue)
709
        relations = {}
710
        issue.relations_to.each do |relation|
711
          relation_type = relation.relation_type_for(relation.issue_to)
712
          (relations[relation_type] ||= []) << relation.issue_from_id
713
        end
714
        relations
715
      end
716

  
708 717
      def html_task(params, coords, options={})
709 718
        output = ''
710 719
        # Renders the task bar, with progress and late
......
714 723
          style << "top:#{params[:top]}px;"
715 724
          style << "left:#{coords[:bar_start]}px;"
716 725
          style << "width:#{width}px;"
717
          output << view.content_tag(:div, '&nbsp;'.html_safe,
718
                                     :style => style,
719
                                     :class => "#{options[:css]} task_todo")
726
          html_id = "task-todo-issue-#{options[:issue].id}" if options[:issue]
727
          content_opt = {:style => style,
728
                         :class => "#{options[:css]} task_todo",
729
                         :id => html_id}
730
          if options[:issue]
731
            relations = issue_relations(options[:issue])
732
            relations.each do |k, v|
733
              content_opt[:"data-rel-#{k}"] = v.join(',')
734
            end
735
          end
736
          output << view.content_tag(:div, '&nbsp;'.html_safe, content_opt)
720 737
          if coords[:bar_late_end]
721 738
            width = coords[:bar_late_end] - coords[:bar_start] - 2
722 739
            style = ""
public/javascripts/gantt.js
3 3
var draw_right;
4 4
var draw_left;
5 5

  
6
var draw_relations = {
7
  "relates": {
8
    "landscape_mergin": 8,
9
    "no_arrow": true,
10
  },
11
  "duplicates": {
12
    "landscape_mergin": 12,
13
  },
14
  "blocks": {
15
    "landscape_mergin": 16,
16
  },
17
  "precedes": {
18
    "landscape_mergin": 20,
19
  },
20
  "copied_to": {
21
    "landscape_mergin": 24,
22
  },
23
};
24

  
6 25
function setDrawArea() {
7 26
  draw_top   = $("#gantt_draw_area").position().top;
8 27
  draw_right = $("#gantt_draw_area").width();
9 28
  draw_left  = $("#gantt_area").scrollLeft();
10 29
}
11 30

  
31
function getRelationsArray() {
32
  var arr = new Array();
33
  $.each($('div.task_todo'), function(index_div, element) {
34
    var element_id = $(element).attr("id");
35
    if (element_id != null) {
36
      var issue_id = element_id.replace("task-todo-issue-", "");
37
      for(rel_type_key in issue_relation_type) {
38
        var data_rel_attr = $(element).attr("data-rel-" + rel_type_key);
39
        if (data_rel_attr != null) {
40
          var issue_arr = data_rel_attr.split(",");
41
          if ("reverse" in issue_relation_type[rel_type_key]) {
42
            $.each(issue_arr, function(index_issue, element_issue) {
43
              arr.push({issue_from: element_issue, issue_to: issue_id,
44
                        rel_type: issue_relation_type[rel_type_key]["reverse"]});
45
              });
46
          } else {
47
            $.each(issue_arr, function(index_issue, element_issue) {
48
              arr.push({issue_from: issue_id, issue_to: element_issue,
49
                        rel_type: rel_type_key});
50
              });
51
          }
52
        }
53
      }
54
    }
55
  });
56
  return arr;
57
}
58

  
59
function drawRelations() {
60
  var arr = getRelationsArray();
61
  $.each(arr, function(index_issue, element_issue) {
62
    if (!$("#draw_" + element_issue["rel_type"]).attr('checked')) {
63
      return;
64
    }
65
    var issue_from = $("#task-todo-issue-" + element_issue["issue_from"]);
66
    var issue_to   = $("#task-todo-issue-" + element_issue["issue_to"]);
67
    var issue_height = issue_from.height();
68
    var issue_from_top   = issue_from.position().top  + (issue_height / 2) - draw_top;
69
    var issue_from_right = issue_from.position().left + issue_from.width();
70
    var issue_to_top   = issue_to.position().top  + (issue_height / 2) - draw_top;
71
    var issue_to_left  = issue_to.position().left;
72
    var color = $("#gantt_draw_rel_color_" + element_issue["rel_type"])
73
                    .css("background-color");
74
    var landscape_mergin = draw_relations[element_issue["rel_type"]]["landscape_mergin"];
75
    var issue_from_right_rel = issue_from_right + landscape_mergin;
76
    var issue_to_left_rel    = issue_to_left    - landscape_mergin;
77
    var x1, y1, x2, y2;
78
    draw_gantt.path(["M", issue_from_right + draw_left,     issue_from_top,
79
                     "L", issue_from_right_rel + draw_left, issue_from_top])
80
                   .attr({stroke: color, "stroke-width": 2});
81
    if (issue_from_right_rel < issue_to_left_rel) {
82
      draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_from_top,
83
                       "L", issue_from_right_rel + draw_left, issue_to_top])
84
                   .attr({stroke: color, "stroke-width": 2});
85
      draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_to_top,
86
                       "L", issue_to_left + draw_left,        issue_to_top])
87
                   .attr({stroke: color,
88
                          "stroke-width": 2,
89
                          "stroke-linecap": "butt",
90
                          "stroke-linejoin": "miter",
91
                          });
92
    } else {
93
      var issue_middle_top = issue_to_top +
94
                                (issue_height *
95
                                   ((issue_from_top > issue_to_top) ? 1 : -1 ));
96
      draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_from_top,
97
                       "L", issue_from_right_rel + draw_left, issue_middle_top])
98
                   .attr({stroke: color, "stroke-width": 2});
99
      draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_middle_top,
100
                       "L", issue_to_left_rel + draw_left,    issue_middle_top])
101
                   .attr({stroke:color, "stroke-width": 2});
102
      draw_gantt.path(["M", issue_to_left_rel + draw_left, issue_middle_top,
103
                       "L", issue_to_left_rel + draw_left, issue_to_top])
104
                   .attr({stroke: color, "stroke-width": 2});
105
      draw_gantt.path(["M", issue_to_left_rel + draw_left, issue_to_top,
106
                       "L", issue_to_left + draw_left,     issue_to_top])
107
                   .attr({stroke: color,
108
                          "stroke-width": 2,
109
                          "stroke-linecap": "butt",
110
                          "stroke-linejoin": "miter",
111
                          });
112
    }
113
    if (!("no_arrow" in draw_relations[element_issue["rel_type"]])) {
114
      draw_gantt.path(["M", issue_to_left + draw_left, issue_to_top,
115
                       "l", -8, -4, "l", 0, 8, "z"])
116
                   .attr({stroke: "none",
117
                        fill: color,
118
                        "stroke-linecap": "butt",
119
                        "stroke-linejoin": "miter",
120
                          });
121
    }
122
  });
123
}
124

  
12 125
function drawGanttHandler() {
13 126
  var folder = document.getElementById('gantt_draw_area');
14 127
  if(draw_gantt != null)
......
16 129
  else
17 130
    draw_gantt = Raphael(folder);
18 131
  setDrawArea();
132
  drawRelations();
19 133
}
public/stylesheets/application.css
868 868
a.close-icon:hover {background-image:url('../images/close_hl.png');}
869 869

  
870 870
/***** Gantt chart *****/
871
#gantt_draw_rel_color_relates    {background-color:#00c551;}
872
#gantt_draw_rel_color_duplicates {background-color:#4f52c3;}
873
#gantt_draw_rel_color_blocks     {background-color:#fb7d2f;}
874
#gantt_draw_rel_color_precedes   {background-color:#df347c;}
875
#gantt_draw_rel_color_copied_to  {background-color:#00c5c2;}
876

  
871 877
.gantt_hdr {
872 878
  position:absolute;
873 879
  top:0;
(2-2/13)