scruffy 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,5 +1,13 @@
1
1
  = Scruffy Changelog
2
2
 
3
+ == Version 0.2.1
4
+ (August 18th, 2006)
5
+
6
+ * Mostly documentation.
7
+ * Added Builder 2.0 dependency to gem spec.
8
+ * Removed minimum size hack in RMagickRasterizer, for now.
9
+
10
+
3
11
  == Version 0.2.0
4
12
  (August 14th, 2006)
5
13
 
data/Rakefile CHANGED
@@ -39,11 +39,14 @@ Rake::RDocTask.new { |rdoc|
39
39
  rdoc.title = "Scruffy - Graphing Library for Ruby"
40
40
  # rdoc.options << '--line-numbers --inline-source --main README --accessor adv_attr_accessor=M'
41
41
  # rdoc.template = "#{ENV['template']}.rb" if ENV['template']
42
- rdoc.rdoc_files.include('README', 'CHANGES')
42
+ rdoc.rdoc_files.include('README', 'CHANGES', 'MIT-LICENSE')
43
43
  rdoc.rdoc_files.include('lib/scruffy.rb')
44
44
  rdoc.rdoc_files.include('lib/scruffy/*.rb')
45
45
  rdoc.rdoc_files.include('lib/scruffy/layers/*.rb')
46
46
  rdoc.rdoc_files.include('lib/scruffy/renderers/*.rb')
47
+ rdoc.rdoc_files.include('lib/scruffy/components/*.rb')
48
+ rdoc.rdoc_files.include('lib/scruffy/helpers/*.rb')
49
+ rdoc.rdoc_files.include('lib/scruffy/rasterizers/*.rb')
47
50
  }
48
51
 
49
52
  spec = Gem::Specification.new do |s|
@@ -53,6 +56,7 @@ spec = Gem::Specification.new do |s|
53
56
  s.email = "brasten@nagilum.com"
54
57
  s.homepage = "http://scruffy.rubyforge.org"
55
58
  s.summary = "A powerful, clean graphing library for Ruby."
59
+ s.add_dependency('builder', '>= 2.0')
56
60
  s.description = <<-EOF
57
61
  Scruffy is a Ruby library for generating powerful graphs. It is based on
58
62
  SVG, allowing for powerful, clean code, as well as a good foundation for
@@ -84,7 +88,10 @@ task :publish_packages => [:verify_user, :verify_password, :package] do
84
88
  release_files = FileList[
85
89
  "pkg/#{PKG_FILE_NAME}.gem",
86
90
  "pkg/#{PKG_FILE_NAME}.tgz",
87
- "pkg/#{PKG_FILE_NAME}.zip"
91
+ "pkg/#{PKG_FILE_NAME}.zip",
92
+ "pkg/#{PKG_FILE_NAME}.gem.md5",
93
+ "pkg/#{PKG_FILE_NAME}.tgz.md5",
94
+ "pkg/#{PKG_FILE_NAME}.zip.md5"
88
95
  ]
89
96
 
90
97
  Rake::XForge::Release.new(MetaProject::Project::XForge::RubyForge.new(PKG_NAME)) do |xf|
data/lib/scruffy.rb CHANGED
@@ -1,3 +1,16 @@
1
+ # ===Scruffy Graphing Library for Ruby
2
+ #
3
+ # Author:: Brasten Sager
4
+ # Date:: August 5th, 2006
5
+ #
6
+ # For information on generating graphs using Scruffy, see the
7
+ # documentation in Scruffy::Graph.
8
+ #
9
+ # For information on creating your own graph types, see the
10
+ # documentation in Scruffy::Layers::Base.
11
+ module Scruffy; end
12
+
13
+
1
14
  $:.unshift(File.dirname(__FILE__)) unless
2
15
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
16
 
@@ -1,3 +1,13 @@
1
+ # ===Scruffy Components
2
+ #
3
+ # Author:: Brasten Sager
4
+ # Date:: August 16th, 2006
5
+ #
6
+ # Components make up the visual elements of a Scruffy graph.
7
+ #
8
+ # For examples, see Scruffy::Components::Base.
9
+ module Scruffy::Components; end
10
+
1
11
  require 'scruffy/components/base'
