ghazel-googlecharts 1.4.0.1 → 1.4.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/gchart.rb +107 -70
  2. metadata +1 -1
data/lib/gchart.rb CHANGED
@@ -6,10 +6,11 @@ require "uri"
6
6
  require "cgi"
7
7
  require 'enumerator'
8
8
 
9
+
9
10
  class Gchart
10
11
 
11
12
  include GchartInfo
12
-
13
+
13
14
  @@url = "http://chart.apis.google.com/chart?"
14
15
  @@types = ['line', 'line_xy', 'scatter', 'bar', 'venn', 'pie', 'pie_3d', 'jstize', 'sparkline', 'meter', 'map']
15
16
  @@simple_chars = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a
@@ -17,9 +18,11 @@ class Gchart
17
18
  @@ext_pairs = @@chars.map { |char_1| @@chars.map { |char_2| char_1 + char_2 } }.flatten
18
19
  @@file_name = 'chart.png'
19
20
 
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
21
+ attr_accessor :title, :type, :width, :height, :horizontal, :grouped, :legend,
22
+ :data, :encoding, :bar_colors, :title_color,
23
+ :title_size, :custom, :axis_with_labels, :axis_labels,
24
+ :bar_width_and_spacing, :id, :alt, :class, :range_markers,
25
+ :geographical_area, :map_colors, :country_codes, :axis_range
23
26
 
24
27
  # Support for Gchart.line(:title => 'my title', :size => '400x600')
25
28
  def self.method_missing(m, options={})
@@ -46,14 +49,11 @@ class Gchart
46
49
 
47
50
  def initialize(options={})
48
51
  @type = :line
49
- @data = []
50
52
  @width = 300
51
53
  @height = 200
52
54
  @horizontal = false
53
55
  @grouped = false
54
56
  @encoding = 'simple'
55
- self.min_value = 'auto'
56
- self.max_value = 'auto'
57
57
  # Sets the alt tag when chart is exported as image tag
58
58
  @alt = 'Google Chart'
59
59
  # Sets the CSS id selector when chart is exported as image tag
@@ -137,57 +137,94 @@ class Gchart
137
137
  def full_data_range(ds)
138
138
  return if @max_value == false
139
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
- if @type == :bar and not grouped
156
- @min_value = ds.compact.first.compact.min if @min_value.nil?
157
- if @max_value.nil?
158
- totals = []
159
- ds.compact.each do |mds|
160
- mds.each_with_index do |v, index|
161
- next if v.nil?
162
- totals[index] ||= 0
163
- totals[index] += v
164
- end
140
+ ds.each do |mds|
141
+ # global limits override individuals. is this preferred?
142
+ mds[:min_value] = @min_value if not @min_value.nil?
143
+ mds[:max_value] = @max_value if not @max_value.nil?
144
+
145
+ # TODO: can you have grouped stacked bars?
146
+ if @type == :bar and not grouped and mds[:data].first.is_a?(Array)
147
+ mds[:min_value] ||= mds[:data].first.to_a.compact.min
148
+ totals = []
149
+ mds[:data].each do |l|
150
+ l.each_with_index do |v, index|
151
+ next if v.nil?
152
+ totals[index] ||= 0
153
+ totals[index] += v
165
154
  end
166
- @max_value = totals.compact.max
167
155
  end
156
+ mds[:max_value] ||= totals.compact.max
168
157
  else
169
- @min_value = ds.compact.map{|mds| mds.compact.min}.min if @min_value.nil?
170
- @max_value = ds.compact.map{|mds| mds.compact.max}.max if @max_value.nil?
158
+ all = mds[:data].flatten.compact
159
+ mds[:min_value] ||= all.min
160
+ mds[:max_value] ||= all.max
171
161
  end
172
- @axis << [@min_value, @max_value]
173
162
  end
174
163
 
175
164
  if not @axis_range
176
- @axis_range = @axis.map{|axis| axis.nil? ? [] : axis}
177
- if @type != :line_xy and (@type != :bar or not @horizontal)
165
+ @axis_range = ds.map{|mds| [mds[:min_value], mds[:max_value]]}
166
+ if dimensions == 1 and (@type != :bar or not @horizontal)
178
167
  tmp = @axis_range.fetch(0, [])
179
168
  @axis_range[0] = @axis_range.fetch(1, [])
180
169
  @axis_range[1] = tmp
181
170
  end
182
171
  end
183
172
  end
184
-
185
- def dataset
186
- @dataset ||= prepare_dataset(data)
173
+
174
+ def number_visible
175
+ n = 0
176
+ axis_set.each do |mds|
177
+ return n.to_s if mds[:invisible] == true
178
+ if mds[:data].first.is_a?(Array)
179
+ n += mds[:data].length
180
+ else
181
+ n += 1
182
+ end
183
+ end
184
+ ""
185
+ end
186
+
187
+ # Turns input into an array of axis hashes, dependent on the chart type
188
+ def convert_dataset(ds)
189
+ if dimensions == 2
190
+ # valid inputs include:
191
+ # an array of >=2 arrays, or an array of >=2 hashes
192
+ ds = ds.map do |d|
193
+ d.is_a?(Hash) ? d : {:data => d}
194
+ end
195
+ elsif dimensions == 1
196
+ # valid inputs include:
197
+ # a hash, an array of data, an array of >=1 array, or an array of >=1 hash
198
+ if ds.is_a?(Hash)
199
+ ds = [ds]
200
+ elsif not ds.first.is_a?(Hash)
201
+ ds = [{:data => ds}]
202
+ end
203
+ end
204
+ ds
205
+ end
206
+
207
+ def prepare_dataset
208
+ @dataset = convert_dataset(data || [])
187
209
  full_data_range(@dataset)
