Class: TaskJuggler::GanttChart

Inherits:
Object
  • Object
show all
Includes:
HTMLGraphics
Defined in:
lib/taskjuggler/reports/GanttChart.rb

Overview

This class represents an abstract (output format independent) Gantt chart. It provides generator functions that can transform the abstract form into formats such as HTML or SVG. The appearance of the chart depend on 3 variable: the report period, the geometrical width and the scale. The report period is always provided by the user. In addition the width or the scale can be provided. The non-provided value will then be calculated. So after the object has been created, the user must call generateByWidth or generateByResolution.

Constant Summary collapse

SCROLLBARHEIGHT =

The height in pixels of a horizontal scrollbar on an HTML page. This value should be large enough to work for all browsers.

20

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from HTMLGraphics

#arrowHeadToHTML, #diamondToHTML, #jagToHTML, #lineToHTML, #rectToHTML

Constructor Details

#initialize(now, weekStartsMonday, columnDef, table = nil, markdate = nil) ⇒ GanttChart

Create the GanttChart object, but don’t do much right now. We still need more information about the chart before we can actually generate it. now is the date that should be used as current date. weekStartsMonday is true if the weeks should start on Mondays instead of Sundays. table is a reference to the TableReport that the chart is part of.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/taskjuggler/reports/GanttChart.rb', line 46

def initialize(now, weekStartsMonday, columnDef, table = nil, markdate = nil)
  # The start and end dates of the reported interval.
  @start = nil
  @end = nil
  @now = now
  @columnDef = columnDef
  @table = table
  @markdate = markdate

  # This defines the possible horizontal scales that the Gantt chart can
  # have. The scales differ in their resolution and the amount of detail
  # that is displayed. A scale is defined by its name. The _name_ must be
  # unique and can be used to select the scale. The _stepSize_ defines the
  # width of a scale step in pixels. The _stepsToFunc_ is a TjTime method
  # that determines the number of steps between 2 dates. _minTimeOff_
  # defines the minimum required length of an time-off interval that is
  # displayed in this scale.
  @@scales = [
    { 'name' => 'hour', 'stepSize' => 20, 'stepsToFunc' => :hoursTo,
      'minTimeOff' => 5 * 60 },
    { 'name' => 'day', 'stepSize' => 20, 'stepsToFunc' => :daysTo,
      'minTimeOff' => 6 * 60 * 60 },
    { 'name' => 'week', 'stepSize' => 20, 'stepsToFunc' => :weeksTo,
      'minTimeOff' => 24 * 60 * 60 },
    { 'name' => 'month', 'stepSize' => 35, 'stepsToFunc' => :monthsTo,
      'minTimeOff' => 5 * 24 * 60 * 60 },
    { 'name' => 'quarter', 'stepSize' => 28, 'stepsToFunc' => :quartersTo,
      'minTimeOff' => -1 },
    { 'name' => 'year', 'stepSize' => 20, 'stepsToFunc' => :yearsTo,
      'minTimeOff' => -1 }
  ]
  # This points to one of the scales above and marks the current scale.
  @scale = nil
  # The height of the chart (without the header)
  @height = 0
  # The width of the chart in pixels.
  @width = 0
  # The width of the view that the chart is presented in. If it's nil, the
  # view will be adapted to the width of the chart.
  @viewWidth = nil
  # True of the week starts on a Monday.
  @weekStartsMonday = weekStartsMonday

  # Reference to the GanttHeader object that models the chart header.
  @header = nil
  # The GanttLine objects that model the lines of the chart.
  @lines = []
  # The router for dependency lines.
  @router = nil
  # This dictionary stores primary task lines indexed by their task. To
  # handle multiple scenarios, the dictionary stored the lines in an Array.
  # This is used to generate dependency arrows.
  @tasks = {}
  # This is a list of the dependency lines. Each entry is an Array of [x, y]
  # coordinate pairs.
  @depArrows = []
  # This is the list of arrow heads used for the dependency arrows. It
  # contains an Array of [ x, y ] coordinates that mark the tip of the
  # arrow.
  @arrowHeads = []
end

Instance Attribute Details

#endObject (readonly)

Returns the value of attribute end.



37
38
39
# File 'lib/taskjuggler/reports/GanttChart.rb', line 37

def end
  @end
end

#headerObject (readonly)

Returns the value of attribute header.



37
38
39
# File 'lib/taskjuggler/reports/GanttChart.rb', line 37

def header
  @header
end

#markdateObject (readonly)

Returns the value of attribute markdate.



37
38
39
# File 'lib/taskjuggler/reports/GanttChart.rb', line 37

def markdate
  @markdate
end

#nowObject (readonly)

Returns the value of attribute now.



37
38
39
# File 'lib/taskjuggler/reports/GanttChart.rb', line 37

def now
  @now
end

#scaleObject (readonly)

Returns the value of attribute scale.



37
38
39
# File 'lib/taskjuggler/reports/GanttChart.rb', line 37

def scale
  @scale
end

#scalesObject (readonly)

Returns the value of attribute scales.



37
38
39
# File 'lib/taskjuggler/reports/GanttChart.rb', line 37

def scales
  @scales
end

#startObject (readonly)

Returns the value of attribute start.



37
38
39
# File 'lib/taskjuggler/reports/GanttChart.rb', line 37

def start
  @start
end

#tableObject (readonly)

Returns the value of attribute table.



37
38
39
# File 'lib/taskjuggler/reports/GanttChart.rb', line 37

def table
  @table
end

#viewWidth=(value) ⇒ Object (writeonly)

Sets the attribute viewWidth

