smart_chart 0.0.1 → 0.0.9

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/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