glennr-seer 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTORS +6 -0
- data/LICENSE +20 -0
- data/README.rdoc +51 -0
- data/Rakefile +65 -0
- data/init.rb +1 -0
- data/lib/seer.rb +73 -0
- data/lib/seer/area_chart.rb +139 -0
- data/lib/seer/bar_chart.rb +124 -0
- data/lib/seer/chart.rb +68 -0
- data/lib/seer/column_chart.rb +124 -0
- data/lib/seer/gauge.rb +119 -0
- data/lib/seer/geomap.rb +166 -0
- data/lib/seer/line_chart.rb +143 -0
- data/lib/seer/pie_chart.rb +128 -0
- data/spec/area_chart_spec.rb +108 -0
- data/spec/bar_chart_spec.rb +51 -0
- data/spec/chart_spec.rb +62 -0
- data/spec/column_chart_spec.rb +51 -0
- data/spec/custom_matchers.rb +23 -0
- data/spec/gauge_spec.rb +59 -0
- data/spec/geomap_spec.rb +67 -0
- data/spec/helpers.rb +37 -0
- data/spec/line_chart_spec.rb +86 -0
- data/spec/pie_chart_spec.rb +51 -0
- data/spec/seer_spec.rb +134 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +13 -0
- metadata +121 -0
data/lib/seer/chart.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
module Seer
|
2
|
+
|
3
|
+
module Chart #:nodoc:
|
4
|
+
|
5
|
+
attr_accessor :chart_element, :colors
|
6
|
+
|
7
|
+
DEFAULT_COLORS = ['#324F69','#919E4B', '#A34D4D', '#BEC8BE']
|
8
|
+
DEFAULT_LEGEND_LOCATION = 'bottom'
|
9
|
+
DEFAULT_HEIGHT = 350
|
10
|
+
DEFAULT_WIDTH = 550
|
11
|
+
|
12
|
+
def hash_options
|
13
|
+
[]
|
14
|
+
end
|
15
|
+
|
16
|
+
def in_element=(elem)
|
17
|
+
@chart_element = elem
|
18
|
+
end
|
19
|
+
|
20
|
+
def colors=(colors_list)
|
21
|
+
unless colors_list.include?('darker')
|
22
|
+
raise ArgumentError, "Invalid color option: #{colors_list}" unless colors_list.is_a?(Array)
|
23
|
+
colors_list.each do |color|
|
24
|
+
raise ArgumentError, "Invalid color option: #{colors_list}" unless Seer.valid_hex_number?(color)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@colors = colors_list
|
28
|
+
end
|
29
|
+
|
30
|
+
def formatted_colors
|
31
|
+
if @colors.include?('darker')
|
32
|
+
@colors
|
33
|
+
else
|
34
|
+
"[#{@colors.map{|color| "'#{color.gsub(/\#/,'')}'"} * ','}]"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def data_columns
|
39
|
+
_data_columns = " data.addRows(#{data_table.size});\r"
|
40
|
+
_data_columns << " data.addColumn('string', '#{label_method}');\r"
|
41
|
+
_data_columns << " data.addColumn('number', '#{data_method}');\r"
|
42
|
+
_data_columns
|
43
|
+
end
|
44
|
+
|
45
|
+
def options
|
46
|
+
_options = ""
|
47
|
+
nonstring_options.each do |opt|
|
48
|
+
next unless self.send(opt)
|
49
|
+
if opt == :colors
|
50
|
+
_options << " options['#{opt.to_s.camelize(:lower)}'] = #{self.send(:formatted_colors)};\r"
|
51
|
+
else
|
52
|
+
_options << " options['#{opt.to_s.camelize(:lower)}'] = #{self.send(opt)};\r"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
string_options.each do |opt|
|
56
|
+
next unless self.send(opt)
|
57
|
+
_options << " options['#{opt.to_s.camelize(:lower)}'] = '#{self.send(opt)}';\r"
|
58
|
+
end
|
59
|
+
hash_options.each do |opt|
|
60
|
+
next unless self.send(opt)
|
61
|
+
_options << " options['#{opt.to_s.camelize(:lower)}'] = #{Seer.options_for_javascript(self.send(opt))};\r"
|
62
|
+
end
|
63
|
+
_options
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Seer
|
2
|
+
|
3
|
+
# =USAGE
|
4
|
+
#
|
5
|
+
# In your controller:
|
6
|
+
#
|
7
|
+
# @data = Widgets.all # Must be an array, and must respond
|
8
|
+
# # to the data method specified below (in this example, 'quantity')
|
9
|
+
#
|
10
|
+
# In your view:
|
11
|
+
#
|
12
|
+
# <div id="chart"></div>
|
13
|
+
#
|
14
|
+
# <%= Seer::visualize(
|
15
|
+
# @widgets,
|
16
|
+
# :as => :column_chart,
|
17
|
+
# :in_element => 'chart',
|
18
|
+
# :series => {:series_label => 'name', :data_method => 'quantity'},
|
19
|
+
# :chart_options => {
|
20
|
+
# :height => 300,
|
21
|
+
# :width => 300,
|
22
|
+
# :is_3_d => true,
|
23
|
+
# :legend => 'none',
|
24
|
+
# :colors => "[{color:'#990000', darker:'#660000'}]",
|
25
|
+
# :title => "Widget Quantities",
|
26
|
+
# :title_x => 'Widgets',
|
27
|
+
# :title_y => 'Quantities'
|
28
|
+
# }
|
29
|
+
# )
|
30
|
+
# -%>
|
31
|
+
#
|
32
|
+
# Colors are treated differently for 2d and 3d graphs. If you set is_3_d to false, set the
|
33
|
+
# graph color like this:
|
34
|
+
#
|
35
|
+
# :colors => "#990000"
|
36
|
+
#
|
37
|
+
# For details on the chart options, see the Google API docs at
|
38
|
+
# http://code.google.com/apis/visualization/documentation/gallery/columnchart.html
|
39
|
+
#
|
40
|
+
class ColumnChart
|
41
|
+
|
42
|
+
include Seer::Chart
|
43
|
+
|
44
|
+
# Chart options accessors
|
45
|
+
attr_accessor :axis_color, :axis_background_color, :axis_font_size, :background_color, :border_color, :enable_tooltip, :focus_border_color, :height, :is_3_d, :is_stacked, :legend, :legend_background_color, :legend_font_size, :legend_text_color, :log_scale, :max, :min, :reverse_axis, :show_categories, :title, :title_x, :title_y, :title_color, :title_font_size, :tooltip_font_size, :tooltip_height, :tooltip_width, :width
|
46
|
+
|
47
|
+
# Graph data
|
48
|
+
attr_accessor :data, :data_method, :data_table, :label_method
|
49
|
+
|
50
|
+
def initialize(args={}) #:nodoc:
|
51
|
+
|
52
|
+
# Standard options
|
53
|
+
args.each{ |method,arg| self.send("#{method}=",arg) if self.respond_to?(method) }
|
54
|
+
|
55
|
+
# Chart options
|
56
|
+
args[:chart_options].each{ |method, arg| self.send("#{method}=",arg) if self.respond_to?(method) }
|
57
|
+
|
58
|
+
# Handle defaults
|
59
|
+
@colors ||= args[:chart_options][:colors] || DEFAULT_COLORS
|
60
|
+
@legend ||= args[:chart_options][:legend] || DEFAULT_LEGEND_LOCATION
|
61
|
+
@height ||= args[:chart_options][:height] || DEFAULT_HEIGHT
|
62
|
+
@width ||= args[:chart_options][:width] || DEFAULT_WIDTH
|
63
|
+
@is_3_d ||= args[:chart_options][:is_3_d]
|
64
|
+
|
65
|
+
@data_table = []
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def data_table #:nodoc:
|
70
|
+
data.each_with_index do |datum, column|
|
71
|
+
@data_table << [
|
72
|
+
" data.setValue(#{column}, 0,'#{datum.send(label_method)}');\r",
|
73
|
+
" data.setValue(#{column}, 1, #{datum.send(data_method)});\r"
|
74
|
+
]
|
75
|
+
end
|
76
|
+
@data_table
|
77
|
+
end
|
78
|
+
|
79
|
+
def is_3_d #:nodoc:
|
80
|
+
@is_3_d.blank? ? false : @is_3_d
|
81
|
+
end
|
82
|
+
|
83
|
+
def nonstring_options #:nodoc:
|
84
|
+
[:axis_font_size, :colors, :enable_tooltip, :height, :is_3_d, :is_stacked, :legend_font_size, :log_scale, :max, :min, :reverse_axis, :show_categories, :title_font_size, :tooltip_font_size, :tooltip_width, :width]
|
85
|
+
end
|
86
|
+
|
87
|
+
def string_options #:nodoc:
|
88
|
+
[:axis_color, :axis_background_color, :background_color, :border_color, :focus_border_color, :legend, :legend_background_color, :legend_text_color, :title, :title_x, :title_y, :title_color]
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_js #:nodoc:
|
92
|
+
|
93
|
+
%{
|
94
|
+
<script type="text/javascript">
|
95
|
+
google.load('visualization', '1', {'packages':['corechart']});
|
96
|
+
google.setOnLoadCallback(drawChart);
|
97
|
+
function drawChart() {
|
98
|
+
var data = new google.visualization.DataTable();
|
99
|
+
#{data_columns}
|
100
|
+
#{data_table.to_s}
|
101
|
+
var options = {};
|
102
|
+
#{options}
|
103
|
+
var container = document.getElementById('#{self.chart_element}');
|
104
|
+
var chart = new google.visualization.ColumnChart(container);
|
105
|
+
chart.draw(data, options);
|
106
|
+
}
|
107
|
+
</script>
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.render(data, args) #:nodoc:
|
112
|
+
graph = Seer::ColumnChart.new(
|
113
|
+
:data => data,
|
114
|
+
:label_method => args[:series][:series_label],
|
115
|
+
:data_method => args[:series][:data_method],
|
116
|
+
:chart_options => args[:chart_options],
|
117
|
+
:chart_element => args[:in_element] || 'chart'
|
118
|
+
)
|
119
|
+
graph.to_js
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
data/lib/seer/gauge.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
module Seer
|
2
|
+
|
3
|
+
# =USAGE
|
4
|
+
#
|
5
|
+
# In your controller:
|
6
|
+
#
|
7
|
+
# @data = Widgets.all # Must be an array, and must respond
|
8
|
+
# # to the data method specified below (in this example, 'quantity')
|
9
|
+
#
|
10
|
+
# In your view:
|
11
|
+
#
|
12
|
+
# <div id="chart"></div>
|
13
|
+
#
|
14
|
+
# <%= Seer::visualize(
|
15
|
+
# @data,
|
16
|
+
# :as => :gauge,
|
17
|
+
# :in_element => 'chart',
|
18
|
+
# :series => {:series_label => 'name', :data_method => 'quantity'},
|
19
|
+
# :chart_options => {
|
20
|
+
# :green_from => 0,
|
21
|
+
# :green_to => 50,
|
22
|
+
# :height => 300,
|
23
|
+
# :max => 100,
|
24
|
+
# :min => 0,
|
25
|
+
# :minor_ticks => 5,
|
26
|
+
# :red_from => 76,
|
27
|
+
# :red_to => 100,
|
28
|
+
# :width => 600,
|
29
|
+
# :yellow_from => 51,
|
30
|
+
# :yellow_to => 75
|
31
|
+
# }
|
32
|
+
# )
|
33
|
+
# -%>
|
34
|
+
#
|
35
|
+
# For details on the chart options, see the Google API docs at
|
36
|
+
# http://code.google.com/apis/visualization/documentation/gallery/gauge.html
|
37
|
+
#
|
38
|
+
class Gauge
|
39
|
+
|
40
|
+
include Seer::Chart
|
41
|
+
|
42
|
+
# Chart options accessors
|
43
|
+
attr_accessor :green_from, :green_to, :height, :major_ticks, :max, :min, :minor_ticks, :red_from, :red_to, :width, :yellow_from, :yellow_to
|
44
|
+
|
45
|
+
# Graph data
|
46
|
+
attr_accessor :data, :data_method, :data_table, :label_method
|
47
|
+
|
48
|
+
def initialize(args={}) #:nodoc:
|
49
|
+
|
50
|
+
# Standard options
|
51
|
+
args.each{ |method,arg| self.send("#{method}=",arg) if self.respond_to?(method) }
|
52
|
+
|
53
|
+
# Chart options
|
54
|
+
args[:chart_options].each{ |method, arg| self.send("#{method}=",arg) if self.respond_to?(method) }
|
55
|
+
|
56
|
+
# Handle defaults
|
57
|
+
@height ||= args[:chart_options][:height] || DEFAULT_HEIGHT
|
58
|
+
@width ||= args[:chart_options][:width] || DEFAULT_WIDTH
|
59
|
+
|
60
|
+
@data_table = []
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
def data_table #:nodoc:
|
65
|
+
data.each_with_index do |datum, column|
|
66
|
+
@data_table << [
|
67
|
+
" data.setValue(#{column}, 0,'#{datum.send(label_method)}');\r",
|
68
|
+
" data.setValue(#{column}, 1, #{datum.send(data_method)});\r"
|
69
|
+
]
|
70
|
+
end
|
71
|
+
@data_table
|
72
|
+
end
|
73
|
+
|
74
|
+
def is_3_d #:nodoc:
|
75
|
+
@is_3_d.blank? ? false : @is_3_d
|
76
|
+
end
|
77
|
+
|
78
|
+
def nonstring_options #:nodoc:
|
79
|
+
[:green_from, :green_to, :height, :major_ticks, :max, :min, :minor_ticks, :red_from, :red_to, :width, :yellow_from, :yellow_to]
|
80
|
+
end
|
81
|
+
|
82
|
+
def string_options #:nodoc:
|
83
|
+
[]
|
84
|
+
end
|
85
|
+
|
86
|
+
def to_js #:nodoc:
|
87
|
+
|
88
|
+
%{
|
89
|
+
<script type="text/javascript">
|
90
|
+
google.load('visualization', '1', {'packages':['gauge']});
|
91
|
+
google.setOnLoadCallback(drawChart);
|
92
|
+
function drawChart() {
|
93
|
+
var data = new google.visualization.DataTable();
|
94
|
+
#{data_columns}
|
95
|
+
#{data_table.join}
|
96
|
+
var options = {};
|
97
|
+
#{options}
|
98
|
+
var container = document.getElementById('#{self.chart_element}');
|
99
|
+
var chart = new google.visualization.Gauge(container);
|
100
|
+
chart.draw(data, options);
|
101
|
+
}
|
102
|
+
</script>
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.render(data, args) #:nodoc:
|
107
|
+
graph = Seer::Gauge.new(
|
108
|
+
:data => data,
|
109
|
+
:label_method => args[:series][:series_label],
|
110
|
+
:data_method => args[:series][:data_method],
|
111
|
+
:chart_options => args[:chart_options],
|
112
|
+
:chart_element => args[:in_element] || 'chart'
|
113
|
+
)
|
114
|
+
graph.to_js
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
data/lib/seer/geomap.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
module Seer
|
2
|
+
|
3
|
+
# Geomap creates a map of a country, continent, or region, with colors and values assigned to
|
4
|
+
# specific regions. Values are displayed as a color scale, and you can specify optional hovertext
|
5
|
+
# for regions.
|
6
|
+
#
|
7
|
+
# =USAGE=
|
8
|
+
#
|
9
|
+
# In your view:
|
10
|
+
#
|
11
|
+
# <div id="my_geomap_container" class="chart"></div>
|
12
|
+
#
|
13
|
+
# <%= Seer::visualize(
|
14
|
+
# @widgets,
|
15
|
+
# :as => :geomap,
|
16
|
+
# :in_element => 'my_geomap_container',
|
17
|
+
# :series => {
|
18
|
+
# :series_label => 'name',
|
19
|
+
# :data_label => '# widgets',
|
20
|
+
# :data_method => 'quantity'
|
21
|
+
# },
|
22
|
+
# :chart_options => {
|
23
|
+
# :data_mode => 'regions',
|
24
|
+
# :region => 'US',
|
25
|
+
# }
|
26
|
+
# )
|
27
|
+
# -%>
|
28
|
+
#
|
29
|
+
# ==@widgets==
|
30
|
+
#
|
31
|
+
# A collection of objects (ActiveRecord or otherwise) that must respond to the
|
32
|
+
# following methods:
|
33
|
+
#
|
34
|
+
# latitude # => returns the latitude in decimal format
|
35
|
+
# longitude # => returns the longitude in decimal format
|
36
|
+
# geocoded? # => result of latitude && longitude
|
37
|
+
#
|
38
|
+
# For details on the chart options, see the Google API docs at
|
39
|
+
# http://code.google.com/apis/visualization/documentation/gallery/geomap.html
|
40
|
+
#
|
41
|
+
class Geomap
|
42
|
+
|
43
|
+
include Seer::Chart
|
44
|
+
|
45
|
+
COUNTRY_CODES = ['world', 'AX', 'AF', 'AL', 'DZ', 'AS', 'AD', 'AO', 'AI', 'AQ', 'AG', 'AR', 'AM', 'AW', 'AU', 'AT', 'AZ', 'BS', 'BH', 'BD', 'BB', 'BY', 'BE', 'BZ', 'BJ', 'BM', 'BT', 'BO', 'BA', 'BW', 'BV', 'BR', 'IO', 'BN', 'BG', 'BF', 'BI', 'KH', 'CM', 'CA', 'CV', 'KY', 'CF', 'TD', 'CL', 'CN', 'CX', 'CC', 'CO', 'KM', 'CD', 'CG', 'CK', 'CR', 'CI', 'HR', 'CU', 'CY', 'CZ', 'DK', 'DJ', 'DM', 'DO', 'EC', 'EG', 'SV', 'GQ', 'ER', 'EE', 'ET', 'FK', 'FO', 'FJ', 'FI', 'FR', 'GF', 'PF', 'TF', 'GA', 'GM', 'GE', 'DE', 'GH', 'GI', 'GR', 'GL', 'GD', 'GP', 'GU', 'GT', 'GN', 'GW', 'GY', 'HT', 'HM', 'HN', 'HK', 'HU', 'IS', 'IN', 'ID', 'IR', 'IQ', 'IE', 'IL', 'IT', 'JM', 'JP', 'JO', 'KZ', 'KE', 'KI', 'KP', 'KR', 'KW', 'KG', 'LA', 'LV', 'LB', 'LS', 'LR', 'LY', 'LI', 'LT', 'LU', 'MO', 'MK', 'MG', 'MW', 'MY', 'MV', 'ML', 'MT', 'MH', 'MQ', 'MR', 'MU', 'YT', 'MX', 'FM', 'MD', 'MC', 'MN', 'MS', 'MA', 'MZ', 'MM', 'NA', 'NR', 'NP', 'NL', 'AN', 'NC', 'NZ', 'NI', 'NE', 'NG', 'NU', 'NF', 'MP', 'NO', 'OM', 'PK', 'PW', 'PS', 'PA', 'PG', 'PY', 'PE', 'PH', 'PN', 'PL', 'PT', 'PR', 'QA', 'RE', 'RO', 'RU', 'RW', 'SH', 'KN', 'LC', 'PM', 'VC', 'WS', 'SM', 'ST', 'SA', 'SN', 'CS', 'SC', 'SL', 'SG', 'SK', 'SI', 'SB', 'SO', 'ZA', 'GS', 'ES', 'LK', 'SD', 'SR', 'SJ', 'SZ', 'SE', 'CH', 'SY', 'TW', 'TJ', 'TZ', 'TH', 'TL', 'TG', 'TK', 'TO', 'TT', 'TN', 'TR', 'TM', 'TC', 'TV', 'UG', 'UA', 'AE', 'GB', 'US', 'us_metro', 'UM', 'UY', 'UZ', 'VU', 'VA', 'VE', 'VN', 'VG', 'VI', 'WF', 'EH', 'YE', 'ZM', 'ZW', '005', '013', '021', '002', '017', '015', '018', '030', '034', '035', '143', '145', '151', '154', '155', '039']
|
46
|
+
|
47
|
+
# Chart options accessors
|
48
|
+
attr_accessor :data_mode, :enable_tooltip, :height, :legend_background_color, :legend_font_size, :legend_text_color, :legend, :region, :show_legend, :show_zoom_out, :title_color, :title_font_size, :title_x, :title_y, :title, :tooltip_font_size, :tooltip_height, :tooltip_width, :width, :zoom_out_label
|
49
|
+
|
50
|
+
# Graph data
|
51
|
+
attr_accessor :data, :data_label, :data_method, :data_table, :label_method
|
52
|
+
|
53
|
+
def initialize(args={}) #:nodoc:
|
54
|
+
|
55
|
+
# Standard options
|
56
|
+
args.each{ |method,arg| self.send("#{method}=",arg) if self.respond_to?(method) }
|
57
|
+
|
58
|
+
# Chart options
|
59
|
+
args[:chart_options].each{ |method, arg| self.send("#{method}=",arg) if self.respond_to?(method) }
|
60
|
+
|
61
|
+
# Handle defaults
|
62
|
+
@colors ||= args[:chart_options][:colors] || DEFAULT_COLORS
|
63
|
+
@legend ||= args[:chart_options][:legend] || DEFAULT_LEGEND_LOCATION
|
64
|
+
@height ||= args[:chart_options][:height] || DEFAULT_HEIGHT
|
65
|
+
@width ||= args[:chart_options][:width] || DEFAULT_WIDTH
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def data_columns #:nodoc:
|
70
|
+
_data_columns = "data.addRows(#{data_table.size});"
|
71
|
+
if self.data_mode == 'markers'
|
72
|
+
_data_columns << %{
|
73
|
+
data.addColumn('number', 'LATITUDE');
|
74
|
+
data.addColumn('number', 'LONGITUDE');
|
75
|
+
data.addColumn('number', '#{data_method}');
|
76
|
+
data.addColumn('string', '#{label_method}');
|
77
|
+
}
|
78
|
+
else
|
79
|
+
_data_columns << " data.addColumn('string', '#{label_method}');"
|
80
|
+
_data_columns << " data.addColumn('number', '#{data_method}');"
|
81
|
+
_data_columns
|
82
|
+
end
|
83
|
+
_data_columns
|
84
|
+
end
|
85
|
+
|
86
|
+
def data_mode=(mode) #:nodoc:
|
87
|
+
raise ArgumentError, "Invalid data mode option: #{mode}. Must be one of 'regions' or 'markers'." unless ['regions', 'markers'].include?(mode)
|
88
|
+
@data_mode = mode
|
89
|
+
end
|
90
|
+
|
91
|
+
def data_table #:nodoc:
|
92
|
+
@data_table = []
|
93
|
+
data.each_with_index do |datum, column|
|
94
|
+
next unless datum.geocoded?
|
95
|
+
if data_mode == "markers"
|
96
|
+
@data_table << [
|
97
|
+
" data.setValue(#{column}, 0, #{datum.latitude});\r",
|
98
|
+
" data.setValue(#{column}, 1, #{datum.longitude});\r",
|
99
|
+
" data.setValue(#{column}, 2, #{datum.send(data_method)});\r",
|
100
|
+
" data.setValue(#{column}, 3, '#{datum.send(label_method)}');\r"
|
101
|
+
]
|
102
|
+
else # Regions
|
103
|
+
@data_table << [
|
104
|
+
" data.setValue(#{column}, 0, '#{datum.name}');\r",
|
105
|
+
" data.setValue(#{column}, 1, #{datum.send(data_method)});\r"
|
106
|
+
]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
@data_table
|
110
|
+
end
|
111
|
+
|
112
|
+
# Because Google is not consistent in their @#!$ API...
|
113
|
+
def formatted_colors
|
114
|
+
"[#{@colors.map{|color| "'#{color.gsub(/\#/,'0x')}'"} * ','}]"
|
115
|
+
end
|
116
|
+
|
117
|
+
def nonstring_options #:nodoc:
|
118
|
+
[:colors, :enable_tooltip, :height, :legend_font_size, :title_font_size, :tooltip_font_size, :tooltip_width, :width]
|
119
|
+
end
|
120
|
+
|
121
|
+
def string_options #:nodoc:
|
122
|
+
[:data_mode, :legend, :legend_background_color, :legend_text_color, :title, :title_x, :title_y, :title_color, :region]
|
123
|
+
end
|
124
|
+
|
125
|
+
def to_js
|
126
|
+
%{
|
127
|
+
<script type="text/javascript">
|
128
|
+
google.load('visualization', '1', {'packages':['geomap']});
|
129
|
+
google.setOnLoadCallback(drawChart);
|
130
|
+
function drawChart() {
|
131
|
+
var data = new google.visualization.DataTable();
|
132
|
+
#{data_columns}
|
133
|
+
#{data_table.to_s}
|
134
|
+
var options = {};
|
135
|
+
#{options}
|
136
|
+
var container = document.getElementById('#{self.chart_element}');
|
137
|
+
var geomap = new google.visualization.GeoMap(container);
|
138
|
+
geomap.draw(data, options);
|
139
|
+
}
|
140
|
+
</script>
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
def region=(desired_region)
|
145
|
+
raise ArgumentError, "Invalid region: #{desired_region}" unless COUNTRY_CODES.include?(desired_region)
|
146
|
+
@region = desired_region
|
147
|
+
end
|
148
|
+
|
149
|
+
# ====================================== Class Methods =========================================
|
150
|
+
|
151
|
+
def self.render(data, args)
|
152
|
+
map = Seer::Geomap.new(
|
153
|
+
:region => args[:chart_options][:region],
|
154
|
+
:data_mode => args[:chart_options][:data_mode],
|
155
|
+
:data => data,
|
156
|
+
:label_method => args[:series][:series_label],
|
157
|
+
:data_method => args[:series][:data_method],
|
158
|
+
:chart_options => args[:chart_options],
|
159
|
+
:chart_element => args[:in_element] || 'chart'
|
160
|
+
)
|
161
|
+
map.to_js
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|