2
12
  require 'scruffy/components/title'
3
13
  require 'scruffy/components/background'
@@ -1,21 +1,21 @@
1
- module Scruffy
2
- module Components
3
- # Component used to limit other visual components to a certain area on the graph.
4
- class Viewport < Base
5
- include Scruffy::Helpers::Canvas
1
+ module Scruffy::Components
2
+ # Component used to limit other visual components to a certain area on the graph.
3
+ class Viewport < Base
4
+ include Scruffy::Helpers::Canvas
5
+
6
+ attr_accessor :components
7
+
8
+ def initialize(*args, &block)
9
+ super(*args)
6
10
 
7
- attr_accessor :components
8
-
9
- def initialize(*args, &block)
10
- super(*args)
11
-
12
- self.components = []
13
- if block
14
- block.call(self.components)
15
- end
11
+ self.components = []
12
+ if block
13
+ block.call(self.components)
16
14
  end
15
+ end
17
16
 
18
- def draw(svg, bounds, options={})
17
+ def draw(svg, bounds, options={})
18
+ svg.g(options_for) {
19
19
  self.components.each do |component|
20
20
  component.render(svg,
21
21
  bounds_for( [bounds[:width], bounds[:height]],
@@ -23,8 +23,20 @@ module Scruffy
23
23
  component.size ),
24
24
  options)
25
25
  end
26
-
27
- end
26
+ }
28
27
  end
28
+
29
+ private
30
+ def options_for
31
+ options = {}
32
+ %w(skewX skewY).each do |option|
33
+ if @options[option.to_sym]
34
+ options[:transform] ||= ''
35
+ options[:transform] = options[:transform] + "#{option.to_s}(#{@options[option.to_sym]})"
36
+ end
37
+ end
38
+
39
+ options
40
+ end
29
41
  end
30
42
  end
@@ -1,111 +1,176 @@
1
- module Scruffy
2
- module Formatters
3
- class Base
4
- def route_format(target, idx, options = {})
5
- args = [target, idx, options]
6
- if respond_to?(:format)
7
- send :format, *args[0...self.method(:format).arity]
8
- elsif respond_to?(:format!)
9
- send :format!, *args[0...self.method(:format!).arity]
10
- target
11
- else
12
- raise NameError, "Formatter subclass must container either a format() method or format!() method."
13
- end
1
+ # ===Scruffy Formatters
2
+ #
3
+ # Author:: Brasten Sager
4
+ # Date:: August 16th, 2006
5
+ #
6
+ # Formatters are used to format the values displayed on the y-axis by
7
+ # setting graph.value_formatter.
8
+ #
9
+ # Example:
10
+ #
11
+ # graph.value_formatter = Scruffy::Formatters::Currency.new(:precision => 0)
12
+ #
13
+ module Scruffy::Formatters
14
+
15
+ # == Scruffy::Formatters::Base
16
+ #
17
+ # Author:: Brasten Sager
18
+ # Date:: August 16th, 2006
19
+ #
20
+ # Formatters are used to format the values displayed on the y-axis by
21
+ # setting graph.value_formatter.
22
+ class Base
23
+
24
+ # Called by the value marker component. Routes the format call
25
+ # to one of a couple possible methods.
26
+ #
27
+ # If the formatter defines a #format method, the returned value is used
28
+ # as the value. If the formatter defines a #format! method, the value passed is
29
+ # expected to be modified, and is used as the value. (This may not actually work,
30
+ # in hindsight.)
31
+ def route_format(target, idx, options = {})
32
+ args = [target, idx, options]
33
+ if respond_to?(:format)
34
+ send :format, *args[0...self.method(:format).arity]
35
+ elsif respond_to?(:format!)
36
+ send :format!, *args[0...self.method(:format!).arity]
37
+ target
38
+ else
39
+ raise NameError, "Formatter subclass must container either a format() method or format!() method."
14
40
  end
41
+ end
15
42
 
