Class: CumulativeFlowDiagram
Constant Summary
Constants inherited
from ChartBase
ChartBase::LABEL_POSITIONS
Instance Attribute Summary
Attributes inherited from ChartBase
#aggregated_project, #all_boards, #atlassian_document_format, #board_id, #canvas_height, #canvas_width, #data_quality, #date_range, #file_system, #fix_versions, #holiday_dates, #issues, #settings, #time_range, #timezone_offset, #x_axis_title, #y_axis_title
Instance Method Summary
collapse
Methods inherited from ChartBase
#aggregated_project?, #before_run, #call_before_run, #canvas, #canvas_responsive?, #chart_format, #collapsible_issues_panel, #color_block, #color_for, #completed_issues_in_range, #current_board, #cycletime, #cycletime_for_issue, #daily_chart_dataset, #date_annotation, #describe_non_working_days, #description_text, #format_integer, #format_status, #header_text, #holidays, #html_directory, #icon_span, #label_days, #label_hours, #label_issues, #label_minutes, #link_to_issue, #next_id, #normalize_annotation_datetime, #not_visible_text, #random_color, #render, #render_axis_title, #render_top_text, #seam_end, #seam_start, #stagger_label_positions, #status_category_color, #to_human_readable, #working_days_annotation, #wrap_and_render
Constructor Details
Returns a new instance of CumulativeFlowDiagram.
38
39
40
41
42
43
44
45
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
|
# File 'lib/jirametrics/cumulative_flow_diagram.rb', line 38
def initialize block
super()
'Cumulative Flow Diagram'
description_text <<~HTML
<div class="p">
A Cumulative Flow Diagram (CFD) shows how work accumulates across board columns over time.
Each coloured band represents a workflow stage. The top edge of the leftmost band shows
total work entered; the top edge of the rightmost band shows total work completed.
</div>
<div class="p">
A widening band means work is piling up in that stage — a bottleneck. Parallel top edges
(bands staying the same width) indicate smooth flow. Steep rises in the leftmost band
without corresponding rises on the right mean new work is arriving faster than it is
being finished.
</div>
<div class="p">
Dashed lines and hatched regions indicate periods where an item moved backwards through
the workflow (a correction). These highlight rework or process irregularities worth
investigating.
</div>
<div class="p">
The chart also overlays two trend lines and an interactive triangle. The <b>arrival rate</b>
trend line shows how fast work is entering the system; the <b>departure rate</b> trend line
shows how fast it is leaving. Move the mouse over the chart to see a Little's Law triangle
at that point in time, labelled with three derived metrics: <b>Work In Progress (WIP)</b> (items started
but not finished), <b>approximate average cycle time (CT)</b> (roughly how long an average item takes to complete), and
<b>average throughput (TP)</b> (items completed per day). Use the checkbox above the chart to toggle
between the triangle and the normal data tooltips.
</div>
<div class="p">
CT and TP require a future point C where cumulative completions catch up to current arrivals.
When the cursor is near the right edge and that point falls outside the visible date range,
CT and TP cannot be calculated and are hidden; only WIP is shown.
</div>
<div class="p">
See also: This article on <a href="https://blog.mikebowler.ca/2026/03/27/cumulative-flow-diagram/">how to read a CFD</a>.
</div>
HTML
instance_eval(&block)
end
|
Instance Method Details
#arrival_rate_line_color(color) ⇒ Object
87
88
89
|
# File 'lib/jirametrics/cumulative_flow_diagram.rb', line 87
def arrival_rate_line_color color
@arrival_rate_line_color = parse_theme_color(color)
end
|
#column_rules(&block) ⇒ Object
79
80
81
|
# File 'lib/jirametrics/cumulative_flow_diagram.rb', line 79
def column_rules &block
@column_rules_block = block
end
|
#departure_rate_line_color(color) ⇒ Object
91
92
93
|
# File 'lib/jirametrics/cumulative_flow_diagram.rb', line 91
def departure_rate_line_color color
@departure_rate_line_color = parse_theme_color(color)
end
|
#run ⇒ Object
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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
|
# File 'lib/jirametrics/cumulative_flow_diagram.rb', line 95
def run
all_columns = current_board.visible_columns
column_rules_list = all_columns.map do |column|
rules = CfdColumnRules.new
@column_rules_block&.call(column, rules)
rules
end
active_pairs = all_columns.zip(column_rules_list).reject { |_, rules| rules.ignored? }
active_columns = active_pairs.map(&:first)
active_rules = active_pairs.map(&:last)
cfd = CfdDataBuilder.new(
board: current_board,
issues: issues,
date_range: date_range,
columns: active_columns
).run
columns = cfd[:columns]
daily_counts = cfd[:daily_counts]
correction_windows = cfd[:correction_windows]
column_count = columns.size
daily_marginals = daily_counts.transform_values do |cumulative|
cumulative.each_with_index.map do |count, i|
i < column_count - 1 ? count - cumulative[i + 1] : count
end
end
border_colors = active_rules.map { |rules| rules.color || random_color }
fill_colors = active_rules.zip(border_colors).map { |rules, border| fill_color_for(rules, border) }
data_sets = columns.each_with_index.map do |name, col_index|
col_windows = correction_windows
.select { |w| w[:column_index] == col_index }
.map { |w| { start_date: w[:start_date].to_s, end_date: w[:end_date].to_s } }
{
label: active_rules[col_index].label || name,
label_hint: active_rules[col_index].label_hint,
data: date_range.map { |date| { x: date.to_s, y: daily_marginals[date][col_index] } },
backgroundColor: fill_colors[col_index],
borderColor: border_colors[col_index],
fill: true,
tension: 0,
segment: Segment.new(col_windows)
}
end.reverse
hatch_windows = correction_windows.map do |w|
{
dataset_index: column_count - 1 - w[:column_index],
start_date: w[:start_date].to_s,
end_date: w[:end_date].to_s,
color: border_colors[w[:column_index]],
fill_color: fill_colors[w[:column_index]]
}
end
@triangle_color = parse_theme_color(['#333333', '#ffffff']) unless instance_variable_defined?(:@triangle_color)
unless instance_variable_defined?(:@arrival_rate_line_color)
@arrival_rate_line_color = 'rgba(255,138,101,0.85)'
end
unless instance_variable_defined?(:@departure_rate_line_color)
@departure_rate_line_color = 'rgba(128,203,196,0.85)'
end
wrap_and_render(binding, __FILE__)
end
|
#triangle_color(color) ⇒ Object
83
84
85
|
# File 'lib/jirametrics/cumulative_flow_diagram.rb', line 83
def triangle_color color
@triangle_color = parse_theme_color(color)
end
|