Project

General

Profile

Feature #3436 » gantt-relations-r11060.diff

Toshi MARUYAMA, 2012-12-20 07:43

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/models/issue_relation.rb
51 51
    TYPE_DUPLICATED =>  { :name => :label_duplicated_by, :sym_name => :label_duplicates,
52 52
                          :order => 3, :sym => TYPE_DUPLICATES, :reverse => TYPE_DUPLICATES },
53 53
    TYPE_BLOCKS =>      { :name => :label_blocks, :sym_name => :label_blocked_by,
54
                          :order => 4, :sym => TYPE_BLOCKED },
54
                          :order => 4, :sym => TYPE_BLOCKED,
55
                          :landscape_margin => 12 },
55 56
    TYPE_BLOCKED =>     { :name => :label_blocked_by, :sym_name => :label_blocks,
56 57
                          :order => 5, :sym => TYPE_BLOCKS, :reverse => TYPE_BLOCKS },
57 58
    TYPE_PRECEDES =>    { :name => :label_precedes, :sym_name => :label_follows,
58
                          :order => 6, :sym => TYPE_FOLLOWS },
59
                          :order => 6, :sym => TYPE_FOLLOWS,
60
                          :landscape_margin => 16 },
59 61
    TYPE_FOLLOWS =>     { :name => :label_follows, :sym_name => :label_precedes,
60 62
                          :order => 7, :sym => TYPE_PRECEDES, :reverse => TYPE_PRECEDES },
61 63
    TYPE_COPIED_TO =>   { :name => :label_copied_to, :sym_name => :label_copied_from,
......
64 66
                          :order => 9, :sym => TYPE_COPIED_TO, :reverse => TYPE_COPIED_TO }
65 67
  }.freeze
66 68

  
69
  DRAW_TYPES = {
70
    TYPE_BLOCKS   => TYPES[TYPE_BLOCKS],
71
    TYPE_BLOCKED  => TYPES[TYPE_BLOCKED],
72
    TYPE_PRECEDES => TYPES[TYPE_PRECEDES],
73
    TYPE_FOLLOWS  => TYPES[TYPE_FOLLOWS],
74
  }.freeze
75

  
76
  DRAW_TYPES_JSON = DRAW_TYPES.to_json
77

  
67 78
  validates_presence_of :issue_from, :issue_to, :relation_type
68 79
  validates_inclusion_of :relation_type, :in => TYPES.keys
69 80
  validates_numericality_of :delay, :allow_nil => true
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::DRAW_TYPES_JSON.html_safe %>;
6 7
  $(document).ready(drawGanttHandler);
7 8
  $(window).resize(drawGanttHandler);
9
  $(function() {
10
    $("#draw_rels").change(drawGanttHandler);
11
  });
8 12
<% end %>
9 13
<% @gantt.view = self %>
10 14
<h2><%= @query.new_record? ? l(:label_gantt) : h(@query.name) %></h2>
......
20 24
    <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
21 25
  </div>
22 26
</fieldset>
27
<fieldset id="filters" class="collapsible">
28
  <legend onclick="toggleFieldset(this);"><%= l(:label_display) %></legend>
29
  <div>
30
    <fieldset>
31
      <legend><%= l(:label_related_issues) %></legend>
32
      <label>
33
        <%= check_box_tag "draw_rels", 0, params["draw_rels"] %>
34
        <% rels = [IssueRelation::TYPE_BLOCKS, IssueRelation::TYPE_PRECEDES] %>
35
        <% rels.each do |rel| %>
36
          <%= content_tag(:span, '&nbsp;&nbsp;&nbsp;'.html_safe,
37
                          :id => "gantt_draw_rel_color_#{rel}") %>
38
          <%= l(IssueRelation::TYPES[rel][:name]) %>
39
        <% end %>
40
      </label>
41
    </fieldset>
42
  </div>
43
</fieldset>
23 44

  
24 45
<p class="contextual">
25 46
  <%= 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
          if !IssueRelation::DRAW_TYPES[relation_type].nil?
713
            (relations[relation_type] ||= []) << relation.issue_from_id
714
          end
715
        end
716
        relations
717
      end