16
- protected
17
- def number_with_precision(number, precision=3)
18
- sprintf("%01.#{precision}f", number)
19
- end
43
+ protected
44
+ def number_with_precision(number, precision=3) #:nodoc:
45
+ sprintf("%01.#{precision}f", number)
46
+ end
47
+ end
48
+
49
+ # Default number formatter.
50
+ # Limits precision, beautifies numbers.
51
+ class Number < Base
52
+ attr_accessor :precision, :separator, :delimiter, :precision_limit
53
+
54
+ # Returns a new Number formatter.
55
+ #
56
+ # Options:
57
+ # precision:: precision to use for value. Can be set to an integer, :none or :auto.
58
+ # :auto will use whatever precision is necessary to portray all the numerical
59
+ # information, up to :precision_limit.
60
+ #
61
+ # Example: [100.1, 100.44, 200.323] will result in [100.100, 100.440, 200.323]
62
+ #
63
+ # separator:: decimal separator. Defaults to '.'
64
+ # delimiter:: delimiter character. Defaults to ','
65
+ # precision_limit:: upper limit for auto precision.
66
+ def initialize(options = {})
67
+ @precision = options[:precision] || :none
68
+ @separator = options[:separator] || '.'
69
+ @delimiter = options[:delimiter] || ','
70
+ @precision_limit = options[:precision_limit] || 4
20
71
  end
21
72
 
22
- # Default number formatter. Limits precision, beautifies numbers.
23
- class Number < Base
24
- attr_accessor :precision, :separator, :delimiter, :precision_limit
73
+ # Formats the value.
74
+ def format(target, idx, options)
75
+ my_precision = @precision
25
76
 
26
- def initialize(options = {})
27
- @precision = options[:precision] || :none
28
- @separator = options[:separator] || '.'
29
- @delimiter = options[:delimiter] || ','
30
- @precision_limit = options[:precision_limit] || 4
77
+ if @precision == :auto
78
+ my_precision = options[:all_values].inject(0) do |highest, current|
79
+ cur = current.to_f.to_s.split(".").last.size
80
+ cur > highest ? cur : highest
81
+ end
82
+
83
+ my_precision = @precision_limit if my_precision > @precision_limit
84
+ elsif @precision == :none
85
+ my_precision = 0
31
86
  end
32
87
 
33
- def format(target, idx, options)
34
- my_precision = @precision
88
+ my_separator = @separator
89
+ my_separator = "" unless my_precision > 0
90
+ begin
91
+ parts = number_with_precision(target, my_precision).split('.')
35
92
 
36
- if @precision == :auto
37
- my_precision = options[:all_values].inject(0) do |highest, current|
38
- cur = current.to_f.to_s.split(".").last.size
39
- cur > highest ? cur : highest
40
- end
41
-
42
- my_precision = @precision_limit if my_precision > @precision_limit
43
- elsif @precision == :none
44
- my_precision = 0
45
- end
46
-
47
- my_separator = @separator
48
- my_separator = "" unless my_precision > 0
49
- begin
50
- parts = number_with_precision(target, my_precision).split('.')
51
-
52
- number = parts[0].to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{@delimiter}") + my_separator + parts[1].to_s
53
- number
54
- rescue StandardError => e
55
- target
56
- end
93
+ number = parts[0].to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{@delimiter}") + my_separator + parts[1].to_s
94
+ number
95
+ rescue StandardError => e
96
+ target
57
97
  end
58
98
  end
99
+ end
100
+
101
+ # Currency formatter.
102
+ #
103
+ # Provides formatting for currencies.
104
+ class Currency < Base
59
105
 
