scruffy 0.2.2 → 0.2.3

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.
Files changed (84) hide show
  1. data/CHANGES +8 -0
  2. data/History.txt +104 -0
  3. data/License.txt +20 -0
  4. data/Manifest.txt +105 -0
  5. data/PostInstall.txt +6 -0
  6. data/README.txt +66 -0
  7. data/Rakefile +108 -104
  8. data/config/hoe.rb +78 -0
  9. data/config/requirements.rb +15 -0
  10. data/lib/scruffy.rb +8 -6
  11. data/lib/scruffy/components/base.rb +4 -0
  12. data/lib/scruffy/components/legend.rb +65 -30
  13. data/lib/scruffy/components/viewport.rb +14 -17
  14. data/lib/scruffy/formatters.rb +1 -1
  15. data/lib/scruffy/graph.rb +18 -7
  16. data/lib/scruffy/graph_state.rb +24 -0
  17. data/lib/scruffy/helpers.rb +2 -1
  18. data/lib/scruffy/helpers/canvas.rb +19 -17
  19. data/lib/scruffy/helpers/layer_container.rb +8 -3
  20. data/lib/scruffy/helpers/meta.rb +5 -5
  21. data/lib/scruffy/helpers/point_container.rb +70 -0
  22. data/lib/scruffy/layers.rb +2 -0
  23. data/lib/scruffy/layers/average.rb +6 -1
  24. data/lib/scruffy/layers/bar.rb +1 -0
  25. data/lib/scruffy/layers/base.rb +38 -14
  26. data/lib/scruffy/layers/pie.rb +123 -0
  27. data/lib/scruffy/layers/pie_slice.rb +114 -0
  28. data/lib/scruffy/layers/scatter.rb +21 -0
  29. data/lib/scruffy/layers/sparkline_bar.rb +1 -0
  30. data/lib/scruffy/layers/stacked.rb +2 -5
  31. data/lib/scruffy/rasterizers/rmagick_rasterizer.rb +1 -2
  32. data/lib/scruffy/renderers.rb +2 -1
  33. data/lib/scruffy/renderers/base.rb +6 -4
  34. data/lib/scruffy/renderers/pie.rb +20 -0
  35. data/lib/scruffy/themes.rb +54 -4
  36. data/lib/scruffy/version.rb +8 -2
  37. data/script/console +10 -0
  38. data/script/destroy +14 -0
  39. data/script/generate +14 -0
  40. data/script/txt2html +82 -0
  41. data/setup.rb +1585 -0
  42. data/spec/scruffy/graph_spec.rb +175 -0
  43. data/spec/scruffy/layers/base_spec.rb +30 -0
  44. data/spec/{layers → scruffy/layers}/line_spec.rb +2 -1
  45. data/spec/spec_helper.rb +8 -0
  46. data/tasks/deployment.rake +34 -0
  47. data/tasks/environment.rake +7 -0
  48. data/tasks/website.rake +17 -0
  49. data/test/graph_creation_test.rb +101 -0
  50. data/test/test_helper.rb +2 -0
  51. data/test/test_scruffy.rb +11 -0
  52. data/website/images/blank.gif.html +7 -0
  53. data/website/images/graphs/all_smiles.png +0 -0
  54. data/website/images/graphs/bar_test.png +0 -0
  55. data/website/images/graphs/bar_test.svg +71 -0
  56. data/website/images/graphs/line_test.png +0 -0
  57. data/website/images/graphs/line_test.svg +60 -0
  58. data/website/images/graphs/multi_test.png +0 -0
  59. data/website/images/graphs/multi_test.svg +296 -0
  60. data/website/images/graphs/pie_test.png +0 -0
  61. data/website/images/graphs/pie_test.svg +40 -0
  62. data/website/images/graphs/split_test.png +0 -0
  63. data/website/images/graphs/split_test.svg +295 -0
  64. data/website/images/graphs/stacking_test.png +0 -0
  65. data/website/images/graphs/stacking_test.svg +146 -0
  66. data/website/images/header.png +0 -0
  67. data/website/images/header_gradient.png +0 -0
  68. data/website/images/overlay.png +0 -0
  69. data/website/images/scruffy.png +0 -0
  70. data/website/index.html +294 -0
  71. data/website/index.txt +199 -0
  72. data/website/javascripts/application.js +2 -0
  73. data/website/javascripts/controls.js +815 -0
  74. data/website/javascripts/dragdrop.js +913 -0
  75. data/website/javascripts/effects.js +958 -0
  76. data/website/javascripts/lightbox.js +437 -0
  77. data/website/javascripts/prototype.js +2006 -0
  78. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  79. data/website/stylesheets/lightbox.css +27 -0
  80. data/website/stylesheets/screen.css +147 -0
  81. data/website/stylesheets/scruffy.css +227 -0
  82. data/website/template.html.erb +47 -0
  83. metadata +135 -55
  84. data/spec/graph_spec.rb +0 -162
