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
@@ -30,15 +30,20 @@ module Scruffy::Helpers
|
|
30
30
|
else
|
31
31
|
type = args.first.is_a?(Symbol) ? args.shift : @default_type
|
32
32
|
title = args.shift if args.first.is_a?(String)
|
33
|
-
|
33
|
+
|
34
|
+
# Layer handles PointContainer mixin, don't do it here
|
35
|
+
points = [Array, Hash].include?(args.first.class) ? args.shift : []
|
34
36
|
options = args.first.is_a?(Hash) ? args.shift : {}
|
35
37
|
|
36
38
|
title ||= ''
|
37
39
|
|
38
40
|
raise ArgumentError,
|
39
41
|
'You must specify a graph type (:area, :bar, :line, etc) if you do not have a default type specified.' if type.nil?
|
40
|
-
|
41
|
-
|
42
|
+
|
43
|
+
class_name = "Scruffy::Layers::#{to_camelcase(type.to_s)}"
|
44
|
+
layer_class = Kernel::module_eval(class_name)
|
45
|
+
options = {:points => points, :title => title}.merge options
|
46
|
+
layer = layer_class.new(options, &block)
|
42
47
|
layers << layer
|
43
48
|
end
|
44
49
|
layer
|
data/lib/scruffy/helpers/meta.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
module Scruffy::MetaAttributes
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
end
|
1
|
+
# module Scruffy::Helpers::MetaAttributes
|
2
|
+
# def singleton_class
|
3
|
+
# (class << self; self; end)
|
4
|
+
# end
|
5
|
+
# end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Scruffy::Helpers
|
2
|
+
|
3
|
+
# ==Scruffy::Helpers::PointContainer
|
4
|
+
#
|
5
|
+
# Author:: Mat Schaffer
|
6
|
+
# Date:: March 22nd, 2007
|
7
|
+
#
|
8
|
+
# Allows all standard point operations to be called on both Array and Hash
|
9
|
+
module PointContainer
|
10
|
+
def self.extended point_set
|
11
|
+
point_set.extend(const_get(point_set.class.to_s))
|
12
|
+
end
|
13
|
+
|
14
|
+
def sortable_values
|
15
|
+
values.find_all { |v| v.respond_to? :<=> }
|
16
|
+
end
|
17
|
+
|
18
|
+
def summable_values
|
19
|
+
values.find_all { |v| v.respond_to? :+ }
|
20
|
+
end
|
21
|
+
|
22
|
+
def maximum_value
|
23
|
+
sortable_values.sort.last
|
24
|
+
end
|
25
|
+
|
26
|
+
def minimum_value
|
27
|
+
sortable_values.sort.first
|
28
|
+
end
|
29
|
+
|
30
|
+
def sum
|
31
|
+
summable_values.inject(0) { |sum, i| sum += i }
|
32
|
+
end
|
33
|
+
|
34
|
+
def inject_with_index memo
|
35
|
+
index = 0
|
36
|
+
inject(memo) do |memo, item|
|
37
|
+
ret = yield memo, item, index
|
38
|
+
index = index.succ
|
39
|
+
ret
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Array
|
44
|
+
def values
|
45
|
+
self
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module Hash
|
50
|
+
def minimum_key
|
51
|
+
self.keys.sort.first
|
52
|
+
end
|
53
|
+
|
54
|
+
def maximum_key
|
55
|
+
self.keys.sort.last
|
56
|
+
end
|
57
|
+
|
58
|
+
def inject memo
|
59
|
+
(minimum_key..maximum_key).each do |i|
|
60
|
+
memo = yield memo, self[i]
|
61
|
+
end
|
62
|
+
memo
|
63
|
+
end
|
64
|
+
|
65
|
+
def size
|
66
|
+
maximum_key - minimum_key + 1
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/scruffy/layers.rb
CHANGED
@@ -12,12 +12,16 @@ module Scruffy::Layers
|
|
12
12
|
# for some reason, creating a massive black line. Any help resolving this would
|
13
13
|
# be useful.
|
14
14
|
class Average < Base
|
15
|
+
attr_reader :layers
|
15
16
|
|
16
17
|
# Returns new Average graph.
|
17
18
|
def initialize(options = {})
|
18
19
|
# Set self's relevant_data to false. Otherwise we get stuck in a
|
19
20
|
# recursive loop.
|
20
21
|
super(options.merge({:relevant_data => false}))
|
22
|
+
|
23
|
+
# The usual :points argument is actually layers for Average, name it as such
|
24
|
+
@layers = options[:points]
|
21
25
|
end
|
22
26
|
|
23
27
|
# Render average graph.
|
@@ -30,12 +34,13 @@ module Scruffy::Layers
|
|
30
34
|
# Override default generate_coordinates method to iterate through the layers and
|
31
35
|
# generate coordinates based on the average data points.
|
32
36
|
def generate_coordinates(options = {})
|
33
|
-
key_layer =
|
37
|
+
key_layer = layers.find { |layer| layer.relevant_data? }
|
34
38
|
|
35
39
|
options[:point_distance] = width / (key_layer.points.size - 1).to_f
|
36
40
|
|
37
41
|
coords = []
|
38
42
|
|
43
|
+
#TODO this will likely break with the new hash model
|
39
44
|
key_layer.points.each_with_index do |layer, idx|
|
40
45
|
sum, objects = points.inject([0, 0]) do |arr, elem|
|
41
46
|
if elem.relevant_data?
|
data/lib/scruffy/layers/bar.rb
CHANGED
@@ -38,6 +38,7 @@ module Scruffy::Layers
|
|
38
38
|
@bar_width = (width / points.size) * 0.9
|
39
39
|
options[:point_distance] = (width - (width / points.size)) / (points.size - 1).to_f
|
40
40
|
|
41
|
+
#TODO more array work with index, try to rework to be accepting of hashes
|
41
42
|
coords = (0...points.size).map do |idx|
|
42
43
|
x_coord = (options[:point_distance] * idx) + (width / points.size * 0.5)
|
43
44
|
|
data/lib/scruffy/layers/base.rb
CHANGED
@@ -2,7 +2,9 @@ module Scruffy::Layers
|
|
2
2
|
# ==Scruffy::Layers::Base
|
3
3
|
#
|
4
4
|
# Author:: Brasten Sager
|
5
|
-
#
|
5
|
+
# Extended By:: A.J. Ostman
|
6
|
+
# Created:: August 5th, 2006
|
7
|
+
# Last Modified:: August 27, 2006
|
6
8
|
#
|
7
9
|
# Scruffy::Layers::Base contains the basic functionality needed by the various types of graphs. The Base
|
8
10
|
# class is responsible holding layer information such as the title and data points.
|
@@ -49,9 +51,11 @@ module Scruffy::Layers
|
|
49
51
|
# included in any graph data aggregations, such as averaging data points.
|
50
52
|
def initialize(options = {})
|
51
53
|
@title = options.delete(:title) || ''
|
52
|
-
@points = options.delete(:points) || []
|
53
54
|
@preferred_color = options.delete(:preferred_color)
|
54
55
|
@relevant_data = options.delete(:relevant_data) || true
|
56
|
+
@points = options.delete(:points) || []
|
57
|
+
@points.extend Scruffy::Helpers::PointContainer unless @points.kind_of? Scruffy::Helpers::PointContainer
|
58
|
+
|
55
59
|
@options = options
|
56
60
|
end
|
57
61
|
|
@@ -98,15 +102,20 @@ module Scruffy::Layers
|
|
98
102
|
def relevant_data?
|
99
103
|
@relevant_data
|
100
104
|
end
|
101
|
-
|
105
|
+
|
102
106
|
# The highest data point on this layer, or nil if relevant_data == false
|
103
107
|
def top_value
|
104
|
-
@relevant_data ? points.
|
108
|
+
@relevant_data ? points.maximum_value : nil
|
105
109
|
end
|
106
110
|
|
107
111
|
# The lowest data point on this layer, or nil if relevant_data == false
|
108
112
|
def bottom_value
|
109
|
-
|
113
|
+
@relevant_data ? points.minimum_value : nil
|
114
|
+
end
|
115
|
+
|
116
|
+
# The sum of all values
|
117
|
+
def sum_values
|
118
|
+
points.sum
|
110
119
|
end
|
111
120
|
|
112
121
|
protected
|
@@ -125,17 +134,19 @@ module Scruffy::Layers
|
|
125
134
|
# in pie charting and bar charts).
|
126
135
|
def generate_coordinates(options = {})
|
127
136
|
options[:point_distance] = width / (points.size - 1).to_f
|
128
|
-
|
129
|
-
coords = (0...points.size).map do |idx|
|
130
|
-
x_coord = options[:point_distance] * idx
|
131
137
|
|
132
|
-
|
133
|
-
|
138
|
+
points.inject_with_index([]) do |memo, point, idx|
|
139
|
+
x_coord = options[:point_distance] * idx
|
134
140
|
|
135
|
-
|
141
|
+
if point
|
142
|
+
relative_percent = ((point == min_value) ? 0 : ((point - min_value) / (max_value - min_value).to_f))
|
143
|
+
y_coord = (height - (height * relative_percent))
|
144
|
+
|
145
|
+
memo << [x_coord, y_coord]
|
146
|
+
end
|
147
|
+
|
148
|
+
memo
|
136
149
|
end
|
137
|
-
|
138
|
-
coords
|
139
150
|
end
|
140
151
|
|
141
152
|
# Converts a percentage into a pixel value, relative to the height.
|
@@ -143,8 +154,21 @@ module Scruffy::Layers
|
|
143
154
|
# Example:
|
144
155
|
# relative(5) # On a 100px high layer, this returns 5. 200px high layer, this returns 10, etc.
|
145
156
|
def relative(pct)
|
146
|
-
|
157
|
+
# Default to Relative Height
|
158
|
+
relative_height(pct)
|
159
|
+
end
|
160
|
+
|
161
|
+
def relative_width(pct)
|
162
|
+
if pct # Added to handle nils
|
163
|
+
@width * (pct / 100.to_f)
|
164
|
+
end
|
147
165
|
end
|
166
|
+
|
167
|
+
def relative_height(pct)
|
168
|
+
if pct # Added to handle nils
|
169
|
+
@height * (pct / 100.to_f)
|
170
|
+
end
|
171
|
+
end
|
148
172
|
|
149
173
|
# Some SVG elements take a long string of multiple coordinates. This is here
|
150
174
|
# to make that a little easier.
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module Scruffy::Layers
|
2
|
+
# ==Scruffy::Layers::Pie
|
3
|
+
#
|
4
|
+
# Author:: A.J. Ostman
|
5
|
+
# Date:: August 15, 2006
|
6
|
+
#
|
7
|
+
# Provides a container for pie slice.
|
8
|
+
class Pie < Base
|
9
|
+
include Scruffy::Helpers::LayerContainer
|
10
|
+
|
11
|
+
# Basic Example:
|
12
|
+
#
|
13
|
+
# graph = Scruffy::Graph.new
|
14
|
+
# graph.title = "Snack Preference"
|
15
|
+
# graph.renderer = Scruffy::Renderers::Pie.new
|
16
|
+
# graph.add :pie, 'Example', {'Apples' => 90, 'Orange' => 60, 'Taco' => 30}
|
17
|
+
#
|
18
|
+
# Or, using a block to add slices:
|
19
|
+
#
|
20
|
+
# graph = Scruffy::Graph.new
|
21
|
+
# graph.title = "Snack Preference"
|
22
|
+
# graph.renderer = Scruffy::Renderers::Pie.new
|
23
|
+
# graph.add :pie do |pie|
|
24
|
+
# pie.add :pie_slice, 'Apple', [90]
|
25
|
+
# pie.add :pie_slice, 'Orange', [60]
|
26
|
+
# pie.add :pie_slice, 'Taco', [30]
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# Another Example:
|
30
|
+
# graph.title = "Scruff-Pac!"
|
31
|
+
# graph.renderer = Scruffy::Renderers::Pie.new
|
32
|
+
# graph.add :pie, :diameter => 40, :degree_offset => 30 do |pie|
|
33
|
+
# pie.add :pie_slice, '', [160], :preferred_color => "yellow", :shadow => true,
|
34
|
+
# :shadow_x => -1, :shadow_y => 1, :shadow_color=>"black", :shadow_opacity => 0.4
|
35
|
+
# pie.add :pie_slice, '', [50], :preferred_color => "green", :explode => 5, :diameter => 20,
|
36
|
+
# :shadow => true, :shadow_x => -1, :shadow_y => 1, :shadow_color => "black", :shadow_opacity => 0.4
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# graph.add :pie, :diameter => 3, :center_x => 48, :center_y=> 37, :degree_offset => 20 do |pie|
|
40
|
+
# pie.add :pie_slice, '', [160], :preferred_color => "blue", :stroke => "black"
|
41
|
+
# end
|
42
|
+
|
43
|
+
|
44
|
+
# Setup Constants
|
45
|
+
RADIANS = Math::PI/180
|
46
|
+
|
47
|
+
attr_accessor :diameter
|
48
|
+
attr_accessor :percent_used
|
49
|
+
attr_accessor :degree_offset
|
50
|
+
attr_accessor :scaler
|
51
|
+
attr_accessor :center_x, :center_y
|
52
|
+
|
53
|
+
|
54
|
+
# The initialize method passes itself to the block, and since Pie is a
|
55
|
+
# LayerContainer, layers (pie slice) can be added just as if they were being
|
56
|
+
# added to Graph.
|
57
|
+
def initialize(options = {}, &block)
|
58
|
+
super(options)
|
59
|
+
|
60
|
+
# Allow for population of data with a block during initialization.
|
61
|
+
if block
|
62
|
+
block.call(self)
|
63
|
+
else
|
64
|
+
# Otherwise, just iterate over the points, adding the slices
|
65
|
+
if @points.class == Hash
|
66
|
+
@points.keys.each {|k|
|
67
|
+
self.add :pie_slice, k.to_s, [@points[k]]}
|
68
|
+
end
|
69
|
+
if @points.class == Array
|
70
|
+
@points.each {|v|
|
71
|
+
self.add :pie_slice, '', [v]}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
# Overrides Base#render to fiddle with layers' points to achieve a stacked
|
78
|
+
# effect.
|
79
|
+
def render(svg, options = {})
|
80
|
+
# #current_points = points.dup
|
81
|
+
|
82
|
+
@scaler = 1
|
83
|
+
total = 0
|
84
|
+
|
85
|
+
layers.each do |layer|
|
86
|
+
total += layer.sum_values
|
87
|
+
end
|
88
|
+
|
89
|
+
@scaler = 100.0 / total
|
90
|
+
|
91
|
+
@percent_used = 30
|
92
|
+
|
93
|
+
layers.each do |layer|
|
94
|
+
layer_options = options.dup
|
95
|
+
layer_options = layer_options.merge(@options)
|
96
|
+
layer_options = layer_options.merge(layer.options)
|
97
|
+
layer_options[:scaler] = @scaler
|
98
|
+
layer_options[:percent_used] = @percent_used
|
99
|
+
@percent_used += @scaler * layer.sum_values
|
100
|
+
layer_options[:color] = layer.preferred_color || layer.color || options[:theme].next_color
|
101
|
+
|
102
|
+
layer.render(svg, layer_options)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# A stacked graph has many data sets. Return legend information for all of them.
|
107
|
+
def legend_data
|
108
|
+
if relevant_data?
|
109
|
+
retval = []
|
110
|
+
layers.each do |layer|
|
111
|
+
retval << layer.legend_data
|
112
|
+
end
|
113
|
+
retval
|
114
|
+
else
|
115
|
+
nil
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def points=(val)
|
120
|
+
throw ArgumentsError, "Pie layers cannot accept points, only pie slices."
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Scruffy::Layers
|
2
|
+
# ==Scruffy::Layers::PieSlice
|
3
|
+
#
|
4
|
+
# Author:: A.J. Ostman
|
5
|
+
# Date:: August 14th, 2006
|
6
|
+
#
|
7
|
+
# Basic Pie Chart Slice..
|
8
|
+
|
9
|
+
class PieSlice < Base
|
10
|
+
|
11
|
+
# Setup Constants
|
12
|
+
RADIANS = Math::PI / 180
|
13
|
+
MARKER_OFFSET_RATIO = 1.2
|
14
|
+
MARKER_FONT_SIZE = 6
|
15
|
+
|
16
|
+
attr_accessor :diameter
|
17
|
+
attr_accessor :percent_used
|
18
|
+
attr_accessor :degree_offset
|
19
|
+
attr_accessor :scaler
|
20
|
+
attr_accessor :center_x, :center_y
|
21
|
+
|
22
|
+
def draw(svg, coords, options = {})
|
23
|
+
# Scaler is the multiplier to normalize the values to a percentage across the Pie Chart
|
24
|
+
@scaler = options[:scaler] || 1
|
25
|
+
|
26
|
+
# Degree Offset is degrees by which the pie chart is twisted when it begins
|
27
|
+
@degree_offset = options[:degree_offset] || @options[:degree_offset] || 0
|
28
|
+
|
29
|
+
# Percent Used keeps track of where in the pie chart we are
|
30
|
+
@percent_used = options[:percent_used] || @options[:percent_used] || 0
|
31
|
+
|
32
|
+
# Diameter of the pie chart defaults to 80% of the height
|
33
|
+
@diameter = relative(options[:diameter]) || relative(@options[:diameter]) || relative(80.0)
|
34
|
+
|
35
|
+
# Stroke
|
36
|
+
stroke = options[:stroke] || @options[:stroke] || "none"
|
37
|
+
|
38
|
+
# Shadow
|
39
|
+
shadow = options[:shadow] || @options[:shadow_] || false
|
40
|
+
shadow_x = relative(options[:shadow_x]) || relative(@options[:shadow_x]) || relative(-0.5)
|
41
|
+
shadow_y = relative(options[:shadow_y]) || relative(@options[:shadow_y]) || relative(0.5)
|
42
|
+
shadow_color = options[:shadow_color] || @options[:shadow_color] || "white"
|
43
|
+
shadow_opacity = options[:shadow_opacity] || @options[:shadow_opacity] || 0.06
|
44
|
+
|
45
|
+
# Coordinates for the center of the pie chart.
|
46
|
+
@center_x = relative_width(options[:center_x]) || relative_width(@options[:center_x]) || relative_width(50)
|
47
|
+
@center_y = relative_height(options[:center_y]) || relative_height(@options[:center_y]) || relative_height(50)
|
48
|
+
radius = @diameter / 2.0
|
49
|
+
|
50
|
+
# Graphing calculated using percent of graph.
|
51
|
+
# We later multiply by 3.6 to convert to 360 degree system.
|
52
|
+
percent = @scaler * sum_values
|
53
|
+
|
54
|
+
|
55
|
+
# Calculate the Radian Start Point
|
56
|
+
radians_start = ((@percent_used * 3.6) + @degree_offset) * RADIANS
|
57
|
+
# Calculate the Radian End Point
|
58
|
+
radians_end = ((@percent_used + percent) * 3.6 + @degree_offset) * RADIANS
|
59
|
+
|
60
|
+
radians_mid_point = radians_start + ((radians_end - radians_start) / 2)
|
61
|
+
|
62
|
+
if options[:explode]
|
63
|
+
@center_x = @center_x + (Math.sin(radians_mid_point) * relative(options[:explode]))
|
64
|
+
@center_y = @center_y - (Math.cos(radians_mid_point) * relative(options[:explode]))
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# Calculate the beginning coordinates
|
69
|
+
x_start = @center_x + (Math.sin(radians_start) * radius)
|
70
|
+
y_start = @center_y - (Math.cos(radians_start) * radius)
|
71
|
+
|
72
|
+
# Calculate the End Coords
|
73
|
+
x_end = @center_x + (Math.sin(radians_end) * radius)
|
74
|
+
y_end = @center_y - (Math.cos(radians_end) * radius)
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
# If percentage is really really close to 100% then draw a circle instead!
|
79
|
+
if percent >= 99.9999
|
80
|
+
|
81
|
+
if shadow
|
82
|
+
svg.circle(:cx => "#{@center_x + shadow_x}", :cy => "#{@center_y + shadow_y}", :r=>"#{radius}",:stroke => "none",
|
83
|
+
:fill => shadow_color.to_s, :style => "fill-opacity: #{shadow_opacity.to_s};")
|
84
|
+
end
|
85
|
+
|
86
|
+
svg.circle(:cx => "#{@center_x}", :cy => "#{@center_y}", :r=>"#{radius}",:stroke => stroke, :fill => color.to_s)
|
87
|
+
|
88
|
+
else
|
89
|
+
if shadow
|
90
|
+
svg.path(:d => "M#{@center_x + shadow_x},#{@center_y + shadow_y} L#{x_start + shadow_x},#{y_start + shadow_y} A#{radius},#{radius} 0, #{percent >= 50 ? '1' : '0'}, 1, #{x_end + shadow_x} #{y_end + shadow_y} Z",
|
91
|
+
:fill => shadow_color.to_s, :style => "fill-opacity: #{shadow_opacity.to_s};")
|
92
|
+
end
|
93
|
+
|
94
|
+
svg.path(:d => "M#{@center_x},#{@center_y} L#{x_start},#{y_start} A#{radius},#{radius} 0, #{percent >= 50 ? '1' : '0'}, 1, #{x_end} #{y_end} Z",
|
95
|
+
:stroke => stroke, :fill => color.to_s)
|
96
|
+
end
|
97
|
+
|
98
|
+
text_x = @center_x + (Math.sin(radians_mid_point) * radius * MARKER_OFFSET_RATIO)
|
99
|
+
text_y = @center_y - (Math.cos(radians_mid_point) * radius * MARKER_OFFSET_RATIO)
|
100
|
+
|
101
|
+
svg.text("#{sprintf('%d', percent)}%", :x => text_x, :y => text_y + relative(MARKER_FONT_SIZE / 2),
|
102
|
+
'font-size' => relative(MARKER_FONT_SIZE),
|
103
|
+
:fill => (options[:theme].marker || 'black').to_s,
|
104
|
+
'text-anchor' => 'middle')
|
105
|
+
end
|
106
|
+
|
107
|
+
protected
|
108
|
+
def generate_coordinates(options = {})
|
109
|
+
# Coordinate Generation didn't make much sense here.
|
110
|
+
# Overridden just because Brasten said this would be overridden.
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|