60
- class Currency < Base
61
- def initialize(options = {})
62
- @precision = options[:precision] || 2
63
- @unit = options[:unit] || '$'
64
- @separator = options[:separator] || '.'
65
- @delimiter = options[:delimiter] || ','
66
- @negative_color = options[:negative_color] || 'red'
67
- @special_negatives = options[:special_negatives] || false
68
- end
69
-
70
- def format(target, idx, options)
71
- @separator = "" unless @precision > 0
72
- begin
73
- parts = number_with_precision(target, @precision).split('.')
74
- if @special_negatives && (target.to_f < 0)
75
- number = "(" + @unit + parts[0].to_i.abs.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{@delimiter}") + @separator + parts[1].to_s + ")"
76
- else
77
- number = @unit + parts[0].to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{@delimiter}") + @separator + parts[1].to_s
78
- end
79
- if (target.to_f < 0) && @negative_color
80
- options[:marker_color_override] = @negative_color
81
- end
82
- number
83
- rescue
84
- target
106
+ # Returns a new Currency class.
107
+ #
108
+ # Options:
109
+ # precision:: precision of value
110
+ # unit:: Defaults to '$'
111
+ # separator:: Defaults to '.'
112
+ # delimiter:: Defaults to ','
113
+ # negative_color:: Color of value marker for negative values. Defaults to 'red'
114
+ # special_negatives:: If set to true, parenthesizes negative numbers. ie: -$150.50 becomes ($150.50).
115
+ # Defaults to false.
116
+ def initialize(options = {})
117
+ @precision = options[:precision] || 2
118
+ @unit = options[:unit] || '$'
119
+ @separator = options[:separator] || '.'
120
+ @delimiter = options[:delimiter] || ','
121
+ @negative_color = options[:negative_color] || 'red'
122
+ @special_negatives = options[:special_negatives] || false
123
+ end
124
+
125
+ # Formats value marker.
126
+ def format(target, idx, options)
127
+ @separator = "" unless @precision > 0
128
+ begin
129
+ parts = number_with_precision(target, @precision).split('.')
130
+ if @special_negatives && (target.to_f < 0)
131
+ number = "(" + @unit + parts[0].to_i.abs.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{@delimiter}") + @separator + parts[1].to_s + ")"
132
+ else
133
+ number = @unit + parts[0].to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{@delimiter}") + @separator + parts[1].to_s
134
+ end
135
+ if (target.to_f < 0) && @negative_color
136
+ options[:marker_color_override] = @negative_color
85
137
  end
138
+ number
139
+ rescue
140
+ target
86
141
  end
87
142
  end
143
+ end
144
+
145
+ # Percentage formatter.
146
+ #
147
+ # Provides formatting for percentages.
148
+ class Percentage < Base
149
+
150
+ # Returns new Percentage formatter.
151
+ #
152
+ # Options:
153
+ # precision:: Defaults to 3.
154
+ # separator:: Defaults to '.'
155
+ def initialize(options = {})
156
+ @precision = options[:precision] || 3
157
+ @separator = options[:separator] || '.'
158
+ end
88
159
 
89
- class Percentage < Base
90
- def initialize(options = {})
91
- @precision = options[:precision] || 3
92
- @separator = options[:separator] || '.'
93
- end
94
-
95
- def format(target)
96
- begin
97
- number = number_with_precision(target, @precision)
98
- parts = number.split('.')
99
- if parts.at(1).nil?
100
- parts[0] + "%"
101
- else
102
- parts[0] + @separator + parts[1].to_s + "%"
103
- end
104
- rescue
105
- target
160
+ # Formats percentages.
161
+ def format(target)
162
+ begin
163
+ number = number_with_precision(target, @precision)
164
+ parts = number.split('.')
165
+ if parts.at(1).nil?
166
+ parts[0] + "%"
167
+ else
168
+ parts[0] + @separator + parts[1].to_s + "%"
106
169
  end
170
+ rescue
171
+ target
107
172
  end
108
173
  end
109
-
110
174
  end
175
+
111
176
  end
data/lib/scruffy/graph.rb CHANGED
@@ -1,13 +1,3 @@
1
- # ===Scruffy Graphing Library for Ruby
2
- #
3
- # Author:: Brasten Sager
4
- # Date:: August 5th, 2006
5
- #
6
- # For information on generating graphs using Scruffy, see the
7
- # documentation in Scruffy::Graph.
8
- #
9
- # For information on creating your own graph types, see the
10
- # documentation in Scruffy::Layers::Base.
11
1
  module Scruffy
12
2
 
13
3
  # ==Scruffy Graphs
@@ -21,7 +11,7 @@ module Scruffy
21
11
  # Scruffy::Graph is the primary class you will use to generate your graphs. A Graph does not
22
12
  # define a graph type nor does it directly hold any data. Instead, a Graph object can be thought
23
13
  # of as a canvas on which other graphs are draw. (The actual graphs themselves are subclasses of Scruffy::Layers::Base)
24
- # Despite the technical distinction, we will refer to Scruffy::Graph objects as 'graphs' and Scruffy::GraphLayers as
14
+ # Despite the technical distinction, we will refer to Scruffy::Graph objects as 'graphs' and Scruffy::Layers as
25
15
  # 'layers' or 'graph types.'
