wayneeseguin-dynamic_reports 0.0.2

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.
@@ -0,0 +1,539 @@
1
+ require 'uri'
2
+
3
+ module GoogleChart
4
+ class Base
5
+ BASE_URL = "http://chart.apis.google.com/chart?"
6
+
7
+ SIMPLE_ENCODING = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split('');
8
+ COMPLEX_ENCODING_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.'.split('');
9
+ @@complex_encoding = []
10
+ COMPLEX_ENCODING_ALPHABET.each_with_index do |outer,index_outer|
11
+ COMPLEX_ENCODING_ALPHABET.each_with_index do |inner, index_inner|
12
+ @@complex_encoding[index_outer * 64 + index_inner] = outer + inner
13
+ end
14
+ end
15
+
16
+ SHAPE_MARKERS = {:arrow => "a",
17
+ :cross => "c",
18
+ :diamond => "d",
19
+ :circle => "o",
20
+ :square => "s",
21
+ :vline_segment => "v",
22
+ :vline_full => "V",
23
+ :hline_full => "h",
24
+ :x => "x"
25
+ }
26
+
27
+ DEFAULT_LINE_STYLE = '1'
28
+
29
+
30
+ # Size of the chart in WIDTHxHEIGHT format
31
+ attr_accessor :chart_size
32
+
33
+ # Type of the chart. Usually, you do not need to set this yourself
34
+ attr_accessor :chart_type
35
+
36
+ # Chart title
37
+ attr_accessor :chart_title
38
+
39
+ # RRGGBB hex value for the color of the title
40
+ attr_accessor :title_color
41
+
42
+ # Font size of the title
43
+ attr_accessor :title_font_size
44
+
45
+ # Data encoding to use. Can be one of <tt>:simple</tt>, <tt>:text</tt> or <tt>:extended</tt> (see http://code.google.com/apis/chart/#chart_data)
46
+ attr_accessor :data_encoding
47
+
48
+ # A hash of the params used to construct the URL
49
+ attr_accessor :params
50
+
51
+ # Set to <tt>true</tt> or <tt>false</tt> to show or hide the chart legend. Not applicable for Scatter Chart.
52
+ attr_accessor :show_legend
53
+
54
+ def initialize(chart_size, chart_title)
55
+ # Declare instance variables to be a good citizen.
56
+ @background_fill = nil, @chart_fill = nil, @grid_str = nil, @max_data = nil, @bar_width_spacing_options = nil, @background_fill = nil, @chart_fill = nil, @grid_str = nil, @max_data = nil, @bar_width_spacing_options = nil, @background_fill = nil, @chart_fill = nil, @grid_str = nil, @max_data = nil, @bar_width_spacing_options = nil, @background_fill = nil, @chart_fill = nil, @grid_str = nil, @max_data = nil, @bar_width_spacing_options = nil
57
+ self.params = Hash.new
58
+ @labels = []
59
+ @data = []
60
+ @colors = []
61
+ @axis = []
62
+ @markers = []
63
+ @line_styles = []
64
+ self.chart_size = chart_size
65
+ self.chart_title = chart_title
66
+ self.data_encoding = :simple
67
+ self.show_legend = true
68
+ end
69
+
70
+ # Generates the URL string that can be used to retrieve the graph image in PNG format.
71
+ # Use this after assigning all the properties to the graph
72
+ # You can pass in additional params as a hash for features that may not have been implemented
73
+ # For e.g
74
+ # lc = GoogleChart::LineChart.new('320x200', "Line Chart", false)
75
+ # lc.data "Trend 1", [5,4,3,1,3,5,6], '0000ff'
76
+ # lc.data "Trend 2", [1,2,3,4,5,6], '00ff00'
77
+ # lc.data "Trend 3", [6,5,4,3,2,1], 'ff0000'
78
+ # puts lc.to_url({:chm => "000000,0,0.1,0.11"}) # Single black line as a horizontal marker
79
+ def to_url(extras={})
80
+ prepare_params
81
+ params.merge!(extras)
82
+ query_string = params.map { |k,v| "#{k}=#{URI.escape(v.to_s).gsub(/%20/,'+').gsub(/%7C/,'|')}" }.join('&')
83
+ BASE_URL + query_string
84
+ end
85
+
86
+ # Generates a fully encoded URL string that can be used to retrieve the graph image in PNG format.
87
+ # For less verbose URLs, use the <tt>to_url</tt> method. Use this only if you are doing further
88
+ # processing with the URLs, like passing the URL to a method for downloading the images
89
+ #
90
+ # Use this after assigning all the properties to the graph
91
+ # You can pass in additional params as a hash for features that may not have been implemented
92
+ # For e.g
93
+ # lc = GoogleChart::LineChart.new('320x200', "Line Chart", false)
94
+ # lc.data "Trend 1", [5,4,3,1,3,5,6], '0000ff'
95
+ # lc.data "Trend 2", [1,2,3,4,5,6], '00ff00'
96
+ # lc.data "Trend 3", [6,5,4,3,2,1], 'ff0000'
97
+ # puts lc.to_escaped_url({:chm => "000000,0,0.1,0.11"}) # Single black line as a horizontal marker
98
+ def to_escaped_url(extras={})
99
+ prepare_params
100
+ params.merge!(extras)
101
+ query_string = params.map { |k,v| "#{k}=#{URI.escape(v.to_s)}" }.join('&')
102
+ BASE_URL + query_string
103
+ end
104
+
105
+ # Adds the data to the chart, according to the type of the graph being generated.
106
+ #
107
+ # [+name+] is a string containing a label for the data.
108
+ # [+value+] is either a number or an array of numbers containing the data. Pie Charts and Venn Diagrams take a single number, but other graphs require an array of numbers
109
+ # [+color+ (optional)] is a hexadecimal RGB value for the color to represent the data
110
+ #
111
+ # ==== Examples
112
+ #
113
+ # for GoogleChart::LineChart (normal)
114
+ # lc.data "Trend 1", [1,2,3,4,5], 'ff00ff'
115
+ #
116
+ # for GoogleChart::LineChart (XY chart)
117
+ # lc.data "Trend 2", [[4,5], [2,2], [1,1], [3,4]], 'ff00ff'
118
+ #
119
+ # for GoogleChart::PieChart
120
+ # lc.data "Apples", 5, 'ff00ff'
121
+ # lc.data "Oranges", 7, '00ffff'
122
+ def data(name, value, color=nil)
123
+ @data << value
124
+ @labels << name
125
+ @colors << color if color
126
+ end
127
+
128
+ # Allows (optional) setting of a max value for the chart, which will be used for data encoding and axis plotting.
129
+ # The value to pass depends on the type of chart
130
+ # * For Line Chart and Bar Charts it should be a single integer or float value
131
+ # * For Scatter Charts and Line XY Charts, you MUST pass an array containing the maximum values for X and Y
132
+ #
133
+ # ==== Examples
134
+ # For bar charts
135
+ # bc.max_value 5 # 5 will be used to calculate the relative encoding values
136
+ # For scatter chart
137
+ # sc.max_value [5,6] # 5 is the max x value and 6 is the max y value
138
+ #
139
+ # Note : MAKE SURE you are passing the right values otherwise an exception will be raised
140
+ def max_value(value)
141
+ if [:lxy, :s].member?(self.chart_type) and value.is_a?(Array)
142
+ @max_x = value.first
143
+ @max_y = value.last
144
+ elsif [:lc,:bhg,:bhs,:bvg,:bvs] and (value.is_a?(Integer) or value.is_a?(Float))
145
+ @max_data = value
146
+ else
147
+ raise "Invalid max value for this chart type"
148
+ end
149
+ end
150
+
151
+ # Adds a background or chart fill. Call this option twice if you want both a background and a chart fill
152
+ # [+bg_or_c+] Can be one of <tt>:background</tt> or <tt>:chart</tt> depending on the kind of fill requested
153
+ # [+type+] Can be one of <tt>:solid</tt>, <tt>:gradient</tt> or <tt>:stripes</tt>
154
+ # [+options+] : Options depend on the type of fill selected above
155
+ #
156
+ # ==== Options
157
+ # For <tt>:solid</tt> type
158
+ # * A <tt>:color</tt> option which specifies the RGB hex value of the color to be used as a fill. For e.g <tt>lc.fill(:chart, :solid, {:color => 'ffcccc'})</tt>
159
+ #
160
+ # For <tt>:gradient</tt> type
161
+ # * An <tt>:angle</tt>, which is the angle of the gradient between 0(horizontal) and 90(vertical)
162
+ # * A <tt>:color</tt> option which is a 2D array containing the colors and an offset each, which specifies at what point the color is pure where: 0 specifies the right-most chart position and 1 the left-most. e,g <tt>lc.fill :background, :gradient, :angle => 0, :color => [['76A4FB',1],['ffffff',0]]</tt>
163
+ #
164
+ # For <tt>:stripes</tt> type
165
+ # * An <tt>:angle</tt>, which is the angle of the stripe between 0(horizontal) and 90(vertical)
166
+ # * A <tt>:color</tt> option which is a 2D array containing the colors and width value each, which must be between 0 and 1 where 1 is the full width of the chart. for e.g <tt>lc.fill :chart, :stripes, :angle => 90, :color => [ ['76A4FB',0.2], ['ffffff',0.2] ]</tt>
167
+ def fill(bg_or_c, type, options = {})
168
+ case bg_or_c
169
+ when :background
170
+ @background_fill = "bg," + process_fill_options(type, options)
171
+ when :chart
172
+ @chart_fill = "c," + process_fill_options(type, options)
173
+ end
174
+ end
175
+
176
+ # Adds an axis to the graph. Not applicable for Pie Chart (GoogleChart::PieChart) or Venn Diagram (GoogleChart::VennDiagram)
177
+ #
178
+ # [+type+] is a symbol which can be one of <tt>:x</tt>, <tt>:y</tt>, <tt>:right</tt>, <tt>:top</tt>
179
+ # [+options+] is a hash containing the options (see below)
180
+ #
181
+ # ==== Options
182
+ # Not all the options are mandatory.
183
+ # [<tt>:labels</tt>] An array containing the labels for the axis
184
+ # [<tt>:positions</tt>] An Array containing the positions for the labels
185
+ # [<tt>:range</tt>] An array containing 2 elements, the start value and end value
186
+ #
187
+ # axis styling options have to be specified as follows
188
+ # [<tt>:color</tt>] Hexadecimal RGB value for the color to represent the data for the axis labels
189
+ # [<tt>:font_size</tt>] Font size of the labels in pixels
190
+ # [<tt>:alignment</tt>] can be one of <tt>:left</tt>, <tt>:center</tt> or <tt>:right</tt>
191
+ #
192
+ # ==== Examples
193
+ # lc.axis :y, :range => [0,6], :color => 'ff00ff', :font_size => 16, :alignment => :center
194
+ #
195
+ def axis(type, options = {})
196
+ raise "Illegal axis type" unless [:x, :y, :right, :top].member?(type)
197
+ @axis << [type, options]
198
+ end
199
+
200
+ # Adds a grid to the graph. Applicable only for Line Chart (GoogleChart::LineChart) and Scatter Chart (GoogleChart::ScatterChart)
201
+ #
202
+ # [+options+] is a hash containing the options (see below)
203
+ #
204
+ # === Options
205
+ # [<tt>:xstep</tt>] X axis step size
206
+ # [<tt>:ystep</tt>] Y axis step size
207
+ # [<tt>:length_segment</tt> (optional)] Length of the line segement. Useful with the :length_blank value to have dashed lines
208
+ # [<tt>:length_blank</tt> (optional)] Length of the blank segment. use 0 if you want a solid grid
209
+ #
210
+ # === Examples
211
+ # lc.grid :x_step => 5, :y_step => 5, :length_segment => 1, :length_blank => 0
212
+ #
213
+ def grid(options={})
214
+ @grid_str = "#{options[:x_step].to_f},#{options[:y_step].to_f}"
215
+ if options[:length_segment] or options[:length_blank]
216
+ @grid_str += ",#{options[:length_segment].to_f},#{options[:length_blank].to_f}"
217
+ end
218
+ end
219
+
220
+ # Defines a horizontal or vertical range marker. Applicable for line charts and vertical charts
221
+ #
222
+ # [+alignment+] can be <tt>:horizontal</tt> or <tt>:vertical</tt>
223
+ # [+options+] specifies the color, start point and end point
224
+ #
225
+ # ==== Options
226
+ # [<tt>:color</tt>] RRGGBB hex value for the color of the range marker
227
+ # [<tt>:start_point</tt>] position on the x-axis/y-axis at which the range starts where 0.00 is the left/bottom and 1.00 is the right/top
228
+ # [<tt>:end_point</tt>] position on the x-axis/y-axis at which the range ends where 0.00 is the left/bottom and 1.00 is the right/top
229
+ #
230
+ # ==== Examples
231
+ # lc.range_marker :horizontal, :color => 'E5ECF9', :start_point => 0.1, :end_point => 0.5
232
+ # lc.range_marker :vertical, :color => 'a0bae9', :start_point => 0.1, :end_point => 0.5
233
+ def range_marker(alignment, options={})
234
+ raise "Invalid alignment specified" unless [:horizontal, :vertical].member?(alignment)
235
+ str = (alignment == :horizontal ) ? "r" : "R"
236
+ str += ",#{options[:color]},0,#{options[:start_point]},#{options[:end_point]}"
237
+ @markers << str
238
+ end
239
+
240
+ # Defines a shape marker. Applicable for line charts and scatter plots
241
+ #
242
+ # [+type+] can be <tt>:arrow</tt>, <tt>:cross</tt>, <tt>:diamond</tt>, <tt>:circle</tt>, <tt>:square</tt>, <tt>:vline_segment</tt>, <tt>:vline_full</tt>, <tt>:hline_full</tt>, <tt>:x</tt>
243
+ # [+options+] specifies the color, data set index, data point index and size in pixels
244
+ #
245
+ # ==== Options
246
+ # [<tt>:color</tt>] RRGGBB hex value for the color of the range marker
247
+ # [<tt>:data_set_index</tt>] the index of the line on which to draw the marker. This is 0 for the first data set, 1 for the second and so on.
248
+ # [<tt>:data_point_index</tt>] is a floating point value that specifies on which data point of the data set the marker will be drawn. This is 0 for the first data point, 1 for the second and so on. Specify a fraction to interpolate a marker between two points.
249
+ # [<tt>:size</tt>] is the size of the marker in pixels.
250
+ #
251
+ # ==== Examples
252
+ # lcxy.shape_marker :circle, :color => "000000", :data_set_index => 1, :data_point_index => 2, :pixel_size => 10
253
+ # lcxy.shape_marker :cross, :color => "E5ECF9", :data_set_index => 0, :data_point_index => 0.5, :pixel_size => 10
254
+ def shape_marker(type, options={})
255
+ raise "Invalid shape marker type specified" unless SHAPE_MARKERS.has_key?(type)
256
+ shape_marker_str = "#{SHAPE_MARKERS[type]},#{options[:color]},#{options[:data_set_index]},#{options[:data_point_index]},#{options[:pixel_size]}"
257
+ @markers << shape_marker_str
258
+ end
259
+
260
+ # Defines a Fill area. Applicable for line charts only
261
+ #
262
+ # [+color+] is the color of the fill area
263
+ # [+start_index+] is the index of the line at which the fill starts. This is 0 for the first data set, 1 for the second and so on.
264
+ # [+end_index+] is the index of the line at which the fill ends.
265
+ #
266
+ # ==== Examples
267
+ # # Fill Area (Multiple Datasets)
268
+ # lc = GoogleChart::LineChart.new('320x200', "Line Chart", false) do |lc|
269
+ # lc.show_legend = false
270
+ # lc.data "Trend 1", [5,5,6,5,5], 'ff0000'
271
+ # lc.data "Trend 2", [3,3,4,3,3], '00ff00'
272
+ # lc.data "Trend 3", [1,1,2,1,1], '0000ff'
273
+ # lc.data "Trend 4", [0,0,0,0,0], 'ffffff'
274
+ # lc.fill_area '0000ff',2,3
275
+ # lc.fill_area '00ff00',1,2
276
+ # lc.fill_area 'ff0000',0,1
277
+ # end
278
+ # puts "\nFill Area (Multiple Datasets)"
279
+ # puts lc.to_url
280
+ #
281
+ # # Fill Area (Single Dataset)
282
+ # lc = GoogleChart::LineChart.new('320x200', "Line Chart", false) do |lc|
283
+ # lc.show_legend = false
284
+ # lc.data "Trend 1", [5,5,6,5,5], 'ff0000'
285
+ # lc.fill_area 'cc6633', 0, 0
286
+ # end
287
+ # puts "\nFill Area (Single Dataset)"
288
+ # puts lc.to_url
289
+ #
290
+ def fill_area(color, start_index, end_index)
291
+ if (start_index == 0 and end_index == 0)
292
+ @markers << "B,#{color},0,0,0"
293
+ else
294
+ @markers << "b,#{color},#{start_index},#{end_index},0"
295
+ end
296
+ end
297
+
298
+ protected
299
+
300
+ def prepare_params
301
+ params.clear
302
+ set_size
303
+ set_type
304
+ set_colors
305
+ set_fill_options
306
+ add_axis unless @axis.empty?
307
+ add_grid
308
+ add_data
309
+ add_line_styles unless @line_styles.empty?
310
+ set_bar_width_spacing_options if @bar_width_spacing_options
311
+ add_markers unless @markers.empty?
312
+ add_labels(@labels) if [:p, :p3].member?(self.chart_type)
313
+ add_legend(@labels) if show_legend
314
+ add_title if chart_title.to_s.length > 0
315
+ end
316
+
317
+ def process_fill_options(type, options)
318
+ case type
319
+ when :solid
320
+ "s,#{options[:color]}"
321
+ when :gradient
322
+ "lg,#{options[:angle]}," + options[:color].collect { |o| "#{o.first},#{o.last}" }.join(",")
323
+ when :stripes
324
+ "ls,#{options[:angle]}," + options[:color].collect { |o| "#{o.first},#{o.last}" }.join(",")
325
+ end
326
+
327
+ end
328
+
329
+ def set_type
330
+ params.merge!({:cht => chart_type})
331
+ end
332
+
333
+ def set_size
334
+ params.merge!({:chs => chart_size})
335
+ end
336
+
337
+ def set_colors
338
+ params.merge!({:chco => @colors.collect{|c| c.downcase}.join(",") }) if @colors.size > 0
339
+ end
340
+
341
+ def set_fill_options
342
+ fill_opt = [@background_fill, @chart_fill].compact.join("|")
343
+ params.merge!({:chf => fill_opt}) if fill_opt.length > 0
344
+ end
345
+
346
+ def add_labels(labels)
347
+ params.merge!({:chl => labels.collect{|l| l.to_s}.join("|") }) if self.show_labels
348
+ end
349
+
350
+ def add_legend(labels)
351
+ params.merge!({:chdl => labels.collect{ |l| l.to_s}.join("|")})
352
+ end
353
+
354
+ def add_title
355
+ params.merge!({:chtt => chart_title})
356
+ params.merge!({:chts => title_color}) if title_color
357
+ params.merge!({:chts => "#{title_color},#{title_font_size}"}) if title_color and title_font_size
358
+ end
359
+
360
+ def add_axis
361
+ chxt = []
362
+ chxl = []
363
+ chxp = []
364
+ chxr = []
365
+ chxs = []
366
+ # Process params
367
+ @axis.each_with_index do |axis, idx|
368
+ # Find axis type
369
+ case axis.first
370
+ when :x
371
+ chxt << "x"
372
+ when :y
373
+ chxt << "y"
374
+ when :top
375
+ chxt << "t"
376
+ when :right
377
+ chxt << "r"
378
+ end
379
+
380
+ # Axis labels
381
+ axis_opts = axis.last
382
+
383
+ if axis_opts[:labels]
384
+ chxl[idx] = "#{idx}:|" + axis_opts[:labels].join("|")
385
+ end
386
+
387
+ # Axis positions
388
+ if axis_opts[:positions]
389
+ chxp[idx] = "#{idx}," + axis_opts[:positions].join(",")
390
+ end
391
+
392
+ # Axis range
393
+ if axis_opts[:range]
394
+ chxr[idx] = "#{idx},#{axis_opts[:range].first},#{axis_opts[:range].last}"
395
+ end
396
+
397
+ # Axis Styles
398
+ if axis_opts[:color] or axis_opts[:font_size] or axis_opts[:alignment]
399
+ if axis_opts[:alignment]
400
+ alignment = case axis_opts[:alignment]
401
+ when :center
402
+ 0
403
+ when :left
404
+ -1
405
+ when :right
406
+ 1
407
+ else
408
+ nil
409
+ end
410
+ end
411
+ chxs[idx] = "#{idx}," + [axis_opts[:color], axis_opts[:font_size], alignment].compact.join(",")
412
+ end
413
+ end
414
+
415
+ # Add to params hash
416
+ params.merge!({ :chxt => chxt.join(",") }) unless chxt.empty?
417
+ params.merge!({ :chxl => chxl.compact.join("|") }) unless chxl.compact.empty?
418
+ params.merge!({ :chxp => chxp.compact.join("|") }) unless chxp.compact.empty?
419
+ params.merge!({ :chxr => chxr.compact.join("|") }) unless chxr.compact.empty?
420
+ params.merge!({ :chxs => chxs.compact.join("|") }) unless chxs.compact.empty?
421
+ end
422
+
423
+ def add_grid
424
+ params.merge!({ :chg => @grid_str }) if @grid_str
425
+ end
426
+
427
+ def add_line_styles
428
+ 0.upto(@line_styles.length - 1) { |i|
429
+ @line_styles[i] = DEFAULT_LINE_STYLE unless @line_styles[i]
430
+ }
431
+ params.merge!({:chls => @line_styles.join("|")})
432
+ end
433
+
434
+ def set_bar_width_spacing_options
435
+ params.merge!({:chbh => @bar_width_spacing_options})
436
+ end
437
+
438
+ def add_markers
439
+ params.merge!({:chm => @markers.join("|")})
440
+ end
441
+
442
+ def add_data
443
+ converted_data = process_data
444
+ case data_encoding
445
+ when :simple
446
+ converted_data = "s:" + converted_data
447
+ when :text
448
+ converted_data = "t:" + converted_data
449
+ when :extended
450
+ converted_data = "e:" + converted_data
451
+ else
452
+ raise "Illegal Encoding Specified"
453
+ end
454
+ params.merge!({:chd => converted_data})
455
+ end
456
+
457
+ def encode_data(values, max_value=nil)
458
+ case data_encoding
459
+ when :simple
460
+ simple_encode(values, max_value)
461
+ when :text
462
+ text_encode(values, max_value)
463
+ when :extended
464
+ extended_encode(values, max_value)
465
+ else
466
+ raise "Illegal Encoding Specified"
467
+ end
468
+ end
469
+
470
+ def simple_encode(values, max_value=nil)
471
+ alphabet_length = 61
472
+ max_value = values.max unless max_value
473
+
474
+ chart_data = values.collect do |val|
475
+ if val.to_i >=0
476
+ if max_value == 0
477
+ SIMPLE_ENCODING[0]
478
+ else
479
+ SIMPLE_ENCODING[(alphabet_length * val / max_value).to_i]
480
+ end
481
+ else
482
+ "_"
483
+ end
484
+ end
485
+
486
+ return chart_data.join('')
487
+ end
488
+
489
+ def text_encode(values, max_value=nil)
490
+ max_value = values.max unless max_value
491
+ values.inject("") { |sum, v|
492
+ if max_value == 0
493
+ sum += "0,"
494
+ else
495
+ sum += ( "%.1f" % (v*100/max_value) ) + ","
496
+ end
497
+ }.chomp(",")
498
+ end
499
+
500
+ def extended_encode(values, max_value)
501
+ max_value = values.max unless max_value
502
+ values.collect { |v|
503
+ if max_value == 0
504
+ @@complex_encoding[0]
505
+ else
506
+ @@complex_encoding[(v * 4095/max_value).to_i]
507
+ end
508
+ }.join('')
509
+ end
510
+
511
+ def join_encoded_data(encoded_data)
512
+ encoded_data.join((self.data_encoding == :simple or self.data_encoding == :extended) ? "," : "|")
513
+ end
514
+
515
+ def max_data_value
516
+ @max_data or @data.flatten.max
517
+ end
518
+
519
+ def max_x_value
520
+ @max_x or x_data.flatten.max
521
+ end
522
+
523
+ def max_y_value
524
+ @max_y or y_data.flatten.max
525
+ end
526
+
527
+ def x_data
528
+ @data.collect do |series|
529
+ series.collect { |val| val.first }
530
+ end
531
+ end
532
+
533
+ def y_data
534
+ @data.collect do |series|
535
+ series.collect { |val| val.last }
536
+ end
537
+ end
538
+ end
539
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+ module GoogleChart
3
+
4
+ # Generates a Financial Line Chart. This feature is UNDOCUMENTED and EXPERIMENTAL.
5
+ # For a sample usage, visit (right at the bottom) http://24ways.org/2007/tracking-christmas-cheer-with-google-charts
6
+ #
7
+ # ==== Examples
8
+ # flc = GoogleChart::FinancialLineChart.new do |chart|
9
+ # chart.data "", [3,10,20,37,40,25,68,75,89,99], "ff0000"
10
+ # end
11
+ # puts flc.to_url
12
+ #
13
+ class FinancialLineChart < Base
14
+
15
+ # Specify the
16
+ # * +chart_size+ in WIDTHxHEIGHT format
17
+ # * +chart_title+ as a string
18
+ def initialize(chart_size='100x15', chart_title=nil) # :yield: self
19
+ super(chart_size, chart_title)
20
+ self.chart_type = :lfi
21
+ self.show_legend = false
22
+ yield self if block_given?
23
+ end
24
+
25
+ def process_data
26
+ join_encoded_data(@data.collect { |series|
27
+ encode_data(series, max_data_value)
28
+ })
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,79 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+ module GoogleChart
3
+
4
+ # Generates a Line chart. An option can be passed that allows you to create a Line XY Chart
5
+ #
6
+ # ==== Examples
7
+ #
8
+ # # Line Chart
9
+ # lc = GoogleChart::LineChart.new('320x200', "Line Chart", false)
10
+ # lc.data "Trend 1", [5,4,3,1,3,5,6], '0000ff'
11
+ # lc.data "Trend 2", [1,2,3,4,5,6], '00ff00'
12
+ # lc.data "Trend 3", [6,5,4,3,2,1], 'ff0000'
13
+ # lc.axis :y, :range => [0,6], :color => 'ff00ff', :font_size => 16, :alignment => :center
14
+ # lc.axis :x, :range => [0,6], :color => '00ffff', :font_size => 16, :alignment => :center
15
+ #
16
+ # # Line XY Chart
17
+ # lcxy = GoogleChart::LineChart.new('320x200', "Line XY Chart", true)
18
+ # lcxy.data "Trend 1", [[1,1], [2,2], [3,3], [4,4]], '0000ff'
19
+ # lcxy.data "Trend 2", [[4,5], [2,2], [1,1], [3,4]], '00ff00'
20
+ # puts lcxy.to_url
21
+ class LineChart < Base
22
+ attr_accessor :is_xy
23
+
24
+ # Specify the
25
+ # * +chart_size+ in WIDTHxHEIGHT format
26
+ # * +chart_title+ as a string
27
+ # * +is_xy+ is <tt>false</tt> by default. Set it to <tt>true</tt> if you want to plot a Line XY chart
28
+ def initialize(chart_size='300x200', chart_title=nil, is_xy=false) # :yield: self
29
+ super(chart_size, chart_title)
30
+ self.is_xy = is_xy
31
+ @line_styles = []
32
+ yield self if block_given?
33
+ end
34
+
35
+ # Pass in <tt>true</tt> here to create a Line XY.
36
+ #
37
+ # Note: This must be done before passing in any data to the chart
38
+ def is_xy=(value)
39
+ @is_xy = value
40
+ if value
41
+ self.chart_type = :lxy
42
+ else
43
+ self.chart_type = :lc
44
+ end
45
+ end
46
+
47
+ # Defines a line style. Applicable for line charts.
48
+ # [+data_set_index+] Can be one of <tt>:background</tt> or <tt>:chart</tt> depending on the kind of fill requested
49
+ # [+options+] : Options for the style, specifying things like line thickness and lengths of the line segment and blank portions
50
+ #
51
+ # ==== Options
52
+ # * <tt>:line_thickness</tt> (mandatory) option which specifies the thickness of the line segment in pixels
53
+ # * <tt>:length_segment</tt>, which specifies the length of the line segment
54
+ # * <tt>:length_blank</tt>, which specifies the lenght of the blank segment
55
+ def line_style(data_set_index, options={})
56
+ @line_styles[data_set_index] = "#{options[:line_thickness]}"
57
+ @line_styles[data_set_index] += ",#{options[:length_segment]},#{options[:length_blank]}" if options[:length_segment]
58
+ end
59
+
60
+ def process_data
61
+ if self.is_xy or @data.size > 1
62
+ if self.is_xy # XY Line graph data series
63
+ encoded_data = []
64
+ @data.size.times { |i|
65
+ # Interleave X and Y co-ordinate data
66
+ encoded_data << join_encoded_data([encode_data(x_data[i],max_x_value), encode_data(y_data[i],max_y_value)])
67
+ }
68
+ join_encoded_data(encoded_data)
69
+ else # Line graph multiple data series
70
+ join_encoded_data(@data.collect { |series|
71
+ encode_data(series, max_data_value)
72
+ })
73
+ end
74
+ else
75
+ encode_data(@data.flatten, max_data_value)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+ module GoogleChart
3
+ class PieChart < Base
4
+
5
+ # set to <tt>true</tt> or <tt>false</tt> to indicate if this is a 3d chart
6
+ attr_accessor :is_3d
7
+
8
+ # set to <tt>true</tt> or <tt>false</tt> to show or hide pie chart labels
9
+ attr_accessor :show_labels
10
+
11
+ # Initializes a Pie Chart object with a +chart_size+ and +chart_title+. Specify <tt>is_3d</tt> as +true+ to generate a 3D Pie chart
12
+ def initialize(chart_size='300x200', chart_title=nil, is_3d = false) # :yield: self
13
+ super(chart_size, chart_title)
14
+ self.is_3d = is_3d
15
+ self.show_legend = false
16
+ self.show_labels = true
17
+ yield self if block_given?
18
+ end
19
+
20
+ # Set this value to <tt>true</tt> if you want the Pie Chart to be rendered as a 3D image
21
+ def is_3d=(value)
22
+ if value
23
+ self.chart_type = :p3
24
+ else
25
+ self.chart_type = :p
26
+ end
27
+ end
28
+
29
+ def process_data
30
+ encode_data(@data, max_data_value)
31
+ end
32
+ end
33
+ end