210
+ end
211
+
212
+ def axis_set
188
213
  @dataset
189
214
  end
190
-
215
+
216
+ def dataset
217
+ datasets = []
218
+ @dataset.each do |d|
219
+ if d[:data].first.is_a?(Array)
220
+ datasets += d[:data]
221
+ else
222
+ datasets << d[:data]
223
+ end
224
+ end
225
+ datasets
226
+ end
227
+
191
228
  def self.jstize(string)
192
229
  string.gsub(' ', '+').gsub(/\[|\{|\}|\||\\|\^|\[|\]|\`|\]/) {|c| "%#{c[0].to_s(16).upcase}"}
193
230
  end
@@ -379,7 +416,6 @@ class Gchart
379
416
  # a passed axis_range should look like:
380
417
  # [[10,100]] or [[10,100,4]] or [[10,100], [20,300]]
381
418
  # in the second example, 4 is the interval
382
- dataset # just making sure we processed the data before
383
419
  if axis_range && axis_range.respond_to?(:each) && axis_range.first.respond_to?(:each)
384
420
  'chxr=' + axis_range.enum_for(:each_with_index).map{|range, index| [index, range[0], range[1], range[2]].compact.join(',')}.join("|")
385
421
  else
@@ -426,33 +462,34 @@ class Gchart
426
462
  'ls'
427
463
  end
428
464
  end
429
-
430
- # Wraps a single dataset inside another array to support more datasets
431
- def prepare_dataset(ds)
432
- ds = [ds] unless ds.first.is_a?(Array)
433
- ds
434
- end
435
465
 
436
466
  def encode_scaled_dataset chars, nil_char
437
- dataset.enum_with_index.map do |ds, index|
467
+ dsets = []
468
+ axis_set.each do |ds|
438
469
  if @max_value != false
439
- ax = @axis[index%dimensions]
440
- min = ax[0]
441
- range = ax[1] - min
470
+ range = ds[:max_value] - ds[:min_value]
442
471
  range = 1 if range == 0
443
472
  end
444
- ds.map do |number|
445
- if number.nil?
446
- nil_char
447
- else
448
- if not range.nil?
449
- number = chars.size * (number - min) / range
450
- number = [number, chars.size - 1].min
451
- end
452
- chars[number.to_i]
453
- end
454
- end.join
455
- end.join(',')
473
+ if not ds[:data].first.is_a?(Array)
474
+ datasets = [ds[:data]]
475
+ else
476
+ datasets = ds[:data]
477
+ end
478
+ datasets.each do |l|
479
+ dsets << l.map do |number|
480
+ if number.nil?
481
+ nil_char
482
+ else
483
+ if not range.nil?
484
+ number = chars.size * (number - ds[:min_value]) / range
485
+ number = [number, chars.size - 1].min
486
+ end
487
+ chars[number.to_i]
488
+ end
489
+ end.join
490
+ end
491
+ end
492
+ dsets.join(',')
456
493
  end
457
494
 
458
495
  # http://code.google.com/apis/chart/#simple
@@ -460,7 +497,7 @@ class Gchart
460
497
  # Allowing five pixels per data point, this is sufficient for line and bar charts up
461
498
  # to about 300 pixels. Simple encoding is suitable for all other types of chart regardless of size.
462
499
  def simple_encoding
463
- "s:" + encode_scaled_dataset(@@simple_chars, '_')
500
+ "s" + number_visible + ":" + encode_scaled_dataset(@@simple_chars, '_')
464
501
  end
465
502
 
466
503
  # http://code.google.com/apis/chart/#text
@@ -476,19 +513,19 @@ class Gchart
476
513
  # This encoding is not available for maps.
477
514
  #
478
515
  def text_encoding
479
- # TODO: text encoding should use @axis too
480
- "t:" + dataset.map{ |ds| ds.join(',') }.join('|') + "&chds=#{@min_value},#{@max_value}"
516
+ chds = axis_set.map{ |ds| "#{ds[:min_value]},#{ds[:max_value]}" }.join(",")
517
+ "t" + number_visible + ":" + dataset.map{ |ds| ds.join(',') }.join('|') + "&chds=" + chds
481
518
  end
482
519
 
483
520
  # http://code.google.com/apis/chart/#extended
484
521
  # Extended encoding has a resolution of 4,096 different values
485
522
  # and is best used for large charts where a large data range is required.
486
523
  def extended_encoding
487
- "e:" + encode_scaled_dataset(@@ext_pairs, '__')
524
+ "e" + number_visible + ":" + encode_scaled_dataset(@@ext_pairs, '__')
488
525
  end
489
526
 
490
527
  def query_builder(options="")
491
- dataset
528
+ prepare_dataset
492
529
  query_params = instance_variables.map do |var|
493
530
  case var
494
531
  when '@data'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ghazel-googlecharts
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0.1
4
+ version: 1.4.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Aimonetti