ghazel-googlecharts 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,48 @@
1
+ == 1.3.6
2
+ * support nil values. The Google Charts API specifies that a single underscore (_) can be used to omit a value from a line chart with 'simple' data encoding, and a double underscore (__) can do the same for a chart with 'extended' data encoding. (Matt Moyer)
3
+ * allow a label to appear on a google-o-meter via the :legend option. (hallettj)
4
+
5
+ == 1.3.5
6
+ * added code to properly escape image tag URLs (mokolabs)
7
+ * added themes support + 4 default themes (keynote, thirty7signals, pastel, greyscale) chart.line(:theme=>:keynote) (jakehow)
8
+
9
+ == 1.3.4
10
+ * updated documentation and cleaned it up (mokolabs)
11
+ * added support for custom class, id and alt tags when using the image_tag format (i.e Gchart.line(:data => [0, 26], :format => 'image_tag')) (mokolabs)
12
+
13
+ == 1.3.2 - 1.3.3
14
+ * changes required by github
15
+
16
+ == 1.3.1
17
+ * added width and spacing options
18
+
19
+ == 1.3.0
20
+ * added support for google-o-meter
21
+ * fixed a bug when the max value of a data set was 0
22
+
23
+ == 1.2.0
24
+ * added support for sparklines
25
+
26
+ == 1.1.0
27
+ * fixed another bug fix related to the uri escaping required to download the file properly.
28
+
29
+ == 1.0.0
30
+ * fixed the (URI::InvalidURIError) issue
31
+
32
+ == 0.2.0
33
+ * added export options (file and image tag)
34
+ * added support for all arguments to be passed as a string or an array
35
+
36
+ == 0.1.0 2007-12-11
37
+ * fixed the axis labels
38
+
39
+ == 0.0.3 2007-12-11
40
+ * added :chart_background alias and fixed a bug related to the background colors.
41
+
42
+ == 0.0.2 2007-12-11
43
+ * added support for more features and aliases
44
+
45
+ == 0.0.1 2007-12-08
46
+
47
+ * 1 major enhancement:
48
+ * Initial release
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Matt Aimonetti
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.
data/Manifest.txt ADDED
@@ -0,0 +1,18 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ config/hoe.rb
7
+ config/requirements.rb
8
+ lib/gchart.rb
9
+ lib/gchart/aliases.rb
10
+ lib/gchart/theme.rb
11
+ lib/gchart/version.rb
12
+ setup.rb
13
+ spec/gchart_spec.rb
14
+ spec/theme_spec.rb
15
+ spec/spec.opts
16
+ spec/spec_helper.rb
17
+ tasks/environment.rake
18
+ tasks/rspec.rake
data/README.txt ADDED
@@ -0,0 +1,9 @@
1
+ CHECK README.markdown (open as a text file)
2
+
3
+ Or check:
4
+
5
+ http://googlecharts.rubyforge.org
6
+
7
+ and/or
8
+
9
+ http://github.com/mattetti/googlecharts
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
5
+
6
+ desc %{Update ".manifest" with the latest list of project filenames. Respect\
7
+ .gitignore by excluding everything that git ignores. Update `files` and\
8
+ `test_files` arrays in "*.gemspec" file if it's present.}
9
+ task :manifest do
10
+ list = Dir['**/*'].sort
11
+ spec_file = Dir['*.gemspec'].first
12
+ list -= [spec_file] if spec_file
13
+
14
+ File.read('.gitignore').each_line do |glob|
15
+ glob = glob.chomp.sub(/^\//, '')
16
+ list -= Dir[glob]
17
+ list -= Dir["#{glob}/**/*"] if File.directory?(glob) and !File.symlink?(glob)
18
+ puts "excluding #{glob}"
19
+ end
20
+
21
+ if spec_file
22
+ spec = File.read spec_file
23
+ spec.gsub! /^(\s* s.(test_)?files \s* = \s* )( \[ [^\]]* \] | %w\( [^)]* \) )/mx do
24
+ assignment = $1
25
+ bunch = $2 ? list.grep(/^test\//) : list
26
+ '%s%%w(%s)' % [assignment, bunch.join(' ')]
27
+ end
28
+
29
+ File.open(spec_file, 'w') {|f| f << spec }
30
+ end
31
+ File.open('.manifest', 'w') {|f| f << list.join("\n") }
32
+ end
data/config/hoe.rb ADDED
@@ -0,0 +1,71 @@
1
+ require 'gchart/version'
2
+
3
+ AUTHOR = 'Matt Aimonetti' # can also be an array of Authors
4
+ EMAIL = "mattaimonetti@gmail.com"
5
+ DESCRIPTION = "description of gem"
6
+ GEM_NAME = 'googlecharts' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'googlecharts' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+
11
+ @config_file = "~/.rubyforge/user-config.yml"
12
+ @config = nil
13
+ RUBYFORGE_USERNAME = "matt_a"
14
+ def rubyforge_username
15
+ unless @config
16
+ begin
17
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
18
+ rescue
19
+ puts <<-EOS
20
+ ERROR: No rubyforge config file found: #{@config_file}
21
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
22
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
23
+ EOS
24
+ exit
25
+ end
26
+ end
27
+ RUBYFORGE_USERNAME.replace @config["username"]
28
+ end
29
+
30
+
31
+ REV = nil
32
+ # UNCOMMENT IF REQUIRED:
33
+ # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
+ VERS = GchartInfo::VERSION::STRING + (REV ? ".#{REV}" : "")
35
+ RDOC_OPTS = ['--quiet', '--title', 'gchart documentation',
36
+ "--opname", "index.html",
37
+ "--line-numbers",
38
+ "--main", "README",
39
+ "--inline-source"]
40
+
41
+ class Hoe
42
+ def extra_deps
43
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
44
+ @extra_deps
45
+ end
46
+ end
47
+
48
+ # Generate all the Rake tasks
49
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
50
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
51
+ p.author = AUTHOR
52
+ p.description = DESCRIPTION
53
+ p.email = EMAIL
54
+ p.summary = DESCRIPTION
55
+ p.url = HOMEPATH
56
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
57
+ p.test_globs = ["test/**/test_*.rb"]
58
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
59
+
60
+ # == Optional
61
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
62
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
63
+
64
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
65
+
66
+ end
67
+
68
+ CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
69
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
70
+ hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
71
+ hoe.rsync_args = '-av --delete --ignore-errors'
@@ -0,0 +1,16 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile could use '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ end
12
+ end
13
+
14
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
15
+
16
+ require 'gchart'
data/lib/gchart.rb ADDED
@@ -0,0 +1,526 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ require 'gchart/version'
3
+ require 'gchart/theme'
4
+ require "open-uri"
5
+ require "uri"
6
+ require "cgi"
7
+ require 'enumerator'
8
+
9
+ class Gchart
10
+
11
+ include GchartInfo
12
+
13
+ @@url = "http://chart.apis.google.com/chart?"
14
+ @@types = ['line', 'line_xy', 'scatter', 'bar', 'venn', 'pie', 'pie_3d', 'jstize', 'sparkline', 'meter', 'map']
15
+ @@simple_chars = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a
16
+ @@chars = @@simple_chars + ['-', '.']
17
+ @@ext_pairs = @@chars.map { |char_1| @@chars.map { |char_2| char_1 + char_2 } }.flatten
18
+ @@file_name = 'chart.png'
19
+
20
+ attr_accessor :title, :type, :width, :height, :horizontal, :grouped, :legend, :data, :encoding, :bar_colors,
21
+ :title_color, :title_size, :custom, :axis_with_labels, :axis_labels, :bar_width_and_spacing, :id, :alt, :class,
22
+ :range_markers, :geographical_area, :map_colors, :country_codes, :axis_range
23
+
24
+ # Support for Gchart.line(:title => 'my title', :size => '400x600')
25
+ def self.method_missing(m, options={})
26
+ # Start with theme defaults if a theme is set
27
+ theme = options[:theme]
28
+ options = theme ? Chart::Theme.load(theme).to_options.merge(options) : options
29
+ # Extract the format and optional filename, then clean the hash
30
+ format = options[:format] || 'url'
31
+ @@file_name = options[:filename] unless options[:filename].nil?
32
+ options.delete(:format)
33
+ options.delete(:filename)
34
+ #update map_colors to be bar_colors
35
+ options.update(:bar_colors => options[:map_colors]) if options.has_key?(:map_colors)
36
+ # create the chart and return it in the format asked for
37
+ if @@types.include?(m.to_s)
38
+ chart = new(options.merge!({:type => m}))
39
+ chart.send(format)
40
+ elsif m.to_s == 'version'
41
+ Gchart::VERSION::STRING
42
+ else
43
+ "#{m} is not a supported chart format, please use one of the following: #{supported_types}."
44
+ end
45
+ end
46
+
47
+ def initialize(options={})
48
+ @type = :line
49
+ @data = []
50
+ @width = 300
51
+ @height = 200
52
+ @horizontal = false
53
+ @grouped = false
54
+ @encoding = 'simple'
55
+ self.min_value = 'auto'
56
+ self.max_value = 'auto'
57
+ # Sets the alt tag when chart is exported as image tag
58
+ @alt = 'Google Chart'
59
+ # Sets the CSS id selector when chart is exported as image tag
60
+ @id = false
61
+ # Sets the CSS class selector when chart is exported as image tag
62
+ @class = false
63
+
64
+ # set the options value if definable
65
+ options.each do |attribute, value|
66
+ send("#{attribute.to_s}=", value) if self.respond_to?("#{attribute}=")
67
+ end
68
+ end
69
+
70
+ def self.supported_types
71
+ @@types.join(' ')
72
+ end
73
+
74
+ # Defines the Graph size using the following format:
75
+ # width X height
76
+ def size=(size='300x200')
77
+ @width, @height = size.split("x").map { |dimension| dimension.to_i }
78
+ end
79
+
80
+ def size
81
+ "#{@width}x#{@height}"
82
+ end
83
+
84
+ def dimensions
85
+ # TODO: maybe others?
86
+ [:line_xy, :scatter].include?(@type) ? 2 : 1
87
+ end
88
+
89
+ # Sets the orientation of a bar graph
90
+ def orientation=(orientation='h')
91
+ if orientation == 'h' || orientation == 'horizontal'
92
+ self.horizontal = true
93
+ elsif orientation == 'v' || orientation == 'vertical'
94
+ self.horizontal = false
95
+ end
96
+ end
97
+
98
+ # Sets the bar graph presentation (stacked or grouped)
99
+ def stacked=(option=true)
100
+ @grouped = option ? false : true
101
+ end
102
+
103
+ def bg=(options)
104
+ if options.is_a?(String)
105
+ @bg_color = options
106
+ elsif options.is_a?(Hash)
107
+ @bg_color = options[:color]
108
+ @bg_type = options[:type]
109
+ @bg_angle = options[:angle]
110
+ end
111
+ end
112
+
113
+ def graph_bg=(options)
114
+ if options.is_a?(String)
115
+ @chart_color = options
116
+ elsif options.is_a?(Hash)
117
+ @chart_color = options[:color]
118
+ @chart_type = options[:type]
119
+ @chart_angle = options[:angle]
120
+ end
121
+ end
122
+
123
+ def max_value=(max_value)
124
+ @max_value = max_value
125
+ @max_value = nil if ['auto', :auto].include? @max_value
126
+ @max_value = false if ['false', :false].include? @max_value
127
+ end
128
+
129
+ def min_value=(min_value)
130
+ @min_value = min_value
131
+ @min_value = nil if ['auto', :auto].include? @min_value
132
+ @min_value = false if ['false', :false].include? @min_value
133
+ end
134
+
135
+ # auto sets the range if required
136
+ # it also sets the axis_range if not defined
137
+ def full_data_range(ds)
138
+ return if @max_value == false
139
+
140
+ @axis = []
141
+ # TODO: text encoding should use @axis too
142
+ if dimensions == 2 and @encoding != :text
143
+ ds.each_with_index do |mds,index|
144
+ cmds = mds.compact
145
+ if cmds.empty?
146
+ @axis << nil
147
+ next
148
+ end
149
+ @axis[index%dimensions] ||= []
150
+ ax = @axis[index%dimensions]
151
+ ax[0] = @min_value.nil? ? [ax[0], cmds.min].compact.min : @min_value
152
+ ax[1] = @max_value.nil? ? [ax[0], cmds.max].compact.max : @max_value
153
+ end
154
+ else
155
+ @min_value = ds.compact.map{|mds| mds.compact.min}.min if @min_value.nil?
156
+ @max_value = ds.compact.map{|mds| mds.compact.max}.max if @max_value.nil?
157
+ @axis << [@min_value, @max_value]
158
+ end
159
+
160
+ if not @axis_range
161
+ @axis_range = @axis.map{|axis| axis.nil? ? [] : axis}
162
+ if @type != :line_xy and (@type != :bar or not @horizontal)
163
+ tmp = @axis_range.fetch(0, [])
164
+ @axis_range[0] = @axis_range.fetch(1, [])
165
+ @axis_range[1] = tmp
166
+ end
167
+ end
168
+ end
169
+
170
+ def dataset
171
+ @dataset ||= prepare_dataset(data)
172
+ full_data_range(@dataset)
173
+ @dataset
174
+ end
175
+
176
+ def self.jstize(string)
177
+ string.gsub(' ', '+').gsub(/\[|\{|\}|\||\\|\^|\[|\]|\`|\]/) {|c| "%#{c[0].to_s(16).upcase}"}
178
+ end
179
+ # load all the custom aliases
180
+ require 'gchart/aliases'
181
+
182
+ protected
183
+
184
+ # Returns the chart's generated PNG as a blob. (borrowed from John's gchart.rubyforge.org)
185
+ def fetch
186
+ open(query_builder) { |io| io.read }
187
+ end
188
+
189
+ # Writes the chart's generated PNG to a file. (borrowed from John's gchart.rubyforge.org)
190
+ def write(io_or_file=@@file_name)
191
+ return io_or_file.write(fetch) if io_or_file.respond_to?(:write)
192
+ open(io_or_file, "w+") { |io| io.write(fetch) }
193
+ end
194
+
195
+ # Format
196
+
197
+ def image_tag
198
+ image = "<img"
199
+ image += " id=\"#{@id}\"" if @id
200
+ image += " class=\"#{@class}\"" if @class
201
+ image += " src=\"#{query_builder(:html)}\""
202
+ image += " width=\"#{@width}\""
203
+ image += " height=\"#{@height}\""
204
+ image += " alt=\"#{@alt}\""
205
+ image += " title=\"#{@title}\"" if @title
206
+ image += " />"
207
+ end
208
+
209
+ alias_method :img_tag, :image_tag
210
+
211
+ def url
212
+ query_builder
213
+ end
214
+
215
+ def file
216
+ write
217
+ end
218
+
219
+ #
220
+ def jstize(string)
221
+ Gchart.jstize(string)
222
+ end
223
+
224
+ private
225
+
226
+ # The title size cannot be set without specifying a color.
227
+ # A dark key will be used for the title color if no color is specified
228
+ def set_title
229
+ title_params = "chtt=#{title}"
230
+ unless (title_color.nil? && title_size.nil? )
231
+ title_params << "&chts=" + (color, size = (@title_color || '454545'), @title_size).compact.join(',')
232
+ end
233
+ title_params
234
+ end
235
+
236
+ def set_size
237
+ "chs=#{size}"
238
+ end
239
+
240
+ def set_data
241
+ data = send("#{@encoding}_encoding")
242
+ "chd=#{data}"
243
+ end
244
+
245
+ def set_colors
246
+ bg_type = fill_type(@bg_type) || 's' if @bg_color
247
+ chart_type = fill_type(@chart_type) || 's' if @chart_color
248
+
249
+ "chf=" + {'bg' => fill_for(bg_type, @bg_color, @bg_angle), 'c' => fill_for(chart_type, @chart_color, @chart_angle)}.map{|k,v| "#{k},#{v}" unless v.nil?}.compact.join('|')
250
+ end
251
+
252
+ # set bar, line colors
253
+ def set_bar_colors
254
+ @bar_colors = @bar_colors.join(',') if @bar_colors.is_a?(Array)
255
+ "chco=#{@bar_colors}"
256
+ end
257
+
258
+ def set_country_codes
259
+ @country_codes = @country_codes.join() if @country_codes.is_a?(Array)
260
+ "chld=#{@country_codes}"
261
+ end
262
+
263
+ # set bar spacing
264
+ # chbh=
265
+ # <bar width in pixels>,
266
+ # <optional space between bars in a group>,
267
+ # <optional space between groups>
268
+ def set_bar_width_and_spacing
269
+ width_and_spacing_values = case @bar_width_and_spacing
270
+ when String
271
+ @bar_width_and_spacing
272
+ when Array
273
+ @bar_width_and_spacing.join(',')
274
+ when Hash
275
+ width = @bar_width_and_spacing[:width] || 23
276
+ spacing = @bar_width_and_spacing[:spacing] || 4
277
+ group_spacing = @bar_width_and_spacing[:group_spacing] || 8
278
+ [width,spacing,group_spacing].join(',')
279
+ else
280
+ @bar_width_and_spacing.to_s
281
+ end
282
+ "chbh=#{width_and_spacing_values}"
283
+ end
284
+
285
+ def set_range_markers
286
+ markers = case @range_markers
287
+ when Hash
288
+ set_range_marker(@range_markers)
289
+ when Array
290
+ range_markers.collect{|marker| set_range_marker(marker)}.join('|')
291
+ end
292
+ "chm=#{markers}"
293
+ end
294
+
295
+ def set_range_marker(options)
296
+ orientation = ['vertical', 'Vertical', 'V', 'v', 'R'].include?(options[:orientation]) ? 'R' : 'r'
297
+ "#{orientation},#{options[:color]},0,#{options[:start_position]},#{options[:stop_position]}#{',1' if options[:overlaid?]}"
298
+ end
299
+
300
+ def fill_for(type=nil, color='', angle=nil)
301
+ unless type.nil?
302
+ case type
303
+ when 'lg'
304
+ angle ||= 0
305
+ color = "#{color},0,ffffff,1" if color.split(',').size == 1
306
+ "#{type},#{angle},#{color}"
307
+ when 'ls'
308
+ angle ||= 90
309
+ color = "#{color},0.2,ffffff,0.2" if color.split(',').size == 1
310
+ "#{type},#{angle},#{color}"
311
+ else
312
+ "#{type},#{color}"
313
+ end
314
+ end
315
+ end
316
+
317
+ # A chart can have one or many legends.
318
+ # Gchart.line(:legend => 'label')
319
+ # or
320
+ # Gchart.line(:legend => ['first label', 'last label'])
321
+ def set_legend
322
+ return set_labels if @type == :pie || @type == :pie_3d || @type == :meter
323
+
324
+ if @legend.is_a?(Array)
325
+ "chdl=#{@legend.map{|label| "#{CGI::escape(label)}"}.join('|')}"
326
+ else
327
+ "chdl=#{@legend}"
328
+ end
329
+
330
+ end
331
+
332
+ def set_labels
333
+ if @legend.is_a?(Array)
334
+ "chl=#{@legend.map{|label| "#{label}"}.join('|')}"
335
+ else
336
+ "chl=#{@legend}"
337
+ end
338
+ end
339
+
340
+ def set_axis_with_labels
341
+ @axis_with_labels = @axis_with_labels.join(',') if @axis_with_labels.is_a?(Array)
342
+ "chxt=#{@axis_with_labels}"
343
+ end
344
+
345
+ def set_axis_labels
346
+ if axis_labels.is_a?(Array)
347
+ labels_arr = axis_labels.enum_with_index.map{|labels,index| [index,labels]}
348
+ elsif axis_labels.is_a?(Hash)
349
+ labels_arr = axis_labels.to_a
350
+ end
351
+ labels_arr.map! do |index,labels|
352
+ if labels.is_a?(Array)
353
+ "#{index}:|#{labels.to_a.join('|')}"
354
+ else
355
+ "#{index}:|#{labels}"
356
+ end
357
+ end
358
+ "chxl=#{labels_arr.join('|')}"
359
+ end
360
+
361
+ # http://code.google.com/apis/chart/labels.html#axis_range
362
+ # Specify a range for axis labels
363
+ def set_axis_range
364
+ # a passed axis_range should look like:
365
+ # [[10,100]] or [[10,100,4]] or [[10,100], [20,300]]
366
+ # in the second example, 4 is the interval
367
+ dataset # just making sure we processed the data before
368
+ if axis_range && axis_range.respond_to?(:each) && axis_range.first.respond_to?(:each)
369
+ 'chxr=' + axis_range.enum_for(:each_with_index).map{|range, index| [index, range[0], range[1], range[2]].compact.join(',')}.join("|")
370
+ else
371
+ nil
372
+ end
373
+ end
374
+
375
+ def set_geographical_area
376
+ "chtm=#{@geographical_area}"
377
+ end
378
+
379
+ def set_type
380
+ case @type
381
+ when :line
382
+ "cht=lc"
383
+ when :line_xy
384
+ "cht=lxy"
385
+ when :bar
386
+ "cht=b" + (horizontal? ? "h" : "v") + (grouped? ? "g" : "s")
387
+ when :pie_3d
388
+ "cht=p3"
389
+ when :pie
390
+ "cht=p"
391
+ when :venn
392
+ "cht=v"
393
+ when :scatter
394
+ "cht=s"
395
+ when :sparkline
396
+ "cht=ls"
397
+ when :meter
398
+ "cht=gom"
399
+ when :map
400
+ "cht=t"
401
+ end
402
+ end
403
+
404
+ def fill_type(type)
405
+ case type
406
+ when 'solid'
407
+ 's'
408
+ when 'gradient'
409
+ 'lg'
410
+ when 'stripes'
411
+ 'ls'
412
+ end
413
+ end
414
+
415
+ # Wraps a single dataset inside another array to support more datasets
416
+ def prepare_dataset(ds)
417
+ ds = [ds] unless ds.first.is_a?(Array)
418
+ ds
419
+ end
420
+
421
+ def encode_scaled_dataset chars, nil_char
422
+ dataset.enum_with_index.map do |ds, index|
423
+ if @max_value != false
424
+ ax = @axis[index%dimensions]
425
+ min = ax[0]
426
+ range = ax[1] - min
427
+ range = 1 if range == 0
428
+ end
429
+ ds.map do |number|
430
+ if number.nil?
431
+ nil_char
432
+ else
433
+ if not range.nil?
434
+ number = chars.size * (number - min) / range
435
+ number = [number, chars.size - 1].min
436
+ end
437
+ chars[number.to_i]
438
+ end
439
+ end.join
440
+ end.join(',')
441
+ end
442
+
443
+ # http://code.google.com/apis/chart/#simple
444
+ # Simple encoding has a resolution of 62 different values.
445
+ # Allowing five pixels per data point, this is sufficient for line and bar charts up
446
+ # to about 300 pixels. Simple encoding is suitable for all other types of chart regardless of size.
447
+ def simple_encoding
448
+ "s:" + encode_scaled_dataset(@@simple_chars, '_')
449
+ end
450
+
451
+ # http://code.google.com/apis/chart/#text
452
+ # Text encoding with data scaling lets you specify arbitrary positive or
453
+ # negative floating point numbers, in combination with a scaling parameter
454
+ # that lets you specify a custom range for your chart. This chart is useful
455
+ # when you don't want to worry about limiting your data to a specific range,
456
+ # or do the calculations to scale your data down or up to fit nicely inside
457
+ # a chart.
458
+ #
459
+ # Valid values range from (+/-)9.999e(+/-)100, and only four non-zero digits are supported (that is, 123400, 1234, 12.34, and 0.1234 are valid, but 12345, 123.45 and 123400.5 are not).
460
+ #
461
+ # This encoding is not available for maps.
462
+ #
463
+ def text_encoding
464
+ # TODO: text encoding should use @axis too
465
+ "t:" + dataset.map{ |ds| ds.join(',') }.join('|') + "&chds=#{@min_value},#{@max_value}"
466
+ end
467
+
468
+ # http://code.google.com/apis/chart/#extended
469
+ # Extended encoding has a resolution of 4,096 different values
470
+ # and is best used for large charts where a large data range is required.
471
+ def extended_encoding
472
+ "e:" + encode_scaled_dataset(@@ext_pairs, '__')
473
+ end
474
+
475
+ def query_builder(options="")
476
+ dataset
477
+ query_params = instance_variables.map do |var|
478
+ case var
479
+ when '@data'
480
+ set_data unless @data == []
481
+ # Set the graph size
482
+ when '@width'
483
+ set_size unless @width.nil? || @height.nil?
484
+ when '@type'
485
+ set_type
486
+ when '@title'
487
+ set_title unless @title.nil?
488
+ when '@legend'
489
+ set_legend unless @legend.nil?
490
+ when '@bg_color'
491
+ set_colors
492
+ when '@chart_color'
493
+ set_colors if @bg_color.nil?
494
+ when '@bar_colors'
495
+ set_bar_colors
496
+ when '@bar_width_and_spacing'
497
+ set_bar_width_and_spacing
498
+ when '@axis_with_labels'
499
+ set_axis_with_labels
500
+ when '@axis_range'
501
+ set_axis_range if dataset
502
+ when '@axis_labels'
503
+ set_axis_labels
504
+ when '@range_markers'
505
+ set_range_markers
506
+ when '@geographical_area'
507
+ set_geographical_area
508
+ when '@country_codes'
509
+ set_country_codes
510
+ when '@custom'
511
+ @custom
512
+ end
513
+ end.compact
514
+
515
+ # Use ampersand as default delimiter
516
+ unless options == :html
517
+ delimiter = '&'
518
+ # Escape ampersand for html image tags
519
+ else
520
+ delimiter = '&amp;'
521
+ end
522
+
523
+ jstize(@@url + query_params.join(delimiter))
524
+ end
525
+
526
+ end