module ActiveReporter
module Serializer
class Highcharts < Table
def colors
['#7cb5ec', '#434348', '#90ed7d', '#f7a35c', '#8085e9', '#f15c80', '#e4d354', '#2b908f', '#f45b5b', '#91e8e1']
end
def color_hash
# ensure we consistently assign the same color to the same dimension-
# value pair
@color_hash ||= Hash.new do |h, key|
color_cycle = colors.cycle
h[key] = Hash.new do |hh, value|
hh[value] = color_cycle.next
end
end
end
def color_for(dimension, value)
# override this if the values of a particular dimension can take on
# meaningful colors
color_hash[dimension.name][value]
end
# def series
# case report.groupers.count
# when 2
# dim1, dim2 = report.groupers
# report.data.flat_map.with_index do |d2, i|
# d2[:values].map do |d1|
# {
# stack: human_dimension_value_label(dim2, d2[:key]),
# name: human_dimension_value_label(dim1, d1[:key]),
# (i == 0 ? :id : :linkedTo) => human_dimension_value_label(dim1, d1[:key]),
# color: color_for(dim1, d1[:key]),
# data: d1[:values].map do |k,v|
# {
# y: v.to_f,
# tooltip: tooltip_for(k => v, dim1 => d1),
# filters: filters_for(k => v, dim1 => d1)
# }
# end
# }
# end
# end
# when 1
# dim1 = report.groupers.first
# report.data.map do |d1|
# {
# name: human_dimension_value_label(dim1, d1[:key]),
# color: color_for(dim1, d1[:key]),
# data: d1[:values].map do |k,v|
# {
# y: v.to_f,
# tooltip: tooltip_for(k => v, dim1 => d1),
# filters: filters_for(k => v, dim1 => d1)
# }
# end
# }
# end
# else
# raise ActiveReporter::InvalidParamsError, "report must have <= 2 groupers"
# end
# end
def series
case report.groupers.count
when 3
dim1, dim2, dim3 = report.groupers
report.data.flat_map.with_index do |d3, i|
d3[:values].map { |d2| {
stack: human_dimension_value_label(dim3, d3[:key]),
name: human_dimension_value_label(dim2, d2[:key]),
(i == 0 ? :id : :linkedTo) => human_dimension_value_label(dim2, d2[:key]),
color: color_for(dim2, d2[:key]),
data: d2[:values].map { |d1| {
y: d1[:value].to_f,
tooltip: tooltip_for(dim1 => d1, dim2 => d2, dim3 => d3),
filters: filters_for(dim1 => d1, dim2 => d2, dim3 => d3)
}}
}}
end
when 2
dim1, dim2 = report.groupers
report.data.map { |d2| {
name: human_dimension_value_label(dim2, d2[:key]),
color: color_for(dim2, d2[:key]),
data: d2[:values].map { |d1| {
y: d1[:value].to_f,
tooltip: tooltip_for(dim1 => d1, dim2 => d2),
filters: filters_for(dim1 => d1, dim2 => d2)
}}
}}
when 1
dim1 = report.groupers.first
[{
name: human_aggregator_label(report.aggregators),
data: report.data.map { |d1| {
y: d1[:value].to_f,
tooltip: tooltip_for(dim1 => d1),
filters: filters_for(dim1 => d1)
}}
}]
else
raise ActiveReporter::InvalidParamsError, "report must have <= 3 groupers"
end
end
def tooltip_for(xes)
lines = []
xes.each do |dim, d|
lines << [
human_dimension_label(dim),
human_dimension_value_label(dim, d[:key])
]
end
lines << [
human_aggregator_label(report.aggregators),
human_aggregator_value_label(report.aggregators, xes[report.groupers.first][:value])
]
lines.map { |k, v| "#{k}: #{v}" }.join('
')
end
def filters_for(xes)
xes.each_with_object({}) do |(dim, d), h|
h[dim.name] = d[:key]
end
end
def categories
dimension = report.groupers.first
dimension.group_values.map do |value|
human_dimension_value_label(dimension, value)
end
end
def chart_title
axis_summary
end
def chart_subtitle
filter_summary
end
def x_axis_title
human_dimension_label(report.groupers.first)
end
def y_axis_title
human_aggregator_label(report.aggregators)
end
def highcharts_options
{
chart: {
type: 'column'
},
colors: colors,
title: {
text: chart_title
},
subtitle: {
text: chart_subtitle
},
series: series,
xAxis: {
categories: categories,
title: {
text: x_axis_title
}
},
yAxis: {
allowDecimals: true,
title: {
text: y_axis_title
},
stackLabels: {
enabled: report.groupers.length >= 3,
format: '{stack}',
rotation: -45,
textAlign: 'left'
}
},
legend: {
enabled: report.groupers.length >= 2
},
tooltip: {},
plotOptions: {
series: {
events: {}
},
column: {
stacking: ('normal' if report.groupers.length >= 2)
}
}
}
end
end
end
end