Class: ChartBase
- Inherits:
-
Object
- Object
- ChartBase
- Includes:
- ChartFormat
- Defined in:
- lib/jirametrics/chart_base.rb
Direct Known Subclasses
AgingWorkBarChart, AgingWorkInProgressChart, AgingWorkTable, Anonymizer, CumulativeFlowDiagram, DailyView, DailyWipChart, DataQualityReport, DependencyChart, EstimateAccuracyChart, ExpeditedChart, FlowEfficiencyScatterplot, HierarchyTable, SprintBurndown, ThroughputChart, TimeBasedChart, WipByColumnChart
Constant Summary collapse
- OKABE_ITO_PALETTE =
Okabe-Ito palette - perceptually distinct under the most common forms of colour blindness. Ordered from most- to least-commonly useful for chart series.
%w[ #0072B2 #E69F00 #009E73 #56B4E9 #D55E00 #CC79A7 #F0E442 ].freeze
- LABEL_POSITIONS =
%w[5% 25% 45% 65%].freeze
- @@chart_counter =
0
Instance Attribute Summary collapse
-
#aggregated_project ⇒ Object
writeonly
Sets the attribute aggregated_project.
-
#all_boards ⇒ Object
Returns the value of attribute all_boards.
-
#atlassian_document_format ⇒ Object
Returns the value of attribute atlassian_document_format.
-
#board_id ⇒ Object
Returns the value of attribute board_id.
-
#canvas_height ⇒ Object
readonly
Returns the value of attribute canvas_height.
-
#canvas_width ⇒ Object
readonly
Returns the value of attribute canvas_width.
-
#color_palette ⇒ Object
Returns the value of attribute color_palette.
-
#data_quality ⇒ Object
Returns the value of attribute data_quality.
-
#date_range ⇒ Object
Returns the value of attribute date_range.
-
#file_system ⇒ Object
Returns the value of attribute file_system.
-
#fix_versions ⇒ Object
Returns the value of attribute fix_versions.
-
#holiday_dates ⇒ Object
Returns the value of attribute holiday_dates.
-
#issues ⇒ Object
Returns the value of attribute issues.
-
#settings ⇒ Object
Returns the value of attribute settings.
-
#time_range ⇒ Object
Returns the value of attribute time_range.
-
#timezone_offset ⇒ Object
Returns the value of attribute timezone_offset.
-
#x_axis_title ⇒ Object
Returns the value of attribute x_axis_title.
-
#y_axis_title ⇒ Object
Returns the value of attribute y_axis_title.
Instance Method Summary collapse
- #aggregated_project? ⇒ Boolean
- #before_run ⇒ Object
- #call_before_run(&proc) ⇒ Object
- #canvas(width:, height:, responsive: true) ⇒ Object
- #canvas_responsive? ⇒ Boolean
- #collapsible_issues_panel(issue_descriptions, *args) ⇒ Object
- #color_block(color, title: nil) ⇒ Object
- #color_for(type:) ⇒ Object
-
#comma_and(phrases) ⇒ Object
"a and b" for two, "a, b and c" for more.
- #completed_issues_in_range(include_unstarted: false) ⇒ Object
-
#current_board ⇒ Object
Return only the board columns for the current board.
-
#cycletime(&block) ⇒ Object
Set a cycletime for just this one chart, overriding the one for the report.
-
#cycletime_for_issue(issue) ⇒ Object
Returns the cycletime in use right now, which may be specific to the chart or across the report.
- #daily_chart_dataset(date_issues_list:, color:, label:, positive: true) ⇒ Object
- #date_annotation ⇒ Object
- #describe_non_working_days ⇒ Object
- #description_text(text = :none) ⇒ Object
- #expand_template(text) ⇒ Object
-
#expanded_header_text ⇒ Object
The header as the reader sees it.
-
#format_integer(number) ⇒ Object
Convert a number like 1234567 into the string "1,234,567".
-
#format_status(object, board:, is_category: false, use_old_status: false) ⇒ Object
object will be either a Status or a ChangeItem if it's a ChangeItem then use_old_status will specify whether we're using the new or old Either way, is_category will format the category rather than the status.
- #header_text(text = :none) ⇒ Object
-
#holidays(date_range: @date_range) ⇒ Object
Returns the non-working stretches (weekends and holidays) within the range, each as a Date range of consecutive days.
- #html_directory ⇒ Object
- #icon_span(title:, icon:) ⇒ Object
-
#initialize ⇒ ChartBase
constructor
A new instance of ChartBase.
- #link_to_issue(issue, args = {}) ⇒ Object
- #next_id ⇒ Object
-
#next_palette_color ⇒ Object
A colour for something that needs telling apart, where no specific colour is wanted.
- #no_data_text(text = :none) ⇒ Object
- #non_working_day?(date) ⇒ Boolean
- #normalize_annotation_datetime(value) ⇒ Object
-
#not_visible_icon(status, board) ⇒ Object
The 👀 marker for a status that isn't mapped to any column, or '' when it is visible.
- #not_visible_text(issue) ⇒ Object
-
#ordinal(number) ⇒ Object
1st, 2nd, 3rd, 4th ...
-
#percentile_of(values, percentile) ⇒ Object
The nearest rank percentile: the smallest value with at least this percentage of the data at or below it.
- #render(caller_binding, file) ⇒ Object
- #render_axis_title(axis_direction) ⇒ Object
-
#render_binding ⇒ Object
A fresh scope for every template expansion.
- #render_header ⇒ Object
-
#render_no_data ⇒ Object
What a chart shows when it has nothing to show.
- #render_top_text ⇒ Object
-
#resolve_status(object, board:, use_old_status:) ⇒ Object
Resolves the object being formatted into [status, error_message].
- #stagger_label_positions(datetimes) ⇒ Object
- #status_category_color(status) ⇒ Object
- #to_human_readable(number) ⇒ Object
- #working_days_annotation ⇒ Object
-
#wrap_and_render(caller_binding, file) ⇒ Object
Render the file and then wrap it with standard headers and quality checks.
Methods included from ChartFormat
Constructor Details
#initialize ⇒ ChartBase
Returns a new instance of ChartBase.
29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/jirametrics/chart_base.rb', line 29 def initialize @chart_colors = { 'Story' => CssVariable['--type-story-color'], 'Task' => CssVariable['--type-task-color'], 'Bug' => CssVariable['--type-bug-color'], 'Defect' => CssVariable['--type-bug-color'], 'Spike' => CssVariable['--type-spike-color'] } @canvas_width = 800 @canvas_height = 200 @canvas_responsive = true end |
Instance Attribute Details
#aggregated_project=(value) ⇒ Object (writeonly)
Sets the attribute aggregated_project
24 25 26 |
# File 'lib/jirametrics/chart_base.rb', line 24 def aggregated_project=(value) @aggregated_project = value end |
#all_boards ⇒ Object
Returns the value of attribute all_boards.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def all_boards @all_boards end |
#atlassian_document_format ⇒ Object
Returns the value of attribute atlassian_document_format.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def atlassian_document_format @atlassian_document_format end |
#board_id ⇒ Object
Returns the value of attribute board_id.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def board_id @board_id end |
#canvas_height ⇒ Object (readonly)
Returns the value of attribute canvas_height.
25 26 27 |
# File 'lib/jirametrics/chart_base.rb', line 25 def canvas_height @canvas_height end |
#canvas_width ⇒ Object (readonly)
Returns the value of attribute canvas_width.
25 26 27 |
# File 'lib/jirametrics/chart_base.rb', line 25 def canvas_width @canvas_width end |
#color_palette ⇒ Object
Returns the value of attribute color_palette.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def color_palette @color_palette end |
#data_quality ⇒ Object
Returns the value of attribute data_quality.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def data_quality @data_quality end |
#date_range ⇒ Object
Returns the value of attribute date_range.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def date_range @date_range end |
#file_system ⇒ Object
Returns the value of attribute file_system.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def file_system @file_system end |
#fix_versions ⇒ Object
Returns the value of attribute fix_versions.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def fix_versions @fix_versions end |
#holiday_dates ⇒ Object
Returns the value of attribute holiday_dates.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def holiday_dates @holiday_dates end |
#issues ⇒ Object
Returns the value of attribute issues.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def issues @issues end |
#settings ⇒ Object
Returns the value of attribute settings.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def settings @settings end |
#time_range ⇒ Object
Returns the value of attribute time_range.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def time_range @time_range end |
#timezone_offset ⇒ Object
Returns the value of attribute timezone_offset.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def timezone_offset @timezone_offset end |
#x_axis_title ⇒ Object
Returns the value of attribute x_axis_title.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def x_axis_title @x_axis_title end |
#y_axis_title ⇒ Object
Returns the value of attribute y_axis_title.
21 22 23 |
# File 'lib/jirametrics/chart_base.rb', line 21 def y_axis_title @y_axis_title end |
Instance Method Details
#aggregated_project? ⇒ Boolean
50 51 52 |
# File 'lib/jirametrics/chart_base.rb', line 50 def aggregated_project? @aggregated_project end |
#before_run ⇒ Object
46 47 48 |
# File 'lib/jirametrics/chart_base.rb', line 46 def before_run @call_before_run_procs&.each(&:call) end |
#call_before_run(&proc) ⇒ Object
42 43 44 |
# File 'lib/jirametrics/chart_base.rb', line 42 def call_before_run &proc (@call_before_run_procs ||= []) << proc end |
#canvas(width:, height:, responsive: true) ⇒ Object
395 396 397 398 399 |
# File 'lib/jirametrics/chart_base.rb', line 395 def canvas width:, height:, responsive: true @canvas_width = width @canvas_height = height @canvas_responsive = responsive end |
#canvas_responsive? ⇒ Boolean
401 402 403 |
# File 'lib/jirametrics/chart_base.rb', line 401 def canvas_responsive? @canvas_responsive end |
#collapsible_issues_panel(issue_descriptions, *args) ⇒ Object
162 163 164 165 166 167 168 169 |
# File 'lib/jirametrics/chart_base.rb', line 162 def collapsible_issues_panel issue_descriptions, *args link_id = next_id issues_id = next_id issue_descriptions.sort! { |a, b| a[0].key_as_i <=> b[0].key_as_i } erb = ERB.new file_system.load File.join(html_directory, 'collapsible_issues_panel.erb') erb.result(binding) end |
#color_block(color, title: nil) ⇒ Object
405 406 407 408 409 410 411 412 413 414 |
# File 'lib/jirametrics/chart_base.rb', line 405 def color_block color, title: nil result = +'' result << "<div class='color_block' style='" result << "background: #{CssVariable[color]};" if color result << 'visibility: hidden;' unless color result << "'" result << " title=#{title.inspect}" if title result << '></div>' result end |
#color_for(type:) ⇒ Object
118 119 120 |
# File 'lib/jirametrics/chart_base.rb', line 118 def color_for type: @chart_colors[type] ||= next_palette_color end |
#comma_and(phrases) ⇒ Object
"a and b" for two, "a, b and c" for more. Used when listing configured percentiles in prose.
305 306 307 308 309 |
# File 'lib/jirametrics/chart_base.rb', line 305 def comma_and phrases return phrases.join ' and ' if phrases.size <= 2 "#{phrases[0..-2].join ', '} and #{phrases.last}" end |
#completed_issues_in_range(include_unstarted: false) ⇒ Object
265 266 267 268 269 270 271 272 273 274 |
# File 'lib/jirametrics/chart_base.rb', line 265 def completed_issues_in_range include_unstarted: false issues.select do |issue| cycletime = issue.board.cycletime started_time, stopped_time = cycletime.started_stopped_times(issue) stopped_time && date_range.include?(stopped_time.to_date) && # Remove outside range (include_unstarted || (started_time && (stopped_time >= started_time))) end end |
#current_board ⇒ Object
Return only the board columns for the current board.
250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/jirametrics/chart_base.rb', line 250 def current_board if @board_id.nil? case @all_boards.size when 0 raise 'Couldn\'t find any board configurations. Ensure one is set' when 1 return @all_boards.values[0] else raise "Must set board_id so we know which to use. Multiple boards found: #{@all_boards.keys.inspect}" end end @all_boards[@board_id] end |
#cycletime(&block) ⇒ Object
Set a cycletime for just this one chart, overriding the one for the report.
426 427 428 429 430 431 432 433 |
# File 'lib/jirametrics/chart_base.rb', line 426 def cycletime &block call_before_run do @cycletime = CycleTimeConfig.new( possible_statuses: possible_statuses, label: nil, block: block, file_system: file_system, settings: settings ) end end |
#cycletime_for_issue(issue) ⇒ Object
Returns the cycletime in use right now, which may be specific to the chart or across the report.
436 437 438 |
# File 'lib/jirametrics/chart_base.rb', line 436 def cycletime_for_issue issue @cycletime || issue.board.cycletime end |
#daily_chart_dataset(date_issues_list:, color:, label:, positive: true) ⇒ Object
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/jirametrics/chart_base.rb', line 136 def daily_chart_dataset date_issues_list:, color:, label:, positive: true { type: 'bar', label: label, data: date_issues_list.collect do |date, issues| issues.sort_by!(&:key_as_i) title = "#{label} (#{label_issues issues.size})" { x: date, y: positive ? issues.size : -issues.size, title: [title] + issues.collect { |i| "#{i.key} : #{i.summary.strip}#{" #{yield date, i}" if block_given?}" } } end, backgroundColor: color, borderRadius: positive ? 0 : 5 } end |
#date_annotation ⇒ Object
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/jirametrics/chart_base.rb', line 201 def date_annotation annotations = settings['date_annotations'] || [] in_range = annotations .map { |a| [a, normalize_annotation_datetime(a['date'])] } .select { |(_, dt)| date_range.cover?(Date.parse(dt)) } .sort_by { |(_, dt)| dt } positions = stagger_label_positions(in_range.map { |(_, dt)| dt }) in_range.each_with_index.collect do |(a, normalized), index| <<~TEXT dateAnnotation#{index}: { type: 'line', xMin: #{normalized.to_json}, xMax: #{normalized.to_json}, borderColor: 'rgba(0,0,0,0.7)', borderWidth: 1, label: { display: true, content: #{a['label'].to_json}, position: #{positions[index].to_json} } }, TEXT end.join end |
#describe_non_working_days ⇒ Object
416 417 418 419 420 421 422 423 |
# File 'lib/jirametrics/chart_base.rb', line 416 def describe_non_working_days <<-TEXT <div class='p'> The #{color_block '--non-working-days-color'} vertical bars indicate non-working days; weekends and any other holidays mentioned in the configuration. </div> TEXT end |
#description_text(text = :none) ⇒ Object
286 287 288 289 |
# File 'lib/jirametrics/chart_base.rb', line 286 def description_text text = :none @description_text = text unless text == :none @description_text end |
#expand_template(text) ⇒ Object
78 79 80 |
# File 'lib/jirametrics/chart_base.rb', line 78 def text ERB.new(text).result(render_binding) end |
#expanded_header_text ⇒ Object
The header as the reader sees it. Stitch configs match on this through grab_by_title, so it has to be the expanded text rather than the template.
84 |
# File 'lib/jirametrics/chart_base.rb', line 84 def = @header_text.nil? ? '' : (@header_text) |
#format_integer(number) ⇒ Object
Convert a number like 1234567 into the string "1,234,567"
324 325 326 |
# File 'lib/jirametrics/chart_base.rb', line 324 def format_integer number number.to_s.reverse.scan(/.{1,3}/).join(',').reverse end |
#format_status(object, board:, is_category: false, use_old_status: false) ⇒ Object
object will be either a Status or a ChangeItem if it's a ChangeItem then use_old_status will specify whether we're using the new or old Either way, is_category will format the category rather than the status
331 332 333 334 335 336 337 338 339 |
# File 'lib/jirametrics/chart_base.rb', line 331 def format_status object, board:, is_category: false, use_old_status: false status, = resolve_status object, board: board, use_old_status: use_old_status return "<span style='color: red'>#{}</span>" if color = status_category_color status visibility = is_category ? '' : not_visible_icon(status, board) text = is_category ? status.category : status "<span title='Category: #{status.category}'>#{color_block color.name} #{text}</span>#{visibility}" end |
#header_text(text = :none) ⇒ Object
276 277 278 279 |
# File 'lib/jirametrics/chart_base.rb', line 276 def header_text text = :none @header_text = text unless text == :none @header_text end |
#holidays(date_range: @date_range) ⇒ Object
Returns the non-working stretches (weekends and holidays) within the range, each as a Date range of consecutive days.
173 174 175 176 177 178 |
# File 'lib/jirametrics/chart_base.rb', line 173 def holidays date_range: @date_range date_range .select { |date| non_working_day?(date) } .slice_when { |previous_date, date| date != previous_date + 1 } .collect { |run| run.first..run.last } end |
#html_directory ⇒ Object
54 55 56 57 |
# File 'lib/jirametrics/chart_base.rb', line 54 def html_directory pathname = Pathname.new(File.realpath(__FILE__)) "#{pathname.dirname}/html" end |
#icon_span(title:, icon:) ⇒ Object
368 369 370 |
# File 'lib/jirametrics/chart_base.rb', line 368 def icon_span title:, icon: "<span title='#{title}' style='font-size: 0.8em;'>#{icon}</span>" end |
#link_to_issue(issue, args = {}) ⇒ Object
154 155 156 157 158 159 160 |
# File 'lib/jirametrics/chart_base.rb', line 154 def link_to_issue issue, args = {} attributes = { class: 'issue_key' } .merge(args) .collect { |key, value| "#{key}='#{value}'" } .join(' ') "<a href='#{issue.url}' #{attributes}>#{issue.key}</a>" end |
#next_id ⇒ Object
114 115 116 |
# File 'lib/jirametrics/chart_base.rb', line 114 def next_id @@chart_counter += 1 end |
#next_palette_color ⇒ Object
A colour for something that needs telling apart, where no specific colour is wanted. If a specific colour matters, configure it instead. See ColorPalette for why this is not random and why it must not become random again.
391 392 393 |
# File 'lib/jirametrics/chart_base.rb', line 391 def next_palette_color (@color_palette ||= ColorPalette.default).next_color end |
#no_data_text(text = :none) ⇒ Object
281 282 283 284 |
# File 'lib/jirametrics/chart_base.rb', line 281 def no_data_text text = :none @no_data_text = text unless text == :none @no_data_text end |
#non_working_day?(date) ⇒ Boolean
180 181 182 |
# File 'lib/jirametrics/chart_base.rb', line 180 def non_working_day? date date.saturday? || date.sunday? || holiday_dates.include?(date) end |
#normalize_annotation_datetime(value) ⇒ Object
240 241 242 243 244 245 246 247 |
# File 'lib/jirametrics/chart_base.rb', line 240 def normalize_annotation_datetime value offset = timezone_offset || '+00:00' if value.include?('T') value.match?(/([+-]\d{2}:\d{2}|Z)$/) ? value : "#{value}#{offset}" else "#{value}T00:00:00#{offset}" end end |
#not_visible_icon(status, board) ⇒ Object
The 👀 marker for a status that isn't mapped to any column, or '' when it is visible.
359 360 361 362 363 364 365 366 |
# File 'lib/jirametrics/chart_base.rb', line 359 def not_visible_icon status, board return '' if board.visible_columns.any? { |column| column.status_ids.include? status.id } icon_span( title: "Not visible: The status #{status.name.inspect} is not mapped to any column and will not be visible", icon: ' 👀' ) end |
#not_visible_text(issue) ⇒ Object
372 373 374 375 376 377 |
# File 'lib/jirametrics/chart_base.rb', line 372 def not_visible_text issue reasons = issue.reasons_not_visible_on_board return nil if reasons.empty? "<span style='background: var(--warning-banner)'>Not visible on board: #{reasons.join(', ')}</span>" end |
#ordinal(number) ⇒ Object
1st, 2nd, 3rd, 4th ... 11th, 12th, 13th ... 21st. Percentiles are the main caller and they range over 0..100, so blindly appending "th" would render "1th" and "22th".
313 314 315 316 317 318 319 320 321 |
# File 'lib/jirametrics/chart_base.rb', line 313 def ordinal number suffix = if [11, 12, 13].include?(number % 100) 'th' else { 1 => 'st', 2 => 'nd', 3 => 'rd' }.fetch(number % 10, 'th') end "#{number}#{suffix}" end |
#percentile_of(values, percentile) ⇒ Object
The nearest rank percentile: the smallest value with at least this percentage of the data at or below it. One implementation for the whole product, because three call sites used to compute this separately and two of them overshot by one whenever the rank landed exactly on a boundary, so the same percentile of the same data could read differently on two charts. Returns nil when there is nothing to measure.
296 297 298 299 300 301 302 |
# File 'lib/jirametrics/chart_base.rb', line 296 def percentile_of values, percentile return nil if values.empty? sorted = values.sort rank = (percentile / 100.0 * sorted.size).ceil sorted[rank.clamp(1, sorted.size) - 1] end |
#render(caller_binding, file) ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/jirametrics/chart_base.rb', line 59 def render caller_binding, file pathname = Pathname.new(File.realpath(file)) basename = pathname.basename.to_s match = basename.match(/^(?<template_name>.+)\.rb$/) raise "Unexpected filename #{basename.inspect}" unless match # Insert a incrementing chart_id so that all the chart names on the page are unique caller_binding.eval "chart_id='chart#{next_id}'" # chart_id=chart3 erb = ERB.new file_system.load "#{html_directory}/#{match[:template_name]}.erb" erb.result(caller_binding) end |
#render_axis_title(axis_direction) ⇒ Object
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 |
# File 'lib/jirametrics/chart_base.rb', line 448 def render_axis_title axis_direction text = case axis_direction when :x x_axis_title when :y y_axis_title else raise "Unexpected axis_direction: #{axis_direction}" end return '' unless text <<~CONTENT title: { display: true, text: "#{text}" }, CONTENT end |
#render_binding ⇒ Object
A fresh scope for every template expansion. self is still the chart, so instance variables and methods are reachable from a template, but the caller's local variables are not. That is the point: ERB#result assigns its output buffer into whatever binding you hand it, so two templates sharing one scope silently discard each other's output when one renders the other.
76 |
# File 'lib/jirametrics/chart_base.rb', line 76 def render_binding = binding |
#render_header ⇒ Object
86 87 88 89 90 |
# File 'lib/jirametrics/chart_base.rb', line 86 def render_header return '' unless @header_text "<h1 class='foldable'>#{}</h1>" end |
#render_no_data ⇒ Object
What a chart shows when it has nothing to show. Empty means show nothing at all, not even the header, which is what a chart that simply does not apply to this board wants.
100 101 102 103 104 |
# File 'lib/jirametrics/chart_base.rb', line 100 def render_no_data return '' if @no_data_text.nil? || @no_data_text.empty? @no_data_text end |
#render_top_text ⇒ Object
92 93 94 95 96 |
# File 'lib/jirametrics/chart_base.rb', line 92 def render_top_text result = +render_header result << (@description_text) if @description_text result end |
#resolve_status(object, board:, use_old_status:) ⇒ Object
Resolves the object being formatted into [status, error_message]. A Status is itself; a ChangeItem is looked up by id, yielding an error message (the raw value) when the id isn't a known status.
343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/jirametrics/chart_base.rb', line 343 def resolve_status object, board:, use_old_status: case object when ChangeItem id = use_old_status ? object.old_value_id : object.value_id status = board.possible_statuses.find_by_id(id) return [status, nil] unless status.nil? [nil, use_old_status ? object.old_value : object.value] when Status [object, nil] else raise "Unexpected type: #{object.class}" end end |
#stagger_label_positions(datetimes) ⇒ Object
228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/jirametrics/chart_base.rb', line 228 def stagger_label_positions datetimes return [] if datetimes.empty? threshold_days = (date_range.end - date_range.begin).to_f / 5.0 slot = 0 [LABEL_POSITIONS[0]] + datetimes.each_cons(2).map do |a, b| days_apart = (Date.parse(b) - Date.parse(a)).to_f.abs slot = days_apart < threshold_days ? slot + 1 : 0 LABEL_POSITIONS[slot % LABEL_POSITIONS.size] end end |
#status_category_color(status) ⇒ Object
379 380 381 382 383 384 385 386 |
# File 'lib/jirametrics/chart_base.rb', line 379 def status_category_color status case status.category.key when 'new' then CssVariable['--status-category-todo-color'] when 'indeterminate' then CssVariable['--status-category-inprogress-color'] when 'done' then CssVariable['--status-category-done-color'] else CssVariable['--status-category-unknown-color'] # Theoretically impossible but seen in prod. end end |
#to_human_readable(number) ⇒ Object
132 133 134 |
# File 'lib/jirametrics/chart_base.rb', line 132 def to_human_readable number number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse end |
#working_days_annotation ⇒ Object
184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/jirametrics/chart_base.rb', line 184 def working_days_annotation holidays.each_with_index.collect do |range, index| <<~TEXT holiday#{index}: { drawTime: 'beforeDraw', type: 'box', xMin: '#{range.begin}T00:00:00', xMax: '#{range.end}T23:59:59', backgroundColor: #{CssVariable.new('--non-working-days-color').to_json}, borderColor: #{CssVariable.new('--non-working-days-color').to_json} }, TEXT end.join end |
#wrap_and_render(caller_binding, file) ⇒ Object
Render the file and then wrap it with standard headers and quality checks.
107 108 109 110 111 112 |
# File 'lib/jirametrics/chart_base.rb', line 107 def wrap_and_render caller_binding, file result = +'' result << render_top_text result << render(caller_binding, file) result end |