smart_chart 0.0.1 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,12 @@
1
+ = Changelog
2
+
3
+ Per-release changes to SmartChart.
4
+
5
+ == 0.0.9 (2009 Dec 14)
6
+
7
+ * Bar and line charts are now functional, if not complete.
8
+ * Add basic axis style and label functionality.
9
+
10
+ == 0.0.1 (2009 Oct 29)
11
+
12
+ * First release (only maps and barcodes work).
data/README.rdoc CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  SmartChart is an easy way to render charts on web pages. It uses the Google Charts engine so there are no server-side dependencies or performance issues--just install and go.
4
4
 
5
- <b>SmartChart is still in the early stages of development. Only maps, barcodes, and line charts (partially) are working at all. However, much of the interface is described below (plus to-do list) and if you'd like to contribute, please do.</b>
5
+ <b>SmartChart is still in the early stages of development. Only bar charts, line graphs, maps, and barcodes are working. However, much of the interface is described below (plus to-do list) and if you'd like to contribute, please do.</b>
6
6
 
7
7
 
8
8
  == Key Benefits
@@ -29,9 +29,12 @@ SmartChart is an easy way to render charts on web pages. It uses the Google Char
29
29
  {
30
30
  :values => [1,2,3,4],
31
31
  :label => "Profit",
32
- :thickness => 2,
32
+ :thickness => 2, # float, default is 1.5
33
33
  :color => '550055',
34
- :style => {:solid => 3, :blank => 2}
34
+ :style => {
35
+ :solid => 3,
36
+ :blank => 2
37
+ }
35
38
  },
36
39
  {
37
40
  :values => [2,4,6,8],
@@ -42,11 +45,20 @@ SmartChart is an easy way to render charts on web pages. It uses the Google Char
42
45
  }
43
46
  ],
44
47
 
45
- # axis lines
48
+ # axis lines and labels
46
49
  :axis => {
47
- :sides => [:left, :right, :bottom], # empty array for none
48
- :color => 'DDDDDD',
49
- :style => :dashed
50
+ :bottom => {
51
+ :color => 'DDDDDD', # false or nil for hidden
52
+ :ticks => 'DDDDDD', # false or nil for hidden
53
+ :font_size => 12,
54
+ :text_align => :left,
55
+ :labels => {
56
+ 1 => "Jan",
57
+ 4 => "Apr",
58
+ 7 => "Jul",
59
+ 10 => "Oct"
60
+ }
61
+ }
50
62
  }
51
63
 
52
64
  # grid lines
@@ -56,14 +68,6 @@ SmartChart is an easy way to render charts on web pages. It uses the Google Char
56
68
  :style => :dashed # no :color or :thickness
57
69
  },
58
70
 
59
- # labels
60
- :x_labels => {
61
- 1 => "Jan",
62
- 4 => "Apr",
63
- 7 => "Jul",
64
- 10 => "Oct"
65
- }
66
-
67
71
  # options for HTML tag
