svg-graph 2.0.2 → 2.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7101e9e0d576c758450907b8f9d30bf2b8c787ee
4
- data.tar.gz: c370f0c3b179587d0e4bf34d4862f4c1a0366dce
3
+ metadata.gz: 0cd53b929ddc82314e5a2f5905ee19e6945f4a7c
4
+ data.tar.gz: 95968148c4ec92b65c88f8dc1b0796fa95a645b7
5
5
  SHA512:
6
- metadata.gz: da39453fcbd961e3b8758da1b7a5ed49f9fa6142f598151de6625e7294ca3ffc2689aca19110841a6f598bf23305ab85daaf2f5b2d59a03f29b3204d96c2ecc2
7
- data.tar.gz: 58a9de11f45ce90ffbf7600b4d82a0b26b27f4b6598e016221bc838fa074cd7aaaecad537aa7cd69fbcae33d03f4c6da432883b890775dfd9db24900c1c39f3e
6
+ metadata.gz: d08b2f7ec8271044779fb858cb79262a1d8e69a86b76181c7dc4fa0b8c02aec6c5a2e248ab2b90d07774456dbc9e77754a50a62e944d313426678fc216af9dc2
7
+ data.tar.gz: c4ec0861d565c824cc5aed3ce3d4eef79ce85093a730e630fd4255b8797559825f6fb1dfd2e68ff47a267704bffc28eba45579e81089dd997ea695e3f4686500
@@ -2,6 +2,12 @@ TODO / Backlog
2
2
  * add unit tests for all types of graphs
3
3
  * refactor various hardcoded constant pixel offsets in Graph class to use named constants or variables
4
4
 
5
+ === 2.1.0 / 2017-02-12 [lumean]
6
+ * change behavior for number format, Strings axis labels will never be formatted
7
+ previously, when containing numbers they were formatted with the number_format template
8
+ * added options to change x-axis and y-axis position :x_axis_position and :y_axis_position
9
+ * x_guidelines and y_guidelines can now be drawn independently of show_x_labels and show_y_labels,
10
+ before they were only drawn if show_x_labels resp show_y_labels was true
5
11
 
6
12
  === 2.0.2 / 2016-10-24 [lumean]
7
13
  * fix axis-title positioning
@@ -24,7 +30,7 @@ TODO / Backlog
24
30
  * all ruby files in the test directory now run on ruby >2.0 and write output to files [lumean]
25
31
  * changed from autoload to static loading due to issues with unit-testing when the gem is not installed [lumean]
26
32
  * begin transition to minitest for tests [lumean]
27
- * merged fix for 100% pie graphs from https://github.com/endersstocker/svg-graph
33
+ * merged fix for 100% pie graphs from https://github.com/endersstocker/svg-graph
28
34
  * fix wrong margins for labels after merge of number formatting [lumean]
29
35
  * Add new option for locations for the axis titles (at the end of the axis instead of below / left from it) [lumean]
30
36
  * improved x-axis label location when x-axis marks are vertical and long [lumean]
@@ -46,5 +52,3 @@ TODO / Backlog
46
52
  * Max values and improved Time data handling.
47
53
  * Merge pull request #1 from thinkingbox/master
48
54
  * Adding scattered plot support with :show_lines =>false Rounding values to integers in popups can be disabled with :round_popups => false Optional description gets shown in popup
49
-
50
-
@@ -103,29 +103,29 @@ module SVG
103
103
 
104
104
  bar_width = fieldwidth - bargap
105
105
  bar_width /= @data.length if stack == :side
106
-
106
+
107
107
  bottom = @graph_height
108
108
 
109
109
  field_count = 0
