svg-graph 2.1.3 → 2.2.0.beta

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