gruff 0.13.0-java → 0.14.0-java
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +66 -0
- data/.rubocop.yml +6 -10
- data/.rubocop_todo.yml +19 -85
- data/CHANGELOG.md +10 -0
- data/README.md +6 -7
- data/gruff.gemspec +2 -4
- data/lib/gruff.rb +1 -0
- data/lib/gruff/accumulator_bar.rb +3 -1
- data/lib/gruff/area.rb +5 -8
- data/lib/gruff/bar.rb +19 -23
- data/lib/gruff/base.rb +134 -96
- data/lib/gruff/bezier.rb +4 -6
- data/lib/gruff/bullet.rb +11 -10
- data/lib/gruff/dot.rb +10 -10
- data/lib/gruff/font.rb +39 -0
- data/lib/gruff/helper/stacked_mixin.rb +1 -2
- data/lib/gruff/histogram.rb +9 -7
- data/lib/gruff/line.rb +55 -46
- data/lib/gruff/mini/bar.rb +9 -6
- data/lib/gruff/mini/legend.rb +12 -8
- data/lib/gruff/mini/pie.rb +9 -6
- data/lib/gruff/mini/side_bar.rb +9 -6
- data/lib/gruff/net.rb +9 -15
- data/lib/gruff/patch/string.rb +1 -1
- data/lib/gruff/pie.rb +23 -65
- data/lib/gruff/renderer/bezier.rb +8 -9
- data/lib/gruff/renderer/circle.rb +8 -9
- data/lib/gruff/renderer/dash_line.rb +9 -10
- data/lib/gruff/renderer/dot.rb +13 -14
- data/lib/gruff/renderer/ellipse.rb +8 -9
- data/lib/gruff/renderer/line.rb +8 -9
- data/lib/gruff/renderer/polygon.rb +9 -10
- data/lib/gruff/renderer/polyline.rb +8 -9
- data/lib/gruff/renderer/rectangle.rb +7 -8
- data/lib/gruff/renderer/renderer.rb +21 -36
- data/lib/gruff/renderer/text.rb +21 -37
- data/lib/gruff/scatter.rb +41 -46
- data/lib/gruff/scene.rb +15 -13
- data/lib/gruff/side_bar.rb +14 -30
- data/lib/gruff/side_stacked_bar.rb +8 -11
- data/lib/gruff/spider.rb +11 -16
- data/lib/gruff/stacked_area.rb +10 -11
- data/lib/gruff/stacked_bar.rb +9 -9
- data/lib/gruff/store/store.rb +6 -10
- data/lib/gruff/themes.rb +6 -6
- data/lib/gruff/version.rb +1 -1
- data/rails_generators/gruff/templates/controller.rb +1 -1
- metadata +4 -21
- data/.travis.yml +0 -23
- data/assets/plastik/blue.png +0 -0
- data/assets/plastik/green.png +0 -0
- data/assets/plastik/red.png +0 -0
- data/lib/gruff/photo_bar.rb +0 -93
@@ -3,20 +3,19 @@
|
|
3
3
|
module Gruff
|
4
4
|
# @private
|
5
5
|
class Renderer::Ellipse
|
6
|
-
def initialize(color:, width: 1.0)
|
6
|
+
def initialize(renderer, color:, width: 1.0)
|
7
|
+
@renderer = renderer
|
7
8
|
@color = color
|
8
9
|
@width = width
|
9
10
|
end
|
10
11
|
|
11
12
|
def render(origin_x, origin_y, width, height, arc_start, arc_end)
|
12
|
-
draw
|
13
|
-
|
14
|
-
draw.
|
15
|
-
draw.
|
16
|
-
draw.
|
17
|
-
draw.
|
18
|
-
draw.ellipse(origin_x, origin_y, width, height, arc_start, arc_end)
|
19
|
-
draw.pop
|
13
|
+
@renderer.draw.push
|
14
|
+
@renderer.draw.stroke_width(@width)
|
15
|
+
@renderer.draw.stroke(@color)
|
16
|
+
@renderer.draw.fill('transparent')
|
17
|
+
@renderer.draw.ellipse(origin_x, origin_y, width, height, arc_start, arc_end)
|
18
|
+
@renderer.draw.pop
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
data/lib/gruff/renderer/line.rb
CHANGED
@@ -5,7 +5,8 @@ module Gruff
|
|
5
5
|
class Renderer::Line
|
6
6
|
EPSILON = 0.001
|
7
7
|
|
8
|
-
def initialize(color:, width: nil, shadow_color: nil)
|
8
|
+
def initialize(renderer, color:, width: nil, shadow_color: nil)
|
9
|
+
@renderer = renderer
|
9
10
|
@color = color
|
10
11
|
@width = width
|
11
12
|
@shadow_color = shadow_color
|
@@ -30,14 +31,12 @@ module Gruff
|
|
30
31
|
end_y += EPSILON
|
31
32
|
end
|
32
33
|
|
33
|
-
draw
|
34
|
-
|
35
|
-
draw.
|
36
|
-
draw.
|
37
|
-
draw.
|
38
|
-
draw.
|
39
|
-
draw.line(start_x, start_y, end_x, end_y)
|
40
|
-
draw.pop
|
34
|
+
@renderer.draw.push
|
35
|
+
@renderer.draw.stroke(color)
|
36
|
+
@renderer.draw.fill(color)
|
37
|
+
@renderer.draw.stroke_width(@width) if @width
|
38
|
+
@renderer.draw.line(start_x, start_y, end_x, end_y)
|
39
|
+
@renderer.draw.pop
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
@@ -3,22 +3,21 @@
|
|
3
3
|
module Gruff
|
4
4
|
# @private
|
5
5
|
class Renderer::Polygon
|
6
|
-
def initialize(color:, width: 1.0, opacity: 1.0)
|
6
|
+
def initialize(renderer, color:, width: 1.0, opacity: 1.0)
|
7
|
+
@renderer = renderer
|
7
8
|
@color = color
|
8
9
|
@width = width
|
9
10
|
@opacity = opacity
|
10
11
|
end
|
11
12
|
|
12
13
|
def render(points)
|
13
|
-
draw
|
14
|
-
|
15
|
-
draw.
|
16
|
-
draw.
|
17
|
-
draw.
|
18
|
-
draw.
|
19
|
-
draw.
|
20
|
-
draw.polygon(*points)
|
21
|
-
draw.pop
|
14
|
+
@renderer.draw.push
|
15
|
+
@renderer.draw.stroke_width(@width)
|
16
|
+
@renderer.draw.stroke(@color)
|
17
|
+
@renderer.draw.fill(@color)
|
18
|
+
@renderer.draw.fill_opacity(@opacity)
|
19
|
+
@renderer.draw.polygon(*points)
|
20
|
+
@renderer.draw.pop
|
22
21
|
end
|
23
22
|
end
|
24
23
|
end
|
@@ -3,20 +3,19 @@
|
|
3
3
|
module Gruff
|
4
4
|
# @private
|
5
5
|
class Renderer::Polyline
|
6
|
-
def initialize(color:, width:)
|
6
|
+
def initialize(renderer, color:, width:)
|
7
|
+
@renderer = renderer
|
7
8
|
@color = color
|
8
9
|
@width = width
|
9
10
|
end
|
10
11
|
|
11
12
|
def render(points)
|
12
|
-
draw
|
13
|
-
|
14
|
-
draw.
|
15
|
-
draw.
|
16
|
-
draw.
|
17
|
-
draw.
|
18
|
-
draw.polyline(*points)
|
19
|
-
draw.pop
|
13
|
+
@renderer.draw.push
|
14
|
+
@renderer.draw.stroke(@color)
|
15
|
+
@renderer.draw.fill('transparent')
|
16
|
+
@renderer.draw.stroke_width(@width)
|
17
|
+
@renderer.draw.polyline(*points)
|
18
|
+
@renderer.draw.pop
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
@@ -3,18 +3,17 @@
|
|
3
3
|
module Gruff
|
4
4
|
# @private
|
5
5
|
class Renderer::Rectangle
|
6
|
-
def initialize(color: nil)
|
6
|
+
def initialize(renderer, color: nil)
|
7
|
+
@renderer = renderer
|
7
8
|
@color = color
|
8
9
|
end
|
9
10
|
|
10
11
|
def render(upper_left_x, upper_left_y, lower_right_x, lower_right_y)
|
11
|
-
draw
|
12
|
-
|
13
|
-
draw.
|
14
|
-
draw.
|
15
|
-
draw.
|
16
|
-
draw.rectangle(upper_left_x, upper_left_y, lower_right_x, lower_right_y)
|
17
|
-
draw.pop
|
12
|
+
@renderer.draw.push
|
13
|
+
@renderer.draw.stroke('transparent')
|
14
|
+
@renderer.draw.fill(@color) if @color
|
15
|
+
@renderer.draw.rectangle(upper_left_x, upper_left_y, lower_right_x, lower_right_y)
|
16
|
+
@renderer.draw.pop
|
18
17
|
end
|
19
18
|
end
|
20
19
|
end
|
@@ -1,53 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'singleton'
|
4
|
-
|
5
3
|
module Gruff
|
6
4
|
# @private
|
7
5
|
class Renderer
|
8
|
-
|
9
|
-
|
10
|
-
attr_accessor :draw, :image, :scale, :text_renderers
|
11
|
-
|
12
|
-
def self.setup(columns, rows, font, scale, theme_options)
|
13
|
-
draw = Magick::Draw.new
|
14
|
-
draw.font = font if font
|
15
|
-
# Scale down from 800x600 used to calculate drawing.
|
16
|
-
draw.scale(scale, scale)
|
17
|
-
|
18
|
-
image = Renderer.instance.background(columns, rows, scale, theme_options)
|
6
|
+
attr_accessor :text_renderers
|
7
|
+
attr_reader :draw, :image, :scale
|
19
8
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
Renderer.instance.text_renderers = []
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.setup_transparent_background(columns, rows)
|
27
|
-
image = Renderer.instance.render_transparent_background(columns, rows)
|
28
|
-
Renderer.instance.image = image
|
29
|
-
end
|
9
|
+
def initialize(columns, rows, scale, theme_options)
|
10
|
+
@draw = Magick::Draw.new
|
11
|
+
@text_renderers = []
|
30
12
|
|
31
|
-
|
32
|
-
|
13
|
+
@scale = scale
|
14
|
+
@draw.scale(scale, scale)
|
15
|
+
@image = background(columns, rows, scale, theme_options)
|
33
16
|
end
|
34
17
|
|
35
|
-
def
|
36
|
-
draw
|
37
|
-
draw.font = font if font
|
38
|
-
end
|
18
|
+
def finish
|
19
|
+
@draw.draw(@image)
|
39
20
|
|
40
|
-
|
41
|
-
draw = Renderer.instance.draw
|
42
|
-
image = Renderer.instance.image
|
43
|
-
|
44
|
-
draw.draw(image)
|
45
|
-
|
46
|
-
Renderer.instance.text_renderers.each do |renderer|
|
21
|
+
@text_renderers.each do |renderer|
|
47
22
|
renderer.render(renderer.width, renderer.height, renderer.x, renderer.y, renderer.gravity)
|
48
23
|
end
|
49
24
|
end
|
50
25
|
|
26
|
+
def background_image=(image)
|
27
|
+
@image = image
|
28
|
+
end
|
29
|
+
|
51
30
|
def background(columns, rows, scale, theme_options)
|
52
31
|
case theme_options[:background_colors]
|
53
32
|
when Array
|
@@ -59,6 +38,10 @@ module Gruff
|
|
59
38
|
end
|
60
39
|
end
|
61
40
|
|
41
|
+
def transparent_background(columns, rows)
|
42
|
+
@image = render_transparent_background(columns, rows)
|
43
|
+
end
|
44
|
+
|
62
45
|
# Make a new image at the current size with a solid +color+.
|
63
46
|
def solid_background(columns, rows, color)
|
64
47
|
Magick::Image.new(columns, rows) do
|
@@ -101,6 +84,8 @@ module Gruff
|
|
101
84
|
end
|
102
85
|
end
|
103
86
|
|
87
|
+
private
|
88
|
+
|
104
89
|
# Use with a theme to use an image (800x600 original) background.
|
105
90
|
def image_background(scale, image_path)
|
106
91
|
image = Magick::Image.read(image_path)
|
data/lib/gruff/renderer/text.rb
CHANGED
@@ -5,12 +5,10 @@ module Gruff
|
|
5
5
|
class Renderer::Text
|
6
6
|
using Magick::GruffAnnotate
|
7
7
|
|
8
|
-
def initialize(text, font:,
|
8
|
+
def initialize(renderer, text, font:, rotation: nil)
|
9
|
+
@renderer = renderer
|
9
10
|
@text = text.to_s
|
10
11
|
@font = font
|
11
|
-
@font_size = size
|
12
|
-
@font_color = color
|
13
|
-
@font_weight = weight
|
14
12
|
@rotation = rotation
|
15
13
|
end
|
16
14
|
|
@@ -23,50 +21,36 @@ module Gruff
|
|
23
21
|
@y = y
|
24
22
|
@gravity = gravity
|
25
23
|
|
26
|
-
|
24
|
+
@renderer.text_renderers << self
|
27
25
|
end
|
28
26
|
|
29
27
|
def render(width, height, x, y, gravity = Magick::NorthGravity)
|
30
|
-
draw
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
draw.
|
35
|
-
draw.
|
36
|
-
draw.
|
37
|
-
draw.
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
draw.
|
42
|
-
width, height,
|
43
|
-
x, y,
|
44
|
-
@text, scale)
|
45
|
-
draw.rotation = -@rotation if @rotation
|
28
|
+
@renderer.draw.rotation = @rotation if @rotation
|
29
|
+
@renderer.draw.fill = @font.color
|
30
|
+
@renderer.draw.stroke = 'transparent'
|
31
|
+
@renderer.draw.font = @font.file_path
|
32
|
+
@renderer.draw.font_weight = @font.weight
|
33
|
+
@renderer.draw.pointsize = @font.size * @renderer.scale
|
34
|
+
@renderer.draw.gravity = gravity
|
35
|
+
@renderer.draw.annotate_scaled(@renderer.image,
|
36
|
+
width, height,
|
37
|
+
x, y,
|
38
|
+
@text, @renderer.scale)
|
39
|
+
@renderer.draw.rotation = -@rotation if @rotation
|
46
40
|
end
|
47
41
|
|
48
|
-
def
|
49
|
-
draw
|
50
|
-
|
51
|
-
|
52
|
-
draw.font = font || Renderer::Text.default_font(font_weight)
|
53
|
-
draw.font_weight = font_weight
|
54
|
-
draw.pointsize = size
|
42
|
+
def metrics
|
43
|
+
@renderer.draw.font = @font.file_path
|
44
|
+
@renderer.draw.font_weight = @font.weight
|
45
|
+
@renderer.draw.pointsize = @font.size
|
55
46
|
|
56
47
|
# The old ImageMagick causes SEGV with string which has '%' + alphabet (eg. '%S').
|
57
48
|
# This format is used to embed value into a string using image properties.
|
58
49
|
# However, gruff use plain image as canvas which does not have any property.
|
59
50
|
# So, in here, it just escape % in order to avoid SEGV.
|
60
|
-
text = text.to_s.gsub(/(%+)/) { ('%' * Regexp.last_match(1).size * 2).to_s }
|
61
|
-
|
62
|
-
draw.get_type_metrics(image, text)
|
63
|
-
end
|
64
|
-
|
65
|
-
FONT_BOLD = File.expand_path(File.join(__FILE__, '../../../../assets/fonts/Roboto-Bold.ttf'))
|
66
|
-
FONT_REGULAR = File.expand_path(File.join(__FILE__, '../../../../assets/fonts/Roboto-Regular.ttf'))
|
51
|
+
text = @text.to_s.gsub(/(%+)/) { ('%' * Regexp.last_match(1).size * 2).to_s }
|
67
52
|
|
68
|
-
|
69
|
-
(font_weight == Magick::BoldWeight) ? FONT_BOLD : FONT_REGULAR
|
53
|
+
@renderer.draw.get_type_metrics(@renderer.image, text)
|
70
54
|
end
|
71
55
|
end
|
72
56
|
end
|
data/lib/gruff/scatter.rb
CHANGED
@@ -35,27 +35,6 @@ class Gruff::Scatter < Gruff::Base
|
|
35
35
|
attr_writer :x_label_margin
|
36
36
|
attr_writer :use_vertical_x_labels
|
37
37
|
|
38
|
-
def initialize_store
|
39
|
-
@store = Gruff::Store.new(Gruff::Store::XYData)
|
40
|
-
end
|
41
|
-
private :initialize_store
|
42
|
-
|
43
|
-
def initialize_ivars
|
44
|
-
super
|
45
|
-
|
46
|
-
@baseline_x_color = @baseline_y_color = 'red'
|
47
|
-
@baseline_x_value = @baseline_y_value = nil
|
48
|
-
@circle_radius = nil
|
49
|
-
@disable_significant_rounding_x_axis = false
|
50
|
-
@show_vertical_markers = false
|
51
|
-
@marker_x_count = nil
|
52
|
-
@maximum_x_value = @minimum_x_value = nil
|
53
|
-
@stroke_width = nil
|
54
|
-
@use_vertical_x_labels = false
|
55
|
-
@x_label_margin = nil
|
56
|
-
end
|
57
|
-
private :initialize_ivars
|
58
|
-
|
59
38
|
# Allow enabling vertical lines. When you have a lot of data, they can work great.
|
60
39
|
# @deprecated Please use +show_vertical_markers+ attribute instead.
|
61
40
|
def enable_vertical_line_markers=(value)
|
@@ -63,28 +42,6 @@ class Gruff::Scatter < Gruff::Base
|
|
63
42
|
@show_vertical_markers = value
|
64
43
|
end
|
65
44
|
|
66
|
-
def draw
|
67
|
-
super
|
68
|
-
return unless data_given?
|
69
|
-
|
70
|
-
# Check to see if more than one datapoint was given. NaN can result otherwise.
|
71
|
-
@x_increment = (@x_spread > 1) ? (@graph_width / (@x_spread - 1).to_f) : @graph_width
|
72
|
-
|
73
|
-
store.norm_data.each do |data_row|
|
74
|
-
data_row.coordinates.each do |x_value, y_value|
|
75
|
-
next if y_value.nil? || x_value.nil?
|
76
|
-
|
77
|
-
new_x = get_x_coord(x_value, @graph_width, @graph_left)
|
78
|
-
new_y = @graph_top + (@graph_height - y_value * @graph_height)
|
79
|
-
|
80
|
-
# Reset each time to avoid thin-line errors
|
81
|
-
stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4), 5.0)
|
82
|
-
circle_radius = @circle_radius || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 2.5), 5.0)
|
83
|
-
Gruff::Renderer::Circle.new(color: data_row.color, width: stroke_width).render(new_x, new_y, new_x - circle_radius, new_y)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
45
|
# The first parameter is the name of the dataset. The next two are the
|
89
46
|
# x and y axis data points contain in their own array in that respective
|
90
47
|
# order. The final parameter is the color.
|
@@ -138,6 +95,44 @@ class Gruff::Scatter < Gruff::Base
|
|
138
95
|
|
139
96
|
private
|
140
97
|
|
98
|
+
def initialize_store
|
99
|
+
@store = Gruff::Store.new(Gruff::Store::XYData)
|
100
|
+
end
|
101
|
+
|
102
|
+
def initialize_attributes
|
103
|
+
super
|
104
|
+
|
105
|
+
@baseline_x_color = @baseline_y_color = 'red'
|
106
|
+
@baseline_x_value = @baseline_y_value = nil
|
107
|
+
@circle_radius = nil
|
108
|
+
@disable_significant_rounding_x_axis = false
|
109
|
+
@show_vertical_markers = false
|
110
|
+
@marker_x_count = nil
|
111
|
+
@maximum_x_value = @minimum_x_value = nil
|
112
|
+
@stroke_width = nil
|
113
|
+
@use_vertical_x_labels = false
|
114
|
+
@x_label_margin = nil
|
115
|
+
end
|
116
|
+
|
117
|
+
def draw_graph
|
118
|
+
# Check to see if more than one datapoint was given. NaN can result otherwise.
|
119
|
+
@x_increment = (@x_spread > 1) ? (@graph_width / (@x_spread - 1).to_f) : @graph_width
|
120
|
+
|
121
|
+
store.norm_data.each do |data_row|
|
122
|
+
data_row.coordinates.each do |x_value, y_value|
|
123
|
+
next if y_value.nil? || x_value.nil?
|
124
|
+
|
125
|
+
new_x = get_x_coord(x_value, @graph_width, @graph_left)
|
126
|
+
new_y = @graph_top + (@graph_height - y_value * @graph_height)
|
127
|
+
|
128
|
+
# Reset each time to avoid thin-line errors
|
129
|
+
stroke_width = @stroke_width || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 4), 5.0)
|
130
|
+
circle_radius = @circle_radius || clip_value_if_greater_than(@columns / (store.norm_data.first[1].size * 2.5), 5.0)
|
131
|
+
Gruff::Renderer::Circle.new(renderer, color: data_row.color, width: stroke_width).render(new_x, new_y, new_x - circle_radius, new_y)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
141
136
|
def setup_data
|
142
137
|
# Update the global min/max values for the x data
|
143
138
|
@maximum_x_value ||= store.max_x
|
@@ -187,7 +182,7 @@ private
|
|
187
182
|
end
|
188
183
|
else
|
189
184
|
# TODO: Make this work for negative values
|
190
|
-
@maximum_x_value = [
|
185
|
+
@maximum_x_value = [@maximum_x_value.ceil, @x_axis_increment].max
|
191
186
|
@minimum_x_value = @minimum_x_value.floor
|
192
187
|
calculate_spread
|
193
188
|
normalize
|
@@ -203,7 +198,7 @@ private
|
|
203
198
|
if @show_vertical_markers
|
204
199
|
x = @graph_left + @graph_width - index.to_f * increment_x_scaled
|
205
200
|
|
206
|
-
line_renderer = Gruff::Renderer::Line.new(color: @marker_color, shadow_color: @marker_shadow_color)
|
201
|
+
line_renderer = Gruff::Renderer::Line.new(renderer, color: @marker_color, shadow_color: @marker_shadow_color)
|
207
202
|
line_renderer.render(x, @graph_top, x, @graph_bottom)
|
208
203
|
end
|
209
204
|
|
@@ -214,7 +209,7 @@ private
|
|
214
209
|
|
215
210
|
label = x_axis_label(marker_label, @x_increment)
|
216
211
|
rotation = -90.0 if @use_vertical_x_labels
|
217
|
-
text_renderer = Gruff::Renderer::Text.new(label, font: @
|
212
|
+
text_renderer = Gruff::Renderer::Text.new(renderer, label, font: @marker_font, rotation: rotation)
|
218
213
|
text_renderer.add_to_render_queue(1.0, 1.0, x_offset, y_offset)
|
219
214
|
end
|
220
215
|
end
|