110
110
  @config[:fields].each_index { |i|
111
111
  dataset_count = 0
112
112
  for dataset in @data
113
-
113
+
114
114
  # cases (assume 0 = +ve):
115
115
  # value min length
116
116
  # +ve +ve value - min
117
117
  # +ve -ve value - 0
118
118
  # -ve -ve value.abs - 0
119
-
119
+
120
120
  value = dataset[:data][i]/@y_scale_division
121
-
121
+
122
122
  left = (fieldwidth * field_count)
123
-
123
+
124
124
  length = (value.abs - (minvalue > 0 ? minvalue : 0)) * unit_size
125
125
  # top is 0 if value is negative
126
126
  top = bottom - (((value < 0 ? 0 : value) - minvalue) * unit_size)
127
127
  left += bar_width * dataset_count if stack == :side
128
-
128
+
129
129
  @graph.add_element( "rect", {
130
130
  "x" => left.to_s,
131
131
  "y" => top.to_s,
@@ -134,7 +134,8 @@ module SVG
134
134
  "class" => "fill#{dataset_count+1}"
135
135
  })
136
136
 
137
- make_datapoint_text(left + bar_width/2.0, top - font_size/2, dataset[:data][i].to_s)
137
+ make_datapoint_text(left + bar_width/2.0, top - font_size/2, dataset[:data][i])
138
+ # number format shall not apply to popup (use .to_s conversion)
138
139
  add_popup(left + bar_width/2.0, top , dataset[:data][i].to_s)
139
140
  dataset_count += 1
140
141
  end
@@ -4,43 +4,43 @@ require_relative 'BarBase'
4
4
  module SVG
5
5
  module Graph
6
6
  # === Create presentation quality SVG horitonzal bar graphs easily
7
- #
7
+ #
8
8
  # = Synopsis
9
- #
9
+ #
10
10
  # require 'SVG/Graph/BarHorizontal'
11
- #
11
+ #
12
12
  # fields = %w(Jan Feb Mar)
13
13
  # data_sales_02 = [12, 45, 21]
14
- #
14
+ #
15
15
  # graph = SVG::Graph::BarHorizontal.new({
16
16
  # :height => 500,
17
17
  # :width => 300,
18
18
  # :fields => fields,
19
19
  # })
20
- #
20
+ #
21
21
  # graph.add_data({
22
22
  # :data => data_sales_02,
23
23
  # :title => 'Sales 2002',
24
24
  # })
25
- #
25
+ #
26
26
  # print "Content-type: image/svg+xml\r\n\r\n"
27
27
  # print graph.burn
28
- #
28
+ #
29
29
  # = Description
30
- #
30
+ #
31
31
  # This object aims to allow you to easily create high quality
32
32
  # SVG horitonzal bar graphs. You can either use the default style sheet
33
33
  # or supply your own. Either way there are many options which can
34
34
  # be configured to give you control over how the graph is
35
35
  # generated - with or without a key, data elements at each point,
36
36
  # title, subtitle etc.
37
- #
37
+ #
38
38
  # = Examples
39
- #
39
+ #
40
40
  # * http://germane-software.com/repositories/public/SVG/test/test.rb
41
- #
41
+ #
42
42
  # = See also
43
- #
43
+ #
44
44
  # * SVG::Graph::Graph
45
45
  # * SVG::Graph::Bar
46
46
  # * SVG::Graph::Line
@@ -62,14 +62,14 @@ module SVG
62
62
  # [show_y_guidelines] false
63
63
  def set_defaults
64
64
  super
65
- init_with(
65
+ init_with(
66
66
  :rotate_y_labels => true,
67
67
  :show_x_guidelines => true,
68
68
  :show_y_guidelines => false
69
69
  )
70
70
  # self.right_align = self.right_font = 1
71
71
  end
72
-
72
+
73
73
  protected
74
74
 
75
75
  def get_x_labels
@@ -110,14 +110,14 @@ module SVG
110
110
  bar_height = fieldheight - bargap
111
111
  bar_height /= @data.length if stack == :side
112
112
  y_mod = (bar_height / 2) + (font_size / 2)
113
-
113
+
114
114
  field_count = 1
115
115
  @config[:fields].each_index { |i|
116
116
  dataset_count = 0
117
117
  for dataset in @data
118
118
  value = dataset[:data][i]
119
-
120
- top = @graph_height - (fieldheight * field_count)
119
+
120
+ top = @graph_height - (fieldheight * field_count) + bargap
121
121
  top += (bar_height * dataset_count) if stack == :side
122
122
  # cases (assume 0 = +ve):
123
123
  # value min length left
@@ -135,9 +135,8 @@ module SVG
135
135
  "class" => "fill#{dataset_count+1}"
136
136
  })
137
137
 
138
- make_datapoint_text(
139
- left+length+5, top+y_mod, dataset[:data][i].to_s, "text-anchor: start; "
140
- )
138
+ make_datapoint_text(left+length+5, top+y_mod, dataset[:data][i], "text-anchor: start; ")
139
+ # number format shall not apply to popup (use .to_s conversion)
141
140
  add_popup(left+length, top+y_mod , dataset[:data][i].to_s)
142
141
  dataset_count += 1
143
142
  end
@@ -13,14 +13,14 @@ module SVG
13
13
  # fields = %w(Jan Feb);
14
14
  # myarr1_mean = 10
15
15
  # myarr1_confidence = 1
16
- #
16
+ #
17
17
  # myarr2_mean = 20
18
18
  # myarr2_confidence = 2
19
- #
19
+ #
20
20
  # data= [myarr1_mean, myarr2_mean]
21
- #
21
+ #
22
22
  # err_mesure = [myarr1_confidence, myarr2_confidence]
23
- #
23
+ #
24
24
  # graph = SVG::Graph::ErrBar.new(
25
25
  # :height => 500,
26
26
  # :width => 600,
@@ -28,7 +28,7 @@ module SVG
28
28
  # :errorBars => err_mesure,
29
29
  # :scale_integers => true,
30
30
  # )
31
- #
31
+ #
32
32
  # graph.add_data(
33
33
  # :data => data,
34
34
  # :title => 'Sales 2002'
@@ -71,10 +71,10 @@ module SVG
71
71
  def initialize config
72
72
  raise "fields was not supplied or is empty" unless config[:errorBars] &&
73
73
  config[:errorBars].kind_of?(Array) &&
74
- config[:errorBars].length > 0
74
+ config[:errorBars].length > 0
75
75
  super
76
- end
77
- # Array of confidence values for each item in :fields. A range from
76
+ end
77
+ # Array of confidence values for each item in :fields. A range from
78
78
  # value[i]-errorBars[i] to value[i]+errorBars[i] is drawn into the graph.
79
79
  attr_accessor :errorBars
80
80
 
@@ -103,7 +103,7 @@ module SVG
103
103
  end
104
104
 
105
105
  rv = []
106
- maxvalue = maxvalue%@y_scale_division == 0 ?
106
+ maxvalue = maxvalue%@y_scale_division == 0 ?
107
107
  maxvalue : maxvalue + @y_scale_division
108
108
  minvalue.step( maxvalue, @y_scale_division ) {|v| rv << v}
109
109
  return rv
@@ -122,31 +122,31 @@ module SVG
122
122
 
123
123
  bar_width = fieldwidth - (bargap *2)
124
124
  bar_width /= @data.length if stack == :side
125
-
125
+
126
126
  bottom = @graph_height
127
127
 
128
128
  field_count = 0
129
129
  @config[:fields].each_index { |i|
130
130
  dataset_count = 0
131
131
  for dataset in @data
132
-
132
+
133
133
  # cases (assume 0 = +ve):
134
134
  # value min length
135
135
  # +ve +ve value - min
136
136
  # +ve -ve value - 0
137
137
  # -ve -ve value.abs - 0
138
-
138
+
139
139
  value = dataset[:data][i].to_f/@y_scale_division
140
-
140
+
141
141
  left = (fieldwidth * field_count)
142
142
  left += bargap
143
-
144
-
143
+
144
+
145
145
  length = (value.abs - (minvalue > 0 ? minvalue : 0)) * unit_size
146
146
  # top is 0 if value is negative
147
147
  top = bottom - (((value < 0 ? 0 : value) - minvalue) * unit_size)
148
148
  left += bar_width * dataset_count if stack == :side
149
-
149
+
150
150
  @graph.add_element( "rect", {
151
151
  "x" => left.to_s,
152
152
  "y" => top.to_s,
@@ -160,7 +160,7 @@ module SVG
160
160
  upperErr = top+threshold
161
161
  bottomErr = top-threshold
162
162
  withthErr = bar_width/4
163
-
163
+
164
164
  @graph.add_element( "line", {
165
165
  "x1" => middlePointErr.to_s,
166
166
  "y1" => upperErr.to_s,
@@ -168,7 +168,7 @@ module SVG
168
168
  "y2" => bottomErr.to_s,
169
169
  "style" => "stroke:rgb(0,0,0);stroke-width:1"
170
170
  })
171
-
171
+
172
172
  @graph.add_element( "line", {
173
173
  "x1" => (middlePointErr-withthErr).to_s,
174
174
  "y1" => upperErr.to_s,
@@ -183,15 +183,16 @@ module SVG
183
183
  "y2" => bottomErr.to_s,
184
184
  "style" => "stroke:rgb(0,0,0);stroke-width:1"
185
185
  })
186
-
187
- make_datapoint_text(left + bar_width/2.0, top - 6, dataset[:data][i].to_s)
186
+
187
+ make_datapoint_text(left + bar_width/2.0, top - 6, dataset[:data][i])
188
+ # number format shall not apply to popup (use .to_s conversion)
188
189
  add_popup(left + bar_width/2.0, top , dataset[:data][i].to_s)
189
190
  dataset_count += 1
190
191
  end
191
192
  field_count += 1
192
193
  } # config[:fields].each_index
193
194
  end # draw_data
194
-
195
+
195
196
  end # ErrBar
196
197
  end
197
198
  end
@@ -10,7 +10,7 @@ module SVG
10
10
  module Graph
11
11
 
12
12
  # === Base object for generating SVG Graphs
13
- #
13
+ #
14
14
  # == Synopsis
15
15
  #
16
16
  # This class is only used as a superclass of specialized charts. Do not
@@ -28,9 +28,9 @@ module SVG
28
28
  # * file:test/single.rb
29
29
  # * file:test/test.rb
30
30
  # * file:test/timeseries.rb
31
- #
31
+ #
32
32
  # == Description
33
- #
33
+ #
34
34
  # This package should be used as a base for creating SVG graphs.
35
35
  #
36
36
  # == Acknowledgements
@@ -39,7 +39,7 @@ module SVG
39
39
  # port is based on.
40
40
  #
41
41
  # Stephen Morgan for creating the TT template and SVG.
42
- #
42
+ #
43
43
  # == See
44
44
  #
45
45
  # * SVG::Graph::BarHorizontal
@@ -63,6 +63,8 @@ module SVG
63
63
  # instantiate this class directly; see the subclass for options.
64
64
  # [width] 500
65
65
  # [height] 300
66
+ # [x_axis_position] nil
67
+ # [y_axis_position] nil
66
68
  # [show_x_guidelines] false
67
69
  # [show_y_guidelines] true
68
70
  # [show_data_values] true
@@ -98,7 +100,7 @@ module SVG
98
100
  # [key_font_size] 10
99
101
  # [no_css] false
100
102
  # [add_popups] false
101
- # [number_format] '%.2f'
103
+ # [number_format] '%.2f'
102
104
  def initialize( config )
103
105
  @config = config
104
106
  @data = []
@@ -112,6 +114,9 @@ module SVG
112
114
  :show_y_guidelines => true,
113
115
  :show_data_values => true,
114
116
 
117
+ :x_axis_position => nil,
118
+ :y_axis_position => nil,
119
+
115
120
  :min_scale_value => nil,
116
121
 
117
122
  :show_x_labels => true,
@@ -138,7 +143,7 @@ module SVG
138
143
  :graph_title => 'Graph Title',
139
144
  :show_graph_subtitle => false,
140
145
  :graph_subtitle => 'Graph Sub Title',
141
- :key => true,
146
+ :key => true,
142
147
  :key_position => :right, # bottom or right
143
148
 
144
149
  :font_size =>12,
@@ -149,27 +154,27 @@ module SVG
149
154
  :x_title_font_size =>14,
150
155
  :y_title_font_size =>14,
151
156
  :key_font_size =>10,
152
-
157
+
153
158
  :no_css =>false,
154
159
  :add_popups =>false,
155
- :number_format => '%.2f'
160
+ :number_format => '%.2f'
156
161
  })
157
162
  set_defaults if self.respond_to? :set_defaults
158
163
  init_with config
159
164
  end
160
165
 
161
-
166
+
162
167
  # This method allows you do add data to the graph object.
163
168
  # It can be called several times to add more data sets in.
164
169
  #
165
170
  # data_sales_02 = [12, 45, 21];
166
- #
171
+ #
167
172
  # graph.add_data({
168
173
  # :data => data_sales_02,
169
174
  # :title => 'Sales 2002'
170
175
  # })
171
176
  def add_data conf
172
- @data = [] unless (defined? @data and !@data.nil?)
177
+ @data = [] unless (defined? @data and !@data.nil?)
173
178
 
174
179
  if conf[:data] and conf[:data].kind_of? Array
175
180
  @data << conf
@@ -183,7 +188,7 @@ module SVG
183
188
  # reuse it to create a new graph but with the same config options.
184
189
  #
185
190
  # graph.clear_data
186
- def clear_data
191
+ def clear_data
187
192
  @data = []
188
193
  end
189
194
 
@@ -193,12 +198,12 @@ module SVG
193
198
  #
194
199
  # This method will croak unless at least one data set has
195
200
  # been added to the graph object.
196
- #
201
+ #
197
202
  # print graph.burn
198
- #
203
+ #
199
204
  def burn
200
205
  raise "No data available" unless @data.size > 0
201
-
206
+
202
207
  start_svg
203
208
  calculate_graph_dimensions
204
209
  @foreground = Element.new( "g" )
@@ -223,14 +228,14 @@ module SVG
223
228
  data << "<!-- Ruby Zlib not available for SVGZ -->";
224
229
  end
225
230
  end
226
-
231
+
227
232
  return data
228
233
  end
229
-
230
- # Burns the graph but returns only the <svg> node as String without the
234
+
235
+ # Burns the graph but returns only the <svg> node as String without the
231
236
  # Doctype and XML Declaration. This allows easy integration into
232
237
  # existing xml documents.
233
- #
238
+ #
234
239
  # @return [String] the SVG node which represents the Graph
235
240
  def burn_svg_only
236
241
  # initialize all instance variables by burning the graph
@@ -260,6 +265,19 @@ module SVG
260
265
  attr_accessor :style_sheet
261
266
  # (Bool) Show the value of each element of data on the graph
262
267
  attr_accessor :show_data_values
268
+ # By default (nil/undefined) the x-axis is at the bottom of the graph.
269
+ # With this property a custom position for the x-axis can be defined.
270
+ # Valid values are between :min_scale_value and maximum value of the
271
+ # data.
272
+ # Default: nil
273
+ attr_accessor :x_axis_position
274
+ # By default (nil/undefined) the y-axis is the left border of the graph.
275
+ # With this property a custom position for the y-axis can be defined.
276
+ # Valid values are any values in the range of x-values (in case of a
277
+ # Plot) or any of the :fields values (in case of Line/Bar Graphs, note
278
+ # the '==' operator is used to find at which value to draw the axis).
279
+ # Default: nil
280
+ attr_accessor :y_axis_position
263
281
  # The point at which the Y axis starts, defaults to nil,
264
282
  # if set to nil it will default to the minimum data value.
265
283
  attr_accessor :min_scale_value
@@ -268,17 +286,17 @@ module SVG
268
286
  attr_accessor :show_x_labels
269
287
  # This puts the X labels at alternative levels so if they
270
288
  # are long field names they will not overlap so easily.
271
- # Default it false, to turn on set to true.
289
+ # Default is false, to turn on set to true.
272
290
  attr_accessor :stagger_x_labels
273
291
  # This puts the Y labels at alternative levels so if they
274
292
  # are long field names they will not overlap so easily.
275
- # Default it false, to turn on set to true.
293
+ # Default is false, to turn on set to true.
276
294
  attr_accessor :stagger_y_labels
277
295
  # This turns the X axis labels by 90 degrees.
278
- # Default it false, to turn on set to true.
296
+ # Default is false, to turn on set to true.
279
297
  attr_accessor :rotate_x_labels
280
298
  # This turns the Y axis labels by 90 degrees.
281
- # Default it true, to turn on set to false.
299
+ # Default is true, to turn on set to false.
282
300
  attr_accessor :rotate_y_labels
283
301
  # How many "steps" to use between displayed X axis labels,
284
302
  # a step of one means display every label, a step of two results
@@ -286,7 +304,7 @@ module SVG
286
304
  # a step of three results in every third label being displayed
287
305
  # (label <gap> <gap> label <gap> <gap> label) and so on.
288
306
  attr_accessor :step_x_labels
289
- # Whether to (when taking "steps" between X axis labels) step from
307
+ # Whether to (when taking "steps" between X axis labels) step from
290
308
  # the first label (i.e. always include the first label) or step from
291
309
  # the X axis origin (i.e. start with a gap if step_x_labels is greater
292
310
  # than one).
@@ -295,7 +313,7 @@ module SVG
295
313
  # to true, set to false if you want to turn them off.
296
314
  attr_accessor :show_y_labels
297
315
  # Ensures only whole numbers are used as the scale divisions.
298
- # Default it false, to turn on set to true. This has no effect if
316
+ # Default is false, to turn on set to true. This has no effect if
299
317
  # scale divisions are less than 1.
300
318
  attr_accessor :scale_integers
301
319
  # This defines the gap between markers on the Y axis,
@@ -315,7 +333,7 @@ module SVG
315
333
  # Whether to show the title under the Y axis labels,
316
334
  # default is false, set to true to show.
317
335
  attr_accessor :show_y_title
318
- # Aligns writing mode for Y axis label.
336
+ # Aligns writing mode for Y axis label.
319
337
  # Defaults to :bt (Bottom to Top).
320
338
  # Change to :tb (Top to Bottom) to reverse.
321
339
  attr_accessor :y_title_text_direction
@@ -383,7 +401,7 @@ module SVG
383
401
 
384
402
 
385
403
  protected
386
-
404
+
387
405
  # implementation of quicksort
388
406
  # used for Schedule and Plot
389
407
  def sort( *arrys )
@@ -411,7 +429,7 @@ module SVG
411
429
  # Check size of Y labels
412
430
  @border_left += max_y_label_width_px
413
431
  if (show_y_title && (y_title_location ==:middle))
414
- @border_left += y_title_font_size + 5
432
+ @border_left += y_title_font_size + 5
415
433
  end
416
434
  end
417
435
 
@@ -439,12 +457,12 @@ module SVG
439
457
  @border_right = 7
440
458
  if key and key_position == :right
441
459
  val = keys.max { |a,b| a.length <=> b.length }
442
- @border_right += val.length * key_font_size * 0.6
460
+ @border_right += val.length * key_font_size * 0.6
443
461
  @border_right += KEY_BOX_SIZE
444
462
  @border_right += 10 # Some padding around the box
445
463
  end
446
464
  if (x_title_location == :end)
447
- @border_right = [@border_right, x_title.length * x_title_font_size * 0.6].max
465
+ @border_right = [@border_right, x_title.length * x_title_font_size * 0.6].max
448
466
  end
449
467
  end
450
468
 
@@ -483,16 +501,16 @@ module SVG
483
501
  (x+txt_width > width ? "text-anchor: end;" : "text-anchor: start;")
484
502
  t.text = label.to_s
485
503
  t.attributes["id"] = t.object_id.to_s
486
-
504
+
487
505
  # add a circle to catch the mouseover
488
506
  @foreground.add_element( "circle", {
489
507
  "cx" => x.to_s,
490
508
  "cy" => y.to_s,
491
509
  "r" => "#{popup_radius}",
492
510
  "style" => "opacity: 0",
493
- "onmouseover" =>
511
+ "onmouseover" =>
494
512
  "document.getElementById(#{t.object_id}).setAttribute('visibility', 'visible' )",
495
- "onmouseout" =>
513
+ "onmouseout" =>
496
514
  "document.getElementById(#{t.object_id}).setAttribute('visibility', 'hidden' )",
497
515
  })
498
516
  end # if add_popups
@@ -501,16 +519,16 @@ module SVG
501
519
  # returns the longest label from an array of labels as string
502
520
  # each object in the array must support .to_s
503
521
  def get_longest_label(arry)
504
- longest_label = arry.max{|a,b|
522
+ longest_label = arry.max{|a,b|
505
523
  # respect number_format
506
- a = @number_format % a if numeric?(a)
524
+ a = @number_format % a if numeric?(a)
507
525
  b = @number_format % b if numeric?(b)
508
526
  a.to_s.length <=> b.to_s.length
509
527
  }
510
528
  longest_label = @number_format % longest_label if numeric?(longest_label)
511
529
  return longest_label
512
530
  end
513
-
531
+
514
532
  # Override this (and call super) to change the margin to the bottom
515
533
  # of the plot area. Results in @border_bottom being set.
516
534
  #
@@ -526,13 +544,13 @@ module SVG
526
544
  @border_bottom += x_title_font_size + 5
527
545
  end
528
546
  end
529
-
547
+
530
548
  # returns the maximum height of the labels respect the rotation or 0 if
531
549
  # the labels are not shown
532
550
  def max_x_label_height_px
533
551
  return 0 if !show_x_labels
534
-
535
- if rotate_x_labels
552
+
553
+ if rotate_x_labels
536
554
  max_height = get_longest_label(get_x_labels).to_s.length * x_label_font_size * 0.6
537
555
  else
538
556
  max_height = x_label_font_size + 3
@@ -557,32 +575,92 @@ module SVG
557
575
  "class" => "graphBackground"
558
576
  })
