114 lines
3.9 KiB
Ruby
114 lines
3.9 KiB
Ruby
module OrganisationsHelper
|
|
# Функции для раскраски
|
|
def group_key(code)
|
|
return nil if code.nil? || code.size < 2
|
|
prefix = code[0, 2]
|
|
case prefix
|
|
when '21', '22', '23', '24', '25'
|
|
'21-25'
|
|
else
|
|
prefix
|
|
end
|
|
end
|
|
|
|
def keep_code?(code, type_data: 'min_max')
|
|
return false if code.nil? || code.size < 2
|
|
prefix = code[0, 2]
|
|
return false unless prefix.match?(/\A\d{2}\z/)
|
|
if type_data == 'min_max'
|
|
return false if %w[16 17 29].include?(prefix) || prefix.start_with?("3")
|
|
return true if %w[21 22 23 24 25].include?(prefix)
|
|
return !code.end_with?('00')
|
|
elsif type_data == 'comparsion'
|
|
return code.end_with?('00')
|
|
end
|
|
end
|
|
|
|
def parse_number(value)
|
|
return 0 if value.nil? || value.empty? || ['-', '(-)', 'X'].include?(value)
|
|
negative = value.start_with?('(') && value.end_with?(')')
|
|
value = value.tr('()', '') if negative
|
|
value = value.delete(' ')
|
|
return 0 unless value.match?(/\A\d+\z/)
|
|
number = value.to_i
|
|
negative ? -number : number
|
|
end
|
|
|
|
def prepare_data(data, type_data: 'min_max')
|
|
return {} if data.nil?
|
|
filtered_data = data.reject do |(_, _), values|
|
|
values.all? { |value| ['-', '(-)', 'X'].include?(value) }
|
|
end
|
|
if type_data == 'min_max'
|
|
prepared_data = filtered_data.each_with_object({}) do |((_, code), values), result|
|
|
next if code.nil? || !keep_code?(code)
|
|
group = group_key(code)
|
|
result[group] ||= []
|
|
result[group] += values.map { |value| parse_number(value)}
|
|
end
|
|
min_max_data = prepared_data.transform_values do |values|
|
|
sorted = values.sort
|
|
size = sorted.size
|
|
p50 = size.odd? ? sorted[size / 2] : (sorted[size / 2 - 1] + sorted[size / 2]) / 2.0
|
|
{ min: sorted.first, p50: p50, max: sorted.last }
|
|
end
|
|
elsif type_data == 'comparsion'
|
|
prepared_data = filtered_data.each_with_object({}) do |((_, code), values), result|
|
|
next if code.nil? || !keep_code?(code, type_data: 'comparsion')
|
|
result[code] ||= []
|
|
(0...values.size - 1).each do |index|
|
|
if parse_number(values[index]) == parse_number(values[index + 1])
|
|
result[code] << nil
|
|
elsif
|
|
result[code] << (parse_number(values[index]) > parse_number(values[index + 1]))
|
|
end
|
|
end
|
|
result[code] << nil
|
|
end
|
|
end
|
|
end
|
|
|
|
def get_color_for_cell(value, min:, median:, max:)
|
|
value = parse_number(value)
|
|
return rgb_to_hex(WHITE) if value.nil? || min.nil? || max.nil? || median.nil?
|
|
return rgb_to_hex(GREEN) if min == max
|
|
|
|
if value <= median
|
|
ratio = median == min ? 0.0 : (value - min).to_f / (median - min)
|
|
rgb = interpolate_color(RED, YELLOW, clamp(ratio))
|
|
else
|
|
ratio = max == median ? 0.0 : (value - median).to_f / (max - median)
|
|
rgb = interpolate_color(YELLOW, GREEN, clamp(ratio))
|
|
end
|
|
|
|
rgb_to_hex(rgb)
|
|
end
|
|
|
|
def get_arrow_for_cell(value, condition)
|
|
return content_tag(:td, value) if condition.nil?
|
|
css_class = condition ? 'up': 'down'
|
|
content_tag(:td, value, class: css_class)
|
|
end
|
|
|
|
|
|
private
|
|
|
|
def interpolate_color(from, to, ratio)
|
|
from.zip(to).map { |a, b| (a + (b - a) * ratio).round }
|
|
end
|
|
|
|
def rgb_to_hex(rgb)
|
|
format("#%02X%02X%02X", *rgb)
|
|
end
|
|
|
|
def clamp(value)
|
|
[[value, 0.0].max, 1.0].min
|
|
end
|
|
|
|
RED = [248, 105, 107].freeze
|
|
YELLOW = [255, 235, 132].freeze
|
|
GREEN = [99, 190, 123].freeze
|
|
WHITE = [255, 255, 255].freeze
|
|
|
|
end
|