@@ -0,0 +1,78 @@
1
+ require 'scruffy/version'
2
+
3
+ AUTHOR = 'Brasten Sager' # can also be an array of Authors
4
+ # , 'David Parry', 'A.J. Ostman', 'Mat Schaffer']
5
+ # (Using array of authors doesn't work for some reason.
6
+
7
+ EMAIL = ["brasten@nagilum.com", "david.parry@suranyami.com"]
8
+ DESCRIPTION = "Scruffy is a Ruby library for generating high quality, good looking graphs. It is designed to be easy to use and highly customizable."
9
+ SUMMARY = 'A powerful, clean graphing library for Ruby.'
10
+ GEM_NAME = 'scruffy' # what ppl will type to install your gem
11
+ RUBYFORGE_PROJECT = 'scruffy' # The unix name for your project
12
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
13
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
14
+ EXTRA_DEPENDENCIES = [
15
+ ['builder', '>= 2.0'],
16
+ ['diff-lcs', '>= 1.1.2']
17
+ ] # An array of rubygem dependencies [name, version]
18
+
19
+ @config_file = "~/.rubyforge/user-config.yml"
20
+ @config = nil
21
+ RUBYFORGE_USERNAME = "unknown"
22
+ def rubyforge_username
23
+ unless @config
24
+ begin
25
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
26
+ rescue
27
+ puts <<-EOS
28
+ ERROR: No rubyforge config file found: #{@config_file}
29
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
30
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
31
+ EOS
32
+ exit
33
+ end
34
+ end
35
+ RUBYFORGE_USERNAME.replace @config["username"]
36
+ end
37
+
38
+
39
+ REV = nil
40
+ # UNCOMMENT IF REQUIRED:
41
+ # REV = YAML.load(`svn info`)['Revision']
42
+ VERS = Scruffy::VERSION::STRING + (REV ? ".#{REV}" : "")
43
+ RDOC_OPTS = ['--quiet', '--title', 'scruffy documentation',
44
+ "--opname", "index.html",
45
+ "--line-numbers",
46
+ "--main", "README",
47
+ "--inline-source"]
48
+
49
+ class Hoe
50
+ def extra_deps
51
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
52
+ @extra_deps
53
+ end
54
+ end
55
+
56
+ # Generate all the Rake tasks
57
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
58
+ $hoe = Hoe.new(GEM_NAME, VERS) do |p|
59
+ p.developer(AUTHOR, EMAIL)
60
+ p.description = DESCRIPTION
61
+ p.summary = SUMMARY
62
+ p.url = HOMEPATH
63
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
64
+ p.test_globs = ["test/**/test_*.rb"]
65
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
66
+
67
+ # == Optional
68
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
69
+ #p.extra_deps = EXTRA_DEPENDENCIES
70
+
71
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
72
+ end
73
+
74
+ CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
75
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
76
+ $hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
77
+ $hoe.rsync_args = '-av --delete --ignore-errors'
78
+ $hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
@@ -0,0 +1,15 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
@@ -1,3 +1,6 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
1
4
  # ===Scruffy Graphing Library for Ruby
2
5
  #
3
6
  # Author:: Brasten Sager
@@ -8,16 +11,15 @@
8
11
  #
9
12
  # For information on creating your own graph types, see the
10
13
  # documentation in Scruffy::Layers::Base.
11
- module Scruffy; end
12
-
13
-
14
- $:.unshift(File.dirname(__FILE__)) unless
15
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
14
+ module Scruffy
15
+ end
16
16
 