559
577
 
560
- # Axis
578
+ draw_x_axis
579
+ draw_y_axis
580
+
581
+ draw_x_labels
582
+ draw_y_labels
583
+ end
584
+
585
+ # draws the x-axis; can be overridden by child classes
586
+ def draw_x_axis
587
+ # relative position on y-axis (hence @graph_height is our axis length)
588
+ relative_position = calculate_rel_position(get_y_labels, field_height, @x_axis_position, @graph_height)
589
+ # X-Axis
590
+ y_offset = (1 - relative_position) * @graph_height
561
591
  @graph.add_element( "path", {
562
- "d" => "M 0 0 v#@graph_height",
592
+ "d" => "M 0 #{y_offset} h#@graph_width",
563
593
  "class" => "axis",
564
- "id" => "xAxis"
594
+ "id" => "yAxis"
565
595
  })
596
+ end
597
+
598
+ # draws the y-axis; can be overridden by child classes
599
+ def draw_y_axis
600
+ # relative position on x-axis (hence @graph_width is our axis length)
601
+ relative_position = calculate_rel_position(get_x_labels, field_width, @y_axis_position, @graph_width)
602
+ # Y-Axis
603
+ x_offset = relative_position * @graph_width
566
604
  @graph.add_element( "path", {
567
- "d" => "M 0 #@graph_height h#@graph_width",
605
+ "d" => "M #{x_offset} 0 v#@graph_height",
568
606
  "class" => "axis",
569
- "id" => "yAxis"
607
+ "id" => "xAxis"
570
608
  })