68
72
  :html => {
69
73
  :id => "stock_graph",
@@ -124,37 +128,47 @@ Data can be passed to pie charts in a similar way. For more complex graphs depic
124
128
 
125
129
  == Axis Lines
126
130
 
127
- Actual output is limited by Google's requirements. For example, while Google provides for a line chart with no axis lines ("sparkline"), there is no analogous bar chart type. However, SmartChart will simulate this for you by cropping the chart image using a <div> when you call the chart.to_html method.
131
+ Actual output is limited by Google's requirements. For example, while Google provides for a line chart with no axis lines ("sparkline"), there is no analogous bar chart type. However, SmartChart will simulate this for you by cropping the chart image using a <div> when you call the +to_html+ method.
128
132
 
129
133
 
130
134
  == To-do List
131
135
 
132
- * query_string_params should be a class variable so feature modules can
133
- auto-add their parameters
134
-
135
- * validations
136
- * margins and legend dimensions are integers
137
- * grid line attributes
138
-
139
- * grids
140
- * easy placement of y-gridline at zero, if exists
141
- * easy placement of gridlines at label positions
142
-
143
- * axis lines
144
- * specify which ones to print
145
- * hide all ("sparklines")
146
- * hide bar graph axes by hiding 1px from left and bottom of image when to_html is called
147
- * chxr parameter?
136
+ * bar graphs
137
+ * add chbh tests
138
+ * style and orientation tests
148
139
 
149
140
  * labels
150
141
  * on line, scatter, bar graphs
151
142
  * labels on other axes (top and right)
152
143
  * multiple rows of labels on same axis
153
144
 
145
+ * axes
146
+ * hide bar graph axes by hiding 1px from left and bottom of image when to_html is called
147
+ * eliminate unnecessary characters from chxs parameter
148
+ * chxr parameter? if :auto is given for labels
149
+ * tests for chxl and chxp parameters
150
+ * make sure labels are escaped (commas, pipes, etc)
151
+
152
+ * support OEmbed (oembed.com)
153
+ * check out flotomatic (http://github.com/xdotcommer/flotomatic)
154
+ * use :section: directive in RDoc comments
155
+ * classes should use inheritable query_string_params (like ActiveRecord
156
+ validations) so features can add params
157
+ * change arguments to to_html method so attributes are easier to pass
158
+
159
+ * validations
160
+ * axis colors, font sizes, and alignments
161
+ * margins and legend dimensions are integers
162
+ * grid line attributes
163
+
154
164
  * legend
155
165
  * size, position
156
166
  * inline legends (line up with ends of lines -- see http://code.google.com/p/graphy/wiki/UserGuide)
157
167
 
168
+ * grids
169
+ * easy placement of y-gridline at zero, if exists
170
+ * easy placement of gridlines at label positions
171
+
158
172
  * general
159
173
  * support advanced background ("fill") options like gradients
160
174
 
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.9
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Print a tiny bar chart and hide the axes using a div which is slightly
4
+ # smaller than the chart image.
5
+ #
6
+
7
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ require 'smart_chart'
9
+
10
+ width = 240
11
+ height = 20
12
+
13
+ chart = SmartChart::Bar.new(
14
+ :width => width,
15
+ :height => height,
16
+ :y_min => 0,
17
+ :y_max => 100,
18
+ :bar_width => 3,
19
+ :bar_space => 1,
20
+ :data => [38,60,68,78,52,50,19,23,33,49,38,39,12,18]
21
+ )
22
+
23
+ puts "<div style=\"width:#{width-2}px; height:#{height-1}px; overflow:hidden;\">"
24
+ puts chart.to_html(true, true, :style => "margin:0 0 -1px -2px")
25
+ puts "</div>"
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Generate a URL for a Google line graph depicting the 2008 National League
4
+ # pennant race (games +/- .500 vs. time).
5
+ #
6
+
7
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ require 'smart_chart'
9
+
10
+ data = [{
11
+ :label => "1. Philadelphia (.568)",
12
+ :color => "2f3fe0",
13
+ :thickness => 1,
14
+ :values => [
15
+ 0, 0, 0, -1, -1, -2, -1, 0, -1, -2, -1, 0, -1, -2, -1, 0, -1, -1,
16
+ 0, -1, 0, -1, -2, -1, 0, 1, 0, 1, 2, 3, 2, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5,
17
+ 4, 5, 4, 3, 3, 4, 3, 4, 5, 4, 3, 2, 3, 4, 5, 4, 3, 4, 5, 6, 7, 7, 8, 7,
18
+ 8, 9, 10, 9, 10, 11, 12, 13, 13, 12, 11, 12, 13, 12, 11, 12, 11, 10, 10,
19
+ 9, 8, 7, 7, 6, 7, 6, 5, 6, 5, 5, 6, 7, 8, 9, 8, 7, 6, 5, 6, 7, 8, 7, 8,
20
+ 8, 9, 8, 7, 7, 8, 7, 6, 5, 6, 7, 7, 8, 9, 10, 9, 10, 11, 11, 10, 11, 10,
21
+ 9, 10, 11, 10, 9, 8, 7, 8, 7, 8, 8, 9, 10, 9, 10, 11, 12, 13, 14, 13, 12,
22
+ 11, 12, 13, 12, 13, 12, 12, 13, 13, 13, 14, 13, 12, 13, 13, 14, 16, 16,
23
+ 17, 18, 19, 18, 19, 20, 21, 20, 19, 19, 20, 21, 22, 22, 22
24
+ ]},{
25
+
26
+ :label => "2. New York (.549)",
27
+ :color => "fae12e",
28
+ :thickness => 1,
29
+ :values => [
30
+ 0, 0, 0, 1, 0, 1, 1, 1, 0, -1, -1, -2, -1, 0, 1, 0, -1, -1, 0, 1,
31
+ 2, 3, 4, 3, 2, 1, 2, 1, 0, 1, 2, 2, 3, 2, 2, 3, 2, 3, 2, 1, 2, 2, 2, 2,
32
+ 3, 2, 3, 2, 1, 1, 2, 3, 3, 1, 0, -1, -2, -1, -2, -3, -2, -1, 0, -1, 0,
33
+ 1, 0, 1, 2, 1, 0, -1, -2, -2, -3, -2, -3, -2, -2, -2, -1, -2, -1, -1, 0,
34
+ -1, 0, -1, -2, -1, -1, -1, -2, -1, -2, -1, -2, -1, -2, -1, 0, 1, 2, 3, 4,
35
+ 5, 6, 7, 8, 7, 6, 7, 7, 6, 7, 8, 9, 8, 9, 8, 9, 8, 8, 7, 6, 5, 5, 6, 5,
36
+ 6, 7, 8, 7, 6, 7, 8, 9, 10, 11, 12, 11, 12, 13, 14, 15, 14, 13, 14, 13,
37
+ 14, 14, 15, 14, 15, 16, 17, 18, 18, 17, 17, 17, 17, 18, 19, 19, 19, 19,
38
+ 18, 17, 16, 17, 18, 19, 18, 17, 16, 17, 16, 17, 16, 17, 16, 16, 16
39
+ ]},{
40
+
41
+ :label => "3. Florida (.522)",
42
+ :color => "2dad2d",
43
+ :thickness => 1,
44
+ :values => [
45
+ 0, 0, 0, -1, 0, -1, -1, 0, 1, 0, 1, 1, 2, 3, 4, 3, 2, 2, 3, 4, 3,
46
+ 2, 3, 4, 5, 4, 5, 4, 5, 4, 5, 5, 4, 3, 2, 3, 2, 3, 3, 4, 5, 6, 7, 8, 9,
47
+ 8, 7, 6, 6, 5, 6, 5, 5, 6, 7, 8, 7, 7, 9, 10, 9, 8, 8, 7, 8, 7, 6, 5, 6,
48
+ 5, 4, 5, 6, 5, 6, 7, 6, 5, 4, 5, 6, 5, 6, 6, 5, 6, 5, 5, 4, 3, 2, 3, 2,
49
+ 3, 4, 3, 4, 3, 2, 1, 2, 3, 2, 3, 4, 5, 6, 5, 5, 4, 5, 6, 5, 6, 5, 4, 5,
50
+ 6, 5, 6, 5, 6, 7, 6, 7, 6, 6, 7, 6, 7, 6, 5, 6, 5, 6, 5, 4, 3, 4, 3, 3,
51
+ 4, 3, 2, 3, 2, 3, 3, 2, 3, 2, 1, 2, 1, 2, 1, 2, 2, 3, 2, 1, 0, 1, 2, 2,
52
+ 3, 4, 5, 5, 6, 7, 8, 9, 8, 7, 6, 5, 6, 6, 7, 6, 7, 7, 7
53
+ ]},{
54
+
55
+ :label => "4. Atlanta (.444)",
56
+ :color => "ff0000",
57
+ :thickness => 1,
58
+ :values => [
59
+ 0, 0, -1, -2, -2, -1, -2, -2, -1, 0, -1, -2, -3, -3, -2, -1, -2,
60
+ -2, -3, -4, -3, -2, -1, 0, 1, 0, -1, 0, 1, 0, -1, -1, -2, -3, -3, -2, -1,
61
+ 0, 0, 1, 2, 3, 2, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 3, 4, 5, 4, 5, 4, 5, 4,
62
+ 3, 4, 3, 2, 1, 2, 3, 2, 3, 2, 1, 0, 0, -1, -2, -3, -2, -1, -2, -1, -2,
63
+ -1, -2, -3, -2, -1, -2, -3, -2, -2, -1, -2, -3, -3, -4, -5, -6, -5, -6,
64
+ -5, -6, -5, -6, -6, -7, -6, -5, -5, -4, -5, -6, -5, -6, -5, -5, -4, -5,
65
+ -6, -7, -8, -9, -8, -9, -10, -9, -10, -9, -10, -9, -8, -7, -8, -8, -8,
66
+ -10, -11, -12, -11, -12, -13, -14, -15, -16, -17, -16, -17, -17, -16,
67
+ -17, -16, -17, -18, -19, -20, -19, -20, -19, -18, -19, -20, -20, -19,
68
+ -18, -17, -17, -17, -16, -16, -17, -18, -19, -20, -19, -18, -19, -18,
69
+ -17, -17, -18, -17, -18, -18, -18
70
+ ]},{
71
+
72
+ :label => "5. Washington (.366)",
73
+ :color => "a020f0",
74
+ :thickness => 1,
75
+ :values => [
76
+ 0, 0, 1, 2, 2, 3, 2, 1, 0, -1, -2, -2, -3, -4, -5, -6, -5, -5,
77
+ -6, -7, -8, -7, -8, -9, -10, -9, -10, -9, -8, -9, -8, -8, -7, -6, -5,
78
+ -6, -5, -4, -4, -5, -6, -5, -6, -7, -8, -7, -8, -7, -6, -7, -8, -7, -6,
79
+ -7, -8, -8, -7, -8, -7, -8, -9, -8, -9, -8, -9, -10, -10, -11, -11, -11,
80
+ -12, -13, -14, -15, -14, -15, -16, -15, -14, -13, -13, -14, -15, -16,
81
+ -15, -16, -17, -18, -19, -18, -18, -17, -18, -17, -18, -17, -18, -19,
82
+ -20, -21, -22, -22, -23, -22, -23, -22, -23, -24, -24, -25, -24, -23,
83
+ -23, -24, -25, -26, -27, -28, -29, -29, -30, -31, -32, -31, -30, -29,
84
+ -28, -29, -29, -27, -28, -29, -30, -31, -32, -33, -34, -35, -36, -37,
85
+ -37, -38, -39, -38, -37, -38, -39, -39, -38, -37, -36, -35, -34, -33,
86
+ -32, -33, -32, -33, -34, -33, -32, -32, -33, -34, -34, -35, -36, -37,
87
+ -36, -35, -36, -37, -38, -39, -40, -40, -39, -40, -40, -41, -42, -43,
88
+ -43, -43
89
+ ]}
90
+ ]
91
+
92
+ chart = SmartChart::Line.new(
93
+ :width => 600,
94
+ :height => 230,
95
+ :data => data,
96
+ :y_min => -50,
97
+ :y_max => 30,
98
+ :grid => {
99
+ :x => {:every => 30},
100
+ :y => {:every => 10},
101
+ :style => :dotted
102
+ },
103
+ :axis => {
104
+ :bottom => {
105
+ :labels => {
106
+ 15 => "Apr",
107
+ 45 => "May",
108
+ 75 => "Jun",
109
+ 105 => "Jul",
110
+ 135 => "Aug",
111
+ 165 => "Sep"
112
+ }
113
+ },
114
+ :left => {
115
+ :labels => {
116
+ -40 => "-40",
117
+ -30 => "-30",
118
+ -20 => "-20",
119
+ -10 => "-10",
120
+ 0 => "0",
121
+ 10 => "+10",
122
+ 20 => "+20"
123
+ }
124
+ }
125
+ }
126
+ )
127
+ puts chart.to_url
128
+
@@ -82,10 +82,10 @@ module SmartChart
82
82
  ##
83
83
  # Chart as an HTML tag.
84
84
  #
85
- def to_html(encode = true, validation = true)
86
- '<img src="%s" />' % to_url(encode, validation)
85
+ def to_html(encode = true, validation = true, attributes = {})
86
+ '<img src="%s"%s />' % [to_url(encode, validation), tag_attributes(attributes)]
87
87
  end
88
-
88
+
89
89
  ##
90
90
  # Run validation (may raise exceptions).
91
91
  #
@@ -150,6 +150,22 @@ module SmartChart
150
150
  @y_max || data_values.flatten.compact.max
151
151
  end
152
152
 
153
+ ##
154
+ # Translate a number to a position on the x-axis (percentage). Numbers
155
+ # start at 0 so the maximum allowed number is sample size minus one.
156
+ #
157
+ def x_axis_position(num)
158
+ num.to_f * 100 / data_values_count.to_f
159
+ end
160
+
161
+ ##
162
+ # Translate a number to a position on the y-axis (percentage). Range
163
+ # of the axis is y_min to y_max.
164
+ #
165
+ def y_axis_position(num)
166
+ 100.0 * (num.to_f - y_min.to_f) / (y_max - y_min).to_f
167
+ end
168
+
153
169
  ##
154
170
  # Array of names of required attributes.
155
171
  #
@@ -266,11 +282,22 @@ module SmartChart
266
282
  raise ColorFormatError unless (c.nil? or c.match(/^[0-9A-Fa-f]{6}$/))
267
283
  end
268
284
 
285
+ ##
286
+ # Render attributes of an HTML tag.
287
+ #
288
+ def tag_attributes(attributes)
289
+ attrs = []
290
+ attributes.each_pair do |key, value|
291
+ attrs << %(#{key}="#{value.to_s.gsub('"', '\"')}") unless value.nil?
292
+ end
293
+ " #{attrs.sort * ' '}" unless attrs.empty?
294
+ end
295
+
269
296
 
270
297
  # --- URL parameter list and methods ------------------------------------
271
298
 
272
299
  ##
273
- # Array of names of all possible query string parameters in the order
300
+ # Array of universal query string parameters in the order
274
301
  # in which they are output (for easier testing).
275
302
  #
276
303
  def query_string_params
@@ -290,16 +317,15 @@ module SmartChart
290
317
  :chxr, # axis_range
291
318
  :chma, # margins
292
319
 
293
- :chbh, # bar_spacing
294
320
  :chp, # bar_chart_zero_line, pie chart rotation
295
321
 
296
322
  :chm, # markers
297
323
 
298
324
  :chtt, # title
299
325
  :chdl, # legend
300
- :chdlp, # legend_position
326
+ :chdlp # legend_position
301
327
 
302
- :chds # data_scaling -- never used
328
+ #:chds # data_scaling -- never used
303
329
  ]
304
330
  end
305
331
 
@@ -419,10 +445,5 @@ module SmartChart
419
445
  def chdlp
420
446
  nil
421
447
  end
422
-
423
- # chds -- never used
424
- def chds
425
- nil
426
- end
427
448
  end
428
449
  end
@@ -1,7 +1,16 @@
1
1
  module SmartChart
2
2
  class Bar < MultipleDataSetChart
3
- include GridLines
4
3
 
4
+ # bar width (in pixels)
5
+ attr_accessor :bar_width
6
+
7
+ # space between bars (in pixels)
8
+ attr_accessor :bar_space
9
+
10
+ # space between bar groups (in pixels)
11
+ attr_accessor :bar_group_space
12
+
13
+
5
14
  private # ---------------------------------------------------------------
6
15
 
7
16
  ##
@@ -13,6 +22,46 @@ module SmartChart
13
22
  (style == :stacked ? "s" : "g")
14
23
  end
15
24
 
25
+ ##
26
+ # Google's default bar width.
27
+ #
28
+ def default_bar_width
29
+ 23
30
+ end
31
+
32
+ ##
33
+ # Google's default bar width.
34
+ #
35
+ def default_bar_space
36
+ 8
37
+ end
38
+
39
+ ##
40
+ # Google's default bar width.
41
+ #
42
+ def default_bar_group_space
43
+ 8
44
+ end
45
+
46
+ ##
47
+ # Array of all possible query string parameters.
48
+ #
49
+ def query_string_params
50
+ super + [:chbh]
51
+ end
52
+
53
+ # bar width and spacing
54
+ def chbh
55
+ # use bar_space default for group default if only one data set
56
+ group_default = data_values.size == 1 ?
57
+ bar_space : default_bar_group_space
58
+ [
59
+ bar_width || default_bar_width,
60
+ bar_space || default_bar_space,
61
+ bar_group_space || group_default
62
+ ].map{ |i| i.to_s }.join(',')
63
+ end
64
+
16
65
  # zero line
17
66
  def chp
18
67
  end
@@ -1,15 +1,14 @@
1
1
  module SmartChart
2
2
  class Line < MultipleDataSetChart
3
- include GridLines
4
-
5
3
 
6
4
  private # ---------------------------------------------------------------
7
5
 
8
6
  ##
9
- # Specify the Google Chart type.
7
+ # Specify the Google Chart type. Should be "lc" unless axes are
8
+ # explicitly hidden, then "ls".
10
9
  #
11
10
  def type
12
- "lc"
11
+ show_axes?? "lc" : "ls"
13
12
  end
14
13
 
15
14
  ##
@@ -1,6 +1,5 @@
1
1
  module SmartChart
2
2
  class Radar < MultipleDataSetChart
3
- include GridLines
4
3
 
5
4
  private # ---------------------------------------------------------------
6
5
 
@@ -1,6 +1,5 @@
1
1
  module SmartChart
2
2
  class Scatter < MultipleDataSetChart
3
- include GridLines
4
3
 
5
4
  private # ---------------------------------------------------------------
6
5
 
@@ -22,6 +22,9 @@ module SmartChart
22
22
  class ValidationError < SmartChartError #:nodoc:
23
23
  end
24
24
 
25
+ class LineStyleNameError < ValidationError #:nodoc:
26
+ end
27
+
25
28
  class MissingRequiredAttributeError < ValidationError #:nodoc:
26
29
  def initialize(chart, param)
27
30
  chart_type = chart.class.to_s.sub(/^SmartChart::/, "")
@@ -0,0 +1,115 @@
1
+ module SmartChart
2
+ module Axes
3
+
4
+ def self.included(base)
5
+ base.class_eval do
6
+
7
+ # grid axis style
8
+ attr_accessor :axis
9
+
10
+ # grid axis labels
11
+ attr_accessor :labels
12
+ end
13
+ end
14
+
15
+
16
+ private # ---------------------------------------------------------------
17
+
18
+ ##
19
+ # Labels parameter.
20
+ #
21
+ def chdl
22
+ unless bare_data_set?
23
+ labels = data.map{ |d| d.is_a?(Hash) ? d[:label] : nil }
24
+ labels.compact.size > 0 ? labels.join("|") : nil
25
+ end
26
+ end
27
+
28
+ ##
29
+ # Axis type parameter.
30
+ #
31
+ def chxt
32
+ return nil unless show_axes?
33
+ values = {
34
+ :left => "y",
35
+ :right => "r",
36
+ :top => "t",
37
+ :bottom => "x"
38
+ }
39
+ axis.keys.map{ |i| values[i] }.join(',')
40
+ end
41
+
42
+ ##
43
+ # Axis style parameter.
44
+ #
45
+ def chxs
46
+ return nil unless show_axes?
47
+ data = []
48
+ axis.values.each_with_index do |side,i|
49
+ data << [
50
+ i + 1, # index
51
+ side[:color], # color
52
+ side[:font_size], # font size
53
+ alignment(side[:text_align]), # alignment
54
+ (side[:color] ? "l" : "") +
55
+ (side[:ticks] ? "t" : ""), # drawing control
56
+ side[:ticks] # tick mark color
57
+ ].map{ |i| i.to_s }
58
+ end
59
+ out = data.map{ |i| i.join(',') }.join("|")
60
+ out == "" ? nil : out
61
+ end
62
+
63
+ ##
64
+ # Axis label text parameter.
65
+ #
66
+ def chxl
67
+ return nil unless show_axes?
68
+ labels = []
69
+ axis.values.each_with_index do |a,i|
70
+ a[:labels].each do |pos,text|
71
+ labels[i] ||= "#{i}:"
72
+ labels[i] << "|" + text
73
+ end
74
+ end
75
+ labels.join('|')
76
+ end
77
+
78
+ ##
79
+ # Axis label positions parameter.
80
+ #
81
+ def chxp
82
+ return nil unless show_axes?
83
+ labels = []
84
+ axis.values.each_with_index do |a,i|
85
+ a[:labels].each do |pos,text|
86
+ # figure out whether are we on a vertical or horizontal axis
87
+ dir = [:left, :right].include?(axis.keys[i]) ? "y" : "x"
88
+ p = eval("#{dir}_axis_position(pos)")
89
+ labels[i] ||= i.to_s
90
+ labels[i] << "," + SmartChart.decimal_string(p)
91
+ end
92
+ end
93
+ labels.join('|')
94
+ end
95
+
96
+ ##
97
+ # Translate an alignment name into a URL parameter value.
98
+ #
99
+ def alignment(name)
100
+ {
101
+ "left" => -1,
102
+ "center" => 0,
103
+ "right" => 1
104
+ }[name.to_s]
105
+ end
106
+
107
+ ##
108
+ # Should axes be omitted?
109
+ #
110
+ def show_axes?
111
+ axis.is_a?(Hash) and axis.keys.size > 0 and
112
+ axis.values.reject{ |i| i.nil? or i == {} }.size > 0
113
+ end
114
+ end
115
+ end
@@ -1,8 +1,23 @@
1
1
  module SmartChart
2
2
  class MultipleDataSetChart < BaseChart
3
- include Labels
4
- include AxisLines
3
+ include GridLines
4
+ include Axes
5
5
 
6
+ ##
7
+ # Hash mapping line style names to two-element arrays. This is a class
8
+ # method so exceptions can access it to print a list of valid style names.
9
+ #
10
+ def self.line_styles(thickness = 1)
11
+ {
12
+ :solid => [thickness * 1, thickness * 0],
13
+ :dotted => [thickness * 1, thickness * 2],
14
+ :short => [thickness * 2, thickness * 4],
15
+ :dashed => [thickness * 4, thickness * 4],
16
+ :long => [thickness * 6, thickness * 4]
17
+ }
18
+ end
19
+
20
+
6
21
  private # ---------------------------------------------------------------
7
22
 
8
23
  ##
@@ -23,6 +38,13 @@ module SmartChart
23
38
  super + [:chls]
24
39
  end
25
40
 
41
+ ##
42
+ # Default line style provided by Google if no chls parameter is given.
43
+ #
44
+ def default_line_style
45
+ [1.5, 1, 0]
46
+ end
47
+
26
48
  ##
27
49
  # Line style parameter.
28
50
  #
@@ -33,50 +55,38 @@ module SmartChart
33
55
  if set.is_a?(Hash)
34
56
  line_style_to_array(set)
35
57
  else
36
- [1, 1, 0]
58
+ default_line_style
37
59
  end
38
60
  end
39
61
  # only return non-nil if styles other than default are given
40
- if lines.map{ |l| l == [1,1,0] ? nil : 1 }.compact.size > 0
62
+ if lines.map{ |l| l == default_line_style ? nil : 1 }.compact.size > 0
41
63
  lines.map{ |s| s.join(",") }.join("|")
42
64
  end
43
65
  end
44
66
 
45
67
  ##
46
- # Translate a line style to a three-element array:
47
- #
48
- # [thickness, solid, blank]
49
- #
50
- # Takes a hash or a symbol (shortcut for a pre-defined look).
68
+ # Build a three-element array describing a line style:
69
+ #
70
+ # [thickness, solid_segment_length, blank_segment_length]
71
+ #
72
+ # Takes a data set hash or a symbol (shortcut for a pre-defined look).
51
73
  #
52
74
  def line_style_to_array(data)
53
- return [1, 1, 0] if data.nil?
54
- thickness = data[:thickness] || 1
75
+ return default_line_style if data.nil?
76
+ thickness = data[:thickness] || default_line_style.first
55
77
  style = data[:style]
56
78
  style_arr = style.is_a?(Hash) ? [style[:solid], style[:blank]] :
57
- line_style_definition(style, thickness)
79
+ line_style_definition(style, thickness)
58
80
  [thickness] + style_arr
59
81
  end
60
82
 
61
83
  ##
62
- # Translate a symbol into a line style: a two-element array (solid line
63
- # length, blank line length). Takes a style name and line thickness.
84
+ # Translate a line style name (symbol) into a line style array
85
+ # (two integers: solid segment length, blank segment length).
86
+ # Takes a style name and line thickness.
64
87
  #
65
88
  def line_style_definition(symbol, thickness = 1)
66
- self.class.line_styles(thickness)[symbol] || [1, 0]
67
- end
68
-
69
- ##
70
- # Get a hash of line style definitions.
71
- #
72
- def self.line_styles(thickness = 1)
73
- {
74
- :solid => [thickness * 1, thickness * 0],
75
- :dotted => [thickness * 1, thickness * 1],
76
- :short => [thickness * 2, thickness * 4],
77
- :dashed => [thickness * 4, thickness * 4],
78
- :long => [thickness * 6, thickness * 4]
79
- }
89
+ self.class.line_styles(thickness)[symbol] || default_line_style[1..2]
80
90
  end
81
91
 
82
92
  ##
@@ -107,22 +117,19 @@ module SmartChart
107
117
  end
108
118
  end
109
119
 
120
+ ##
121
+ # Make sure line style names are real.
122
+ #
110
123
  def validate_line_style_names
111
124
  data.each do |d|
112
- if d.is_a?(Hash) and d.is_a?(Hash)
113
- if (style = d[:style]).is_a?(Symbol)
114
- unless self.class.line_styles.keys.include?(style)
115
- raise LineStyleNameError,
116
- "Line style name '#{style}' is not valid. " +
117
- "Try one of: #{self.class.line_styles.keys.join(', ')}"
118
- end
125
+ if d.is_a?(Hash) and (style = d[:style]).is_a?(Symbol)
126
+ unless self.class.line_styles.keys.include?(style)
127
+ raise LineStyleNameError,
128
+ "Line style name '#{style}' is not valid. " +
129
+ "Try one of: #{self.class.line_styles.keys.join(', ')}"
119
130
  end
120
131
  end
121
132
  end
122
133
  end
123
134
  end
124
-
125
-
126
- class LineStyleNameError < ValidationError #:nodoc:
127
- end
128
135
  end
data/lib/smart_chart.rb CHANGED
@@ -8,9 +8,8 @@ require 'encoder'
8
8
  require 'exceptions'
9
9
 
10
10
  # features
11
- require 'features/axis_lines'
11
+ require 'features/axes'
12
12
  require 'features/grid_lines'
13
- require 'features/labels'
14
13
 
15
14
  # chart parents
16
15
  require 'base_chart'
@@ -0,0 +1,73 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{smart_chart}
8
+ s.version = "0.0.9"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Alex Reisner"]
12
+ s.date = %q{2009-12-14}
13
+ s.description = %q{Easily create charts and graphs for the web (uses Google Charts).}
14
+ s.email = %q{alex@alexreisner.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "CHANGELOG.rdoc",
23
+ "LICENSE",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "examples/bar_chart_sparkline.rb",
28
+ "examples/line_graph_pennant_race.rb",
29
+ "lib/smart_chart.rb",
30
+ "lib/smart_chart/base_chart.rb",
31
+ "lib/smart_chart/charts/bar.rb",
32
+ "lib/smart_chart/charts/line.rb",
33
+ "lib/smart_chart/charts/map.rb",
34
+ "lib/smart_chart/charts/meter.rb",
35
+ "lib/smart_chart/charts/pie.rb",
36
+ "lib/smart_chart/charts/qr_code.rb",
37
+ "lib/smart_chart/charts/radar.rb",
38
+ "lib/smart_chart/charts/scatter.rb",
39
+ "lib/smart_chart/charts/venn.rb",
40
+ "lib/smart_chart/data_set.rb",
41
+ "lib/smart_chart/encoder.rb",
42
+ "lib/smart_chart/exceptions.rb",
43
+ "lib/smart_chart/features/axes.rb",
44
+ "lib/smart_chart/features/grid_lines.rb",
45
+ "lib/smart_chart/multiple_data_set_chart.rb",
46
+ "lib/smart_chart/single_data_set_chart.rb",
47
+ "smart_chart.gemspec",
48
+ "test/smart_charts_test.rb",
49
+ "test/test_helper.rb"
50
+ ]
51
+ s.homepage = %q{http://github.com/alexreisner/smart_chart}
52
+ s.rdoc_options = ["--charset=UTF-8"]
53
+ s.require_paths = ["lib"]
54
+ s.rubygems_version = %q{1.3.5}
55
+ s.summary = %q{Easily create charts and graphs for the web (uses Google Charts).}
56
+ s.test_files = [
57
+ "test/smart_charts_test.rb",
58
+ "test/test_helper.rb",
59
+ "examples/line_graph_pennant_race.rb",
60
+ "examples/bar_chart_sparkline.rb"
61
+ ]
62
+
63
+ if s.respond_to? :specification_version then
64
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
65
+ s.specification_version = 3
66
+
67
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
68
+ else
69
+ end
70
+ else
71
+ end
72
+ end
73
+
@@ -72,11 +72,11 @@ class SmartChartTest < Test::Unit::TestCase
72
72
  # apply default line style automatically
73
73
  c.data[1][:thickness] = nil
74
74
  c.data[1][:style] = nil
75
- assert_equal "4,3,2|1,1,0", c.send(:chls).to_s
75
+ assert_equal "4,3,2|1.5,1,0", c.send(:chls).to_s
76
76
 
77
77
  # apply line style by name
78
78
  c.data[0][:style] = :dotted
79
- assert_equal "4,4,4|1,1,0", c.send(:chls).to_s
79
+ assert_equal "4,4,8|1.5,1,0", c.send(:chls).to_s
80
80
 
81
81
  # raise exception on invalid style name
82
82
  assert_raise(SmartChart::LineStyleNameError) do
@@ -102,36 +102,51 @@ class SmartChartTest < Test::Unit::TestCase
102
102
  :style => :dotted
103
103
  }
104
104
  )
105
- assert_equal "25,50,1,1,12.5,25", c.send(:chg).to_s
105
+ assert_equal "25,50,1.5,3.0,12.5,25", c.send(:chg).to_s
106
106
 
107
107
  # test x/y-step decimal points
108
108
  c.data = [0, 2, 3, 4, 5, 6]
109
- assert_equal "33.333,66.667,1,1,16.667,33.333", c.send(:chg).to_s
109
+ assert_equal "33.333,66.667,1.5,3.0,16.667,33.333", c.send(:chg).to_s
110
110
  end
111
111
 
112
112
 
113
- # --- axis lines ----------------------------------------------------------
113
+ # --- axes ----------------------------------------------------------------
114
114
 
115
115
  def test_axis_lines
116
116
  c = line_graph(
117
117
  :data => [0, 2, 3, 4, 5, 6, 7, 8],
118
- :axis => {
119
- :color => "AABBCC",
120
- :style => :dotted
121
- }
118
+ :axis => {}
122
119
  )
123
- assert_nil c.send(:chxt)
124
- assert_equal "???", c.send(:chxs).to_s
125
-
126
- # test axis side specification
127
- c.axis[:sides] = [:left, :bottom, :right]
128
- assert_equal "???", c.send(:chxt).to_s
129
-
130
- # test no axis specification
131
- c.axis[:sides] = []
132
120
  assert_equal "ls", c.send(:cht).to_s
133
121
  assert_nil c.send(:chxt)
134
- assert_nil c.send(:chxs)
122
+ assert_equal "", c.send(:chxs).to_s
123
+
124
+ # test with bottom axis
125
+ c.axis[:bottom] = {
126
+ :color => "aabbcc"
127
+ }
128
+ assert_equal "lc", c.send(:cht).to_s
129
+ assert_equal "x", c.send(:chxt).to_s
130
+ assert_equal "1,aabbcc,,,l,", c.send(:chxs)
131
+ end
132
+
133
+ def test_complex_axis_configuration
134
+ c = line_graph(
135
+ :data => [0, 2, 3, 4, 5, 6, 7, 8],
136
+ :axis => {
137
+ :bottom => {
138
+ :color => "999999",
139
+ :ticks => "888888",
140
+ :font_size => 12,
141
+ :text_align => :left
142
+ },
143
+ :left => {
144
+ :color => "666666"
145
+ }
146
+ }
147
+ )
148
+ assert_equal "x,y", c.send(:chxt).to_s
149
+ assert_equal "1,999999,12,-1,lt,888888|2,666666,,,l,", c.send(:chxs)
135
150
  end
136
151
 
137
152
 
@@ -274,6 +289,15 @@ class SmartChartTest < Test::Unit::TestCase
274
289
  end
275
290
 
276
291
 
292
+ # --- html ----------------------------------------------------------------
293
+
294
+ def test_tag_attributes
295
+ c = map_chart
296
+ tag = c.to_html(true, true, :style => "display:none;")
297
+ assert tag.match(/<img.*style="display:none;".*\/>/)
298
+ end
299
+
300
+
277
301
  # --- encoding ------------------------------------------------------------
278
302
 
279
303
  def test_simple_encoding
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_chart
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Reisner
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-29 00:00:00 -04:00
12
+ date: 2009-12-14 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -25,9 +25,13 @@ extra_rdoc_files:
25
25
  files:
26
26
  - .document
27
27
  - .gitignore
28
+ - CHANGELOG.rdoc
28
29
  - LICENSE
29
30
  - README.rdoc
30
31
  - Rakefile
32
+ - VERSION
33
+ - examples/bar_chart_sparkline.rb
34
+ - examples/line_graph_pennant_race.rb
31
35
  - lib/smart_chart.rb
32
36
  - lib/smart_chart/base_chart.rb
33
37
  - lib/smart_chart/charts/bar.rb
@@ -42,11 +46,11 @@ files:
42
46
  - lib/smart_chart/data_set.rb
43
47
  - lib/smart_chart/encoder.rb
44
48
  - lib/smart_chart/exceptions.rb
45
- - lib/smart_chart/features/axis_lines.rb
49
+ - lib/smart_chart/features/axes.rb
46
50
  - lib/smart_chart/features/grid_lines.rb
47
- - lib/smart_chart/features/labels.rb
48
51
  - lib/smart_chart/multiple_data_set_chart.rb
49
52
  - lib/smart_chart/single_data_set_chart.rb
53
+ - smart_chart.gemspec
50
54
  - test/smart_charts_test.rb
51
55
  - test/test_helper.rb
52
56
  has_rdoc: true
@@ -80,3 +84,5 @@ summary: Easily create charts and graphs for the web (uses Google Charts).
80
84
  test_files:
81
85
  - test/smart_charts_test.rb
82
86
  - test/test_helper.rb
87
+ - examples/line_graph_pennant_race.rb
88
+ - examples/bar_chart_sparkline.rb
@@ -1,29 +0,0 @@
1
- module SmartChart
2
- module AxisLines
3
-
4
- def self.included(base)
5
- base.class_eval do
6
- attr_accessor :axis
7
- end
8
- end
9
-
10
-
11
- private # ---------------------------------------------------------------
12
-
13
- ##
14
- # Axis type parameter.
15
- #
16
- def chxt
17
- #return nil unless (axis.is_a?(Hash) and (axis[:sides].is_a?(Array))
18
- "TODO"
19
- end
20
-
21
- ##
22
- # Axis style parameter.
23
- #
24
- def chxs
25
- #return nil unless (axis.is_a?(Hash) and (axis[:color] or axis[:style]))
26
- "TODO"
27
- end
28
- end
29
- end
@@ -1,23 +0,0 @@
1
- module SmartChart
2
- module Labels
3
-
4
- def self.included(base)
5
- base.class_eval do
6
- attr_accessor :labels
7
- end
8
- end
9
-
10
-
11
- private # ---------------------------------------------------------------
12
-
13
- ##
14
- # Labels parameter.
15
- #
16
- def chdl
17
- unless bare_data_set?
18
- labels = data.map{ |d| d.is_a?(Hash) ? d[:label] : nil }
19
- labels.compact.size > 0 ? labels.join("|") : nil
20
- end
21
- end
22
- end
23
- end