ghazel-googlecharts 1.4.0.1 → 1.4.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.
- data/lib/gchart.rb +107 -70
- 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,
|
21
|
-
:
|
22
|
-
:
|
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
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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
|
-
|
170
|
-
|
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 =
|
177
|
-
if
|
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
|
186
|
-
|
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
|
-
|
467
|
+
dsets = []
|
468
|
+
axis_set.each do |ds|
|
438
469
|
if @max_value != false
|
439
|
-
|
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.
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
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
|
-
|
480
|
-
"t:" + dataset.map{ |ds| ds.join(',') }.join('|') + "&chds
|
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
|
-
|
528
|
+
prepare_dataset
|
492
529
|
query_params = instance_variables.map do |var|
|
493
530
|
case var
|
494
531
|
when '@data'
|