571
-
572
- draw_x_labels
573
- draw_y_labels
574
609
  end
575
610
 
611
+ # calculates the relative position betewen 0 and 1 of a value on the axis
612
+ # can be multiplied with either @graph_height or @graph_width to get the
613
+ # absolute position in pixels.
614
+ # If labels are strings, checks if one of label matches with the value
615
+ # and returns this position.
616
+ # If labels are numeric, compute relative position between first and last value
617
+ # If nothing else applies or the value is nil, the relative position is 0
618
+ # @param labels [Array] the array of x or y labels, see {#get_x_labels} or {#get_y_labels}
619
+ # @param segment_px [Float] number of pixels per label, see {#field_width} or {#field_height}
620
+ # @param value [Numeric, String] the value for which the relative position is computed
621
+ # @param axis_length [Numeric] either @graph_width or @graph_height
622
+ # @return [Float] relative position between 0 and 1, returns 0
623
+ def calculate_rel_position(labels, segment_px, value, axis_length)
624
+ # default value, y-axis on the left side, or x-axis at bottom
625
+ # puts "calculate_rel_position:"
626
+ # p labels
627
+ # p segment_px
628
+ # p value
629
+ # p axis_length
630
+ relative_position = 0
631
+ if !value.nil? # only
632
+ if (labels[0].is_a? Numeric) && (labels[-1].is_a? Numeric) && (value.is_a? Numeric)
633
+ # labels are numeric, compute relative position between first and last value
634
+ range = labels[-1] - labels[0]
635
+ position = value - labels[0]
636
+ # compute how many segments long the offset is
637
+ relative_to_segemts = position/range * (labels.size - 1)
638
+ # convert from segments to relative position on the axis axis,
639
+ # the number of segments (i.e. relative_to_segemts >= 1)
640
+ relative_position = relative_to_segemts * segment_px / axis_length
641
+ elsif labels[0].is_a? String
642
+ # labels are strings, see if one of label matches with the position
643
+ # and place the axis there
644
+ index = labels.index(value)
645
+ if !index.nil? # index would be nil if label is not found
646
+ offset_px = segment_px * index
647
+ relative_position = offset_px/axis_length # between 0 and 1
648
+ end
649
+ end
650
+ end # value.nil?
651
+ return relative_position
652
+ end
576
653
 
