Kelsin-lilygraph 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +0 -0
- data/README +0 -0
- data/VERSION +1 -0
- data/lib/lilygraph.rb +176 -0
- data/lilygraph.gemspec +47 -0
- metadata +78 -0
data/LICENSE
ADDED
File without changes
|
data/README
ADDED
File without changes
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/lilygraph.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
# This is the main graphing class used for generating svg graphs.
|
2
|
+
#
|
3
|
+
# :author: Christopher Giroir <kelsin@valefor.com>
|
4
|
+
|
5
|
+
class Lilygraph
|
6
|
+
# Default options for the initializer
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
:height => '100%',
|
9
|
+
:width => '100%',
|
10
|
+
:indent => 2,
|
11
|
+
:padding => 14,
|
12
|
+
:viewbox => {
|
13
|
+
:width => 800,
|
14
|
+
:height => 600
|
15
|
+
},
|
16
|
+
:margin => { :top => 50, :left => 50, :right => 50, :bottom => 100 }
|
17
|
+
}
|
18
|
+
|
19
|
+
# An array of labels to use on the y axis. Make sure you have the right number
|
20
|
+
# of labels. The size of this array should = the size of the data array.
|
21
|
+
attr_accessor :labels
|
22
|
+
|
23
|
+
# This is the data for the graph. It should be an array where every item is
|
24
|
+
# either a number or an array of numbers.
|
25
|
+
#
|
26
|
+
# Examples:
|
27
|
+
# For a simple bar graph: data=[1,2,3]
|
28
|
+
# For a grouped bar graph: data=[[1,10],[2,20],[3,30]]
|
29
|
+
attr_accessor :data
|
30
|
+
|
31
|
+
# Returns a new graph creator with some default options and other options that you pass.
|
32
|
+
#
|
33
|
+
# The options has includes:
|
34
|
+
# :height - String to use as height parameter on the svg tag. Default is '100%'.
|
35
|
+
# :width - String to use as width parameter on the svg tag. Default is '100%'.
|
36
|
+
# :indent - Indent option to the XmlMarkup object. Defaults to 2.
|
37
|
+
# :padding - Number of svg units in between two bars.
|
38
|
+
# :viewbox - Hash of :height and :width keys to use for the viewbox parameter of the svg tag. Defaults to { :height => 600, :width => 800 }.
|
39
|
+
# :margin - Hash of margins to use for graph (in svg units). Defaults to { :top => 50, :left => 50, :right => 50, :bottom => 100 }.
|
40
|
+
def initialize(options = {})
|
41
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
42
|
+
@data = []
|
43
|
+
@labels = []
|
44
|
+
end
|
45
|
+
|
46
|
+
# Updates the graph options with items from the passed in hash
|
47
|
+
def update_options(options = {})
|
48
|
+
@options = @options.merge(options)
|
49
|
+
end
|
50
|
+
|
51
|
+
# This returns a string of the graph as an svg. You can pass in a block in
|
52
|
+
# order to add your own items to the graph. Your block is passed the XmlMarkup
|
53
|
+
# object to use as well as the options hash in case you need to use some of
|
54
|
+
# that data.
|
55
|
+
def render
|
56
|
+
output = ""
|
57
|
+
xml = Builder::XmlMarkup.new(:target => output, :indent => @options[:indent])
|
58
|
+
|
59
|
+
# Output headers unless we specified otherwise
|
60
|
+
xml.instruct!
|
61
|
+
xml.declare! :DOCTYPE, :svg, :PUBLIC, "-//W3C//DTD SVG 1.1//EN", "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"
|
62
|
+
|
63
|
+
xml.svg(:viewBox => "0 0 #{@options[:viewbox][:width]} #{@options[:viewbox][:height]}",
|
64
|
+
:width => @options[:width], :height => @options[:height],
|
65
|
+
:xmlns => 'http://www.w3.org/2000/svg', :version => '1.1') do |xml|
|
66
|
+
|
67
|
+
xml.g(:fill => 'black', :stroke => 'black', 'stroke-width' => '2',
|
68
|
+
'font-family' => 'Helvetica, Arial, sans-serif', 'font-size' => '10px', 'font-weight' => 'medium') do |xml|
|
69
|
+
|
70
|
+
# Outline
|
71
|
+
xml.rect(:x => @options[:margin][:left], :y => @options[:margin][:top],
|
72
|
+
:width => graph_width,
|
73
|
+
:height => graph_height,
|
74
|
+
:fill => 'lightgray')
|
75
|
+
|
76
|
+
xml.g 'stroke-width' => '1' do |xml|
|
77
|
+
|
78
|
+
# Title
|
79
|
+
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]
|
80
|
+
xml.text(@options[:subtitle], 'font-size' => '18px', :x => (@options[:viewbox][:width] / 2.0).round, :y => 34, 'text-anchor' => 'middle') if @options[:subtitle]
|
81
|
+
|
82
|
+
# Lines
|
83
|
+
xml.g 'font-size' => '10px' do |xml|
|
84
|
+
line_x1 = @options[:margin][:left] + 1
|
85
|
+
line_x2 = @options[:viewbox][:width] - @options[:margin][:right] - 1
|
86
|
+
|
87
|
+
text_x = @options[:margin][:left] - 25
|
88
|
+
|
89
|
+
xml.text 0, :x => text_x, :y => (@options[:viewbox][:height] - @options[:margin][:bottom] + 4), 'stroke-width' => 0.5
|
90
|
+
|
91
|
+
1.upto((max / 10) - 1) do |line_number|
|
92
|
+
y = (@options[:margin][:top] + (line_number * dy)).round
|
93
|
+
xml.line :x1 => line_x1, :y1 => y, :x2 => line_x2, :y2 => y, :stroke => '#666666'
|
94
|
+
xml.text max - line_number * 10, :x => text_x, :y => y + 4, 'stroke-width' => 0.5
|
95
|
+
|
96
|
+
# Smaller Line
|
97
|
+
xml.line(:x1 => line_x1, :y1 => y + (0.5 * dy), :x2 => line_x2, :y2 => y + (0.5 * dy), :stroke => '#999999') if max < 55
|
98
|
+
end
|
99
|
+
|
100
|
+
xml.text max, :x => text_x, :y => @options[:margin][:top] + 4, 'stroke-width' => 0.5
|
101
|
+
# Smaller Line
|
102
|
+
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
|
103
|
+
end
|
104
|
+
|
105
|
+
# Labels
|
106
|
+
xml.g 'text-anchor' => 'end', 'font-size' => '12px', 'stroke-width' => 0.3 do |xml|
|
107
|
+
@labels.each_with_index do |label, index|
|
108
|
+
x = (@options[:margin][:left] + (dx * index) + (dx / 2.0)).round
|
109
|
+
y = @options[:viewbox][:height] - @options[:margin][:bottom] + 15
|
110
|
+
xml.text label, :x => x, :y => y, :transform => "rotate(-45 #{x} #{y})"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Bars
|
115
|
+
xml.g 'font-size' => '8px', 'stroke-width' => 0.3 do |xml|
|
116
|
+
@data.each_with_index do |data, data_index|
|
117
|
+
data = Array(data)
|
118
|
+
width = dx - @options[:padding]
|
119
|
+
bar_width = (width / Float(data.size)).round
|
120
|
+
|
121
|
+
x = (@options[:margin][:left] + (dx * data_index)).round
|
122
|
+
|
123
|
+
data.each_with_index do |number, number_index|
|
124
|
+
color = Color::HSL.from_fraction(data_index * (1.0 / @data.size),1.0, 0.4 + (number_index * 0.2)).to_rgb
|
125
|
+
height = ((dy / 10.0) * number).round
|
126
|
+
|
127
|
+
bar_x = (x + ((dx - width) / 2.0) + (number_index * bar_width)).round
|
128
|
+
text_x = (bar_x + (bar_width / 2.0)).round
|
129
|
+
|
130
|
+
bar_y = @options[:viewbox][:height] - @options[:margin][:bottom] - height
|
131
|
+
text_y = bar_y - 3
|
132
|
+
|
133
|
+
xml.rect :fill => color.html, :stroke => color.html, 'stroke-width' => 0, :x => bar_x, :width => bar_width, :y => bar_y, :height => height - 1
|
134
|
+
xml.text number, :x => text_x, :y => text_y, 'text-anchor' => 'middle'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Yield in case they want to do some custom drawing and have a block ready
|
140
|
+
yield xml, @options if block_given?
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
output
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def max
|
152
|
+
(((@data.map do |num|
|
153
|
+
num.respond_to?(:max) ? num.max : num
|
154
|
+
end.max + 5) / 10.0).ceil * 10).round
|
155
|
+
end
|
156
|
+
|
157
|
+
def graph_height
|
158
|
+
@options[:viewbox][:height] - (@options[:margin][:top] + @options[:margin][:bottom])
|
159
|
+
end
|
160
|
+
|
161
|
+
def graph_width
|
162
|
+
@options[:viewbox][:width] - (@options[:margin][:left] + @options[:margin][:right])
|
163
|
+
end
|
164
|
+
|
165
|
+
def number_of_slots
|
166
|
+
@data.size
|
167
|
+
end
|
168
|
+
|
169
|
+
def dx
|
170
|
+
700.0 / Float(number_of_slots)
|
171
|
+
end
|
172
|
+
|
173
|
+
def dy
|
174
|
+
4500.0 / Float(max)
|
175
|
+
end
|
176
|
+
end
|
data/lilygraph.gemspec
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{lilygraph}
|
8
|
+
s.version = "0.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Christopher Giroir"]
|
12
|
+
s.date = %q{2009-08-19}
|
13
|
+
s.description = %q{Lilygraph is a Ruby library for creating svg charts and graphs based on XmlBuilder.}
|
14
|
+
s.email = %q{kelsin@valefor.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"LICENSE",
|
21
|
+
"README",
|
22
|
+
"VERSION",
|
23
|
+
"lib/lilygraph.rb",
|
24
|
+
"lilygraph.gemspec"
|
25
|
+
]
|
26
|
+
s.homepage = %q{http://github.com/Kelsin/lilygraph}
|
27
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
28
|
+
s.require_paths = ["lib"]
|
29
|
+
s.rubygems_version = %q{1.3.4}
|
30
|
+
s.summary = %q{Lilygraph is a Ruby library for creating svg charts and graphs based on XmlBuilder.}
|
31
|
+
|
32
|
+
if s.respond_to? :specification_version then
|
33
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
34
|
+
s.specification_version = 3
|
35
|
+
|
36
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
37
|
+
s.add_runtime_dependency(%q<builder>, [">= 2.1.2"])
|
38
|
+
s.add_runtime_dependency(%q<color-tools>, [">= 1.3.0"])
|
39
|
+
else
|
40
|
+
s.add_dependency(%q<builder>, [">= 2.1.2"])
|
41
|
+
s.add_dependency(%q<color-tools>, [">= 1.3.0"])
|
42
|
+
end
|
43
|
+
else
|
44
|
+
s.add_dependency(%q<builder>, [">= 2.1.2"])
|
45
|
+
s.add_dependency(%q<color-tools>, [">= 1.3.0"])
|
46
|
+
end
|
47
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Kelsin-lilygraph
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Christopher Giroir
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-08-19 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: builder
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.1.2
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: color-tools
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.3.0
|
34
|
+
version:
|
35
|
+
description: Lilygraph is a Ruby library for creating svg charts and graphs based on XmlBuilder.
|
36
|
+
email: kelsin@valefor.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README
|
44
|
+
files:
|
45
|
+
- LICENSE
|
46
|
+
- README
|
47
|
+
- VERSION
|
48
|
+
- lib/lilygraph.rb
|
49
|
+
- lilygraph.gemspec
|
50
|
+
has_rdoc: false
|
51
|
+
homepage: http://github.com/Kelsin/lilygraph
|
52
|
+
licenses:
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options:
|
55
|
+
- --charset=UTF-8
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
version:
|
70
|
+
requirements: []
|
71
|
+
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 1.3.5
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: Lilygraph is a Ruby library for creating svg charts and graphs based on XmlBuilder.
|
77
|
+
test_files: []
|
78
|
+
|