svg-graph 2.1.3 → 2.2.0.beta

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
- SHA1:
3
- metadata.gz: e90898ce4dcd05963231c3079d62310773f6d5fd
4
- data.tar.gz: 8a3008024055118d688581ff05b09e572d78e35b
2
+ SHA256:
3
+ metadata.gz: ffe9d9ef41e6f8e53cc9acc30eea176b5c08df460fecd4809e5a974930b07316
4
+ data.tar.gz: c7a4de59354a36eb79da7c3b337859425b348a17ba11254a155a8cc4f761d41f
5
5
  SHA512:
6
- metadata.gz: c8b0aa6aafcbf93f64b3410d28d9a8f22b38ecaac4953cdb0d0e577d090f3f6a5772f7340cec6a3e259f43b4318e4ce35cc4bed35f5ca9776501b95a1efe7a5b
7
- data.tar.gz: 1f556e4a745c961400275e1cb5dbafaa5ac22ef9a23caed138bc12c338c473897c46bb9e2af20396928196b63a87d061d7f953ccff161b8f50725d37340bf6e8
6
+ metadata.gz: 742d05482c8cdecf6359ca8aac09e0c1e307c9e063934b3b029908b4ceac87477ea5f3089b44ddebec41c58c5d56b22734246d741a78fb697eee8bc54ffba46d
7
+ data.tar.gz: '078f9a897f0fca0e88b3483e84aba191fb8bfa3eb46bd6505565f0de037d08a12ecb86770270e53ba7e607c0018291b22f4b668af9ec0549d562775e430d6b96'
data/History.txt CHANGED
@@ -1,10 +1,19 @@
1
1
  TODO / Backlog
2
- * add unit tests for all types of graphs
3
2
  * refactor various hardcoded constant pixel offsets in Graph class to use named constants or variables
4
- * add support for c3js / d3js based graphs, see http://c3js.org/
3
+ * Fix bug in Plot where min/max_x/y_value are not respected, TODO
5
4
 
6
- === 2.2.0 / todo
7
5
 
