scruffy 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +8 -0
- data/History.txt +104 -0
- data/License.txt +20 -0
- data/Manifest.txt +105 -0
- data/PostInstall.txt +6 -0
- data/README.txt +66 -0
- data/Rakefile +108 -104
- data/config/hoe.rb +78 -0
- data/config/requirements.rb +15 -0
- data/lib/scruffy.rb +8 -6
- data/lib/scruffy/components/base.rb +4 -0
- data/lib/scruffy/components/legend.rb +65 -30
- data/lib/scruffy/components/viewport.rb +14 -17
- data/lib/scruffy/formatters.rb +1 -1
- data/lib/scruffy/graph.rb +18 -7
- data/lib/scruffy/graph_state.rb +24 -0
- data/lib/scruffy/helpers.rb +2 -1
- data/lib/scruffy/helpers/canvas.rb +19 -17
- data/lib/scruffy/helpers/layer_container.rb +8 -3
- data/lib/scruffy/helpers/meta.rb +5 -5
- data/lib/scruffy/helpers/point_container.rb +70 -0
- data/lib/scruffy/layers.rb +2 -0
- data/lib/scruffy/layers/average.rb +6 -1
- data/lib/scruffy/layers/bar.rb +1 -0
- data/lib/scruffy/layers/base.rb +38 -14
- data/lib/scruffy/layers/pie.rb +123 -0
- data/lib/scruffy/layers/pie_slice.rb +114 -0
- data/lib/scruffy/layers/scatter.rb +21 -0
- data/lib/scruffy/layers/sparkline_bar.rb +1 -0
- data/lib/scruffy/layers/stacked.rb +2 -5
- data/lib/scruffy/rasterizers/rmagick_rasterizer.rb +1 -2
- data/lib/scruffy/renderers.rb +2 -1
- data/lib/scruffy/renderers/base.rb +6 -4
- data/lib/scruffy/renderers/pie.rb +20 -0
- data/lib/scruffy/themes.rb +54 -4
- data/lib/scruffy/version.rb +8 -2
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +82 -0
- data/setup.rb +1585 -0
- data/spec/scruffy/graph_spec.rb +175 -0
- data/spec/scruffy/layers/base_spec.rb +30 -0
- data/spec/{layers → scruffy/layers}/line_spec.rb +2 -1
- data/spec/spec_helper.rb +8 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/graph_creation_test.rb +101 -0
- data/test/test_helper.rb +2 -0
- data/test/test_scruffy.rb +11 -0
- data/website/images/blank.gif.html +7 -0
- data/website/images/graphs/all_smiles.png +0 -0
- data/website/images/graphs/bar_test.png +0 -0
- data/website/images/graphs/bar_test.svg +71 -0
- data/website/images/graphs/line_test.png +0 -0
- data/website/images/graphs/line_test.svg +60 -0
- data/website/images/graphs/multi_test.png +0 -0
- data/website/images/graphs/multi_test.svg +296 -0
- data/website/images/graphs/pie_test.png +0 -0
- data/website/images/graphs/pie_test.svg +40 -0
- data/website/images/graphs/split_test.png +0 -0
- data/website/images/graphs/split_test.svg +295 -0
- data/website/images/graphs/stacking_test.png +0 -0
- data/website/images/graphs/stacking_test.svg +146 -0
- data/website/images/header.png +0 -0
- data/website/images/header_gradient.png +0 -0
- data/website/images/overlay.png +0 -0
- data/website/images/scruffy.png +0 -0
- data/website/index.html +294 -0
- data/website/index.txt +199 -0
- data/website/javascripts/application.js +2 -0
- data/website/javascripts/controls.js +815 -0
- data/website/javascripts/dragdrop.js +913 -0
- data/website/javascripts/effects.js +958 -0
- data/website/javascripts/lightbox.js +437 -0
- data/website/javascripts/prototype.js +2006 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/lightbox.css +27 -0
- data/website/stylesheets/screen.css +147 -0
- data/website/stylesheets/scruffy.css +227 -0
- data/website/template.html.erb +47 -0
- metadata +135 -55
- data/spec/graph_spec.rb +0 -162
data/config/hoe.rb
ADDED
@@ -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]))
|
data/lib/scruffy.rb
CHANGED
@@ -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
|
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
|
-
|
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,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
|
-
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
62
|
+
arr
|
63
|
+
end
|
64
|
+
end # relevant_legend_info
|
44
65
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
data/lib/scruffy/formatters.rb
CHANGED
data/lib/scruffy/graph.rb
CHANGED
@@ -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
|
-
|
77
|
+
extend Forwardable;
|
75
78
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
data/lib/scruffy/helpers.rb
CHANGED
@@ -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
|
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 {
|
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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|