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.
- 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
|