17
17
  require 'rubygems'
18
- require_gem 'builder', '>= 2.0'
18
+ gem 'builder', '>= 2.0'
19
+ require 'builder'
19
20
 
20
21
  require 'scruffy/helpers'
22
+ require 'scruffy/graph_state'
21
23
  require 'scruffy/graph'
22
24
  require 'scruffy/themes'
23
25
  require 'scruffy/version'
@@ -1,5 +1,9 @@
1
1
  module Scruffy
2
2
  module Components
3
+ # ===Scruffy::Components::Base
4
+ #
5
+ # Common attributes for all components, and a standard render method
6
+ # that calls draw after setting up the drawing transformations.
3
7
  class Base
4
8
  attr_reader :id
5
9
 
@@ -1,52 +1,86 @@
1
1
  module Scruffy::Components
2
2
 
3
3
  class Legend < Base
4
+ FONT_SIZE = 80
5
+
4
6
  def draw(svg, bounds, options={})
7
+ vertical = options[:vertical_legend]
5
8
  legend_info = relevant_legend_info(options[:layers])
6
- active_width, points = layout(legend_info)
9
+ @line_height, x, y, size = 0
10
+ set_line_height = 0.08 * bounds[:height]
11
+ @line_height = bounds[:height] / legend_info.length
12
+ @line_height = set_line_height if @line_height > set_line_height
13
+ text_height = @line_height * FONT_SIZE / 100
14
+ # #TODO how does this related to @points?
15
+ active_width, points = layout(legend_info, vertical)
7
16
 
8
17
  offset = (bounds[:width] - active_width) / 2 # Nudge over a bit for true centering
9
18
 
10
19
  # Render Legend
11
20
  points.each_with_index do |point, idx|
21
+ if vertical
22
+ x = 0
23
+ y = point
24
+ size = @line_height * 0.5
25
+ else
26
+ x = offset + point
27
+ y = 0
28
+ size = relative(50)
29
+ end
12
30
 
13
- svg.rect( :x => offset + point,
14
- :y => relative(25),
15
- :width => relative(60),
16
- :height => relative(50),
17
- :fill => legend_info[idx][:color])
31
+ # "#{x} #{y} #{@line_height} #{size}"
32
+
33
+ svg.rect(:x => x,
34
+ :y => y,
35
+ :width => size,
36
+ :height => size,
37
+ :fill => legend_info[idx][:color])
18
38
 
19
- svg.text( legend_info[idx][:title],
20
- :x => offset + point + relative(100),
21
- :y => relative(80),
22
- 'font-size' => relative(80),
23
- :fill => (options[:theme].marker || 'white'))
39
+ svg.text(legend_info[idx][:title],
40
+ :x => x + @line_height,
41
+ :y => y + text_height * 0.75,
42
+ 'font-size' => text_height,
43
+ :style => "color: #{options[:theme].marker || 'white'}",
44
+ :fill => (options[:theme].marker || 'white'))
24
45
  end
25
46
  end # draw
26
47
 
27
48
  protected
28
- # Collects Legend Info from the provided Layers.
29
- #
30
- # Automatically filters by legend's categories.
31
- def relevant_legend_info(layers, categories=(@options[:category] ? [@options[:category]] : @options[:categories]))
32
- legend_info = layers.inject([]) do |arr, layer|
33
- if categories.nil? ||
34
- (categories.include?(layer.options[:category]) ||
35
- (layer.options[:categories] && (categories & layer.options[:categories]).size > 0) )
49
+ # Collects Legend Info from the provided Layers.
50
+ #
51
+ # Automatically filters by legend's categories.
52
+ def relevant_legend_info(layers, categories=(@options[:category] ? [@options[:category]] : @options[:categories]))
53
+ legend_info = layers.inject([]) do |arr, layer|
54
+ if categories.nil? ||
55
+ (categories.include?(layer.options[:category]) ||
56
+ (layer.options[:categories] && (categories & layer.options[:categories]).size > 0) )
36
57
 
37
- data = layer.legend_data
38
- arr << data if data.is_a?(Hash)
39
- arr = arr + data if data.is_a?(Array)
40
- end
41
- arr
58
+ data = layer.legend_data
59
+ arr << data if data.is_a?(Hash)
60
+ arr = arr + data if data.is_a?(Array)
42
61
  end
