scruffy 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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