26
16
  #
27
17
  #
@@ -34,7 +24,7 @@ module Scruffy
34
24
  #
35
25
  # OR
36
26
  #
37
- # graph = Scruffy::Graph.new(:title => "Monthly Profits", :theme => Scruffy::Themes::RUBY_BLOG)
27
+ # graph = Scruffy::Graph.new(:title => "Monthly Profits", :theme => Scruffy::Themes::RubyBlog.new)
38
28
  #
39
29
  # Once you have a Graph object, you can set any Graph-level properties (title, theme, etc), or begin adding
40
30
  # graph layers. You can add a graph layer to a graph by using the Graph#add or Graph#<< methods. The two
@@ -49,13 +39,21 @@ module Scruffy
49
39
  # graph << Scruffy::Layers::Line.new(:title => 'Sara', :points => [120, 50, -80, 20])
50
40
  #
51
41
  # Now that we've created our graph and added a layer to it, we're ready to render! You can render the graph
52
- # directly to SVG with the Graph#render method:
42
+ # directly to SVG or any other image format (supported by RMagick) with the Graph#render method:
53
43
  #
54
44
  # graph.render # Renders a 600x400 SVG graph
55
45
  #
56
46
  # OR
57
47
  #
58
- # graph.render(:size => [1500, 1000])
48
+ # graph.render(:width => 1200)
49
+ #
50
+ # # For image formats other than SVG:
51
+ # graph.render(:width => 1200, :as => 'PNG')
52
+ #
53
+ # # To render directly to a file:
54
+ # graph.render(:width => 5000, :to => '<filename>')
55
+ #
56
+ # graph.render(:width => 700, :as => 'PNG', :to => '<filename>')
59
57
  #
60
58
  # And that's your basic Scruffy graph! Please check the documentation for the various methods and
61
59
  # classes you'll be using, as there are a bunch of options not demonstrated here.
@@ -93,7 +91,7 @@ module Scruffy
93
91
  # Options:
94
92
  #
95
93
  # title:: Graph's title
96
- # theme:: A theme hash to use when rendering graph
94
+ # theme:: A theme object to use when rendering graph
97
95
  # layers:: An array of Layers for this graph to use
98
96
  # default_type:: A symbol indicating the default type of Layer for this graph
99
97
  # value_formatter:: Sets a formatter used to modify marker values prior to rendering
@@ -128,7 +126,7 @@ module Scruffy
128
126
  #
129
127
  # For other image formats:
130
128
  # as:: File format to render to ('PNG', 'JPG', etc)
131
- # to:: Name of file to save graph to, if desired. If not provided, image is returned as blob.
129
+ # to:: Name of file to save graph to, if desired. If not provided, image is returned as blob/string.
132
130
  def render(options = {})
133
131
  options[:theme] ||= theme
134
132
  options[:value_formatter] ||= value_formatter
@@ -140,16 +138,16 @@ module Scruffy
140
138
  options[:max_value] ||= top_value
141
139
  options[:graph] ||= self
142
140
 
143
-
144
- if options[:as] && (options[:size][0] <= 300 || options[:size][1] <= 200)
145
- options[:actual_size] = options[:size]
146
- options[:size] = [800, (800.to_f * (options[:actual_size][1].to_f / options[:actual_size][0].to_f))]
147
- puts options[:size].inspect
148
- end
141
+
142
+ # Removed for now.
143
+ # Added for making smaller fonts more legible, but may not be needed after all.
144
+ #
145
+ # if options[:as] && (options[:size][0] <= 300 || options[:size][1] <= 200)
146
+ # options[:actual_size] = options[:size]
147
+ # options[:size] = [800, (800.to_f * (options[:actual_size][1].to_f / options[:actual_size][0].to_f))]
148
+ # end
149
149
 
150
150
  svg = ( options[:renderer].nil? ? self.renderer.render( options ) : options[:renderer].render( options ) )
151
-
152
- options[:size] = options[:actual_size] if options[:actual_size]
153
151
 
154
152
  # SVG to file.
155
153
  if options[:to] && options[:as].nil?