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