43
- end # relevant_legend_info
62
+ arr
63
+ end
64
+ end # relevant_legend_info
44
65
 
45
- # Returns an array consisting of the total width needed by the legend information,
46
- # as well as an array of x-coords for each element.
47
- #
48
- # ie: [200, [0, 50, 100, 150]]
49
- def layout(legend_info_array)
66
+ # Returns an array consisting of the total width needed by the legend
67
+ # information, as well as an array of @x-coords for each element. If
68
+ # vertical, then these are @y-coords, and @x is 0
69
+ #
70
+ # ie: [200, [0, 50, 100, 150]]
71
+ def layout(legend_info_array, vertical = false)
72
+ if vertical
73
+ longest = 0
74
+ legend_info_array.each {|elem|
75
+ cur_length = relative(50) * elem[:title].length
76
+ longest = longest < cur_length ? cur_length : longest
77
+ }
78
+ y_positions = []
79
+ (0..legend_info_array.length - 1).each {|y|
80
+ y_positions << y * @line_height
81
+ }
82
+ [longest, y_positions]
83
+ else
50
84
  legend_info_array.inject([0, []]) do |enum, elem|
51
85
  enum[0] += (relative(50) * 2) if enum.first != 0 # Add spacer between elements
52
86
  enum[1] << enum.first # Add location to points
@@ -56,6 +90,7 @@ module Scruffy::Components
56
90
  [enum.first, enum.last]
57
91
  end
58
92
  end
93
+ end
59
94
 
60
95
  end # class Legend
61
96
 
@@ -7,34 +7,31 @@ module Scruffy::Components
7
7
  super(*args)
8
8
 
9
9
  self.components = []
10
- if block
11
- block.call(self.components)
12
- end
10
+ block.call(self.components) if block
13
11
  end
14
12
 
15
13
  def draw(svg, bounds, options={})
16
14
  svg.g(options_for) {
17
15
  self.components.each do |component|
18
- component.render(svg,
19
- bounds_for( [bounds[:width], bounds[:height]],
20
- component.position,
21
- component.size ),
22
- options)
16
+ component.render(svg,
17
+ bounds_for([bounds[:width], bounds[:height]],
18
+ component.position,
19
+ component.size),
20
+ options)
23
21
  end
24
22
  }
25
23
  end
26
24
 
27
25
  private
28
- def options_for
29
- options = {}
30
- %w(skewX skewY).each do |option|
31
- if @options[option.to_sym]
32
- options[:transform] ||= ''
33
- options[:transform] = options[:transform] + "#{option.to_s}(#{@options[option.to_sym]})"
34
- end
26
+ def options_for
27
+ options = {}
28
+ %w(skewX skewY).each do |option|
29
+ if @options[option.to_sym]
30
+ options[:transform] ||= ''
31
+ options[:transform] = options[:transform] + "#{option.to_s}(#{@options[option.to_sym]})"
35
32
  end
36
-
37
- options
38
33
  end
34
+ options
35
+ end
39
36
  end
40
37
  end
@@ -55,7 +55,7 @@ module Scruffy::Formatters
55
55
  attr_reader :proc
56
56
 
57
57
  def initialize(&block)
58
- self.proc = block
58
+ @proc = block
59
59
  end
60
60
 
61
61
  def format(target, idx, options)
@@ -1,3 +1,5 @@
1
+ require 'forwardable'
2
+
1
3
  module Scruffy
2
4
 
3
5
  # ==Scruffy Graphs
@@ -70,15 +72,18 @@ module Scruffy
70
72
  #
71
73
  # Of course, while you may be able to combine some things such as pie charts and line graphs, that
72
74
  # doesn't necessarily mean they will make any logical sense together. We leave those decisions up to you. :)
75
+
73
76
  class Graph
74
- include Scruffy::Helpers::LayerContainer
77
+ extend Forwardable;
75
78
 
