ramhoj-scruffy 0.2.6

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 (55) hide show
  1. data/README.txt +66 -0
  2. data/lib/scruffy.rb +25 -0
  3. data/lib/scruffy/components.rb +21 -0
  4. data/lib/scruffy/components/background.rb +24 -0
  5. data/lib/scruffy/components/base.rb +57 -0
  6. data/lib/scruffy/components/data_markers.rb +26 -0
  7. data/lib/scruffy/components/graphs.rb +48 -0
  8. data/lib/scruffy/components/grid.rb +19 -0
  9. data/lib/scruffy/components/label.rb +17 -0
  10. data/lib/scruffy/components/legend.rb +105 -0
  11. data/lib/scruffy/components/style_info.rb +22 -0
  12. data/lib/scruffy/components/title.rb +19 -0
  13. data/lib/scruffy/components/value_markers.rb +32 -0
  14. data/lib/scruffy/components/viewport.rb +37 -0
  15. data/lib/scruffy/formatters.rb +213 -0
  16. data/lib/scruffy/graph.rb +190 -0
  17. data/lib/scruffy/graph_state.rb +24 -0
  18. data/lib/scruffy/helpers.rb +12 -0
  19. data/lib/scruffy/helpers/canvas.rb +41 -0
  20. data/lib/scruffy/helpers/layer_container.rb +95 -0
  21. data/lib/scruffy/helpers/meta.rb +5 -0
  22. data/lib/scruffy/helpers/point_container.rb +70 -0
  23. data/lib/scruffy/layers.rb +24 -0
  24. data/lib/scruffy/layers/all_smiles.rb +137 -0
  25. data/lib/scruffy/layers/area.rb +46 -0
  26. data/lib/scruffy/layers/average.rb +67 -0
  27. data/lib/scruffy/layers/bar.rb +52 -0
  28. data/lib/scruffy/layers/base.rb +191 -0
  29. data/lib/scruffy/layers/line.rb +46 -0
  30. data/lib/scruffy/layers/pie.rb +123 -0
  31. data/lib/scruffy/layers/pie_slice.rb +119 -0
  32. data/lib/scruffy/layers/scatter.rb +21 -0
  33. data/lib/scruffy/layers/sparkline_bar.rb +39 -0
  34. data/lib/scruffy/layers/stacked.rb +87 -0
  35. data/lib/scruffy/rasterizers.rb +14 -0
  36. data/lib/scruffy/rasterizers/batik_rasterizer.rb +39 -0
  37. data/lib/scruffy/rasterizers/rmagick_rasterizer.rb +27 -0
  38. data/lib/scruffy/renderers.rb +22 -0
  39. data/lib/scruffy/renderers/base.rb +93 -0
  40. data/lib/scruffy/renderers/cubed.rb +44 -0
  41. data/lib/scruffy/renderers/cubed3d.rb +53 -0
  42. data/lib/scruffy/renderers/empty.rb +22 -0
  43. data/lib/scruffy/renderers/pie.rb +20 -0
  44. data/lib/scruffy/renderers/reversed.rb +17 -0
  45. data/lib/scruffy/renderers/sparkline.rb +10 -0
  46. data/lib/scruffy/renderers/split.rb +48 -0
  47. data/lib/scruffy/renderers/standard.rb +36 -0
  48. data/lib/scruffy/themes.rb +156 -0
  49. data/lib/scruffy/version.rb +3 -0
  50. data/spec/output/array.svg +47 -0
  51. data/spec/output/hash.svg +47 -0
  52. data/spec/scruffy/graph_spec.rb +175 -0
  53. data/spec/scruffy/layers/base_spec.rb +30 -0
  54. data/spec/spec_helper.rb +8 -0
  55. metadata +155 -0