718

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

  
12
function getRelationsArray() {
13
  var arr = new Array();
14
  $.each($('div.task_todo'), function(index_div, element) {
15
    var element_id = $(element).attr("id");
16
    if (element_id != null) {
17
      var issue_id = element_id.replace("task-todo-issue-", "");
18
      var data_rels = $(element).data("rels");
19
      if (data_rels != null) {
20
        for (rel_type_key in issue_relation_type) {
21
          if (rel_type_key in data_rels) {
22
            var issue_arr = data_rels[rel_type_key].toString().split(",");
23
            if ("reverse" in issue_relation_type[rel_type_key]) {
24
              $.each(issue_arr, function(index_issue, element_issue) {
25
                arr.push({issue_from: element_issue, issue_to: issue_id,
26
                          rel_type: issue_relation_type[rel_type_key]["reverse"]});
27
              });
28
            } else {
29
              $.each(issue_arr, function(index_issue, element_issue) {
30
                arr.push({issue_from: issue_id, issue_to: element_issue,
31
                          rel_type: rel_type_key});
32
              });
33
            }
34
          }
35
        }
36
      }
37
    }
38
  });
39
  return arr;
40
}
41

  
42
function drawRelations() {
43
  var arr = getRelationsArray();
44
  $.each(arr, function(index_issue, element_issue) {
45
    var issue_from = $("#task-todo-issue-" + element_issue["issue_from"]);
46
    var issue_to   = $("#task-todo-issue-" + element_issue["issue_to"]);
47
    if (issue_from.size() == 0 || issue_to.size() == 0) {
48
      return;
49
    }
50
    var issue_height = issue_from.height();
51
    var issue_from_top   = issue_from.position().top  + (issue_height / 2) - draw_top;
52
    var issue_from_right = issue_from.position().left + issue_from.width();
53
    var issue_to_top   = issue_to.position().top  + (issue_height / 2) - draw_top;
54
    var issue_to_left  = issue_to.position().left;
55
    var color = $("#gantt_draw_rel_color_" + element_issue["rel_type"])
56
                    .css("background-color");
57
    var landscape_margin = issue_relation_type[element_issue["rel_type"]]["landscape_margin"];
58
    var issue_from_right_rel = issue_from_right + landscape_margin;
59
    var issue_to_left_rel    = issue_to_left    - landscape_margin;
60
    draw_gantt.path(["M", issue_from_right + draw_left,     issue_from_top,
61
                     "L", issue_from_right_rel + draw_left, issue_from_top])
62
                   .attr({stroke: color, "stroke-width": 2});
63
    if (issue_from_right_rel < issue_to_left_rel) {
64
      draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_from_top,
65
                       "L", issue_from_right_rel + draw_left, issue_to_top])
66
                   .attr({stroke: color, "stroke-width": 2});
67
      draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_to_top,
68
                       "L", issue_to_left + draw_left,        issue_to_top])
69
                   .attr({stroke: color,
70
                          "stroke-width": 2,
71
                          "stroke-linecap": "butt",
72
                          "stroke-linejoin": "miter",
73
                          });
74
    } else {
75
      var issue_middle_top = issue_to_top +
76
                                (issue_height *
77
                                   ((issue_from_top > issue_to_top) ? 1 : -1));
78
      draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_from_top,
79
                       "L", issue_from_right_rel + draw_left, issue_middle_top])
80
                   .attr({stroke: color, "stroke-width": 2});
81
      draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_middle_top,
82
                       "L", issue_to_left_rel + draw_left,    issue_middle_top])
83
                   .attr({stroke:color, "stroke-width": 2});
84
      draw_gantt.path(["M", issue_to_left_rel + draw_left, issue_middle_top,
85
                       "L", issue_to_left_rel + draw_left, issue_to_top])
86
                   .attr({stroke: color, "stroke-width": 2});
87
      draw_gantt.path(["M", issue_to_left_rel + draw_left, issue_to_top,
88
                       "L", issue_to_left + draw_left,     issue_to_top])
89
                   .attr({stroke: color,
90
                          "stroke-width": 2,
91
                          "stroke-linecap": "butt",
92
                          "stroke-linejoin": "miter",
93
                          });
94
    }
95
    draw_gantt.path(["M", issue_to_left + draw_left, issue_to_top,
96
                     "l", -8, -4, "l", 0, 8, "z"])
97
                   .attr({stroke: "none",
98
                          fill: color,
99
                          "stroke-linecap": "butt",
100
                          "stroke-linejoin": "miter",
101
                          });
102
  });
103
}
104

  
12 105
function drawGanttHandler() {
13 106
  var folder = document.getElementById('gantt_draw_area');
14 107
  if(draw_gantt != null)
......
16 109
  else
17 110
    draw_gantt = Raphael(folder);
18 111
  setDrawArea();
112
  if ($("#draw_rels").attr('checked'))
113
    drawRelations();
19 114
}
public/stylesheets/application.css
879 879
a.close-icon:hover {background-image:url('../images/close_hl.png');}
880 880

  
881 881
/***** Gantt chart *****/
882
#gantt_draw_rel_color_blocks     {background-color:#fb7d2f;}
883
#gantt_draw_rel_color_precedes   {background-color:#df347c;}
884

  
882 885
.gantt_hdr {
883 886
  position:absolute;
884 887
  top:0;
(8-8/13)