lilygraph 0.2.5

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.
@@ -0,0 +1,119 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>File: lilygraph.rb</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="fileHeader">
50
+ <h1>lilygraph.rb</h1>
51
+ <table class="header-table">
52
+ <tr class="top-aligned-row">
53
+ <td><strong>Path:</strong></td>
54
+ <td>lib/lilygraph.rb
55
+ </td>
56
+ </tr>
57
+ <tr class="top-aligned-row">
58
+ <td><strong>Last Update:</strong></td>
59
+ <td>Wed Aug 19 16:53:59 -0400 2009</td>
60
+ </tr>
61
+ </table>
62
+ </div>
63
+ <!-- banner header -->
64
+
65
+ <div id="bodyContent">
66
+
67
+
68
+
69
+ <div id="contextContent">
70
+
71
+ <div id="description">
72
+ <p>
73
+ This is the main graphing class used for generating svg graphs.
74
+ </p>
75
+ <table>
76
+ <tr><td valign="top">Author:</td><td>Christopher Giroir &lt;kelsin@valefor.com&gt;
77
+
78
+ </td></tr>
79
+ </table>
80
+
81
+ </div>
82
+
83
+ <div id="requires-list">
84
+ <h3 class="section-bar">Required files</h3>
85
+
86
+ <div class="name-list">
87
+ color&nbsp;&nbsp;
88
+ </div>
89
+ </div>
90
+
91
+ </div>
92
+
93
+
94
+ </div>
95
+
96
+
97
+ <!-- if includes -->
98
+
99
+ <div id="section">
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+ <!-- if method_list -->
109
+
110
+
111
+ </div>
112
+
113
+
114
+ <div id="validator-badges">
115
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
116
+ </div>
117
+
118
+ </body>
119
+ </html>
@@ -0,0 +1,27 @@
1
+
2
+ <?xml version="1.0" encoding="iso-8859-1"?>
3
+ <!DOCTYPE html
4
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
+
7
+ <!--
8
+
9
+ Classes
10
+
11
+ -->
12
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
+ <head>
14
+ <title>Classes</title>
15
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
+ <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
+ <base target="docwin" />
18
+ </head>
19
+ <body>
20
+ <div id="index">
21
+ <h1 class="section-bar">Classes</h1>
22
+ <div id="index-entries">
23
+ <a href="classes/Lilygraph.html">Lilygraph</a><br />
24
+ </div>
25
+ </div>
26
+ </body>
27
+ </html>
@@ -0,0 +1,27 @@
1
+
2
+ <?xml version="1.0" encoding="iso-8859-1"?>
3
+ <!DOCTYPE html
4
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
+
7
+ <!--
8
+
9
+ Files
10
+
11
+ -->
12
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
+ <head>
14
+ <title>Files</title>
15
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
+ <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
+ <base target="docwin" />
18
+ </head>
19
+ <body>
20
+ <div id="index">
21
+ <h1 class="section-bar">Files</h1>
22
+ <div id="index-entries">
23
+ <a href="files/lib/lilygraph_rb.html">lib/lilygraph.rb</a><br />
24
+ </div>
25
+ </div>
26
+ </body>
27
+ </html>
@@ -0,0 +1,29 @@
1
+
2
+ <?xml version="1.0" encoding="iso-8859-1"?>
3
+ <!DOCTYPE html
4
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
+
7
+ <!--
8
+
9
+ Methods
10
+
11
+ -->
12
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
+ <head>
14
+ <title>Methods</title>
15
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
+ <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
+ <base target="docwin" />
18
+ </head>
19
+ <body>
20
+ <div id="index">
21
+ <h1 class="section-bar">Methods</h1>
22
+ <div id="index-entries">
23
+ <a href="classes/Lilygraph.html#M000001">new (Lilygraph)</a><br />
24
+ <a href="classes/Lilygraph.html#M000003">render (Lilygraph)</a><br />
25
+ <a href="classes/Lilygraph.html#M000002">update_options (Lilygraph)</a><br />
26
+ </div>
27
+ </div>
28
+ </body>
29
+ </html>
data/doc/index.html ADDED
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
5
+
6
+ <!--
7
+
8
+ RDoc Documentation
9
+
10
+ -->
11
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
12
+ <head>
13
+ <title>RDoc Documentation</title>
14
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
15
+ </head>
16
+ <frameset rows="20%, 80%">
17
+ <frameset cols="25%,35%,45%">
18
+ <frame src="fr_file_index.html" title="Files" name="Files" />
19
+ <frame src="fr_class_index.html" name="Classes" />
20
+ <frame src="fr_method_index.html" name="Methods" />
21
+ </frameset>
22
+ <frame src="files/lib/lilygraph_rb.html" name="docwin" />
23
+ </frameset>
24
+ </html>
@@ -0,0 +1,208 @@
1
+
2
+ body {
3
+ font-family: Verdana,Arial,Helvetica,sans-serif;
4
+ font-size: 90%;
5
+ margin: 0;
6
+ margin-left: 40px;
7
+ padding: 0;
8
+ background: white;
9
+ }
10
+
11
+ h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
12
+ h1 { font-size: 150%; }
13
+ h2,h3,h4 { margin-top: 1em; }
14
+
15
+ a { background: #eef; color: #039; text-decoration: none; }
16
+ a:hover { background: #039; color: #eef; }
17
+
18
+ /* Override the base stylesheet's Anchor inside a table cell */
19
+ td > a {
20
+ background: transparent;
21
+ color: #039;
22
+ text-decoration: none;
23
+ }
24
+
25
+ /* and inside a section title */
26
+ .section-title > a {
27
+ background: transparent;
28
+ color: #eee;
29
+ text-decoration: none;
30
+ }
31
+
32
+ /* === Structural elements =================================== */
33
+
34
+ div#index {
35
+ margin: 0;
36
+ margin-left: -40px;
37
+ padding: 0;
38
+ font-size: 90%;
39
+ }
40
+
41
+
42
+ div#index a {
43
+ margin-left: 0.7em;
44
+ }
45
+
46
+ div#index .section-bar {
47
+ margin-left: 0px;
48
+ padding-left: 0.7em;
49
+ background: #ccc;
50
+ font-size: small;
51
+ }
52
+
53
+
54
+ div#classHeader, div#fileHeader {
55
+ width: auto;
56
+ color: white;
57
+ padding: 0.5em 1.5em 0.5em 1.5em;
58
+ margin: 0;
59
+ margin-left: -40px;
60
+ border-bottom: 3px solid #006;
61
+ }
62
+
63
+ div#classHeader a, div#fileHeader a {
64
+ background: inherit;
65
+ color: white;
66
+ }
67
+
68
+ div#classHeader td, div#fileHeader td {
69
+ background: inherit;
70
+ color: white;
71
+ }
72
+
73
+
74
+ div#fileHeader {
75
+ background: #057;
76
+ }
77
+
78
+ div#classHeader {
79
+ background: #048;
80
+ }
81
+
82
+
83
+ .class-name-in-header {
84
+ font-size: 180%;
85
+ font-weight: bold;
86
+ }
87
+
88
+
89
+ div#bodyContent {
90
+ padding: 0 1.5em 0 1.5em;
91
+ }
92
+
93
+ div#description {
94
+ padding: 0.5em 1.5em;
95
+ background: #efefef;
96
+ border: 1px dotted #999;
97
+ }
98
+
99
+ div#description h1,h2,h3,h4,h5,h6 {
100
+ color: #125;;
101
+ background: transparent;
102
+ }
103
+
104
+ div#validator-badges {
105
+ text-align: center;
106
+ }
107
+ div#validator-badges img { border: 0; }
108
+
109
+ div#copyright {
110
+ color: #333;
111
+ background: #efefef;
112
+ font: 0.75em sans-serif;
113
+ margin-top: 5em;
114
+ margin-bottom: 0;
115
+ padding: 0.5em 2em;
116
+ }
117
+
118
+
119
+ /* === Classes =================================== */
120
+
121
+ table.header-table {
122
+ color: white;
123
+ font-size: small;
124
+ }
125
+
126
+ .type-note {
127
+ font-size: small;
128
+ color: #DEDEDE;
129
+ }
130
+
131
+ .xxsection-bar {
132
+ background: #eee;
133
+ color: #333;
134
+ padding: 3px;
135
+ }
136
+
137
+ .section-bar {
138
+ color: #333;
139
+ border-bottom: 1px solid #999;
140
+ margin-left: -20px;
141
+ }
142
+
143
+
144
+ .section-title {
145
+ background: #79a;
146
+ color: #eee;
147
+ padding: 3px;
148
+ margin-top: 2em;
149
+ margin-left: -30px;
150
+ border: 1px solid #999;
151
+ }
152
+
153
+ .top-aligned-row { vertical-align: top }
154
+ .bottom-aligned-row { vertical-align: bottom }
155
+
156
+ /* --- Context section classes ----------------------- */
157
+
158
+ .context-row { }
159
+ .context-item-name { font-family: monospace; font-weight: bold; color: black; }
160
+ .context-item-value { font-size: small; color: #448; }
161
+ .context-item-desc { color: #333; padding-left: 2em; }
162
+
163
+ /* --- Method classes -------------------------- */
164
+ .method-detail {
165
+ background: #efefef;
166
+ padding: 0;
167
+ margin-top: 0.5em;
168
+ margin-bottom: 1em;
169
+ border: 1px dotted #ccc;
170
+ }
171
+ .method-heading {
172
+ color: black;
173
+ background: #ccc;
174
+ border-bottom: 1px solid #666;
175
+ padding: 0.2em 0.5em 0 0.5em;
176
+ }
177
+ .method-signature { color: black; background: inherit; }
178
+ .method-name { font-weight: bold; }
179
+ .method-args { font-style: italic; }
180
+ .method-description { padding: 0 0.5em 0 0.5em; }
181
+
182
+ /* --- Source code sections -------------------- */
183
+
184
+ a.source-toggle { font-size: 90%; }
185
+ div.method-source-code {
186
+ background: #262626;
187
+ color: #ffdead;
188
+ margin: 1em;
189
+ padding: 0.5em;
190
+ border: 1px dashed #999;
191
+ overflow: hidden;
192
+ }
193
+
194
+ div.method-source-code pre { color: #ffdead; overflow: hidden; }
195
+
196
+ /* --- Ruby keyword styles --------------------- */
197
+
198
+ .standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
199
+
200
+ .ruby-constant { color: #7fffd4; background: transparent; }
201
+ .ruby-keyword { color: #00ffff; background: transparent; }
202
+ .ruby-ivar { color: #eedd82; background: transparent; }
203
+ .ruby-operator { color: #00ffee; background: transparent; }
204
+ .ruby-identifier { color: #ffdead; background: transparent; }
205
+ .ruby-node { color: #ffa07a; background: transparent; }
206
+ .ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
207
+ .ruby-regexp { color: #ffa07a; background: transparent; }
208
+ .ruby-value { color: #7fffd4; background: transparent; }
data/lib/lilygraph.rb ADDED
@@ -0,0 +1,208 @@
1
+ # This is the main graphing class used for generating svg graphs.
2
+ #
3
+ # Author:: Christopher Giroir <kelsin@valefor.com>
4
+
5
+ require 'color'
6
+
7
+ # This is the main graph to use if you want to create a graph!
8
+ #
9
+ # graph = Lilygraph.new(:title => "My Awesome Graph")
10
+ # graph.data = [1,2,3]
11
+ # graph.labels = ['One','Two','Three']
12
+ # graph.render
13
+ #
14
+ # This class outputs svg as a string once you call render.
15
+ class Lilygraph
16
+ # Default options for the initializer
17
+ DEFAULT_OPTIONS = {
18
+ :height => '100%',
19
+ :width => '100%',
20
+ :indent => 2,
21
+ :padding => 14,
22
+ :bar_text => true,
23
+ :viewbox => {
24
+ :width => 800,
25
+ :height => 600
26
+ },
27
+ :margin => { :top => 50, :left => 50, :right => 50, :bottom => 100 }
28
+ }
29
+
30
+ # An array of labels to use on the y axis. Make sure you have the right number
31
+ # of labels. The size of this array should = the size of the data array.
32
+ attr_accessor :labels
33
+
34
+ # This is the data for the graph. It should be an array where every item is
35
+ # either a number or an array of numbers.
36
+ #
37
+ # For a simple bar graph:
38
+ # graph.data=[1,2,3]
39
+ # For a grouped bar graph:
40
+ # graph.data=[[1,10],[2,20],[3,30]]
41
+ attr_accessor :data
42
+
43
+ # Returns a new graph creator with some default options specified via a hash:
44
+ # height:: String to use as height parameter on the svg tag. Default is <tt>'100%'</tt>.
45
+ # width:: String to use as width parameter on the svg tag. Default is <tt>'100%'</tt>.
46
+ # indent:: Indent option to the XmlMarkup object. Defaults to <tt>2</tt>.
47
+ # padding:: Number of svg units in between two bars. Defaults to <tt>14</tt>.
48
+ # bar_text:: (Boolean) Whether or not to include the text labels above every bar. Defaults to +true+.
49
+ # viewbox:: Hash of <tt>:height</tt> and <tt>:width</tt> keys to use for the viewbox parameter of the svg tag. Defaults to <tt>{:height => 600, :width => 800}</tt>.
50
+ # margin:: Hash of margins to use for graph (in svg units). Defaults to <tt>{:top => 50, :left => 50, :right => 50, :bottom => 100}</tt>.
51
+ #
52
+ # For example, this creates a graph with a title and different indent setting:
53
+ #
54
+ # graph = Lilygraph.new(:title => 'Testing a title', :indent => 4)
55
+ def initialize(options = {})
56
+ @options = DEFAULT_OPTIONS.merge(options)
57
+ @data = []
58
+ @labels = []
59
+ end
60
+
61
+ # Updates the graph options with items from the passed in hash. Please refer
62
+ # to new for a description of available options.
63
+ def update_options(options = {})
64
+ @options = @options.merge(options)
65
+ end
66
+
67
+ # This returns a string of the graph as an svg. You can pass in a block in
68
+ # order to add your own items to the graph. Your block is passed the XmlMarkup
69
+ # object to use as well as the options hash in case you need to use some of
70
+ # that data.
71
+ #
72
+ # graph.render do |xml|
73
+ # xml.text "Hello", :x => 5, :y => 25
74
+ # end
75
+ def render
76
+ output = ""
77
+ xml = Builder::XmlMarkup.new(:target => output, :indent => @options[:indent])
78
+
79
+ # Output headers unless we specified otherwise
80
+ xml.instruct!
81
+ xml.declare! :DOCTYPE, :svg, :PUBLIC, "-//W3C//DTD SVG 1.1//EN", "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"
82
+
83
+ xml.svg(:viewBox => "0 0 #{@options[:viewbox][:width]} #{@options[:viewbox][:height]}",
84
+ :width => @options[:width], :height => @options[:height],
85
+ :xmlns => 'http://www.w3.org/2000/svg', :version => '1.1') do |xml|
86
+
87
+ xml.g(:fill => 'black', :stroke => 'black', 'stroke-width' => '2',
88
+ 'font-family' => 'Helvetica, Arial, sans-serif', 'font-size' => '10px', 'font-weight' => 'medium') do |xml|
89
+
90
+ # Outline
91
+ xml.rect(:x => @options[:margin][:left], :y => @options[:margin][:top],
92
+ :width => graph_width,
93
+ :height => graph_height,
94
+ :fill => 'lightgray')
95
+
96
+ xml.g 'stroke-width' => '1' do |xml|
97
+
98
+ # Title
99
+ xml.text(@options[:title], 'font-size' => '24px', :x => (@options[:viewbox][:width] / 2.0).round, :y => (@options[:subtitle] ? 24 : 32), 'text-anchor' => 'middle') if @options[:title]
100
+ xml.text(@options[:subtitle], 'font-size' => '18px', :x => (@options[:viewbox][:width] / 2.0).round, :y => 34, 'text-anchor' => 'middle') if @options[:subtitle]
101
+
102
+ # Lines
103
+ xml.g 'font-size' => '10px' do |xml|
104
+ line_x1 = @options[:margin][:left] + 1
105
+ line_x2 = @options[:viewbox][:width] - @options[:margin][:right] - 1
106
+
107
+ text_x = @options[:margin][:left] - 25
108
+
109
+ xml.text 0, :x => text_x, :y => (@options[:viewbox][:height] - @options[:margin][:bottom] + 4), 'stroke-width' => 0.5
110
+
111
+ 1.upto((max / 10) - 1) do |line_number|
112
+ y = (@options[:margin][:top] + (line_number * dy)).round
113
+ xml.line :x1 => line_x1, :y1 => y, :x2 => line_x2, :y2 => y, :stroke => '#666666'
114
+ xml.text max - line_number * 10, :x => text_x, :y => y + 4, 'stroke-width' => 0.5
115
+
116
+ # Smaller Line
117
+ xml.line(:x1 => line_x1, :y1 => y + (0.5 * dy), :x2 => line_x2, :y2 => y + (0.5 * dy), :stroke => '#999999') if max < 55
118
+ end
119
+
120
+ xml.text max, :x => text_x, :y => @options[:margin][:top] + 4, 'stroke-width' => 0.5
121
+ # Smaller Line
122
+ xml.line(:x1 => line_x1, :y1 => @options[:margin][:top] + (0.5 * dy), :x2 => line_x2, :y2 => @options[:margin][:top] + (0.5 * dy), :stroke => '#999999') if max < 55
123
+ end
124
+
125
+ # Labels
126
+ xml.g 'text-anchor' => 'end', 'font-size' => '12px', 'stroke-width' => 0.3 do |xml|
127
+ @labels.each_with_index do |label, index|
128
+ x = (@options[:margin][:left] + (dx * index) + (dx / 2.0)).round
129
+ y = @options[:viewbox][:height] - @options[:margin][:bottom] + 15
130
+ xml.text label, :x => x, :y => y, :transform => "rotate(-45 #{x} #{y})"
131
+ end
132
+ end
133
+
134
+ # Bars
135
+ xml.g 'font-size' => '8px', 'stroke-width' => 0.3 do |xml|
136
+ @data.each_with_index do |data, data_index|
137
+ data = Array(data)
138
+ width = dx - @options[:padding]
139
+ bar_width = (width / Float(data.size)).round
140
+
141
+ x = (@options[:margin][:left] + (dx * data_index)).round
142
+
143
+ # Rectangles
144
+ data.each_with_index do |number, number_index|
145
+ color = Color::HSL.from_fraction(data_index * (1.0 / @data.size),1.0, 0.4 + (number_index * 0.2)).to_rgb
146
+ height = ((dy / 10.0) * number).round
147
+
148
+ bar_x = (x + ((dx - width) / 2.0) + (number_index * bar_width)).round
149
+ bar_y = @options[:viewbox][:height] - @options[:margin][:bottom] - height
150
+
151
+ xml.rect :fill => color.html, :stroke => color.html, 'stroke-width' => 0, :x => bar_x, :width => bar_width, :y => bar_y, :height => height - 1
152
+ end
153
+
154
+ # Text
155
+ if @options[:bar_text]
156
+ data.each_with_index do |number, number_index|
157
+ height = ((dy / 10.0) * number).round
158
+
159
+ bar_x = (x + ((dx - width) / 2.0) + (number_index * bar_width)).round
160
+ text_x = (bar_x + (bar_width / 2.0)).round
161
+
162
+ bar_y = @options[:viewbox][:height] - @options[:margin][:bottom] - height
163
+ text_y = bar_y - 3
164
+
165
+ xml.text number, :x => text_x, :y => text_y, 'text-anchor' => 'middle'
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ # Yield in case they want to do some custom drawing and have a block ready
172
+ yield(xml, @options) if block_given?
173
+
174
+ end
175
+ end
176
+ end
177
+
178
+ output
179
+ end
180
+
181
+ private
182
+
183
+ def max
184
+ ((((@data.map do |num|
185
+ num.respond_to?(:max) ? num.max : num
186
+ end.max || 0) + 5) / 10.0).ceil * 10).round
187
+ end
188
+
189
+ def graph_height
190
+ @options[:viewbox][:height] - (@options[:margin][:top] + @options[:margin][:bottom])
191
+ end
192
+
193
+ def graph_width
194
+ @options[:viewbox][:width] - (@options[:margin][:left] + @options[:margin][:right])
195
+ end
196
+
197
+ def number_of_slots
198
+ @data.size
199
+ end
200
+
201
+ def dx
202
+ graph_width / Float(number_of_slots)
203
+ end
204
+
205
+ def dy
206
+ (graph_height * 10.0) / Float(max)
207
+ end
208
+ end