@@ -0,0 +1,66 @@
1
+ = scruffy, unofficial release
2
+
3
+ This is a fork from based on the official 0.2.5 release. See below for
4
+ further a longer description.
5
+
6
+ == DESCRIPTION:
7
+
8
+ * scruffy.rubyforge.org
9
+
10
+ Author:: Brasten Sager (brasten@nagilum.com)
11
+ Date:: July 8, 2008
12
+ Release:: 0.2.5
13
+
14
+ Scruffy is a Ruby library for generating high quality, good looking graphs. It is designed
15
+ to be easy to use and highly customizable.
16
+
17
+ For basic usage instructions, refer to the documentation for Scruffy::Graph.
18
+
19
+
20
+ == FORK DESCRIPTION
21
+
22
+ * http://github.com/delano/scruffy/
23
+
24
+ Author:: Delano Mandelbaum (delano@solutious.com)
25
+ Author:: Kalin Harvey
26
+ Date:: December 12, 2008
27
+
28
+ We love scruffy. Our motivation for creating a forking is to make it useful for hi-resolution
29
+ graphs and charts. We would love to get our changes in to the official release but until
30
+ that time they will be available at the GitHub URI above.
31
+
32
+ CHANGES.txt contains everything we've been up to.
33
+
34
+
35
+ == FEATURES
36
+
37
+ * Renders to SVG or bitmap (PNG, JPG)
38
+
39
+ == PROBLEMS:
40
+
41
+ * 0.2.3 version has missing legend text when rendering to bitmap. This is strange because the text is there in the SVG before it goes to RMagick.
42
+
43
+ == SYNOPSIS:
44
+
45
+ graph = Scruffy::Graph.new
46
+ graph.title = "Sample Line Graph"
47
+ graph.renderer = Scruffy::Renderers::Standard.new
48
+
49
+ graph.add :line, 'Example', [20, 100, 70, 30, 106]
50
+
51
+ graph.render :to => "line_test.svg"
52
+ graph.render :width => 300, :height => 200,
53
+ :to => "line_test.png", :as => 'png'
54
+
55
+ == REQUIREMENTS:
56
+
57
+ * Needs RMagick and Magic installed, if you wish to render to bitmap.
58
+
59
+ == INSTALL:
60
+
61
+ * sudo gem install scruffy
62
+
63
+
64
+ == LICENSE:
65
+
66
+ See Licence.txt
@@ -0,0 +1,25 @@
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
12
+ end
13
+
14
+ require 'builder'
15
+
16
+ require 'scruffy/helpers'
17
+ require 'scruffy/graph_state'
18
+ require 'scruffy/graph'
19
+ require 'scruffy/themes'
20
+ require 'scruffy/version'
21
+ require 'scruffy/formatters'
22
+ require 'scruffy/rasterizers'
23
+ require 'scruffy/layers'
24
+ require 'scruffy/components'
25
+ require 'scruffy/renderers'
@@ -0,0 +1,21 @@
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
+
11
+ require 'scruffy/components/base'
12
+ require 'scruffy/components/title'
13
+ require 'scruffy/components/background'
14
+ require 'scruffy/components/graphs'
15
+ require 'scruffy/components/grid'
16
+ require 'scruffy/components/value_markers'
17
+ require 'scruffy/components/data_markers'
18
+ require 'scruffy/components/legend'
19
+ require 'scruffy/components/style_info'
20
+ require 'scruffy/components/viewport'
21
+ require 'scruffy/components/label'
@@ -0,0 +1,24 @@
1
+ module Scruffy
2
+ module Components
3
+ class Background < Base
4
+ def draw(svg, bounds, options={})
5
+ fill = "#EEEEEE"
6
+ case options[:theme].background
7
+ when Symbol, String
8
+ fill = options[:theme].background.to_s
9
+ when Array
10
+ fill = "url(#BackgroundGradient)"
11
+ svg.defs {
12
+ svg.linearGradient(:id=>'BackgroundGradient', :x1 => '0%', :y1 => '0%', :x2 => '0%', :y2 => '100%') {
13
+ svg.stop(:offset => '5%', 'stop-color' => options[:theme].background[0])
14
+ svg.stop(:offset => '95%', 'stop-color' => options[:theme].background[1])
15
+ }
16
+ }
17
+ end
18
+
19
+ # Render background (maybe)
20
+ svg.rect(:width => bounds[:width], :height => bounds[:height], :x => "0", :y => "0", :fill => fill) unless fill.nil?
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,57 @@
1
+ module Scruffy
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.
7
+ class Base
8
+ attr_reader :id
9
+
10
+ # In terms of percentages: [10, 10] == 10% by 10%
11
+ attr_accessor :position
12
+ attr_accessor :size
13
+ attr_accessor :options
14
+ attr_accessor :visible
15
+
16
+ # Options:
17
+ # stroke_width:: numeric value for width of line (0.1 - 10, default: 1)
18
+ def initialize(id, options = {})
19
+ @id = id.to_sym
20
+ @position = options[:position] || [0, 0]
21
+ @size = options[:size] || [100, 100]
22
+ @visible = options[:visible] || true
23
+
24
+ @options = options
25
+ end
26
+
27
+ def render(svg, bounds, options={})
28
+ if @visible
29
+ unless bounds.nil?
30
+ @render_height = bounds[:height]
31
+
32
+ svg.g(:id => id.to_s,
33
+ :transform => "translate(#{bounds.delete(:x)}, #{bounds.delete(:y)})") {
34
+
35
+ draw(svg, bounds, options.merge(@options))
36
+ }
37
+ else
38
+ process(svg, options.merge(@options))
39
+ end
40
+ end
41
+ end
42
+
43
+ def draw(svg, bounds, options={})
44
+ # Override this if visual component
45
+ end
46
+
47
+ def process(svg, options={})
48
+ # Override this NOT a visual component
49
+ end
50
+
51
+ protected
52
+ def relative(pct)
53
+ @render_height * ( pct / 100.to_f )
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,26 @@
1
+ module Scruffy
2
+ module Components
3
+
4
+ class DataMarkers < Base
5
+
6
+ def draw(svg, bounds, options={})
7
+ unless options[:point_markers].nil?
8
+ point_distance = bounds[:width] / (options[:point_markers].size - 1).to_f
9
+
10
+ (0...options[:point_markers].size).map do |idx|
11
+ x_coord = point_distance * idx
12
+ svg.text(options[:point_markers][idx],
13
+ :x => x_coord,
14
+ :y => bounds[:height],
15
+ 'font-size' => relative(90),
16
+ 'font-family' => options[:theme].font_family,
17
+ :fill => (options[:theme].marker || 'white').to_s,
18
+ 'text-anchor' => 'middle') unless options[:point_markers][idx].nil?
19
+ end
20
+ end
21
+ end # draw
22
+
23
+ end # class
24
+
25
+ end
26
+ end
@@ -0,0 +1,48 @@
1
+ module Scruffy
2
+ module Components
3
+
4
+ # Component for displaying Graphs layers.
5
+ #
6
+ # Is passed all graph layers from the Graph object.
7
+ #
8
+ # (This may change as the capability for Graph filtering and such fills out.)
9
+ class Graphs < Base
10
+ STACKED_OPACITY = 0.85;
11
+
12
+ def draw(svg, bounds, options={})
13
+ # If Graph is limited to a category, reject layers outside of it's scope.
14
+ applicable_layers = options[:layers].reject do |l|
15
+ if @options[:only]
16
+ (l.options[:category].nil? && l.options[:categories].nil?) ||
17
+ (!l.options[:category].nil? && l.options[:category] != @options[:only]) ||
18
+ (!l.options[:categories].nil? && !l.options[:categories].include?(@options[:only]))
19
+ else
20
+ false
21
+ end
22
+ end
23
+
24
+ applicable_layers.each_with_index do |layer, idx|
25
+ layer_options = {}
26
+ layer_options[:index] = idx
27
+ layer_options[:min_value] = options[:min_value]
28
+ layer_options[:max_value] = options[:max_value]
29
+ layer_options[:complexity] = options[:complexity]
30
+ layer_options[:size] = [bounds[:width], bounds[:height]]
31
+ layer_options[:color] = layer.preferred_color || layer.color || options[:theme].next_color
32
+ layer_options[:opacity] = opacity_for(idx)
33
+ layer_options[:theme] = options[:theme]
34
+
35
+ svg.g(:id => "component_#{id}_graph_#{idx}", :class => 'graph_layer') {
36
+ layer.render(svg, layer_options)
37
+ }
38
+ end # applicable_layers
39
+ end # draw
40
+
41
+ protected
42
+ def opacity_for(idx)
43
+ (idx == 0) ? 1.0 : (@options[:stacked_opacity] || STACKED_OPACITY)
44
+ end
45
+
46
+ end #class
47
+ end
48
+ end
@@ -0,0 +1,19 @@
1
+ module Scruffy
2
+ module Components
3
+ class Grid < Base
4
+ attr_accessor :markers
5
+
6
+ def draw(svg, bounds, options={})
7
+ markers = (options[:markers] || self.markers) || 5
8
+
9
+ stroke_width = options[:stroke_width]
10
+
11
+ (0...markers).each do |idx|
12
+ marker = ((1 / (markers - 1).to_f) * idx) * bounds[:height]
13
+ svg.line(:x1 => 0, :y1 => marker, :x2 => bounds[:width], :y2 => marker, :style => "stroke: #{options[:theme].marker.to_s}; stroke-width: #{stroke_width};")
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -0,0 +1,17 @@
1
+ module Scruffy
2
+ module Components
3
+ class Label < Base
4
+ def draw(svg, bounds, options={})
5
+ svg.text(@options[:text],
6
+ :class => 'text',
7
+ :x => (bounds[:width] / 2),
8
+ :y => bounds[:height],
9
+ 'font-size' => relative(100),
10
+ 'font-family' => options[:theme].font_family,
11
+ :fill => options[:theme].marker,
12
+ :stroke => 'none', 'stroke-width' => '0',
13
+ 'text-anchor' => (@options[:text_anchor] || 'middle'))
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,105 @@
1
+ module Scruffy::Components
2
+
3
+ class Legend < Base
4
+ FONT_SIZE = 80
5
+
6
+ def draw(svg, bounds, options={})
7
+ vertical = options[:vertical_legend]
8
+ legend_info = relevant_legend_info(options[:layers])
9
+ @line_height, x, y, size = 0
10
+ if vertical
11
+ set_line_height = 0.08 * bounds[:height]
12
+ @line_height = bounds[:height] / legend_info.length
13
+ @line_height = set_line_height if @line_height >
14
+ set_line_height
15
+ else
16
+ set_line_height = 0.90 * bounds[:height]
17
+ @line_height = set_line_height
18
+ end
19
+
20
+ text_height = @line_height * FONT_SIZE / 100
21
+ # #TODO how does this related to @points?
22
+ active_width, points = layout(legend_info, vertical)
23
+
24
+ offset = (bounds[:width] - active_width) / 2 # Nudge over a bit for true centering
25
+
26
+ # Render Legend
27
+ points.each_with_index do |point, idx|
28
+ if vertical
29
+ x = 0
30
+ y = point
31
+ size = @line_height * 0.5
32
+ else
33
+ x = offset + point
34
+ y = 0
35
+ size = relative(50)
36
+ end
37
+
38
+ # "#{x} #{y} #{@line_height} #{size}"
39
+
40
+ svg.rect(:x => x,
41
+ :y => y,
42
+ :width => size,
43
+ :height => size,
44
+ :fill => legend_info[idx][:color])
45
+
46
+ svg.text(legend_info[idx][:title],
47
+ :x => x + @line_height,
48
+ :y => y + text_height * 0.75,
49
+ 'font-size' => text_height,
50
+ 'font-family' => options[:theme].font_family,
51
+ :style => "color: #{options[:theme].marker || 'white'}",
52
+ :fill => (options[:theme].marker || 'white'))
53
+ end
54
+ end # draw
55
+
56
+ protected
57
+ # Collects Legend Info from the provided Layers.
58
+ #
59
+ # Automatically filters by legend's categories.
60
+ def relevant_legend_info(layers, categories=(@options[:category] ? [@options[:category]] : @options[:categories]))
61
+ legend_info = layers.inject([]) do |arr, layer|
62
+ if categories.nil? ||
63
+ (categories.include?(layer.options[:category]) ||
64
+ (layer.options[:categories] && (categories & layer.options[:categories]).size > 0) )
65
+
66
+ data = layer.legend_data
67
+ arr << data if data.is_a?(Hash)
68
+ arr = arr + data if data.is_a?(Array)
69
+ end
70
+ arr
71
+ end
72
+ end # relevant_legend_info
73
+
74
+ # Returns an array consisting of the total width needed by the legend
75
+ # information, as well as an array of @x-coords for each element. If
76
+ # vertical, then these are @y-coords, and @x is 0
77
+ #
78
+ # ie: [200, [0, 50, 100, 150]]
79
+ def layout(legend_info_array, vertical = false)
80
+ if vertical
81
+ longest = 0
82
+ legend_info_array.each {|elem|
83
+ cur_length = relative(50) * elem[:title].length
84
+ longest = longest < cur_length ? cur_length : longest
85
+ }
86
+ y_positions = []
87
+ (0..legend_info_array.length - 1).each {|y|
88
+ y_positions << y * @line_height
89
+ }
90
+ [longest, y_positions]
91
+ else
92
+ legend_info_array.inject([0, []]) do |enum, elem|
93
+ enum[0] += (relative(50) * 2) if enum.first != 0 # Add spacer between elements
94
+ enum[1] << enum.first # Add location to points
95
+ enum[0] += relative(50) # Add room for color box
96
+ enum[0] += (relative(50) * elem[:title].length) # Add room for text
97
+
98
+ [enum.first, enum.last]
99
+ end
100
+ end
101
+ end
102
+
103
+ end # class Legend
104
+
105
+ end # Scruffy::Components
@@ -0,0 +1,22 @@
1
+ module Scruffy
2
+ module Components
3
+ # Component used for adding CSS styling to SVG graphs.
4
+ #
5
+ # In hindsight, ImageMagick and Mozilla SVG's handling of CSS styling is
6
+ # extremely inconsistant, so use this at your own risk.
7
+ class StyleInfo < Base
8
+ def initialize(*args)
9
+ super
10
+
11
+ @visible = false
12
+ end
13
+ def process(svg, options={})
14
+ svg.defs {
15
+ svg.style(:type => "text/css") {
16
+ svg.cdata!("\n#{options[:selector]} {\n #{options[:style]}\n}\n")
17
+ }
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ module Scruffy
2
+ module Components
3
+ class Title < Base
4
+ def draw(svg, bounds, options={})
5
+ if options[:title]
6
+ svg.text(options[:title],
7
+ :class => 'title',
8
+ :x => (bounds[:width] / 2),
9
+ :y => bounds[:height],
10
+ 'font-size' => relative(100),
11
+ 'font-family' => options[:theme].font_family,
12
+ :fill => options[:theme].marker,
13
+ :stroke => 'none', 'stroke-width' => '0',
14
+ 'text-anchor' => (@options[:text_anchor] || 'middle'))
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end