chart-candy 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/LICENSE +7 -0
- data/README.md +109 -0
- data/Rakefile +11 -0
- data/app/assets/javascripts/chart_candy/base.coffee +16 -0
- data/app/assets/javascripts/chart_candy/counter.coffee +50 -0
- data/app/assets/javascripts/chart_candy/donut.coffee +162 -0
- data/app/assets/javascripts/chart_candy/index.js +4 -0
- data/app/assets/javascripts/chart_candy/line.coffee +338 -0
- data/app/assets/stylesheets/chart_candy/base.css.scss +66 -0
- data/app/assets/stylesheets/chart_candy/counter.css.scss +11 -0
- data/app/assets/stylesheets/chart_candy/donut.css.scss +34 -0
- data/app/assets/stylesheets/chart_candy/index.css +6 -0
- data/app/assets/stylesheets/chart_candy/line.css.scss +107 -0
- data/app/controllers/candy_charts_controller.rb +60 -0
- data/config/locales/fr.yml +36 -0
- data/config/routes.rb +3 -0
- data/lib/chart-candy.rb +23 -0
- data/lib/chart-candy/authentication.rb +45 -0
- data/lib/chart-candy/base_chart.rb +11 -0
- data/lib/chart-candy/builder.rb +46 -0
- data/lib/chart-candy/builder/base.rb +70 -0
- data/lib/chart-candy/builder/counter.rb +12 -0
- data/lib/chart-candy/builder/donut.rb +73 -0
- data/lib/chart-candy/builder/line.rb +114 -0
- data/lib/chart-candy/builder/xls_builder.rb +159 -0
- data/lib/chart-candy/engine.rb +5 -0
- data/lib/chart-candy/helpers.rb +169 -0
- data/lib/chart-candy/implants.rb +10 -0
- data/lib/chart-candy/implants/railtie.rb +17 -0
- data/spec/chart-candy_spec.rb +11 -0
- data/spec/spec_helper.rb +12 -0
- data/vendor/assets/javascripts/d3.js +4 -0
- metadata +118 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
class ChartCandy::Builder::Base
|
2
|
+
def initialize(id, options={})
|
3
|
+
options.reverse_merge! from: nil, to: nil, step: nil
|
4
|
+
|
5
|
+
@from = options[:from] ? Time.parse(options[:from]) : nil
|
6
|
+
@to = options[:to] ? Time.parse(options[:to]) : Time.now
|
7
|
+
|
8
|
+
@chart = { id: id }
|
9
|
+
@chart[:step] = options[:step] if options[:step]
|
10
|
+
@chart[:title] = t('title')
|
11
|
+
@chart[:period] = ChartCandy::Builder.period(@from, @to, step: @chart[:step]) if @from
|
12
|
+
end
|
13
|
+
|
14
|
+
def close_chart
|
15
|
+
# Hooks before closing a chart
|
16
|
+
end
|
17
|
+
|
18
|
+
def filename
|
19
|
+
name = [title.parameterize]
|
20
|
+
name << @from.strftime('%Y%m%d') if @from
|
21
|
+
name << @to.strftime('%Y%m%d') if @to
|
22
|
+
|
23
|
+
return name.compact.join('-')
|
24
|
+
end
|
25
|
+
|
26
|
+
def id
|
27
|
+
@chart[:id]
|
28
|
+
end
|
29
|
+
|
30
|
+
def l(date, options={})
|
31
|
+
options.reverse_merge!(format: :date_long)
|
32
|
+
|
33
|
+
return ChartCandy.localize(date, options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def period
|
37
|
+
@chart[:period]
|
38
|
+
end
|
39
|
+
|
40
|
+
def set_period_from_data(data)
|
41
|
+
@from = data.first
|
42
|
+
@to = data.last
|
43
|
+
|
44
|
+
@chart[:step] = ChartCandy::Builder.get_step_from_interval(data[1] - data[0]) if not @chart[:step]
|
45
|
+
|
46
|
+
@chart[:period] = ChartCandy::Builder.period @from, @to, step: @chart[:step]
|
47
|
+
end
|
48
|
+
|
49
|
+
def t(path, vars={})
|
50
|
+
vars.reverse_merge! :default => ''
|
51
|
+
|
52
|
+
ChartCandy.translate("#{id.gsub('-', '_')}.#{path}", vars)
|
53
|
+
end
|
54
|
+
|
55
|
+
def title
|
56
|
+
@chart[:title]
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_json
|
60
|
+
close_chart
|
61
|
+
|
62
|
+
return @chart.to_json
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_xls
|
66
|
+
close_chart
|
67
|
+
|
68
|
+
return ChartCandy::Builder::XlsBuilder.chart_to_xls @chart
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class ChartCandy::Builder::Counter < ChartCandy::Builder::Base
|
2
|
+
|
3
|
+
def initialize(id, options={})
|
4
|
+
super
|
5
|
+
|
6
|
+
@chart.merge! nature: 'count', data: []
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_primary(id, value)
|
10
|
+
@chart[:data] << { nature: :primary, label: t("data.#{id}.label"), id: id, value: value }
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class ChartCandy::Builder::Donut < ChartCandy::Builder::Base
|
2
|
+
|
3
|
+
def initialize(id, options={})
|
4
|
+
super
|
5
|
+
|
6
|
+
@chart.merge! hole: [], label: t('label'), nature: 'donut', slices: [], show_label: true, unit: :number, value: t('value')
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_hole_item(name, value)
|
10
|
+
@chart[:hole] = [t('hole.title')].flatten if hole.empty?
|
11
|
+
hole << t("hole.#{name}", value: value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_slice(name, value, options={})
|
15
|
+
options.reverse_merge! txt_vars: {}
|
16
|
+
|
17
|
+
return if value.to_i <= 0
|
18
|
+
|
19
|
+
value = value.round(2) if money?
|
20
|
+
valuef = money? ? format_money(value) : value
|
21
|
+
|
22
|
+
options[:txt_vars][:value] = valuef
|
23
|
+
|
24
|
+
label_str = t("slices.#{name}.label", options[:txt_vars])
|
25
|
+
tooltip = t("slices.#{name}.tooltip", options[:txt_vars])
|
26
|
+
|
27
|
+
@chart[:slices] << { label: label_str, percent: 0, tooltip: tooltip, value: value, valuef: valuef }
|
28
|
+
end
|
29
|
+
|
30
|
+
def close_chart
|
31
|
+
total = @chart[:slices].sum{ |s| s[:value] }
|
32
|
+
|
33
|
+
total = total.round(2) if money?
|
34
|
+
|
35
|
+
@chart[:total] = { label: 'Total', value: total }
|
36
|
+
|
37
|
+
fill_percents
|
38
|
+
end
|
39
|
+
|
40
|
+
def format_money(value)
|
41
|
+
sprintf("%0.02f", (value.to_f).round(2)).gsub('.', ',') + ' $'
|
42
|
+
end
|
43
|
+
|
44
|
+
def hole
|
45
|
+
@chart[:hole]
|
46
|
+
end
|
47
|
+
|
48
|
+
def money?
|
49
|
+
@chart[:unit] == :money
|
50
|
+
end
|
51
|
+
|
52
|
+
def show_label=(active)
|
53
|
+
@chart[:show_label] = active
|
54
|
+
end
|
55
|
+
|
56
|
+
def show_label
|
57
|
+
@chart[:show_label]
|
58
|
+
end
|
59
|
+
|
60
|
+
def unit=(unit_sym)
|
61
|
+
@chart[:unit] = unit_sym.to_sym if [:number, :money].include? unit_sym.to_sym
|
62
|
+
end
|
63
|
+
|
64
|
+
def unit
|
65
|
+
@chart[:unit]
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def fill_percents
|
71
|
+
@chart[:slices].each { |s| s[:percent] = (s[:value].to_f * 100 / @chart[:total][:value]).round(2) }
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
class ChartCandy::Builder::Line < ChartCandy::Builder::Base
|
2
|
+
|
3
|
+
def initialize(id, options={})
|
4
|
+
super
|
5
|
+
|
6
|
+
@chart.merge! axis: {}, legend: nil, lines: [], nature: 'line', tooltip: true
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_dot(dot, id, x_name, y_name)
|
10
|
+
{
|
11
|
+
x: dot[x_name],
|
12
|
+
y: dot[y_name],
|
13
|
+
label_x: add_dot_label(id, dot[x_name], @chart[:axis][:x][:nature]),
|
14
|
+
label_y: add_dot_label(id, dot[y_name], @chart[:axis][:y][:nature])
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_dot_label(id, value, nature)
|
19
|
+
case nature
|
20
|
+
when :date then add_dot_label_date value
|
21
|
+
when :money then add_dot_label_money value
|
22
|
+
else value.to_s + ' ' + t("lines.#{id}.unit")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_dot_label_date(date)
|
27
|
+
case @chart[:step]
|
28
|
+
when 'day' then l(date, format: :date_long)
|
29
|
+
when 'week' then ChartCandy.translate('date.week') + ' ' + l(date, format: :date_long).strip
|
30
|
+
when 'month' then l(date, format: :date_without_day).capitalize
|
31
|
+
else l(date, format: :date_long)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_dot_label_money(amount)
|
36
|
+
sprintf("%0.02f", amount.round(2)).gsub('.', ',') + ' $'
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_line(id, original_data, options={})
|
40
|
+
options.reverse_merge! axis_y: "left", txt_vars: {}, key_x: "time", key_y: "value"
|
41
|
+
|
42
|
+
data = original_data.map{ |d| add_dot(d, id, options[:key_x], options[:key_y]) }
|
43
|
+
|
44
|
+
[:x, :y].each do |key|
|
45
|
+
[:min, :max].each { |m| @chart[:axis][key][m] = to_money_format(@chart[:axis][key][m]) } if money? key
|
46
|
+
end
|
47
|
+
|
48
|
+
data = original_data.map do |d|
|
49
|
+
[:key_x, :key_y].each { |key| d[options[key]] = to_money_format(d[options[key]]) if money?(key[-1,1]) }
|
50
|
+
add_dot(d, id, options[:key_x], options[:key_y])
|
51
|
+
end
|
52
|
+
|
53
|
+
@chart[:lines] << { axis_y: options[:axis_y], data: data, label: t("lines.#{id}.label", options[:txt_vars]), unit: t("lines.#{id}.unit"), total: get_total(data) }
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_x_axis(nature, original_data, options={})
|
57
|
+
options.reverse_merge! key: "time"
|
58
|
+
|
59
|
+
data = original_data.map{ |d| d[options[:key]] }
|
60
|
+
|
61
|
+
set_period_from_data data if not @from and nature == :date
|
62
|
+
|
63
|
+
@chart[:axis][:x] = { nature: nature, label: t("axis.x.label"), min: data.min, max: data.max, max_ticks: data.length }
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_y_axis(nature, original_data, options={})
|
67
|
+
options.reverse_merge! key: 'value', max: nil, min: nil
|
68
|
+
|
69
|
+
data = original_data.map{ |d| d[options[:key]] }
|
70
|
+
|
71
|
+
min = options[:min] ? options[:min] : data.min
|
72
|
+
max = options[:max] ? options[:max] : data.max
|
73
|
+
|
74
|
+
@chart[:axis][:y] = { nature: nature, label: t('axis.y.label'), min: min, max: max, max_ticks: data.length }
|
75
|
+
end
|
76
|
+
|
77
|
+
def close_chart
|
78
|
+
super
|
79
|
+
|
80
|
+
@chart[:legend] = (@chart[:lines].length > 1) if @chart[:legend].nil?
|
81
|
+
end
|
82
|
+
|
83
|
+
def date_based?
|
84
|
+
@chart[:axis][:x] and @chart[:axis][:x][:nature] == :date
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_total(data)
|
88
|
+
{ label: 'Total', value: data.sum{ |d| d[:y] } }
|
89
|
+
end
|
90
|
+
|
91
|
+
def legend=(active)
|
92
|
+
@chart[:legend] = active
|
93
|
+
end
|
94
|
+
|
95
|
+
def legend
|
96
|
+
@chart[:legend]
|
97
|
+
end
|
98
|
+
|
99
|
+
def money?(key)
|
100
|
+
@chart[:axis][key.to_sym][:nature] == :money
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_money_format(value)
|
104
|
+
(BigDecimal.new(value) / 100).round(2)
|
105
|
+
end
|
106
|
+
|
107
|
+
def tooltip=(active)
|
108
|
+
@chart[:tooltip] = active
|
109
|
+
end
|
110
|
+
|
111
|
+
def tooltip
|
112
|
+
@chart[:tooltip]
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'spreadsheet'
|
2
|
+
|
3
|
+
class ChartCandy::Builder::XlsBuilder
|
4
|
+
attr_reader :current_row, :current_column, :workbook
|
5
|
+
|
6
|
+
def self.chart_to_xls(chart)
|
7
|
+
xls = self.new(chart)
|
8
|
+
xls.generate
|
9
|
+
|
10
|
+
return xls.workbook
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(chart)
|
14
|
+
@chart = chart
|
15
|
+
@workbook = Spreadsheet::Workbook.new
|
16
|
+
@sheet = @workbook.create_worksheet
|
17
|
+
@formats = build_formats
|
18
|
+
|
19
|
+
@current_row = -1
|
20
|
+
@current_row_format = :normal
|
21
|
+
@current_column = 0
|
22
|
+
|
23
|
+
@columns_width = []
|
24
|
+
@max_column_width = 50
|
25
|
+
@default_column_width = 10
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_align_right_formats(formats)
|
29
|
+
align_right = {}
|
30
|
+
|
31
|
+
formats.each do |k,origin|
|
32
|
+
new_format = origin.dup
|
33
|
+
new_format.horizontal_align = :right
|
34
|
+
|
35
|
+
align_right["#{k}_right".to_sym] = new_format
|
36
|
+
end
|
37
|
+
|
38
|
+
formats.merge! align_right
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_formats
|
42
|
+
f = {}
|
43
|
+
|
44
|
+
f[:h1] = Spreadsheet::Format.new(weight: :bold, size: 16, horizontal_align: :left, vertical_align: :middle)
|
45
|
+
f[:h2] = Spreadsheet::Format.new(weight: :normal, size: 12, horizontal_align: :left, vertical_align: :middle)
|
46
|
+
f[:h3] = Spreadsheet::Format.new(weight: :normal, size: 9, horizontal_align: :left, vertical_align: :middle)
|
47
|
+
f[:h4] = Spreadsheet::Format.new(weight: :bold, size: 8, horizontal_align: :left, vertical_align: :middle)
|
48
|
+
f[:th] = Spreadsheet::Format.new(weight: :bold, size: 8, horizontal_align: :center, vertical_align: :middle, pattern_fg_color: :xls_color_19, pattern: 1)
|
49
|
+
f[:th_foot] = Spreadsheet::Format.new(weight: :bold, size: 8, horizontal_align: :left, vertical_align: :middle, pattern_fg_color: :xls_color_19, pattern: 1)
|
50
|
+
f[:normal] = Spreadsheet::Format.new(size: 8, horizontal_align: :left , vertical_align: :middle)
|
51
|
+
|
52
|
+
add_align_right_formats f
|
53
|
+
|
54
|
+
return f
|
55
|
+
end
|
56
|
+
|
57
|
+
def cell(content=nil, options={})
|
58
|
+
options.reverse_merge! format: nil, nature: :text
|
59
|
+
|
60
|
+
row_obj = @sheet.row(current_row)
|
61
|
+
|
62
|
+
row_obj.set_format current_column, @formats[options[:format]] if options[:format]
|
63
|
+
set_cell_format options[:nature]
|
64
|
+
row_obj.height = row_obj.format(0).font.size * 1.6
|
65
|
+
|
66
|
+
parsed_content = format_data(content)
|
67
|
+
|
68
|
+
@sheet[current_row, current_column] = parsed_content
|
69
|
+
|
70
|
+
@columns_width[current_column] = parsed_content.to_s.length if @columns_width[current_column].to_i < parsed_content.to_s.length
|
71
|
+
|
72
|
+
@current_column += 1
|
73
|
+
end
|
74
|
+
|
75
|
+
def format_data(data)
|
76
|
+
case
|
77
|
+
when data.is_a?(Time) then data.strftime('%d-%m-%Y')
|
78
|
+
else data
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def generate
|
83
|
+
header
|
84
|
+
|
85
|
+
case @chart[:nature]
|
86
|
+
when 'line' then generate_chart_line_table
|
87
|
+
when 'donut' then generate_chart_donut_table
|
88
|
+
end
|
89
|
+
|
90
|
+
set_columns_width
|
91
|
+
end
|
92
|
+
|
93
|
+
def generate_chart_line_table
|
94
|
+
row @chart[:axis][:x][:label], :th
|
95
|
+
|
96
|
+
@chart[:lines].map { |l| cell l[:label] }
|
97
|
+
|
98
|
+
@chart[:lines][0][:data].each_with_index do |l,i|
|
99
|
+
row
|
100
|
+
|
101
|
+
cell l[:x], nature: @chart[:axis][:x][:nature]
|
102
|
+
|
103
|
+
@chart[:lines].each { |line| cell line[:data][i][:y], nature: @chart[:axis][:y][:nature] }
|
104
|
+
end
|
105
|
+
|
106
|
+
row @chart[:lines][0][:total][:label], :th_foot
|
107
|
+
|
108
|
+
@chart[:lines].map { |l| cell l[:total][:value], nature: :number }
|
109
|
+
end
|
110
|
+
|
111
|
+
def generate_chart_donut_table
|
112
|
+
row [@chart[:label], @chart[:value]], :th
|
113
|
+
|
114
|
+
@chart[:slices].map { |s| row [s[:label], s[:value]] }
|
115
|
+
|
116
|
+
row [@chart[:total][:label], @chart[:total][:value]], :th_foot
|
117
|
+
end
|
118
|
+
|
119
|
+
def header
|
120
|
+
row @chart[:title], :h1
|
121
|
+
row @chart[:period], :h3 if @chart[:period]
|
122
|
+
|
123
|
+
reset_columns_width
|
124
|
+
|
125
|
+
skip_row
|
126
|
+
end
|
127
|
+
|
128
|
+
def reset_columns_width
|
129
|
+
@columns_width = Array.new(@columns_width.length, @default_column_width)
|
130
|
+
end
|
131
|
+
|
132
|
+
def row(data=[], format = :normal)
|
133
|
+
@current_column = 0
|
134
|
+
@current_row += 1
|
135
|
+
|
136
|
+
@sheet.row(current_row).default_format = @formats[format]
|
137
|
+
@current_row_format = format
|
138
|
+
|
139
|
+
[data].flatten.each { |d| cell(d) }
|
140
|
+
end
|
141
|
+
|
142
|
+
def set_cell_format(nature)
|
143
|
+
if nature == :number
|
144
|
+
f = "#{@current_row_format}_right".gsub('right_right', 'right').to_sym
|
145
|
+
|
146
|
+
@sheet.row(current_row).set_format(current_column, @formats[f])
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def set_columns_width
|
151
|
+
@columns_width.each_with_index do |c,i|
|
152
|
+
@sheet.column(i).width = (c.to_i < @default_column_width) ? @default_column_width : c.to_i
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def skip_row
|
157
|
+
@current_row += 1
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module ChartCandy::Helpers
|
2
|
+
def counter_chart(id, options={})
|
3
|
+
ChartCandyTagHelper.new(self, id, options[:from], options[:to], options[:step]).counter(options)
|
4
|
+
end
|
5
|
+
|
6
|
+
def d3_include_tag
|
7
|
+
('<![if ! lt IE 9]>' + javascript_include_tag("d3") + '<![endif]>').html_safe
|
8
|
+
end
|
9
|
+
|
10
|
+
def donut_chart(id, options={})
|
11
|
+
ChartCandyTagHelper.new(self, id, options[:from], options[:to], options[:step]).donut(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def line_chart(id, options={})
|
15
|
+
ChartCandyTagHelper.new(self, id, options[:from], options[:to], options[:step]).line(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def excel_chart_button(id, options={})
|
19
|
+
ChartCandyTagHelper.new(self, id, options[:from], options[:to], options[:step]).excel_chart_button(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
class ChartCandyTagHelper
|
23
|
+
def initialize(rails_helpers, id, from, to, step)
|
24
|
+
@rails_helpers = rails_helpers
|
25
|
+
@id = id
|
26
|
+
@from = from
|
27
|
+
@to = to
|
28
|
+
@step = step || 'month'
|
29
|
+
end
|
30
|
+
|
31
|
+
def counter(options={})
|
32
|
+
options.reverse_merge! update_every: 1.minute, tools: nil
|
33
|
+
|
34
|
+
chart 'counter', options
|
35
|
+
end
|
36
|
+
|
37
|
+
def excel_chart_button(options={})
|
38
|
+
build_url 'line', options if not @url
|
39
|
+
|
40
|
+
tool_export_xls options[:label]
|
41
|
+
end
|
42
|
+
|
43
|
+
def line(options={})
|
44
|
+
options.reverse_merge! tools: {}
|
45
|
+
options[:tools].reverse_merge! export_xls: true, step: true, template: true
|
46
|
+
|
47
|
+
chart 'line', options
|
48
|
+
end
|
49
|
+
|
50
|
+
def donut(options={})
|
51
|
+
options.reverse_merge! tools: {}
|
52
|
+
options[:tools].reverse_merge! export_xls: true, step: false, template: true
|
53
|
+
|
54
|
+
chart 'donut', options
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def build_url(nature, options={})
|
60
|
+
params = { from: @from, format: 'json', id: @id, nature: nature, nonce: SecureRandom.hex(20), step: @step, timestamp: Time.now.utc.iso8601, to: @to, version: 'v1' }
|
61
|
+
|
62
|
+
options.each { |k,v| params[k] = v if not ['class', 'tools'].include? k.to_s }
|
63
|
+
|
64
|
+
params[:token] = build_url_token(params)
|
65
|
+
|
66
|
+
@url = @rails_helpers.candy_chart_url params
|
67
|
+
end
|
68
|
+
|
69
|
+
def build_url_token(params)
|
70
|
+
compacted_params = ChartCandy::Authentication.compact_params(params)
|
71
|
+
|
72
|
+
url = @rails_helpers.candy_charts_url + compacted_params
|
73
|
+
|
74
|
+
return ChartCandy::Authentication.tokenize(url)
|
75
|
+
end
|
76
|
+
|
77
|
+
def chart(nature, options={})
|
78
|
+
options.reverse_merge! class: ""
|
79
|
+
options[:class] += " wrapper-chart chart-#{nature}"
|
80
|
+
|
81
|
+
build_url nature, options
|
82
|
+
|
83
|
+
content = ''
|
84
|
+
content += title_tag
|
85
|
+
content += chart_tools(nature, options[:tools]) if options[:tools]
|
86
|
+
content += content_tag(:div, content_tag(:div, '', class: 'chart') + content_tag(:div, '', class: 'table'), class: 'templates')
|
87
|
+
|
88
|
+
wrapper_options = { id: @id, class: options[:class], 'data-chart-candy' => nature, 'data-url' => @url}
|
89
|
+
wrapper_options['data-update-delay'] = options[:update_every].to_i if options[:update_every]
|
90
|
+
|
91
|
+
return content_tag(:div, content.html_safe, wrapper_options)
|
92
|
+
end
|
93
|
+
|
94
|
+
def chart_select_tag(name, choices, selection)
|
95
|
+
if form_candy?
|
96
|
+
candy.select(name, choices, selection)
|
97
|
+
else
|
98
|
+
select_tag(name, options_for_select(choices, selection), id: nil)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def chart_switch_tag(name, choices, selection)
|
103
|
+
if form_candy?
|
104
|
+
candy.switch(name, choices, selection)
|
105
|
+
else
|
106
|
+
select_tag(name, options_for_select(choices, selection), id: nil)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def chart_tools(nature, options={})
|
111
|
+
content = form_tag(@url) do
|
112
|
+
tools = ''
|
113
|
+
tools += tool_export_xls if options[:export_xls]
|
114
|
+
tools += tool_step if options[:step]
|
115
|
+
tools += tool_template if options[:template]
|
116
|
+
|
117
|
+
tools.html_safe
|
118
|
+
end
|
119
|
+
|
120
|
+
return content_tag(:div, content.html_safe, class: 'tools')
|
121
|
+
end
|
122
|
+
|
123
|
+
def form_candy?
|
124
|
+
begin
|
125
|
+
(candy ? true : false)
|
126
|
+
rescue
|
127
|
+
false
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def t(path)
|
132
|
+
ChartCandy.translate(path)
|
133
|
+
end
|
134
|
+
|
135
|
+
def title_tag
|
136
|
+
content_tag(:h2, t("#{@id.underscore}.title").html_safe, class: 'title-chart')
|
137
|
+
end
|
138
|
+
|
139
|
+
def tool_export_xls(label=nil)
|
140
|
+
label = t('base.xls_export') if not label
|
141
|
+
|
142
|
+
content = link_to(content_tag(:span, label, class: 'text'), @url.gsub('.json', '.xls'), class: 'button', title: t('base.xls_export'))
|
143
|
+
|
144
|
+
return content_tag(:div, content.html_safe, class: 'tool holder-export-xls')
|
145
|
+
end
|
146
|
+
|
147
|
+
def tool_step
|
148
|
+
choices = ['day', 'week', 'month'].map{ |c| [t("base.steps.#{c}"), c] }
|
149
|
+
|
150
|
+
return content_tag(:div, chart_select_tag('step', choices, 'month'), class: 'tool holder-step')
|
151
|
+
end
|
152
|
+
|
153
|
+
def tool_template
|
154
|
+
choices = ['chart', 'table'].map { |c| [t("base.template.#{c}"), c] }
|
155
|
+
|
156
|
+
return content_tag(:div, chart_switch_tag('template', choices, 'chart'), class: 'tool holder-template')
|
157
|
+
end
|
158
|
+
|
159
|
+
def method_missing(*args, &block)
|
160
|
+
if [:candy, :content_tag, :form_tag, :link_to, :options_for_select, :select_tag].include?(args.first)
|
161
|
+
return @rails_helpers.send(*args, &block)
|
162
|
+
else
|
163
|
+
raise NoMethodError.new("undefined local variable or method '#{args.first}' for #{self.class}")
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
::ActionView::Base.send :include, self
|
169
|
+
end
|