577
654
  # Where in the X area the label is drawn
578
655
  # Centered in the field, should be width/2. Start, 0.
579
656
  def x_label_offset( width )
580
657
  0
581
658
  end
582
-
659
+
583
660
  # check if an object can be converted to float
584
661
  def numeric?(object)
585
- true if Float(object) rescue false
662
+ # true if Float(object) rescue false
663
+ object.is_a? Numeric
586
664
  end
587
665
 
588
666
  # adds the datapoint text to the graph only if the config option is set
@@ -604,7 +682,7 @@ module SVG
604
682
  "y" => y.to_s,
605
683
  "class" => "dataPointLabel",
606
684
  "style" => "#{style} stroke: #fff; stroke-width: 2;"
607
- }).text = textStr
685
+ }).text = textStr
608
686
  # actual label
609
687
  text = @foreground.add_element( "text", {
610
688
  "x" => x.to_s,
@@ -615,60 +693,60 @@ module SVG
615
693
  text.attributes["style"] = style if style.length > 0
616
694
  end
617
695
  end
618
-
619
696
 
620
- # Draws the X axis labels
697
+
698
+ # Draws the X axis labels. The x-axis (@graph_width) is diveded into
699
+ # {#get_x_labels.length} equal sections. The (center) x-coordinate for a
700
+ # label hence is label_index * width_of_section
621
701
  def draw_x_labels
622
702
  stagger = x_label_font_size + 5
623
- if show_x_labels
624
- label_width = field_width
703
+ label_width = field_width
704
+ count = 0
705
+ x_axis_already_drawn = false
706
+ for label in get_x_labels
707
+ if step_include_first_x_label == true then
708
+ step = count % step_x_labels
709
+ else
710
+ step = (count + 1) % step_x_labels
711
+ end
712
+ # only draw every n-th label as defined by step_x_labels
713
+ if step == 0 && show_x_labels then
714
+ textStr = label.to_s
715
+ if( numeric?(label) )
716
+ textStr = @number_format % label
717
+ end
718
+ text = @graph.add_element( "text" )
719
+ text.attributes["class"] = "xAxisLabels"
720
+ text.text = textStr
625
721
 
626
- count = 0
627
- for label in get_x_labels
628
- if step_include_first_x_label == true then
629
- step = count % step_x_labels
630
- else
631
- step = (count + 1) % step_x_labels
722
+ x = count * label_width + x_label_offset( label_width )
723
+ y = @graph_height + x_label_font_size + 3
724
+ #t = 0 - (font_size / 2)
725
+
726
+ if stagger_x_labels and count % 2 == 1
727
+ y += stagger
728
+ @graph.add_element( "path", {
729
+ "d" => "M#{x} #@graph_height v#{stagger}",
730
+ "class" => "staggerGuideLine"
731
+ })
632
732
  end
633
733
 
634
- if step == 0 then
635
- label = label.to_s
636
- if( numeric?(label) )
637
- label = @number_format % label
638
- end
639
- text = @graph.add_element( "text" )
640
- text.attributes["class"] = "xAxisLabels"
641
- text.text = label.to_s
642
-
643
- x = count * label_width + x_label_offset( label_width )
644
- y = @graph_height + x_label_font_size + 3
645
- #t = 0 - (font_size / 2)
646
-
647
- if stagger_x_labels and count % 2 == 1
648
- y += stagger
649
- @graph.add_element( "path", {
650
- "d" => "M#{x} #@graph_height v#{stagger}",
651
- "class" => "staggerGuideLine"
652
- })
653
- end
654
-
655
- text.attributes["x"] = x.to_s
656
- text.attributes["y"] = y.to_s
657
- if rotate_x_labels
658
- text.attributes["transform"] =
659
- "rotate( 90 #{x} #{y-x_label_font_size} )"+
660
- " translate( 0 -#{x_label_font_size/4} )"
661
- text.attributes["style"] = "text-anchor: start"
662
- else
663
- text.attributes["style"] = "text-anchor: middle"
664
- end
734
+ text.attributes["x"] = x.to_s
735
+ text.attributes["y"] = y.to_s
736
+ if rotate_x_labels
737
+ text.attributes["transform"] =
738
+ "rotate( 90 #{x} #{y-x_label_font_size} )"+
739
+ " translate( 0 -#{x_label_font_size/4} )"
740
+ text.attributes["style"] = "text-anchor: start"
741
+ else
742
+ text.attributes["style"] = "text-anchor: middle"
665
743
  end
744
+ end # if step == 0 && show_x_labels
666
745
 
667
- draw_x_guidelines( label_width, count ) if show_x_guidelines
668
- count += 1
669
- end
670
- end
671
- end
746
+ draw_x_guidelines( label_width, count ) if show_x_guidelines
747
+ count += 1
748
+ end # for label in get_x_labels
749
+ end # draw_x_labels
672
750
 
673
751
 
674
752
  # Where in the Y area the label is drawn
@@ -681,17 +759,17 @@ module SVG
681
759
  # must return the array of labels for the x-axis
682
760
  def get_x_labels
683
761
  end
684
-
762
+
685
763
  # override this method in child class
686
764
  # must return the array of labels for the y-axis
687
765
  # this method defines @y_scale_division
688
766
  def get_y_labels
689
767
  end
690
-
768
+
691
769
  # space in px between x-labels
692
770
  def field_width
693
771
  # -1 is to use entire x-axis
694
- # otherwise there is always 1 division unused
772
+ # otherwise there is always 1 division unused
695
773
  @graph_width.to_f / ( get_x_labels.length - 1 )
696
774
  end
697
775
 
@@ -704,21 +782,20 @@ module SVG
704
782
 
705
783
 
706
784
  # Draws the Y axis labels, the Y-Axis (@graph_height) is divided equally into #get_y_labels.lenght sections
707
- # So the y coordinate for an arbitrary value is calculated as follows:
785
+ # So the y coordinate for an arbitrary value is calculated as follows:
708
786
  # y = @graph_height equals the min_value
709
- # #normalize value of a single scale_division:
710
- # count = value /(@y_scale_division)
711
- # y = @graph_height - count * field_height
712
- #
787
+ # #normalize value of a single scale_division:
788
+ # count = value /(@y_scale_division)
789
+ # y = @graph_height - count * field_height
790
+ #
713
791
  def draw_y_labels
714
792
  stagger = y_label_font_size + 5
715
- if show_y_labels
716
- label_height = field_height
717
-
718
- count = 0
719
- y_offset = @graph_height + y_label_offset( label_height )
720
- y_offset += font_size/1.2 unless rotate_y_labels
721
- for label in get_y_labels
793
+ label_height = field_height
794
+ count = 0
795
+ y_offset = @graph_height + y_label_offset( label_height )
796
+ y_offset += font_size/1.2 unless rotate_y_labels
797
+ for label in get_y_labels
798
+ if show_y_labels
722
799
  y = y_offset - (label_height * count)
723
800
  x = rotate_y_labels ? 0 : -3
724
801
 
@@ -748,14 +825,14 @@ module SVG
748
825
  text.attributes["y"] = (y - (y_label_font_size/2)).to_s
749
826
  text.attributes["style"] = "text-anchor: end"
750
827
  end
751
- draw_y_guidelines( label_height, count ) if show_y_guidelines
752
- count += 1
753
- end
754
- end
755
- end
828
+ end # if show_y_labels
829
+ draw_y_guidelines( label_height, count ) if show_y_guidelines
830
+ count += 1
831
+ end # for label in get_y_labels
832
+ end # draw_y_labels
756
833
 
757
834
 
758
- # Draws the X axis guidelines
835
+ # Draws the X axis guidelines, parallel to the y-axis
759
836
  def draw_x_guidelines( label_height, count )
760
837
  if count != 0
761
838
  @graph.add_element( "path", {
@@ -766,7 +843,7 @@ module SVG
766
843
  end
767
844
 
768
845
 
769
- # Draws the Y axis guidelines
846
+ # Draws the Y axis guidelines, parallel to the x-axis
770
847
  def draw_y_guidelines( label_height, count )
771
848
  if count != 0
772
849
  @graph.add_element( "path", {
@@ -788,7 +865,7 @@ module SVG
788
865
  end
789
866
 
790
867
  if show_graph_subtitle
791
- y_subtitle = show_graph_title ?
868
+ y_subtitle = show_graph_title ?
792
869
  title_font_size + subtitle_font_size + 5 :
793
870
  subtitle_font_size
794
871
  @root.add_element("text", {
@@ -840,7 +917,7 @@ module SVG
840
917
  end
841
918
  end # draw_titles
842
919
 
843
- def keys
920
+ def keys
844
921
  i = 0
845
922
  return @data.collect{ |d| i+=1; d[:title] || "Serie #{i}" }
846
923
  end
@@ -893,7 +970,7 @@ module SVG
893
970
  sort_multiple(arrys, lo, p-1)
894
971
  sort_multiple(arrys, p+1, hi)
895
972
  end
896
- arrys
973
+ arrys
897
974
  end
898
975
 
899
976
  def partition( arrys, lo, hi )
@@ -955,11 +1032,11 @@ module SVG
955
1032
  def add_defs defs
956
1033
  end
957
1034
 
958
- # Creates the XML document and adds the root svg element with
1035
+ # Creates the XML document and adds the root svg element with
959
1036
  # the width, height and viewBox attributes already set.
960
- # The element is stored as @root.
1037
+ # The element is stored as @root.
961
1038
  #
962
- # In addition a rectangle background of the same size as the
1039
+ # In addition a rectangle background of the same size as the
963
1040
  # svg is added.
964
1041
  #
965
1042
  def start_svg
@@ -1096,7 +1173,7 @@ module SVG
1096
1173
  .staggerGuideLine{
1097
1174
  fill: none;
1098
1175
  stroke: #000000;
1099
- stroke-width: 0.5px;
1176
+ stroke-width: 0.5px;
1100
1177
  }
1101
1178
 
1102
1179
  #{get_css}
@@ -3,47 +3,47 @@ require_relative 'Graph'
3
3
  module SVG
4
4
  module Graph
5
5
  # === Create presentation quality SVG line graphs easily
6
- #
6
+ #
7
7
  # = Synopsis
8
- #
8
+ #
9
9
  # require 'SVG/Graph/Line'
10
- #
10
+ #
11
11
  # fields = %w(Jan Feb Mar);
12
12
  # data_sales_02 = [12, 45, 21]
13
13
  # data_sales_03 = [15, 30, 40]
14
- #
14
+ #
15
15
  # graph = SVG::Graph::Line.new({
16
16
  # :height => 500,
17
17
  # :width => 300,
18
18
  # :fields => fields,
19
19
  # })
20
- #
20
+ #
21
21
  # graph.add_data({
22
22
  # :data => data_sales_02,
23
23
  # :title => 'Sales 2002',
24
24
  # })
25
- #
25
+ #
26
26
  # graph.add_data({
27
27
  # :data => data_sales_03,
28
28
  # :title => 'Sales 2003',
29
29
  # })
30
- #
30
+ #
31
31
  # print "Content-type: image/svg+xml\r\n\r\n";
32
32
  # print graph.burn();
33
- #
33
+ #
34
34
  # = Description
35
- #
35
+ #
36
36
  # This object aims to allow you to easily create high quality
37
37
  # SVG line graphs. You can either use the default style sheet
38
38
  # or supply your own. Either way there are many options which can
39
39
  # be configured to give you control over how the graph is
40
40
  # generated - with or without a key, data elements at each point,
41
41
  # title, subtitle etc.
42
- #
42
+ #
43
43
  # = Examples
44
- #
44
+ #
45
45
  # http://www.germane-software/repositories/public/SVG/test/single.rb
46
- #
46
+ #
47
47
  # = Notes
48
48
  # Only number of fileds datapoints will be drawn, additional data values
49
49
  # are ignored. Nil values in data are skipped and
@@ -54,9 +54,9 @@ module SVG
54
54
  # additional settings for the extra data sets. You will know
55
55
  # if you go over 10 data sets as they will have no style and
56
56
  # be in black.
57
- #
57
+ #
58
58
  # = See also
59
- #
59
+ #
60
60
  # * SVG::Graph::Graph
61
61
  # * SVG::Graph::BarHorizontal
62
62
  # * SVG::Graph::Bar
@@ -75,14 +75,14 @@ module SVG
75
75
  # Show a small circle on the graph where the line
76
76
  # goes from one point to the next.
77
77
  attr_accessor :show_data_points
78
- # Accumulates each data set. (i.e. Each point increased by sum of
78
+ # Accumulates each data set. (i.e. Each point increased by sum of
79
79
  # all previous series at same point). Default is 0, set to '1' to show.
80
80
  attr_accessor :stacked
81
81
  # Fill in the area under the plot if true
82
82
  attr_accessor :area_fill
83
83
 
84
84
  # The constructor takes a hash reference, :fields (the names for each
85
- # field on the X axis) MUST be set, all other values are defaulted to
85
+ # field on the X axis) MUST be set, all other values are defaulted to
86
86
  # those shown above - with the exception of style_sheet which defaults
87
87
  # to using the internal style sheet.
88
88
  def initialize config
@@ -112,7 +112,7 @@ module SVG
112
112
  max = 0
113
113
  if stacked
114
114
  sums = Array.new(@config[:fields].length).fill(0)
115
-
115
+
116
116
  @data.each do |data|
117
117
  sums.each_index do |i|
118
118
  sums[i] += data[:data][i].to_f
@@ -125,7 +125,7 @@ module SVG
125
125
  x[:data].compact.max
126
126
  }.max
127
127
  end
128
-
128
+
129
129
  return max
130
130
  end
131
131
 
@@ -167,7 +167,7 @@ module SVG
167
167
 
168
168
  @y_scale_division = scale_divisions || (scale_range / 10.0)
169
169
  @y_offset = 0
170
-
170
+
171
171
  if scale_integers
172
172
  @y_scale_division = @y_scale_division < 1 ? 1 : @y_scale_division.round
173
173
  @y_offset = (minvalue.to_f - minvalue.floor).to_f
@@ -201,10 +201,10 @@ module SVG
201
201
  for data in @data.reverse
202
202
  lpath = ""
203
203
  apath = ""
204
-
204
+
205
205
  # reset cum_sum if we are not in a stacked graph
206
206
  if not stacked then cum_sum.fill(nil) end
207
-
207
+
208
208
  # only consider as many datapoints as we have fields
209
209
  @config[:fields].each_index do |i|
210
210
  next if data[:data][i].nil?
@@ -216,33 +216,33 @@ module SVG
216
216
  c = calc_coords(i, cum_sum[i], fieldwidth, fieldheight)
217
217
  lpath << "#{c[:x]} #{c[:y]} "
218
218
  end
219
-
219
+
220
220
  if area_fill
221
221
  if stacked then
222
222
  (prev_sum.length - 1).downto 0 do |i|
223
223
  next if prev_sum[i].nil?
224
224
  c = calc_coords(i, prev_sum[i], fieldwidth, fieldheight)
225
-
225
+
226
226
  apath << "#{c[:x]} #{c[:y]} "
227
227
  end
228
-
228
+
229
229
  c = calc_coords(0, prev_sum[0], fieldwidth, fieldheight)
230
230
  else
231
231
  apath = "V#@graph_height"
232
232
  c = calc_coords(0, -@y_offset, fieldwidth, fieldheight)
233
233
  end
234
-
234
+
235
235
  @graph.add_element("path", {
236
236
  "d" => "M#{c[:x]} #{c[:y]} L" + lpath + apath + "Z",
237
237
  "class" => "fill#{line}"
238
238
  })
239
239
  end
240
-
240
+
241
241
  @graph.add_element("path", {
242
242
  "d" => "M0 #@graph_height L" + lpath,
243
243
  "class" => "line#{line}"
244
244
  })
245
-
245
+
246
246
  if show_data_points || show_data_values || add_popups
247
247
  cum_sum.each_index do |i|
248
248
  # skip datapoint if nil
@@ -258,7 +258,8 @@ module SVG
258
258
  end
259
259
 
260
260
  make_datapoint_text( c[:x], c[:y] - font_size/2, cum_sum[i] + minvalue)
261
- add_popup(c[:x], c[:y], cum_sum[i] + minvalue)
261
+ # number format shall not apply to popup (use .to_s conversion)
262
+ add_popup(c[:x], c[:y], (cum_sum[i] + minvalue).to_s)
262
263
  end
263
264
  end
264
265
 
@@ -274,62 +275,62 @@ module SVG
274
275
  .line1{
275
276
  fill: none;
276
277
  stroke: #ff0000;
277
- stroke-width: 1px;
278
+ stroke-width: 1px;
278
279
  }
279
280
  .line2{
280
281
  fill: none;
281
282
  stroke: #0000ff;
282
- stroke-width: 1px;
283
+ stroke-width: 1px;
283
284
  }
284
285
  .line3{
285
286
  fill: none;
286
287
  stroke: #00ff00;
287
- stroke-width: 1px;
288
+ stroke-width: 1px;
288
289
  }
289
290
  .line4{
290
291
  fill: none;
291
292
  stroke: #ffcc00;
292
- stroke-width: 1px;
293
+ stroke-width: 1px;
293
294
  }
294
295
  .line5{
295
296
  fill: none;
296
297
  stroke: #00ccff;
297
- stroke-width: 1px;
298
+ stroke-width: 1px;
298
299
  }
299
300
  .line6{
300
301
  fill: none;
301
302
  stroke: #ff00ff;
302
- stroke-width: 1px;
303
+ stroke-width: 1px;
303
304
  }
304
305
  .line7{
305
306
  fill: none;
306
307
  stroke: #00ffff;
307
- stroke-width: 1px;
308
+ stroke-width: 1px;
308
309
  }
309
310
  .line8{
310
311
  fill: none;
311
312
  stroke: #ffff00;
312
- stroke-width: 1px;
313
+ stroke-width: 1px;
313
314
  }
314
315
  .line9{
315
316
  fill: none;
316
317
  stroke: #ccc6666;
317
- stroke-width: 1px;
318
+ stroke-width: 1px;
318
319
  }
319
320
  .line10{
320
321
  fill: none;
321
322
  stroke: #663399;
322
- stroke-width: 1px;
323
+ stroke-width: 1px;
323
324
  }
324
325
  .line11{
325
326
  fill: none;
326
327
  stroke: #339900;
327
- stroke-width: 1px;
328
+ stroke-width: 1px;
328
329
  }
329
330
  .line12{
330
331
  fill: none;
331
332
  stroke: #9966FF;
332
- stroke-width: 1px;
333
+ stroke-width: 1px;
333
334
  }
334
335
  /* default fill styles */
335
336
  .fill1{
@@ -396,62 +397,62 @@ module SVG
396
397
  .key1,.dataPoint1{
397
398
  fill: #ff0000;
398
399
  stroke: none;
399
- stroke-width: 1px;
400
+ stroke-width: 1px;
400
401
  }
401
402
  .key2,.dataPoint2{
402
403
  fill: #0000ff;
403
404
  stroke: none;
404
- stroke-width: 1px;
405
+ stroke-width: 1px;
405
406
  }
406
407
  .key3,.dataPoint3{
407
408
  fill: #00ff00;
408
409
  stroke: none;
409
- stroke-width: 1px;
410
+ stroke-width: 1px;
410
411
  }
411
412
  .key4,.dataPoint4{
412
413
  fill: #ffcc00;
413
414
  stroke: none;
414
- stroke-width: 1px;
415
+ stroke-width: 1px;
415
416
  }
416
417
  .key5,.dataPoint5{
417
418
  fill: #00ccff;
418
419
  stroke: none;
419
- stroke-width: 1px;
420
+ stroke-width: 1px;
420
421
  }
421
422
  .key6,.dataPoint6{
422
423
  fill: #ff00ff;
423
424
  stroke: none;
424
- stroke-width: 1px;
425
+ stroke-width: 1px;
425
426
  }
426
427
  .key7,.dataPoint7{
427
428
  fill: #00ffff;
428
429
  stroke: none;
429
- stroke-width: 1px;
430
+ stroke-width: 1px;
430
431
  }
431
432
  .key8,.dataPoint8{
432
433
  fill: #ffff00;
433
434
  stroke: none;
434
- stroke-width: 1px;
435
+ stroke-width: 1px;
435
436
  }
436
437
  .key9,.dataPoint9{
437
438
  fill: #cc6666;
438
439
  stroke: none;
439
- stroke-width: 1px;
440
+ stroke-width: 1px;
440
441
  }
441
442
  .key10,.dataPoint10{
442
443
  fill: #663399;
443
444
  stroke: none;
444
- stroke-width: 1px;
445
+ stroke-width: 1px;
445
446
  }
446
447
  .key11,.dataPoint11{
447
448
  fill: #339900;
448
449
  stroke: none;
449
- stroke-width: 1px;
450
+ stroke-width: 1px;
450
451
  }
451
452
  .key12,.dataPoint12{
452
453
  fill: #9966FF;
453
454
  stroke: none;
454
- stroke-width: 1px;
455
+ stroke-width: 1px;
455
456
  }
456
457
  EOL
457
458
  end
@@ -1,6 +1,6 @@
1
1
  module SVG
2
2
  module Graph
3
- VERSION = '2.0.2'
3
+ VERSION = '2.1.0.beta1'
4
4
  end
5
5
  end
6
6
  require_relative 'SVG/Graph/DataPoint'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: svg-graph
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.1.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Russell
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2016-10-26 00:00:00.000000000 Z
15
+ date: 2017-02-13 00:00:00.000000000 Z
16
16
  dependencies: []
17
17
  description: "Gem version of SVG:::Graph. SVG:::Graph is a pure Ruby library for generating
18
18
  charts, \nwhich are a type of graph where the values of one axis are not scalar.
@@ -67,12 +67,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
67
67
  version: '0'
68
68
  required_rubygems_version: !ruby/object:Gem::Requirement
69
69
  requirements:
70
- - - ">="
70
+ - - ">"
71
71
  - !ruby/object:Gem::Version
72
- version: '0'
72
+ version: 1.3.1
73
73
  requirements: []
74
74
  rubyforge_project:
75
- rubygems_version: 2.6.7
75
+ rubygems_version: 2.6.10
76
76
  signing_key:
77
77
  specification_version: 4
78
78
  summary: SVG:::Graph is a pure Ruby library for generating charts, which are a type