Parameters:

  • value

    the value to set the attribute viewWidth to.



39
40
41
# File 'lib/taskjuggler/reports/GanttChart.rb', line 39

def viewWidth=(value)
  @viewWidth = value
end

#weekStartsMondayObject (readonly)

Returns the value of attribute weekStartsMonday.



37
38
39
# File 'lib/taskjuggler/reports/GanttChart.rb', line 37

def weekStartsMonday
  @weekStartsMonday
end

#widthObject (readonly)

Returns the value of attribute width.



37
38
39
# File 'lib/taskjuggler/reports/GanttChart.rb', line 37

def width
  @width
end

Instance Method Details

#addLine(line) ⇒ Object

This is not a user callable function. It’s only meant for use within the library.



217
218
219
220
221
222
# File 'lib/taskjuggler/reports/GanttChart.rb', line 217

def addLine(line) #:nodoc:
  if @scale.nil?
    raise "generateByScale or generateByWidth must be called first"
  end
  @lines << line
end

#addTask(task, line) ⇒ Object

Add a primary tasks line to the dictonary. task is a reference to the Task object and line is the corresponding primary ReportTableLine.



110
111
112
113
114
115
116
117
118
# File 'lib/taskjuggler/reports/GanttChart.rb', line 110

def addTask(task, line)
  if @tasks.include?(task)
    # Append the line to the existing lines.
    @tasks[task] << line
  else
    # Add a new Array for this tasks and store the first line.
    @tasks[task] = [ line ]
  end
end

#dateToX(date) ⇒ Object

Utility function that convers a date to the corresponding X-position in the Gantt chart.



211
212
213
# File 'lib/taskjuggler/reports/GanttChart.rb', line 211

def dateToX(date)
  ((@width / (@end - @start)) * (date - @start)).to_i
end

#generateByScale(periodStart, periodEnd, scaleName) ⇒ Object

Generate the actual chart data based on the report interval specified by periodStart and periodEnd as well as the name of the requested scale to be used. This function (or generateByWidth) must be called before any GanttLine objects are created for this chart.



132
133
134
135
136
137
138
139
140
141
# File 'lib/taskjuggler/reports/GanttChart.rb', line 132

def generateByScale(periodStart, periodEnd, scaleName)
  @start = periodStart
  @end = periodEnd
  @scale = scaleByName(scaleName)
  @stepSize = @scale['stepSize']
  steps = @start.send(@scale['stepsToFunc'], @end)
  @width = @stepSize * steps

  @header = GanttHeader.new(@columnDef, self)
end

#generateByWidth(periodStart, periodEnd, width) ⇒ Object



121
122
123
124
125
126
# File 'lib/taskjuggler/reports/GanttChart.rb', line 121

def generateByWidth(periodStart, periodEnd, width)
  @start = periodStart
  @end = periodEnd
  @width = width
  # TODO
end

#hasScrollbar?Boolean

Returns true if the chart includes a scrollbar.

Returns:

  • (Boolean)


225
226
227
# File 'lib/taskjuggler/reports/GanttChart.rb', line 225

def hasScrollbar?
  @viewWidth && (@viewWidth < @width)
end

#to_csv(csv, startColumn) ⇒ Object

This is a noop function.



204
205
206
207
# File 'lib/taskjuggler/reports/GanttChart.rb', line 204

def to_csv(csv, startColumn)
  # Can't put a Gantt chart into a CSV file.
  0
end

#to_htmlObject

Convert the chart into an HTML representation.



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/taskjuggler/reports/GanttChart.rb', line 144

def to_html
  completeChart

  # The chart is rendered into a cell that extends over the full height of
  # the table. No other cells for this column will be generated. In case
  # there is a scrollbar, the table will have an extra line to hold the
  # scrollbar.
  td = XMLElement.new('td',
    'rowspan' => "#{2 + @lines.length + (hasScrollbar? ? 1 : 0)}",
    'style' => 'padding:0px; vertical-align:top;')
  # Now we generate two 'div's nested into each other. The first div is the
  # view. It may contain a scrollbar if the second div is wider than the
  # first one. In case we need a scrollbar The outer div is
  # SCROLLBARHEIGHT pixels heigher to hold the scrollbar. Unfortunately
  # this must be a hardcoded value even though the height of the scrollbar
  # varies from system to system. This value should be good enough for
  # most systems.
  td << (scrollDiv = XMLElement.new('div', 'class' => 'tabback',
    'style' => 'position:relative; ' +
               "overflow:auto; " +
               "width:#{hasScrollbar? ? @viewWidth : @width}px; " +
               "height:#{@height +
                         (hasScrollbar? ? SCROLLBARHEIGHT : 0)}px;"))
  scrollDiv << (div = XMLElement.new('div',
    'style' => "margin:0px; padding:0px; " +
               "position:absolute; overflow:hidden; " +
               "top:0px; left:0px; " +
               "width:#{@width}px; " +
               "height:#{@height}px; " +
               "font-size:10px;"))
  # Add the header.
  div << @header.to_html
  # These are the lines of the chart.
  @lines.each do |line|
    div << line.to_html
  end

  # This is used for debugging and testing only.
  #div << @router.to_html

  # Render the dependency lines.
  @depArrows.each do |arrow|
    xx = yy = nil
    arrow.each do |x, y|
      if xx
        div << lineToHTML(xx, yy, x, y, 'depline')
      end
      xx = x
      yy = y
    end
  end
  # And the corresponsing arrow heads.
  @arrowHeads.each do |x, y|
    div << arrowHeadToHTML(x, y)
  end

  td
end