76
- attr_accessor :title
77
- attr_accessor :theme
78
- attr_accessor :default_type
79
- attr_accessor :point_markers
80
- attr_accessor :value_formatter
81
- attr_accessor :rasterizer
79
+ include Scruffy::Helpers::LayerContainer
80
+
81
+ # Delegating these getters to the internal state object.
82
+ def_delegators :internal_state, :title, :theme, :default_type,
83
+ :point_markers, :value_formatter, :rasterizer
84
+
85
+ def_delegators :internal_state, :title=, :theme=, :default_type=,
86
+ :point_markers=, :value_formatter=, :rasterizer=
82
87
 
83
88
  attr_reader :renderer # Writer defined below
84
89
 
@@ -174,5 +179,11 @@ module Scruffy
174
179
  def remove(id)
175
180
  renderer.remove(id)
176
181
  end
182
+
183
+ private
184
+ def internal_state
185
+ @internal_state ||= GraphState.new
186
+ end
187
+
177
188
  end
178
189
  end
@@ -0,0 +1,24 @@
1
+ # ===GraphState
2
+ #
3
+ # Author:: Brasten Sager
4
+ # Date:: September 27th, 2007
5
+ #
6
+ # State object for holding all of the graph's
7
+ # settings. Attempting to clean up the
8
+ # graph interface a bit.
9
+
10
+ module Scruffy
11
+ class GraphState
12
+
13
+ attr_accessor :title
14
+ attr_accessor :theme
15
+ attr_accessor :default_type
16
+ attr_accessor :point_markers
17
+ attr_accessor :value_formatter
18
+ attr_accessor :rasterizer
19
+
20
+ def initialize
21
+
22
+ end
23
+ end
24
+ end
@@ -8,4 +8,5 @@ module Scruffy::Helpers; end
8
8
 
9
9
  require 'scruffy/helpers/canvas'
10
10
  require 'scruffy/helpers/layer_container'
11
- require 'scruffy/helpers/meta'
11
+ require 'scruffy/helpers/point_container'
12
+ #require 'scruffy/helpers/meta'
@@ -1,11 +1,12 @@
1
1
  module Scruffy::Helpers
2
+
2
3
  # ==Scruffy::Helpers::Canvas
3
- #
4
+ #
4
5
  # Author:: Brasten Sager
5
6
  # Date:: August 16th, 2006
6
- #
7
- # Provides common methods for canvas objects. Primarily used for providing spacial-type calculations
8
- # where necessary.
7
+ #
8
+ # Provides common methods for canvas objects. Primarily used for providing
9
+ # spacial-type calculations where necessary.
9
10
  module Canvas
10
11
  attr_accessor :components
11
12
 
@@ -14,7 +15,7 @@ module Scruffy::Helpers
14
15
  end
15
16
 
16
17
  def component(id, components=self.components)
17
- components.find { |elem| elem.id == id }
18
+ components.find {|elem| elem.id == id}
18
19
  end
19
20
 
20
21
  def remove(id, components=self.components)
@@ -22,18 +23,19 @@ module Scruffy::Helpers
22
23
  end
23
24
 
24
25
  protected
25
- # Converts percentage values into actual pixe values based on the known render size.
26
- #
27
- # Returns a hash consisting of :x, :y, :width, and :height elements.
28
- def bounds_for(canvas_size, position, size)
29
- return nil if (position.nil? || size.nil?)
30
- bounds = {}
31
- bounds[:x] = canvas_size.first * (position.first / 100.to_f)
32
- bounds[:y] = canvas_size.last * (position.last / 100.to_f)
33
- bounds[:width] = canvas_size.first * (size.first / 100.to_f)
34
- bounds[:height] = canvas_size.last * (size.last / 100.to_f)
35
- bounds
36
- end
26
+ # Converts percentage values into actual pixel values based on the known
27
+ # render size.
28
+ #
29
+ # Returns a hash consisting of :x, :y, :width, and :height elements.
30
+ def bounds_for(canvas_size, position, size)
31
+ return nil if (position.nil? || size.nil?)
32
+ bounds = {}
33
+ bounds[:x] = canvas_size.first * (position.first / 100.to_f)
34
+ bounds[:y] = canvas_size.last * (position.last / 100.to_f)
35
+ bounds[:width] = canvas_size.first * (size.first / 100.to_f)
36
+ bounds[:height] = canvas_size.last * (size.last / 100.to_f)
37
+ bounds
38
+ end
37
39
  end # canvas
38
40
 
39
41
  end # scruffy::helpers