6
+ === 2.2.0.beta / 2019-05-07
7
+ * Fix typo in Plot's `scale_y_integers` [thanks ashleydavies, PR #9]
8
+ * Fix bug in Plot which enabled too-short axis [thanks ashleydavies, PR #10]
9
+ * Fix issue where horizontal bar graphs were not lined up properly [thanks erullmann]
10
+ * removed some outdated documentation and uneeded files
11
+ * add support for c3js / d3js based graphs `SVG::Graph::C3js`, see http://c3js.org/
12
+ * add *very* basic unit tests for all types of graphs
13
+ * add :show_percent for Bar graphs [thanks Cameron2920]
14
+ * add :inline_style_sheet parameter for all graphs to allow inline css instead of specifying external stylesheets via url [thanks erullmann]
15
+ * add parameters to control the key :key_box_size, :key_spacing, :key_width [thanks erullmann]
16
+ * add support for X and Y label rotation to be different than 90 degree [thanks frenkel, PR #12]
8
17
 
9
18
  === 2.1.3 / 2017-12-27
10
19
  * fixes float comparison and color for pie chart [thanks tiwi, pull request #7]
@@ -3,7 +3,7 @@ SVG::Graph
3
3
 
4
4
  Description
5
5
  -----------
6
- This is an effort to revive the [SVG::Graph library](http://www.germane-software.com/software/SVG/SVG::Graph/) by Sean Russell. I'd also like to thank Claudio Bustos for giving me permissions to continue publishing the gem under it's original name: [svg-graph](https://rubygems.org/gems/svg-graph)
6
+ This repo is the continuation of the original [SVG::Graph library](http://www.germane-software.com/software/SVG/SVG::Graph/) by Sean Russell. I'd like to thank Claudio Bustos for giving me permissions to continue publishing the gem under it's original name: [svg-graph](https://rubygems.org/gems/svg-graph)
7
7
 
8
8
  [Changelog](../master/History.txt)
9
9
 
@@ -37,7 +37,7 @@ require 'SVG/Graph/Bar'
37
37
 
38
38
  x_axis = ['1-10', '10-30', '30-50', '50-70', 'older']
39
39
 
40
- options = {
40
+ options = {
41
41
  :width => 640,
42
42
  :height => 300,
43
43
  :stack => :side, # the stack option is valid for Bar graphs only
@@ -66,7 +66,7 @@ g.add_data( {
66
66
  :title => "Male"
67
67
  })
68
68
 
69
- # graph.burn # this returns a full valid xml document containing the graph
69
+ # graph.burn # this returns a full valid xml document containing the graph
70
70
  # graph.burn_svg_only # this only returns the <svg>...</svg> node
71
71
  File.open('bar.svg', 'w') {|f| f.write(g.burn_svg_only)}
72
72
  ```
@@ -100,6 +100,14 @@ File.open('bar.svg', 'w') {|f| f.write(g.burn_svg_only)}
100
100
 
101
101
  ![example timeseries graph](https://cdn.rawgit.com/lumean/svg-graph2/master/examples/timeseries.svg)
102
102
 
103
+ ### C3js
104
+
105
+ Source: [C3js.rb](../master/examples/c3js.rb)
106
+
107
+ [Link to Preview](https://cdn.rawgit.com/lumean/svg-graph2/master/examples/c3js.html)
108
+
109
+ <iframe src="https://cdn.rawgit.com/lumean/svg-graph2/master/examples/c3js.html" width="600px"> </iframe>
110
+
103
111
  Also have a look at the original [SVG::Graph web page](http://www.germane-software.com/software/SVG/SVG::Graph/), but note that this repository has already added some additional functionality, not available with the original.
104
112
 
105
113
  Build
data/lib/SVG/Graph/Bar.rb CHANGED
@@ -110,6 +110,10 @@ module SVG
110
110
  @config[:fields].each_index { |i|
111
111
  dataset_count = 0
112
112
  for dataset in @data
113
+ total = 0
114
+ dataset[:data].each {|x|
115
+ total += x
116
+ }
113
117
 
114
118
  # cases (assume 0 = +ve):
115
119
  # value min length
@@ -133,10 +137,13 @@ module SVG
133
137
  "height" => length.to_s,
134
138
  "class" => "fill#{dataset_count+1}"
135
139
  })
136
-
137
- make_datapoint_text(left + bar_width/2.0, top - font_size/2, dataset[:data][i])
140
+ value_string = ""
141
+ value_string += (@number_format % dataset[:data][i]) if show_actual_values
142
+ percent = 100.0 * dataset[:data][i] / total
143
+ value_string += " (" + percent.round.to_s + "%)" if show_percent
144
+ make_datapoint_text(left + bar_width/2.0, top - font_size/2, value_string)
138
145
  # number format shall not apply to popup (use .to_s conversion)
139
- add_popup(left + bar_width/2.0, top , dataset[:data][i].to_s)
146
+ add_popup(left + bar_width/2.0, top , value_string)
140
147
  dataset_count += 1
141
148
  end
142
149
  field_count += 1
@@ -28,7 +28,7 @@ module SVG
28
28
  # [bar_gap] true
29
29
  # [stack] :overlap
30
30
  def set_defaults
31
- init_with( :bar_gap => true, :stack => :overlap )
31
+ init_with( :bar_gap => true, :stack => :overlap, :show_percent => false, :show_actual_values => true)
32
32
  end
33
33
 
34
34
  # Whether to have a gap between the bars or not, default
@@ -38,22 +38,26 @@ module SVG
38
38
  # transparent colors, :top stacks bars on top of one another,
39
39
  # :side stacks the bars side-by-side. Defaults to :overlap.
40
40
  attr_accessor :stack
41
+ # If true, display the percentage value of each bar. Default: false
42
+ attr_accessor :show_percent
43
+ # If true, display the actual field values in the data labels. Default: true
44
+ attr_accessor :show_actual_values
41
45
  protected
42
-
46
+
43
47
  # space in px between x-labels, we override the Graph version because
44
48
  # we need the extra space (i.e. don't subtract 1 from get_x_labels.length)
45
49
  def field_width
46
- # don't use -1 otherwise bar is out of bounds
50
+ # don't use -1 otherwise bar is out of bounds
47
51
  @graph_width.to_f / ( get_x_labels.length )
48
52
  end
49
-
53
+
50
54
  def max_value
51
55
  @data.collect{|x| x[:data].max}.max
52
56
  end
53
57
 
54
58
  def min_value
55
59
  min = 0
56
- if min_scale_value.nil?
60
+ if min_scale_value.nil?
57
61
  min = @data.collect{|x| x[:data].min}.min
58
62
  # by default bar should always start from zero unless there are negative values
59
63
  min = min > 0 ? 0 : min
@@ -70,73 +74,73 @@ module SVG
70
74
  fill: #ff0000;
71
75
  fill-opacity: 0.5;
72
76
  stroke: none;
73
- stroke-width: 0.5px;
77
+ stroke-width: 0.5px;
74
78
  }
75
79
  .key2,.fill2{
76
80
  fill: #0000ff;
77
81
  fill-opacity: 0.5;
78
82
  stroke: none;
79
- stroke-width: 1px;
83
+ stroke-width: 1px;
80
84
  }
81
85
  .key3,.fill3{
82
86
  fill: #00ff00;
83
87
  fill-opacity: 0.5;
84
88
  stroke: none;
85
- stroke-width: 1px;
89
+ stroke-width: 1px;
86
90
  }
87
91
  .key4,.fill4{
88
92
  fill: #ffcc00;
89
93
  fill-opacity: 0.5;
90
94
  stroke: none;
91
- stroke-width: 1px;
95
+ stroke-width: 1px;
92
96
  }
93
97
  .key5,.fill5{
94
98
  fill: #00ccff;
95
99
  fill-opacity: 0.5;
96
100
  stroke: none;
97
- stroke-width: 1px;
101
+ stroke-width: 1px;
98
102
  }
99
103
  .key6,.fill6{
100
104
  fill: #ff00ff;
101
105
  fill-opacity: 0.5;
102
106
  stroke: none;
103
- stroke-width: 1px;
107
+ stroke-width: 1px;
104
108
  }
105
109
  .key7,.fill7{
106
110
  fill: #00ffff;
107
111
  fill-opacity: 0.5;
108
112
  stroke: none;
109
- stroke-width: 1px;
113
+ stroke-width: 1px;
110
114
  }
111
115
  .key8,.fill8{
112
116
  fill: #ffff00;
113
117
  fill-opacity: 0.5;
114
118
  stroke: none;
115
- stroke-width: 1px;
119
+ stroke-width: 1px;
116
120
  }
117
121
  .key9,.fill9{
118
122
  fill: #cc6666;
119
123
  fill-opacity: 0.5;
120
124
  stroke: none;
121
- stroke-width: 1px;
125
+ stroke-width: 1px;
122
126
  }
123
127
  .key10,.fill10{
124
128
  fill: #663399;
125
129
  fill-opacity: 0.5;
126
130
  stroke: none;
127
- stroke-width: 1px;
131
+ stroke-width: 1px;
128
132
  }
129
133
  .key11,.fill11{
130
134
  fill: #339900;
131
135
  fill-opacity: 0.5;
132
136
  stroke: none;
133
- stroke-width: 1px;
137
+ stroke-width: 1px;
134
138
  }
135
139
  .key12,.fill12{
136
140
  fill: #9966FF;
137
141
  fill-opacity: 0.5;
138
142
  stroke: none;
139
- stroke-width: 1px;
143
+ stroke-width: 1px;
140
144
  }
141
145
  EOL
142
146
  end
@@ -110,14 +110,18 @@ 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
-
114
113
  field_count = 1
114
+
115
115
  @config[:fields].each_index { |i|
116
116
  dataset_count = 0
117
117
  for dataset in @data
118
+ total = 0
119
+ dataset[:data].each {|x|
120
+ total += x
121
+ }
118
122
  value = dataset[:data][i]
119
123
 
120
- top = @graph_height - (fieldheight * field_count) + bargap
124
+ top = @graph_height - (fieldheight * field_count) + (bargap/2)
121
125
  top += (bar_height * dataset_count) if stack == :side
122
126
  # cases (assume 0 = +ve):
123
127
  # value min length left
@@ -134,10 +138,13 @@ module SVG
134
138
  "height" => bar_height.to_s,
135
139
  "class" => "fill#{dataset_count+1}"
136
140
  })
137
-
138
- make_datapoint_text(left+length+5, top+y_mod, dataset[:data][i], "text-anchor: start; ")
141
+ value_string = ""
142
+ value_string += (@number_format % dataset[:data][i]) if show_actual_values
143
+ percent = 100.0 * dataset[:data][i] / total
144
+ value_string += " (" + percent.round.to_s + "%)" if show_percent
145
+ make_datapoint_text(left+length+5, top+y_mod, value_string, "text-anchor: start; ")
139
146
  # number format shall not apply to popup (use .to_s conversion)
140
- add_popup(left+length, top+y_mod , dataset[:data][i].to_s)
147
+ add_popup(left+length, top+y_mod , value_string)
141
148
  dataset_count += 1
142
149
  end
143
150
  field_count += 1
@@ -0,0 +1,274 @@
1
+ require 'rexml/document'
2
+ require 'json'
3
+
4
+ module SVG
5
+ module Graph
6
+
7
+ # This class provides a lightweight generator for html code indluding c3js based
8
+ # graphs specified as javascript.
9
+ class C3js
10
+
11
+ # By default, the generated html code links the javascript and css dependencies
12
+ # to the d3 and c3 libraries in the <head> element. The latest versions of d3 and c3 available
13
+ # at the time of gem release are used through cdnjs.
14
+ # Custom versions of d3 and c3 can easily be used by specifying the corresponding keys
15
+ # in the optional Hash argument.
16
+ #
17
+ # If the dependencies are http(s) urls a simple href / src link is inserted in the
18
+ # html header.
19
+ # If you want to create a fully offline capable html file, you can do this by
20
+ # downloading the (minified) versions of d3.js, c3.css, c3.js to disk and then
21
+ # point to the files instead of http links. This will then inline the complete
22
+ # script and css payload directly into the generated html page.
23
+ #
24
+ #
25
+ # @option opts [String] "inline_dependencies" if true will inline the script and css
26
+ # parts of d3 and c3 directly into html, otherwise they are referred
27
+ # as external dependencies. default: false
28
+ # @option opts [String] "d3_js" url or path to local files. default: d3.js url via cdnjs
29
+ # @option opts [String] "c3_css" url or path to local files. default: c3.css url via cdnjs
30
+ # @option opts [String] "c3_js" url or path to local files. default: c3.js url via cdnjs
31
+ # @example create a simple graph
32
+ # my_graph = SVG::Graph::C3js.new("my_funny_chart_var")
33
+ # @example create a graph with custom version of C3 and D3
34
+ # # use external dependencies
35
+ # opts = {
36
+ # "d3_js" => "https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js",
37
+ # "c3_css" => "https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.8/c3.min.css",
38
+ # "c3_js" => "https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.8/c3.min.js"
39
+ # }
40
+ # # or inline dependencies into generated html
41
+ # opts = {
42
+ # "inline_dependencies" => true,
43
+ # "d3_js" => "/path/to/local/copy/of/d3.min.js",
44
+ # "c3_css" => "/path/to/local/copy/of/c3.min.css",
45
+ # "c3_js" => "/path/to/local/copy/of/c3.min.js"
46
+ # }
47
+ # my_graph = SVG::Graph::C3js.new("my_funny_chart_var", opts)
48
+ def initialize(opts = {})
49
+ default_opts = {
50
+ "inline_dependencies" => false,
51
+ "d3_js" => "https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.2/d3.min.js",
52
+ "c3_css" => "https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.0/c3.min.css",
53
+ "c3_js" => "https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.0/c3.min.js"
54
+ }
55
+ @opts = default_opts.merge(opts)
56
+ if @opts["inline_dependencies"]
57
+ # we replace the values in the opts Hash by the referred file contents
58
+ ["d3_js", "c3_css", "c3_js"].each do |key|
59
+ if !File.file?(@opts[key])
60
+ raise "opts[\"#{key}\"]: No such file - #{File.expand_path(@opts[key])}"
61
+ end
62
+ @opts[key] = File.read(@opts[key])
63
+ end # ["d3_js", "c3_css", "c3_js"].each
64
+ end # if @opts["inline_dependencies"]
65
+ start_document()
66
+ end # def initialize
67
+
68
+ # Adds a javascript/json C3js chart definition into the div tag
69
+ # @param javascript [String, Hash] see example
70
+ # @param js_chart_variable_name [String] only needed if the `javascript` parameter is a Hash.
71
+ # unique variable name representing the chart in javascript scope.
72
+ # Note this is a global javascript "var" so make sure to avoid name clashes
73
+ # with other javascript us might use on the same page.
74
+ #
75
+ # @raise
76
+ # @example
77
+ # # see http://c3js.org/examples.html
78
+ # # since ruby 2.3 you can use string symbol keys:
79
+ # chart_spec = {
80
+ # # bindto is mandatory
81
+ # "bindto": "#this_is_my_awesom_graph",
82
+ # "data": {
83
+ # "columns": [
84
+ # ['data1', 30, 200, 100, 400, 150, 250],
85
+ # ['data2', 50, 20, 10, 40, 15, 25]
86
+ # ]
87
+ # }
88
+ # # otherwise simply write plain javascript into a heredoc string:
89
+ # # make sure to include the var <chartname> = c3.generate() if using heredoc
90
+ # chart_spec_string =<<-HEREDOC
91
+ # var mychart1 = c3.generate({
92
+ # // bindto is mandatory
93
+ # "bindto": "#this_is_my_awesom_graph",
94
+ # "data": {
95
+ # "columns": [
96
+ # ['data1', 30, 200, 100, 400, 150, 250],
97
+ # ['data2', 50, 20, 10, 40, 15, 25]
98
+ # ]
99
+ # });
100
+ # HEREDOC
101
+ # graph.add_chart_spec(chart_spec, "my_chart1")
102
+ # # or
103
+ # graph.add_chart_spec(chart_spec_string)
104
+ def add_chart_spec(javascript, js_chart_variable_name = "")
105
+ if javascript.kind_of?(Hash)
106
+ if js_chart_variable_name.to_s.empty? || js_chart_variable_name.to_s.match(/\s/)
107
+ raise "js_chart_variable_name ('#{js_chart_variable_name.to_s}') cannot be empty or contain spaces, " +
108
+ "a valid javascript variable name is needed."
109
+ end
110
+ chart_spec = JSON(javascript)
111
+ inline_script = "var #{js_chart_variable_name} = c3.generate(#{chart_spec});"
112
+ elsif javascript.kind_of?(String)
113
+ inline_script = javascript
114
+ if !inline_script.match(/c3\.generate/)
115
+ raise "var <chartname> = c3.generate({...}) statement is missing in javascript string"
116
+ end
117
+ else
118
+ raise "Unsupported argument type: #{javascript.class}"
119
+ end
120
+ # (.+?)" means non-greedy match up to next double quote
121
+ if m = inline_script.match(/"bindto":\s*"#(.+?)"/)
122
+ @bindto = m[1]
123
+ else
124
+ raise "Missing chart specification is missing the mandatory \"bindto\" key/value pair."
125
+ end
126
+ add_div_element_for_graph()
127
+ add_javascript() {inline_script}
128
+ end # def add_chart_spec
129
+
130
+ # Appends a <script> element to the <div> element, this can be used to add additional animations
131
+ # but any script can also directly be part of the js_chart_specification in the #add_chart_spec
132
+ # method when you use a HEREDOC string as input.
133
+ # @param attrs [Hash] attributes for the <script> element. The following attribute
134
+ # is added by default: type="text/javascript"
135
+ # @yieldreturn [String] the actual javascript code to be added to the <script> element
136
+ # @return [REXML::Element] the Element which was just added
137
+ def add_javascript(attrs={}, &block)
138
+ default_attrs = {"type" => "text/javascript"}
139
+ attrs = default_attrs.merge(attrs)
140
+ temp = REXML::Element.new("script")
141
+ temp.add_attributes(attrs)
142
+ @svg.add_element(temp)
143
+ raise "Block argument is mandatory" unless block_given?
144
+ script_content = block.call()
145
+ cdata(script_content, temp)
146
+ end # def add_javascript
147
+
148
+
149
+ # @return [String] the complete html file
150
+ def burn
151
+ f = REXML::Formatters::Pretty.new(0)
152
+ out = ''
153
+ f.write(@doc, out)
154
+ out
155
+ end # def burn
156
+
157
+ # Burns the graph but returns only the <div> node as String without the
158
+ # Doctype and XML / HTML Declaration. This allows easy integration into
159
+ # existing xml/html documents. The Javascript to create the C3js graph
160
+ # is inlined into the div tag.
161
+ #
162
+ # You have to take care to refer the proper C3 and D3 dependencies in your
163
+ # html page.
164
+ #
165
+ # @return [String] the div element into which the graph will be rendered
166
+ # by C3.js
167
+ def burn_svg_only
168
+ # initialize all instance variables by burning the graph
169
+ burn
170
+ f = REXML::Formatters::Pretty.new(0)
171
+ f.compact = true
172
+ out = ''
173
+ f.write(@svg, out)
174
+ return out
175
+ end # def burn_svg_only
176
+
177
+ private
178
+
179
+ # Appends a <style> element to the <div> element, this can be used to add additional animations
180
+ # but any script can also directly be part of the js_chart_specification in the #add_chart_spec
181
+ # method when you use a HEREDOC string as input.
182
+ # @yieldreturn [String] the actual javascript code to be added to the <script> element
183
+ # @return [REXML::Element] the Element which was just added
184
+ def add_css_to_head(&block)
185
+ raise "Block argument is mandatory" unless block_given?
186
+ css_content_or_url = block.call()
187
+ if @opts["inline_dependencies"]
188
+ # for inline css use "style"
189
+ temp = REXML::Element.new("style")
190
+ attrs = {
191
+ "type" => "text/css"
192
+ }
193
+ cdata(css_content_or_url, temp)
194
+ else
195
+ # for external css use "link"
196
+ temp = REXML::Element.new("link")
197
+ attrs = {
198
+ "href" => @opts["c3_css"],
199
+ "rel" => "stylesheet"
200
+ }
201
+ end
202
+ temp.add_attributes(attrs)
203
+ @head.add_element(temp)
204
+ end # def add_css_to_head
205
+
206
+ # Appends a <script> element to the <head> element, this can be used to add
207
+ # the dependencies/libraries.
208
+ # @yieldreturn [String] the actual javascript code to be added to the <script> element
209
+ # @return [REXML::Element] the Element which was just added
210
+ def add_js_to_head(&block)
211
+ raise "Block argument is mandatory" unless block_given?
212
+ script_content_or_url = block.call()
213
+ attrs = {"type" => "text/javascript"}
214
+ temp = REXML::Element.new("script")
215
+ if @opts["inline_dependencies"]
216
+ cdata(script_content_or_url, temp)
217
+ else
218
+ attrs["src"] = script_content_or_url
219
+ # note: self-closing xml script tags are not allowed in html. Only for xhtml this is ok.
220
+ # Thus add a space textnode to enforce closing tags.
221
+ temp.add_text(" ")
222
+ end
223
+ temp.add_attributes(attrs)
224
+ @head.add_element(temp)
225
+ end # def add_js_to_head
226
+
227
+ def start_document
228
+ # Base document
229
+ @doc = REXML::Document.new
230
+ @doc << REXML::XMLDecl.new("1.0", "UTF-8")
231
+ @doc << REXML::DocType.new("html")
232
+ # attribute xmlns is needed, otherwise the browser will only display raw xml
233
+ # instead of rendering the page
234
+ @html = @doc.add_element("html", {"xmlns" => 'http://www.w3.org/1999/xhtml'})
235
+ @html << REXML::Comment.new( " "+"\\"*66 )
236
+ @html << REXML::Comment.new( " Created with SVG::Graph - https://github.com/lumean/svg-graph2" )
237
+ @head = @html.add_element("head")
238
+ @body = @html.add_element("body")
239
+ @head.add_element("meta", {"charset" => "utf-8"})
240
+ add_js_to_head() {@opts["d3_js"]}
241
+ add_css_to_head() {@opts["c3_css"]}
242
+ add_js_to_head() {@opts["c3_js"]}
243
+ end # def start_svg
244
+
245
+ # @param attrs [Hash] html attributes for the <div> tag to which svg graph
246
+ # is bound to by C3js. The "id" attribute
247
+ # is filled automatically by this method. default: an empty hash {}
248
+ def add_div_element_for_graph(attrs={})
249
+ if @bindto.to_s.empty?
250
+ raise "#add_chart_spec needs to be called before the svg can be added"
251
+ end
252
+ attrs["id"] = @bindto
253
+ @svg = @body.add_element("div", attrs)
254
+ end
255
+
256
+ # Surrounds CData tag with c-style comments to remain compatible with normal html.
257
+ # This can be used to inline arbitrary javascript code and is compatible with many browsers.
258
+ # Example /*<![CDATA[*/\n ...content ... \n/*]]>*/
259
+ # @param str [String] the string to be enclosed in cdata
260
+ # @param parent_element [REXML::Element] the element to which cdata should be added
261
+ # @return [REXML::Element] parent_element
262
+ def cdata(str, parent_element)
263
+ # somehow there is a problem with CDATA, any text added after will automatically go into the CDATA
264
+ # so we have do add a dummy node after the CDATA and then add the text.
265
+ parent_element.add_text("/*")
266
+ parent_element.add(REXML::CData.new("*/\n"+str+"\n/*"))
267
+ parent_element.add(REXML::Comment.new("dummy comment to make c-style comments for cdata work"))
268
+ parent_element.add_text("*/")
269
+ end # def cdata
270
+
271
+ end # class C3js
272
+
273
+ end # module Graph
274
+ end # module SVG
@@ -144,22 +144,29 @@ module SVG
144
144
  :show_graph_subtitle => false,
145
145
  :graph_subtitle => 'Graph Sub Title',
146
146
  :key => true,
147
+ :key_width => nil,
147
148
  :key_position => :right, # bottom or right
148
149
 
149
- :font_size =>12,
150
- :title_font_size =>16,
151
- :subtitle_font_size =>14,
152
- :x_label_font_size =>12,
153
- :y_label_font_size =>12,
154
- :x_title_font_size =>14,
155
- :y_title_font_size =>14,
156
- :key_font_size =>10,
157
-
158
- :no_css =>false,
159
- :add_popups =>false,
160
- :number_format => '%.2f'
150
+ :font_size => 12,
151
+ :title_font_size => 16,
152
+ :subtitle_font_size => 14,
153
+ :x_label_font_size => 12,
154
+ :y_label_font_size => 12,
155
+ :x_title_font_size => 14,
156
+ :y_title_font_size => 14,
157
+ :key_font_size => 10,
158
+ :key_box_size => 12,
159
+ :key_spacing => 5,
160
+
161
+ :no_css => false,
162
+ :add_popups => false,
163
+ :popup_radius => 10,
164
+ :number_format => '%.2f',
165
+ :style_sheet => '',
166
+ :inline_style_sheet => ''
161
167
  })
162
168
  set_defaults if self.respond_to? :set_defaults
169
+ # override default values with user supplied values
163
170
  init_with config
164
171
  end
165
172
 
@@ -256,13 +263,23 @@ module SVG
256
263
  # of the SVG box created - not the graph it self which auto
257
264
  # scales to fix the space.
258
265
  attr_accessor :width
259
- # Set the path to an external stylesheet, set to '' if
266
+ # Set the path/url to an external stylesheet, set to '' if
260
267
  # you want to revert back to using the defaut internal version.
261
268
  #
262
269
  # To create an external stylesheet create a graph using the
263
270
  # default internal version and copy the stylesheet section to
264
271
  # an external file and edit from there.
265
272
  attr_accessor :style_sheet
273
+ # Define as String the stylesheet contents to be inlined, set to '' to disable.
274
+ # This can be used, when referring to a url via :style_sheet is not suitable.
275
+ # E.g. in situations where there will be no internet access or the graph must
276
+ # consist of only one file.
277
+ #
278
+ # If not empty, the :style_sheet parameter (url) above will be ignored and is
279
+ # not written to the file
280
+ # see also https://github.com/erullmann/svg-graph2/commit/55eb6e983f6fcc69cc5a110d0ee6e05f906f639a
281
+ # Default: ''
282
+ attr_accessor :inline_style_sheet
266
283
  # (Bool) Show the value of each element of data on the graph
267
284
  attr_accessor :show_data_values
268
285
  # By default (nil/undefined) the x-axis is at the bottom of the graph.
@@ -292,10 +309,12 @@ module SVG
292
309
  # are long field names they will not overlap so easily.
293
310
  # Default is false, to turn on set to true.
294
311
  attr_accessor :stagger_y_labels
295
- # This turns the X axis labels by 90 degrees.
312
+ # This turns the X axis labels by 90 degrees when true or by a custom
313
+ # amount when a numeric value is given.
296
314
  # Default is false, to turn on set to true.
297
315
  attr_accessor :rotate_x_labels
298
- # This turns the Y axis labels by 90 degrees.
316
+ # This turns the Y axis labels by 90 degrees when true or by a custom
317
+ # amount when a numeric value is given.
299
318
  # Default is true, to turn on set to false.
300
319
  attr_accessor :rotate_y_labels
301
320
  # How many "steps" to use between displayed X axis labels,
@@ -358,6 +377,13 @@ module SVG
358
377
  # Where the key should be positioned, defaults to
359
378
  # :right, set to :bottom if you want to move it.
360
379
  attr_accessor :key_position
380
+
381
+ attr_accessor :key_box_size
382
+
383
+ attr_accessor :key_spacing
384
+
385
+ attr_accessor :key_width
386
+
361
387
  # Set the font size (in points) of the data point labels.
362
388
  # Defaults to 12.
363
389
  attr_accessor :font_size
@@ -414,12 +440,8 @@ module SVG
414
440
  config.each { |key, value|
415
441
  self.send( key.to_s+"=", value ) if self.respond_to? key
416
442
  }
417
- @popup_radius ||= 10
418
443
  end
419
444
 
420
- # size of the square box in the legend which indicates the colors
421
- KEY_BOX_SIZE = 12
422
-
423
445
  # Override this (and call super) to change the margin to the left
424
446
  # of the plot area. Results in @border_left being set.
425
447
  #
@@ -458,8 +480,14 @@ module SVG
458
480
  if key and key_position == :right
459
481
  val = keys.max { |a,b| a.length <=> b.length }
460
482
  @border_right += val.length * key_font_size * 0.6
461
- @border_right += KEY_BOX_SIZE
483
+ @border_right += key_box_size
462
484
  @border_right += 10 # Some padding around the box
485
+
486
+ if key_width.nil?
487
+ @border_right
488
+ else
489
+ @border_right = [key_width, @border_right].min
490
+ end
463
491
  end
464
492
  if (x_title_location == :end)
465
493
  @border_right = [@border_right, x_title.length * x_title_font_size * 0.6].max
@@ -734,8 +762,12 @@ module SVG
734
762
  text.attributes["x"] = x.to_s
735
763
  text.attributes["y"] = y.to_s
736
764
  if rotate_x_labels
765
+ degrees = 90
766
+ if numeric? rotate_x_labels
767
+ degrees = rotate_x_labels
768
+ end
737
769
  text.attributes["transform"] =
738
- "rotate( 90 #{x} #{y-x_label_font_size} )"+
770
+ "rotate( #{degrees} #{x} #{y-x_label_font_size} )"+
739
771
  " translate( 0 -#{x_label_font_size/4} )"
740
772
  text.attributes["style"] = "text-anchor: start"
741
773
  else
@@ -818,8 +850,12 @@ module SVG
818
850
  end
819
851
  text.text = textStr
820
852
  if rotate_y_labels
853
+ degrees = 90
854
+ if numeric? rotate_y_labels
855
+ degrees = rotate_y_labels
856
+ end
821
857
  text.attributes["transform"] = "translate( -#{font_size} 0 ) "+
822
- "rotate( 90 #{x} #{y} ) "
858
+ "rotate( #{degrees} #{x} #{y} ) "
823
859
  text.attributes["style"] = "text-anchor: middle"
824
860
  else
825
861
  text.attributes["y"] = (y - (y_label_font_size/2)).to_s
@@ -929,17 +965,17 @@ module SVG
929
965
 
930
966
  key_count = 0
931
967
  for key_name in keys
932
- y_offset = (KEY_BOX_SIZE * key_count) + (key_count * 5)
968
+ y_offset = (key_box_size * key_count) + (key_count * key_spacing)
933
969
  group.add_element( "rect", {
934
970
  "x" => 0.to_s,
935
971
  "y" => y_offset.to_s,
936
- "width" => KEY_BOX_SIZE.to_s,
937
- "height" => KEY_BOX_SIZE.to_s,
972
+ "width" => key_box_size.to_s,
973
+ "height" => key_box_size.to_s,
938
974
  "class" => "key#{key_count+1}"
939
975
  })
940
976
  group.add_element( "text", {
941
- "x" => (KEY_BOX_SIZE + 5).to_s,
942
- "y" => (y_offset + KEY_BOX_SIZE).to_s,
977
+ "x" => (key_box_size + key_spacing).to_s,
978
+ "y" => (y_offset + key_box_size).to_s,
943
979
  "class" => "keyText"
944
980
  }).text = key_name.to_s
945
981
  key_count += 1
@@ -947,15 +983,15 @@ module SVG
947
983
 
948
984
  case key_position
949
985
  when :right
950
- x_offset = @graph_width + @border_left + 10
951
- y_offset = @border_top + 20
986
+ x_offset = @graph_width + @border_left + (key_spacing * 2)
987
+ y_offset = @border_top + (key_spacing * 2)
952
988
  when :bottom
953
- x_offset = @border_left + 20
954
- y_offset = @border_top + @graph_height + 5
989
+ x_offset = @border_left + (key_spacing * 2)
990
+ y_offset = @border_top + @graph_height + key_spacing
955
991
  if show_x_labels
956
992
  y_offset += max_x_label_height_px
957
993
  end
958
- y_offset += x_title_font_size + 5 if show_x_title
994
+ y_offset += x_title_font_size + key_spacing if show_x_title
959
995
  end
960
996
  group.attributes["transform"] = "translate(#{x_offset} #{y_offset})"
961
997
  end
@@ -1045,7 +1081,8 @@ module SVG
1045
1081
  @doc << XMLDecl.new
1046
1082
  @doc << DocType.new( %q{svg PUBLIC "-//W3C//DTD SVG 1.0//EN" } +
1047
1083
  %q{"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"} )
1048
- if style_sheet && style_sheet != ''
1084
+ if style_sheet && style_sheet != '' && inline_style_sheet.to_s.empty?
1085
+ # if inline_style_sheet is defined, url style sheet is ignored
1049
1086
  @doc << Instruction.new( "xml-stylesheet",
1050
1087
  %Q{href="#{style_sheet}" type="text/css"} )
1051
1088
  end
@@ -1067,10 +1104,15 @@ module SVG
1067
1104
 
1068
1105
  defs = @root.add_element( "defs" )
1069
1106
  add_defs defs
1070
- if not(style_sheet && style_sheet != '') and !no_css
1071
- @root << Comment.new(" include default stylesheet if none specified ")
1072
- style = defs.add_element( "style", {"type"=>"text/css"} )
1073
- style << CData.new( get_style )
1107
+ if !no_css
1108
+ if inline_style_sheet && inline_style_sheet != ''
1109
+ style = defs.add_element( "style", {"type"=>"text/css"} )
1110
+ style << CData.new( inline_style_sheet )
1111
+ else
1112
+ @root << Comment.new(" include default stylesheet if none specified ")
1113
+ style = defs.add_element( "style", {"type"=>"text/css"} )
1114
+ style << CData.new( get_style )
1115
+ end
1074
1116
  end
1075
1117
 
1076
1118
  @root << Comment.new( "SVG Background" )
@@ -4,48 +4,48 @@ require_relative 'DataPoint'
4
4
  module SVG
5
5
  module Graph
6
6
  # === For creating SVG plots of scalar data
7
- #
7
+ #
8
8
  # = Synopsis
9
- #
9
+ #
10
10
  # require 'SVG/Graph/Plot'
11
- #
11
+ #
12
12
  # # Data sets are x,y pairs
13
13
  # # Note that multiple data sets can differ in length, and that the
14
14
  # # data in the datasets needn't be in order; they will be ordered
15
15
  # # by the plot along the X-axis.
16
16
  # projection = [
17
17
  # 6, 11, 0, 5, 18, 7, 1, 11, 13, 9, 1, 2, 19, 0, 3, 13,
18
- # 7, 9
18
+ # 7, 9
19
19
  # ]
20
20
  # actual = [
21
- # 0, 18, 8, 15, 9, 4, 18, 14, 10, 2, 11, 6, 14, 12,
21
+ # 0, 18, 8, 15, 9, 4, 18, 14, 10, 2, 11, 6, 14, 12,
22
22
  # 15, 6, 4, 17, 2, 12
23
23
  # ]
24
- #
24
+ #
25
25
  # graph = SVG::Graph::Plot.new({
26
26
  # :height => 500,
27
27
  # :width => 300,
28
28
  # :key => true,
29
29
  # :scale_x_integers => true,
30
- # :scale_y_integerrs => true,
30
+ # :scale_y_integers => true,
31
31
  # })
32
- #
32
+ #
33
33
  # graph.add_data({
34
34
  # :data => projection
35
35
  # :title => 'Projected',
36
36
  # })
37
- #
37
+ #
38
38
  # graph.add_data({
39
39
  # :data => actual,
40
40
  # :title => 'Actual',
41
41
  # })
42
- #
42
+ #
43
43
  # print graph.burn()
44
- #
44
+ #
45
45
  # = Description
46
- #
46
+ #
47
47
  # Produces a graph of scalar data.
48
- #
48
+ #
49
49
  # This object aims to allow you to easily create high quality
50
50
  # SVG[http://www.w3c.org/tr/svg] scalar plots. You can either use the
51
51
  # default style sheet or supply your own. Either way there are many options
@@ -54,11 +54,11 @@ module SVG
54
54
  # subtitle etc.
55
55
  #
56
56
  # = Examples
57
- #
57
+ #
58
58
  # http://www.germane-software/repositories/public/SVG/test/plot.rb
59
- #
59
+ #
60
60
  # = Notes
61
- #
61
+ #
62
62
  # The default stylesheet handles upto 10 data sets, if you
63
63
  # use more you must create your own stylesheet and add the
64
64
  # additional settings for the extra data sets. You will know
@@ -72,9 +72,9 @@ module SVG
72
72
  # Additional possible notation
73
73
  # [ [1,2], 5,6] # A data set with 2 points: (1,2) and (5,6), mixed notation
74
74
  # [ [1,2], [5,6]] # A data set with 2 points: (1,2) and (5,6), nested array
75
- #
75
+ #
76
76
  # = See also
77
- #
77
+ #
78
78
  # * SVG::Graph::Graph
79
79
  # * SVG::Graph::BarHorizontal
80
80
  # * SVG::Graph::Bar
@@ -105,7 +105,7 @@ module SVG
105
105
  :show_lines => true,
106
106
  :round_popups => true,
107
107
  :scale_x_integers => false,
108
- :scale_y_integerrs => false,
108
+ :scale_y_integers => false,
109
109
  )
110
110
  end
111
111
 
@@ -124,20 +124,20 @@ module SVG
124
124
  # would cause the graph to attempt to generate labels stepped by 0.5; EG:
125
125
  # 0, 0.5, 1, 1.5, 2, ...
126
126
  # default is automatic such that there are 10 labels
127
- attr_accessor :scale_y_divisions
127
+ attr_accessor :scale_y_divisions
128
128
  # Make the X axis labels integers, default: false
129
- attr_accessor :scale_x_integers
129
+ attr_accessor :scale_x_integers
130
130
  # Make the Y axis labels integers, default: false
131
- attr_accessor :scale_y_integers
131
+ attr_accessor :scale_y_integers
132
132
  # Fill the area under the line, default: false
133
- attr_accessor :area_fill
133
+ attr_accessor :area_fill
134
134
  # Show a small circle on the graph where the line
135
135
  # goes from one point to the next. default: true
136
136
  attr_accessor :show_data_points
137
137
  # Set the minimum value of the X axis, if nil the minimum from data is chosen, default: nil
138
- attr_accessor :min_x_value
138
+ attr_accessor :min_x_value
139
139
  # Set the maximum value of the X axis, if nil the maximum from data is chosen, default: nil
140
- attr_accessor :max_x_value
140
+ attr_accessor :max_x_value
141
141
  # Set the minimum value of the Y axis, if nil the minimum from data is chosen, default: nil
142
142
  attr_accessor :min_y_value
143
143
  # Set the maximum value of the Y axis, if nil the maximum from data is chosen, default: nil
@@ -155,15 +155,15 @@ module SVG
155
155
  # data_set2 = [[1,2], 5,6]
156
156
  # or
157
157
  # data_set2 = [[1,2], [5,6]]
158
- #
158
+ #
159
159
  # graph.add_data({
160
160
  # :data => data_set1,
161
161
  # :title => 'single point'
162
- # })
162
+ # })
163
163
  # graph.add_data({
164
164
  # :data => data_set2,
165
165
  # :title => 'two points'
166
- # })
166
+ # })
167
167
  def add_data(conf)
168
168
  @data ||= []
169
169
  raise "No data provided by #{conf.inspect}" unless conf[:data] and
@@ -174,10 +174,10 @@ module SVG
174
174
  raise "Data supplied must be x,y pairs! "+
175
175
  "The data provided contained an odd set of "+
176
176
  "data points" unless conf[:data].length % 2 == 0
177
-
177
+
178
178
  # remove nil values
179
179
  conf[:data] = conf[:data].compact
180
-
180
+
181
181
  return if conf[:data].length == 0
182
182
 
183
183
  conf[:description] ||= Array.new(conf[:data].size/2)
@@ -248,7 +248,7 @@ module SVG
248
248
 
249
249
  scale_division = scale_x_divisions || (scale_range / 10.0)
250
250
  @x_offset = 0
251
-
251
+
252
252
  if scale_x_integers
253
253
  scale_division = scale_division < 1 ? 1 : scale_division.round
254
254
  @x_offset = min_value.to_f - min_value.floor
@@ -261,7 +261,7 @@ module SVG
261
261
  def get_x_values
262
262
  min_value, max_value, @x_scale_division = x_label_range
263
263
  rv = []
264
- min_value.step( max_value, @x_scale_division ) {|v| rv << v}
264
+ min_value.step( max_value + @x_scale_division , @x_scale_division ) {|v| rv << v}
265
265
  return rv
266
266
  end
267
267
  alias :get_x_labels :get_x_values
@@ -270,7 +270,7 @@ module SVG
270
270
  # exclude values which are outside max_x_range
271
271
  values = get_x_values
272
272
  @graph_width.to_f / (values.length - 1 ) # -1 is to use entire x-axis
273
- # otherwise there is always 1 division unused
273
+ # otherwise there is always 1 division unused
274
274
  end
275
275
 
276
276
 
@@ -300,7 +300,7 @@ module SVG
300
300
 
301
301
  scale_division = scale_y_divisions || (scale_range / 10.0)
302
302
  @y_offset = 0
303
-
303
+
304
304
  if scale_y_integers
305
305
  scale_division = scale_division < 1 ? 1 : scale_division.round
306
306
  @y_offset = (min_value.to_f - min_value.floor).to_f
@@ -318,7 +318,7 @@ module SVG
318
318
  end
319
319
  end
320
320
  rv = []
321
- min_value.step( max_value, @y_scale_division ) {|v| rv << v}
321
+ min_value.step( max_value + @y_scale_division, @y_scale_division ) {|v| rv << v}
322
322
  rv << rv[0] + 1 if rv.length == 1
323
323
  return rv
324
324
  end
@@ -335,19 +335,19 @@ module SVG
335
335
  end
336
336
  @graph_height.to_f / values.length
337
337
  end
338
-
338
+
339
339
  def calc_coords(x, y)
340
340
  coords = {:x => 0, :y => 0}
341
341
  # scale the coordinates, use float division / multiplication
342
342
  # otherwise the point will be place inaccurate
343
- coords[:x] = (x + @x_offset)/@x_scale_division.to_f * field_width
343
+ coords[:x] = (x + @x_offset)/@x_scale_division.to_f * field_width
344
344
  coords[:y] = @graph_height - (y + @y_offset)/@y_scale_division.to_f * field_height
345
345
  return coords
346
346
  end
347
347
 
348
348
  def draw_data
349
349
  line = 1
350
-
350
+
351
351
  x_min = min_x_range
352
352
  x_max = max_x_range
353
353
  y_min = min_y_range
@@ -395,7 +395,7 @@ module SVG
395
395
  line += 1
396
396
  end
397
397
  end
398
-
398
+
399
399
  # returns the formatted string which is added as popup information
400
400
  def format x, y, desc
401
401
  info = []
@@ -404,69 +404,69 @@ module SVG
404
404
  info << desc
405
405
  "(#{info.compact.join(', ')})"
406
406
  end
407
-
407
+
408
408
  def get_css
409
409
  return <<EOL
410
410
  /* default line styles */
411
411
  .line1{
412
412
  fill: none;
413
413
  stroke: #ff0000;
414
- stroke-width: 1px;
414
+ stroke-width: 1px;
415
415
  }
416
416
  .line2{
417
417
  fill: none;
418
418
  stroke: #0000ff;
419
- stroke-width: 1px;
419
+ stroke-width: 1px;
420
420
  }
421
421
  .line3{
422
422
  fill: none;
423
423
  stroke: #00ff00;
424
- stroke-width: 1px;
424
+ stroke-width: 1px;
425
425
  }
426
426
  .line4{
427
427
  fill: none;
428
428
  stroke: #ffcc00;
429
- stroke-width: 1px;
429
+ stroke-width: 1px;
430
430
  }
431
431
  .line5{
432
432
  fill: none;
433
433
  stroke: #00ccff;
434
- stroke-width: 1px;
434
+ stroke-width: 1px;
435
435
  }
436
436
  .line6{
437
437
  fill: none;
438
438
  stroke: #ff00ff;
439
- stroke-width: 1px;
439
+ stroke-width: 1px;
440
440
  }
441
441
  .line7{
442
442
  fill: none;
443
443
  stroke: #00ffff;
444
- stroke-width: 1px;
444
+ stroke-width: 1px;
445
445
  }
446
446
  .line8{
447
447
  fill: none;
448
448
  stroke: #ffff00;
449
- stroke-width: 1px;
449
+ stroke-width: 1px;
450
450
  }
451
451
  .line9{
452
452
  fill: none;
453
- stroke: #ccc6666;
454
- stroke-width: 1px;
453
+ stroke: #cc6666;
454
+ stroke-width: 1px;
455
455
  }
456
456
  .line10{
457
457
  fill: none;
458
458
  stroke: #663399;
459
- stroke-width: 1px;
459
+ stroke-width: 1px;
460
460
  }
461
461
  .line11{
462
462
  fill: none;
463
463
  stroke: #339900;
464
- stroke-width: 1px;
464
+ stroke-width: 1px;
465
465
  }
466
466
  .line12{
467
467
  fill: none;
468
468
  stroke: #9966FF;
469
- stroke-width: 1px;
469
+ stroke-width: 1px;
470
470
  }
471
471
  /* default fill styles */
472
472
  .fill1{
@@ -533,62 +533,62 @@ module SVG
533
533
  .key1,.dataPoint1{
534
534
  fill: #ff0000;
535
535
  stroke: none;
536
- stroke-width: 1px;
536
+ stroke-width: 1px;
537
537
  }
538
538
  .key2,.dataPoint2{
539
539
  fill: #0000ff;
540
540
  stroke: none;
541
- stroke-width: 1px;
541
+ stroke-width: 1px;
542
542
  }
543
543
  .key3,.dataPoint3{
544
544
  fill: #00ff00;
545
545
  stroke: none;
546
- stroke-width: 1px;
546
+ stroke-width: 1px;
547
547
  }
548
548
  .key4,.dataPoint4{
549
549
  fill: #ffcc00;
550
550
  stroke: none;
551
- stroke-width: 1px;
551
+ stroke-width: 1px;
552
552
  }
553
553
  .key5,.dataPoint5{
554
554
  fill: #00ccff;
555
555
  stroke: none;
556
- stroke-width: 1px;
556
+ stroke-width: 1px;
557
557
  }
558
558
  .key6,.dataPoint6{
559
559
  fill: #ff00ff;
560
560
  stroke: none;
561
- stroke-width: 1px;
561
+ stroke-width: 1px;
562
562
  }
563
563
  .key7,.dataPoint7{
564
564
  fill: #00ffff;
565
565
  stroke: none;
566
- stroke-width: 1px;
566
+ stroke-width: 1px;
567
567
  }
568
568
  .key8,.dataPoint8{
569
569
  fill: #ffff00;
570
570
  stroke: none;
571
- stroke-width: 1px;
571
+ stroke-width: 1px;
572
572
  }
573
573
  .key9,.dataPoint9{
574
574
  fill: #cc6666;
575
575
  stroke: none;
576
- stroke-width: 1px;
576
+ stroke-width: 1px;
577
577
  }
578
578
  .key10,.dataPoint10{
579
579
  fill: #663399;
580
580
  stroke: none;
581
- stroke-width: 1px;
581
+ stroke-width: 1px;
582
582
  }
583
583
  .key11,.dataPoint11{
584
584
  fill: #339900;
585
585
  stroke: none;
586
- stroke-width: 1px;
586
+ stroke-width: 1px;
587
587
  }
588
588
  .key12,.dataPoint12{
589
589
  fill: #9966FF;
590
590
  stroke: none;
591
- stroke-width: 1px;
591
+ stroke-width: 1px;
592
592
  }
593
593
  EOL
594
594
  end
data/lib/svggraph.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  module SVG
2
2
  module Graph
3
- VERSION = '2.1.3'
3
+ VERSION = '2.2.0.beta'
4
+
4
5
  end
5
6
  end
7
+ require_relative 'SVG/Graph/C3js'
8
+ require_relative 'SVG/Graph/Graph'
6
9
  require_relative 'SVG/Graph/DataPoint'
7
10
  require_relative 'SVG/Graph/BarBase'
8
- require_relative 'SVG/Graph/Graph'
9
11
  require_relative 'SVG/Graph/Bar'
10
12
  require_relative 'SVG/Graph/BarHorizontal'
11
13
  require_relative 'SVG/Graph/ErrBar'
@@ -12,7 +12,7 @@ class TestSvgGraph < Minitest::Test
12
12
  def test_bar_line_and_pie
13
13
  fields = %w(Jan Feb Mar);
14
14
  data_sales_02 = [12, 45, 21]
15
- [SVG::Graph::Bar, SVG::Graph::BarHorizontal, SVG::Graph::Line, SVG::Graph::Pie].each do
15
+ [SVG::Graph::Bar, SVG::Graph::BarHorizontal, SVG::Graph::Line, SVG::Graph::Pie].each do
16
16
  |klass|
17
17
  graph = klass.new(
18
18
  :height => 500,
@@ -27,14 +27,14 @@ class TestSvgGraph < Minitest::Test
27
27
  assert(out=~/Created with SVG::Graph/)
28
28
  end
29
29
  end # test_bar_line_and_pie
30
-
30
+
31
31
  def test_pie_100_percent
32
32
  fields = %w(Internet TV Newspaper Magazine Radio)
33
33
  #data1 = [2, 3, 1, 3, 1]
34
34
  #data2 = [0, 2, 1, 5, 4]
35
35
  data1 = [0, 3, 0, 0, 0]
36
36
  data2 = [0, 6, 0, 0, 0]
37
-
37
+
38
38
  graph = SVG::Graph::Pie.new(
39
39
  :height => 500,
40
40
  :width => 300,
@@ -50,19 +50,19 @@ class TestSvgGraph < Minitest::Test
50
50
  :data => data1,
51
51
  :title => 'data1'
52
52
  )
53
-
53
+
54
54
  graph.add_data(
55
55
  :data => data2,
56
56
  :title => 'data2'
57
57
  )
58
58
  out = graph.burn
59
- File.open("pie_100.svg", "w") {|fout|
59
+ File.open(File.expand_path("pie_100.svg",__dir__), "w") {|fout|
60
60
  fout.print( out )
61
61
  }
62
- assert_match(/TV 100%/, out, "100% text not found in graph")
62
+ assert_match(/TV 100%/, out, "100% text not found in graph")
63
63
  assert_match(/circle/, out, "no circle was found in graph")
64
64
 
65
65
  end # test_pie_100_percent
66
-
66
+
67
67
  end
68
68
 
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.1.3
4
+ version: 2.2.0.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Russell
@@ -12,14 +12,14 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2017-12-27 00:00:00.000000000 Z
15
+ date: 2019-05-07 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
- charts, \nwhich are a type of graph where the values of one axis are not scalar.
19
- SVG::Graph has a verry similar API to \nthe Perl library SVG::TT::Graph, and the
20
- resulting charts also look the same. This isn't surprising, \nbecause SVG::Graph
18
+ charts,\nwhich are a type of graph where the values of one axis are not scalar.
19
+ SVG::Graph has a verry similar API to\nthe Perl library SVG::TT::Graph, and the
20
+ resulting charts also look the same. This isn't surprising,\nbecause SVG::Graph
21
21
  started as a loose port of SVG::TT::Graph, although the internal code no longer
22
- resembles \nthe Perl original at all.\n "
22
+ resembles\nthe Perl original at all.\n "
23
23
  email:
24
24
  - ser_AT_germane-software.com
25
25
  - clbustos_AT_gmail.com
@@ -30,18 +30,19 @@ executables: []
30
30
  extensions: []
31
31
  extra_rdoc_files:
32
32
  - LICENSE.txt
33
- - README.markdown
33
+ - README.md
34
34
  - README.txt
35
35
  files:
36
36
  - GPL.txt
37
37
  - History.txt
38
38
  - LICENSE.txt
39
- - README.markdown
39
+ - README.md
40
40
  - README.txt
41
41
  - Rakefile
42
42
  - lib/SVG/Graph/Bar.rb
43
43
  - lib/SVG/Graph/BarBase.rb
44
44
  - lib/SVG/Graph/BarHorizontal.rb
45
+ - lib/SVG/Graph/C3js.rb
45
46
  - lib/SVG/Graph/DataPoint.rb
46
47
  - lib/SVG/Graph/ErrBar.rb
47
48
  - lib/SVG/Graph/Graph.rb
@@ -52,7 +53,7 @@ files:
52
53
  - lib/SVG/Graph/TimeSeries.rb
53
54
  - lib/svggraph.rb
54
55
  - test/test_svg_graph.rb
55
- homepage: http://www.germane-software.com/software/SVG/SVG::Graph/
56
+ homepage: https://github.com/lumean/svg-graph2
56
57
  licenses:
57
58
  - GPL-2.0
58
59
  metadata: {}
@@ -67,12 +68,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
67
68
  version: '0'
68
69
  required_rubygems_version: !ruby/object:Gem::Requirement
69
70
  requirements:
70
- - - ">="
71
+ - - ">"
71
72
  - !ruby/object:Gem::Version
72
- version: '0'
73
+ version: 1.3.1
73
74
  requirements: []
74
- rubyforge_project:
75
- rubygems_version: 2.6.14
75
+ rubygems_version: 3.0.1
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