ramhoj-scruffy 0.2.6

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