seer 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Corey Ehmke / SEO Logic
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,49 @@
1
+ =Seer
2
+
3
+ Seer is a lightweight, semantically rich wrapper for the Google Visualization API. It allows you to easily create a visualization of data in a variety of formats, including area charts, bar charts, column charts, gauges, line charts, and pie charts.
4
+
5
+ ==Usage
6
+
7
+ Add the following to the head of the page that will display a chart, or add it to your layout file:
8
+
9
+ <%= Seer::init_visualization -%>
10
+
11
+ Gather the data you want to visualize in an instance variable in your controller, then use the visualize method to insert the appropriate chart in your view.
12
+
13
+ == Example
14
+
15
+ In your controller:
16
+
17
+ # @data must be an array, and each object in the array must respond to the data method specified
18
+ # in the visualize call (in this example, 'quantity')
19
+ @data = Widget.all
20
+
21
+ In your view:
22
+
23
+ <div id="chart" class="chart"></div>
24
+
25
+ <%= Seer::visualize(
26
+ @widgets,
27
+ :as => :bar_chart,
28
+ :in_element => 'chart',
29
+ :series => {:series_label => 'name', :data_method => 'quantity'},
30
+ :chart_options => {
31
+ :height => 300,
32
+ :width => 200 * @widgets.size,
33
+ :is_3_d => false,
34
+ :legend => 'none',
35
+ :colors => ["#990000"],
36
+ :title => "Widget Quantities",
37
+ :title_x => 'Quantity',
38
+ :title_y => 'Widgets'
39
+ }
40
+ )
41
+ -%>
42
+
43
+ == More information
44
+
45
+ For examples of additional chart types, refer to the documentation for each of the individual chart objects, or see the blog post announcing Seer: {Simple, Semantic Graphing for Ruby on Rails with Seer}[http://www.idolhands.com/ruby-on-rails/gems-plugins-and-engines/graphing-for-ruby-on-rails-with-seer]
46
+
47
+ Seer is developed and maintained by {Corey Ehmke}[http://www.idolhands.com/] at {SEO Logic}[http://www.seologic.com/].
48
+
49
+ Copyright (c) 2010 Corey Ehmke / SEO Logic, released under the MIT license
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "seer"
8
+ gem.summary = %Q{Seer is a lightweight, semantically rich wrapper for the Google Visualization API.}
9
+ gem.description = %Q{ Seer is a lightweight, semantically rich wrapper for the Google Visualization API. It allows you to easily create a visualization of data in a variety of formats, including area charts, bar charts, column charts, gauges, line charts, and pie charts.}
10
+ gem.email = "corey@seologic.com"
11
+ gem.homepage = "http://github.com/Bantik/seer"
12
+ gem.authors = ["Corey Ehmke / SEO Logic"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ gem.files = [
15
+ "init.rb",
16
+ "lib/seer.rb",
17
+ "lib/seer/area_chart.rb",
18
+ "lib/seer/bar_chart.rb",
19
+ "lib/seer/chart.rb",
20
+ "lib/seer/column_chart.rb",
21
+ "lib/seer/gauge.rb",
22
+ "lib/seer/line_chart.rb",
23
+ "lib/seer/pie_chart.rb",
24
+ "lib/seer/visualization_helper.rb",
25
+ "LICENSE",
26
+ "Rakefile",
27
+ "README.rdoc",
28
+ "rails/init.rb",
29
+ "spec/spec.opts",
30
+ "spec/spec_helper.rb",
31
+ "spec/seer_spec.rb"
32
+ ]
33
+ end
34
+ Jeweler::GemcutterTasks.new
35
+ rescue LoadError
36
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
37
+ end
38
+
39
+ require 'spec/rake/spectask'
40
+ Spec::Rake::SpecTask.new(:spec) do |spec|
41
+ spec.libs << 'lib' << 'spec'
42
+ spec.spec_files = FileList['spec/**/*_spec.rb']
43
+ end
44
+
45
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
46
+ spec.libs << 'lib' << 'spec'
47
+ spec.pattern = 'spec/**/*_spec.rb'
48
+ spec.rcov = true
49
+ end
50
+
51
+ task :spec => :check_dependencies
52
+
53
+ task :default => :spec
54
+
55
+ require 'rake/rdoctask'
56
+ Rake::RDocTask.new do |rdoc|
57
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
58
+
59
+ rdoc.rdoc_dir = 'rdoc'
60
+ rdoc.title = "seer #{version}"
61
+ rdoc.rdoc_files.include('README*')
62
+ rdoc.rdoc_files.include('lib/**/*.rb')
63
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'seer'
@@ -0,0 +1,58 @@
1
+ module Seer
2
+
3
+ require 'seer/chart'
4
+ require 'seer/area_chart'
5
+ require 'seer/bar_chart'
6
+ require 'seer/column_chart'
7
+ require 'seer/gauge'
8
+ require 'seer/line_chart'
9
+ require 'seer/pie_chart'
10
+
11
+ VISUALIZERS = [:area_chart, :bar_chart, :column_chart, :gauge, :line_chart, :pie_chart]
12
+
13
+ def self.valid_hex_number?(val) #:nodoc:
14
+ return false unless val.is_a?(String) && ! val.empty?
15
+ ! (val =~ /^\#([0-9]|[a-f]|[A-F])+$/).nil? && val.length == 7
16
+ end
17
+
18
+ def self.log(message) #:nodoc:
19
+ RAILS_DEFAULT_LOGGER.info(message)
20
+ end
21
+
22
+ def self.init_visualization
23
+ %{<script type="text/javascript" src="http://www.google.com/jsapi"></script> }
24
+ end
25
+
26
+ def self.visualize(data, args={})
27
+ raise ArgumentError, "Seer: Invalid visualizer: #{args[:as]}" unless args[:as] && VISUALIZERS.include?(args[:as])
28
+ raise ArgumentError, "Seer: No data provided!" unless data && ! data.empty?
29
+ self.send(args[:as], data, args)
30
+ end
31
+
32
+ private
33
+
34
+ def self.area_chart(data, args)
35
+ AreaChart.render(data, args)
36
+ end
37
+
38
+ def self.bar_chart(data, args)
39
+ BarChart.render(data, args)
40
+ end
41
+
42
+ def self.column_chart(data, args)
43
+ ColumnChart.render(data, args)
44
+ end
45
+
46
+ def self.gauge(data, args)
47
+ Gauge.render(data, args)
48
+ end
49
+
50
+ def self.line_chart(data, args)
51
+ LineChart.render(data, args)
52
+ end
53
+
54
+ def self.pie_chart(data, args)
55
+ PieChart.render(data, args)
56
+ end
57
+
58
+ end
@@ -0,0 +1,133 @@
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
+ # @series = @data.map{|w| w.widget_stats} # An array of arrays
11
+ #
12
+ # In your view:
13
+ #
14
+ # <div id="chart" class="chart"></div>
15
+ #
16
+ # <%= Seer::visualize(
17
+ # @data,
18
+ # :as => :area_chart,
19
+ # :in_element => 'chart',
20
+ # :series => {
21
+ # :series_label => 'name',
22
+ # :data_label => 'date',
23
+ # :data_method => 'quantity',
24
+ # :data_series => @series
25
+ # },
26
+ # :chart_options => {
27
+ # :height => 300,
28
+ # :width => 300,
29
+ # :axis_font_size => 11,
30
+ # :colors => ['#7e7587','#990000','#009900'],
31
+ # :title => "Widget Quantities",
32
+ # :point_size => 5
33
+ # }
34
+ # )
35
+ # -%>
36
+ #
37
+ # For details on the chart options, see the Google API docs at
38
+ # http://code.google.com/apis/visualization/documentation/gallery/areachart.html
39
+ #
40
+ class AreaChart
41
+
42
+ include Seer::Chart
43
+
44
+ # Graph options
45
+ attr_accessor :axis_color, :axis_background_color, :axis_font_size, :background_color, :border_color, :data_table, :enable_tooltip, :focus_border_color, :height, :is_stacked, :legend, :legend_background_color, :legend_font_size, :legend_text_color, :line_size, :log_scale, :max, :min, :point_size, :reverse_axis, :show_categories, :title, :title_x, :title_y, :title_color, :title_font_size, :tooltip_font_size, :tooltip_height, :number, :tooltip_width, :width
46
+
47
+ # Graph data
48
+ attr_accessor :series_label, :data_label, :data, :data_method, :data_series
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
+
64
+ @data_table = []
65
+
66
+ end
67
+
68
+ def data_columns #:nodoc:
69
+ _data_columns = " data.addRows(#{data_series.first.map{|d| d.send(data_label)}.uniq.size});\r"
70
+ _data_columns << " data.addColumn('string', 'Date');\r"
71
+ data.each do |datum|
72
+ _data_columns << " data.addColumn('number', '#{datum.send(series_label)}');\r"
73
+ end
74
+ _data_columns
75
+ end
76
+
77
+ def data_table #:nodoc:
78
+ _rows = data_series.first.map{|d| d.send(data_label)}.uniq
79
+ _rows.each_with_index do |r,i|
80
+ @data_table << " data.setCell(#{i}, 0,'#{r}');\r"
81
+ end
82
+ data_series.each_with_index do |column,i|
83
+ column.each_with_index do |c,j|
84
+ @data_table << "data.setCell(#{j},#{i+1},#{c.send(data_method)});\r"
85
+ end
86
+ end
87
+ @data_table
88
+ end
89
+
90
+ def nonstring_options #:nodoc:
91
+ [ :axis_font_size, :colors, :enable_tooltip, :height, :legend_font_size, :line_size, :log_scale, :max, :min, :point_size, :reverse_axis, :show_categories, :title_font_size, :tooltip_font_size, :tooltip_height, :tooltip_width, :width]
92
+ end
93
+
94
+ def string_options #:nodoc:
95
+ [ :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 ]
96
+ end
97
+
98
+ def to_js #:nodoc:
99
+
100
+ %{
101
+ <script type="text/javascript">
102
+ google.load('visualization', '1', {'packages':['areachart']});
103
+ google.setOnLoadCallback(drawChart);
104
+ function drawChart() {
105
+ var data = new google.visualization.DataTable();
106
+ #{data_columns}
107
+ #{data_table.to_s}
108
+ var options = {};
109
+ #{options}
110
+ var container = document.getElementById('chart');
111
+ var chart = new google.visualization.AreaChart(container);
112
+ chart.draw(data, options);
113
+ }
114
+ </script>
115
+ }
116
+ end
117
+
118
+ def self.render(data, args) #:nodoc:
119
+ graph = Seer::AreaChart.new(
120
+ :data => data,
121
+ :series_label => args[:series][:series_label],
122
+ :data_series => args[:series][:data_series],
123
+ :data_label => args[:series][:data_label],
124
+ :data_method => args[:series][:data_method],
125
+ :chart_options => args[:chart_options],
126
+ :chart_element => args[:in_element] || 'chart'
127
+ )
128
+ graph.to_js
129
+ end
130
+
131
+ end
132
+
133
+ 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" class="chart"></div>
13
+ #
14
+ # <%= Seer::visualize(
15
+ # @widgets,
16
+ # :as => :bar_chart,
17
+ # :in_element => 'chart',
18
+ # :series => {:series_label => 'name', :data_method => 'quantity'},
19
+ # :chart_options => {
20
+ # :height => 300,
21
+ # :width => 200 * @widgets.size,
22
+ # :is_3_d => false,
23
+ # :legend => 'none',
24
+ # :colors => ["#990000"],
25
+ # :title => "Widget Quantities",
26
+ # :title_x => 'Quantity',
27
+ # :title_y => 'Widgets'
28
+ # }
29
+ # )
30
+ # -%>
31
+ #
32
+ # Colors are treated differently for 2d and 3d graphs. If you set is_3_d to true, set the
33
+ # graph colors like this:
34
+ #
35
+ # :colors => "[{color:'#990000', darker:'#660000'}]",
36
+ #
37
+ # For details on the chart options, see the Google API docs at
38
+ # http://code.google.com/apis/visualization/documentation/gallery/barchart.html
39
+ #
40
+ class BarChart
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, :data_table, :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, :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, :is_3_d, :is_stacked, :legend_font_size, :log_scale, :max, :min, :reverse_axis, :show_categories, :title_font_size, :tooltip_font_size, :tooltip_width]
85
+ end
86
+
87
+ def string_options #:nodoc:
88
+ [:axis_color, :axis_background_color, :background_color, :border_color, :focus_border_color, :height, :legend, :legend_background_color, :legend_text_color, :title, :title_x, :title_y, :title_color, :width]
89
+ end
90
+
91
+ def to_js #:nodoc:
92
+
93
+ %{
94
+ <script type="text/javascript">
95
+ google.load('visualization', '1', {'packages':['barchart']});
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('chart');
104
+ var chart = new google.visualization.BarChart(container);
105
+ chart.draw(data, options);
106
+ }
107
+ </script>
108
+ }
109
+ end
110
+
111
+ def self.render(data, args) #:nodoc:
112
+ graph = Seer::BarChart.new(
113
+ :label_method => args[:series][:series_label],
114
+ :data_method => args[:series][:data_method],
115
+ :chart_options => args[:chart_options],
116
+ :chart_element => args[:in_element] || 'chart',
117
+ :data => data
118
+ )
119
+ graph.to_js
120
+ end
121
+
122
+ end
123
+
124
+ end