prawn-graph 0.0.4 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +16 -0
  3. data/.gitignore +9 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +1168 -0
  6. data/.travis.yml +17 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/CONTRIBUTORS.md +6 -0
  9. data/Gemfile +4 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +142 -0
  12. data/Rakefile +7 -43
  13. data/bin/console +14 -0
  14. data/bin/setup +8 -0
  15. data/lib/prawn-graph.rb +16 -0
  16. data/lib/prawn/graph/calculations.rb +1 -0
  17. data/lib/prawn/graph/calculations/layout_calculator.rb +108 -0
  18. data/lib/prawn/graph/chart_components.rb +2 -0
  19. data/lib/prawn/graph/chart_components/canvas.rb +138 -0
  20. data/lib/prawn/graph/chart_components/series_renderer.rb +173 -0
  21. data/lib/prawn/graph/charts.rb +4 -0
  22. data/lib/prawn/graph/charts/bar.rb +18 -0
  23. data/lib/prawn/graph/charts/base.rb +69 -0
  24. data/lib/prawn/graph/charts/legacy.rb +4 -0
  25. data/lib/prawn/graph/charts/legacy/bar.rb +28 -0
  26. data/lib/prawn/graph/charts/legacy/base.rb +193 -0
  27. data/lib/prawn/graph/charts/legacy/grid.rb +51 -0
  28. data/lib/prawn/graph/charts/legacy/line.rb +39 -0
  29. data/lib/prawn/graph/charts/line.rb +18 -0
  30. data/lib/prawn/graph/extension.rb +59 -0
  31. data/lib/prawn/graph/series.rb +79 -0
  32. data/lib/prawn/graph/theme.rb +41 -0
  33. data/lib/prawn/graph/version.rb +5 -0
  34. data/prawn-graph.gemspec +42 -0
  35. metadata +156 -80
  36. data/README.markdown +0 -64
  37. data/examples/example_helper.rb +0 -10
  38. data/examples/graph/advanced_bar_chart.rb +0 -22
  39. data/examples/graph/bar_chart.pdf +0 -185
  40. data/examples/graph/bar_chart.rb +0 -18
  41. data/examples/graph/line_chart.pdf +0 -219
  42. data/examples/graph/line_chart.rb +0 -18
  43. data/examples/graph/themed_bar_chart.rb +0 -18
  44. data/examples/graph/themed_line_chart.rb +0 -18
  45. data/lib/prawn/graph.rb +0 -94
  46. data/lib/prawn/graph/bar.rb +0 -64
  47. data/lib/prawn/graph/base.rb +0 -231
  48. data/lib/prawn/graph/chart.rb +0 -4
  49. data/lib/prawn/graph/errors.rb +0 -7
  50. data/lib/prawn/graph/grid.rb +0 -50
  51. data/lib/prawn/graph/line.rb +0 -74
  52. data/lib/prawn/graph/themes.rb +0 -116
  53. data/lib/prawn/graph/themes/37signals.yml +0 -14
  54. data/lib/prawn/graph/themes/keynote.yml +0 -14
  55. data/lib/prawn/graph/themes/monochome.yml +0 -8
  56. data/lib/prawn/graph/themes/odeo.yml +0 -14
@@ -1,231 +0,0 @@
1
- module Prawn
2
- module Chart
3
-
4
- # Prawn::Chart::Base implements the common methods shared by most of the graphs
5
- # and charts whcih will need to be plotted.
6
- #
7
- # All Prawn::Chart::Base instances and their children will have the following
8
- # associated with them:
9
- #
10
- # 1. A Prawn::Chart::Grid which is where the graph will be drawn
11
- # 2. A refernce to the Prawn::Document being affected
12
- # 3. A set of data to be plotted.
13
- #
14
- # A public draw method is available which does what it says on the tin and...
15
- # well.. draws the graph on the document it has a reference to.
16
- #
17
- class Base
18
-
19
- attr_accessor :grid, :headings, :values, :highest_value, :document, :colour
20
-
21
- # Returns a new instance of a graph to be drawn, really only useful for the
22
- # subclasses which actually have a plot_values method declared so the data
23
- # is actually rendered as a graph.
24
- #
25
- # Takes an Array of +data+, which should contain complete rows of data for
26
- # values to be plotted; a reference to a +document+ which should be an
27
- # instance of Prawn::Document and an +options+ with at least a value for :at
28
- # specified.
29
- #
30
- # Options are:
31
- #
32
- # :at , which should be an Array representing the point at which the graph
33
- # should be drawn.
34
- #
35
- # :title, the title for this graph, wil be rendered centered to the top of
36
- # the Grid.
37
- #
38
- # :label_x, a label to be shown along the X axis of he graph, rendered centered
39
- # on the grid.
40
- #
41
- # :label_y, a label to be shown along the Y axis of he graph, rendered centered
42
- # on the grid and rotated to be perpendicular to the axis.
43
- #
44
- # :theme, the theme to be used to draw this graph, defaults to monochrome.
45
- #
46
- def initialize(data, document, options = {})
47
- if options[:at].nil? || options[:at].empty?
48
- raise Prawn::Errors::NoGraphStartSet,
49
- "you must specify options[:at] as the coordinates where you" +
50
- " wish this graph to be drawn from."
51
- end
52
- opts = { :theme => Prawn::Chart::Themes.monochrome, :width => 500, :height => 200, :spacing => 20 }.merge(options)
53
- (@headings, @values, @highest_value) = process_the data
54
- (grid_x_start, grid_y_start, grid_width, grid_height) = parse_sizing_from opts
55
- @colour = (!opts[:use_color].nil? || !opts[:use_colour].nil?)
56
- @document = document
57
- @theme = opts[:theme]
58
- off = 20
59
- @grid = Prawn::Chart::Grid.new(grid_x_start, grid_y_start, grid_width, grid_height, opts[:spacing], document, @theme)
60
- end
61
-
62
- # Draws the graph on the document which we have a reference to.
63
- #
64
- def draw
65
- draw_bounding_box
66
- @grid.draw
67
- label_axes
68
- if @title
69
- draw_title
70
- end
71
- plot_values
72
- if @x_label
73
- draw_x_axis_label
74
- end
75
- if @y_label
76
- draw_y_axis_label
77
- end
78
- reset
79
- end
80
-
81
- private
82
-
83
- def draw_bounding_box
84
- @document.fill_color @theme.background_colour
85
- @document.fill_and_stroke_rectangle [(@point.first - 10), (@point.last + ( @total_height + 40 ))], @document.bounds.width, (@total_height + 40)
86
- @document.fill_color '000000'
87
- end
88
-
89
- def label_axes
90
- @document.fill_color @theme.font_colour
91
- base_x = @grid.start_x + 1
92
- base_y = @grid.start_y + 1
93
-
94
- # Put the values up the Y Axis
95
- #
96
- @document.draw_text @highest_value, :at => [base_x - 15, base_y + @grid.height], :size => 5
97
- @document.draw_text '0', :at => [base_x - 15, base_y ], :size => 5
98
-
99
- # Put the column headings along the X Axis
100
- #
101
- point_spacing = calculate_plot_spacing
102
- last_position = base_x + (point_spacing / 2)
103
- @headings.each do |heading|
104
- @document.draw_text heading, :at => [last_position, base_y - 15 ], :size => 5
105
- last_position += point_spacing
106
- end
107
- @document.fill_color @theme.background_colour
108
- end
109
-
110
- def draw_title
111
- @document.fill_color @theme.font_colour
112
- x_coord = calculate_x_axis_center_point(@title, 10)
113
- y_coord = @grid.start_y + @grid.height + 10
114
- @document.draw_text @title, :at => [x_coord, y_coord] ,:size => 10
115
- @document.fill_color @theme.background_colour
116
- end
117
-
118
- def draw_x_axis_label
119
- @document.fill_color @theme.font_colour
120
- x_coord = calculate_x_axis_center_point(@x_label, 8)
121
- y_coord = @grid.start_y - 30
122
- @document.draw_text @x_label, :at => [x_coord, y_coord] ,:size => 8
123
- @document.fill_color @theme.background_colour
124
- end
125
-
126
- def draw_y_axis_label
127
- @document.fill_color @theme.font_colour
128
- y_coord = calculate_y_axis_center_point(@y_label, 8)
129
- x_coord = @grid.start_x - 30
130
- @document.draw_text @y_label, :at => [x_coord, y_coord] ,:size => 8, :rotate => 90
131
- @document.fill_color @theme.background_colour
132
- end
133
-
134
- # All subclasses of Prawn::Chart::Base must implement thier own plot_values
135
- # method, which does the actual real heavy lifting of drawing the graph.
136
- #
137
- def plot_values
138
- raise Prawn::Errors::NoPlotValuesMethod, 'subclasses of Prawn::Chart::Base must implement '
139
- + 'their own plot_values method.'
140
- end
141
-
142
- def reset
143
- @document.line_width 1
144
- @document.stroke_color '000000'
145
- @document.fill_color '000000'
146
- @document.move_to @grid.point
147
- end
148
-
149
-
150
- # Utility methods for dealing with working out where things should be
151
- # the calculations and such done here are all very rough, but are
152
- # sufficient for now to plot just what we need.
153
- #
154
-
155
-
156
- def parse_sizing_from(o)
157
- x_offset = 15
158
- y_offset = 0
159
- move_y_up = 0
160
- grid_width = o[:width]
161
- grid_height = o[:height]
162
-
163
- @total_width = o[:width]
164
- @total_height = o[:height]
165
- @point = o[:at].dup
166
-
167
- # Make room for the title if we're choosing to Render it.
168
- #
169
- if o[:title]
170
- @title = o[:title]
171
- y_offset += 10
172
- end
173
-
174
- # Make room for X Axis labels if we're using them.
175
- #
176
- if o[:label_x]
177
- y_offset += 30
178
- move_y_up += 30
179
- @x_label = o[:label_x]
180
- end
181
-
182
- # Make room for Y Axis labels if we're using them.
183
- #
184
- if o[:label_y]
185
- @y_label = o[:label_y]
186
- x_offset += 15
187
- end
188
-
189
-
190
- # Return the values calculated here.
191
- #
192
- [ (o[:at][0] + x_offset), (o[:at][1] + move_y_up + 20), (grid_width - (x_offset - 20)), (grid_height - y_offset) ]
193
- end
194
-
195
- def process_the(data_array)
196
- col = []
197
- val = []
198
- data_array.each { |i| val << i[1]; col << i[0] }
199
- [ col, val ,val.sort.last ]
200
- end
201
-
202
- def calculate_x_axis_center_point(text, text_size, graph_start_x = @grid.start_x, graph_width = @grid.width)
203
- ((graph_start_x + (graph_width / 2)) - ((text.length * text_size) / 4))
204
- end
205
- alias calculate_x_axis_centre_point calculate_x_axis_center_point
206
-
207
- def calculate_y_axis_center_point(text, text_size, graph_start_y = @grid.start_y, graph_height = @grid.height)
208
- ((graph_start_y + (graph_height / 2)) - ((text.length * text_size) / 4))
209
- end
210
- alias calculate_y_axis_centre_point calculate_y_axis_center_point
211
-
212
- def calculate_plot_spacing
213
- (@grid.width / @values.nitems)
214
- end
215
-
216
- def calculate_bar_width
217
- calculate_plot_spacing / 2
218
- end
219
-
220
- def calculate_point_height_from(column_value)
221
- cv = BigDecimal("#{column_value}")
222
- hv = BigDecimal("#{@highest_value}")
223
- gh = BigDecimal("#{@grid.height}")
224
- percentage = (cv / (hv / 100))
225
- ((gh / 100) * percentage).to_i
226
- end
227
-
228
-
229
- end
230
- end
231
- end
@@ -1,4 +0,0 @@
1
- module Prawn
2
- module Chart
3
- end
4
- end
@@ -1,7 +0,0 @@
1
- module Prawn
2
- module Errors
3
- NoGraphData = Class.new(StandardError)
4
- NoGraphStartSet = Class.new(StandardError)
5
- NoPlotValuesMethod = Class.new(StandardError)
6
- end
7
- end
@@ -1,50 +0,0 @@
1
- module Prawn
2
- module Chart
3
-
4
- # Prawn::Chart::Grid represents the area whcih your data will be plotted. It
5
- # is drawn before your data is plotted and serves to mark where the axes of
6
- # your plot will be and to give an indication of scale.
7
- #
8
- class Grid
9
-
10
- attr_accessor :width, :height, :point, :spacing, :document
11
-
12
- def initialize(grid_x_start, grid_y_start, grid_width, grid_height, spacing, document, theme)
13
- @point = [grid_x_start, grid_y_start]
14
- @width = grid_width
15
- @height = grid_height
16
- @spacing = spacing
17
- @document = document
18
- @theme = theme
19
- end
20
-
21
- def start_x; @point.first; end
22
- def start_y; @point.last; end
23
-
24
- # Draws the Grid on the specified Prawn::Document
25
- #
26
- def draw
27
- @document.stroke_color @theme.marker_colour
28
- if @theme.stroke_grid_markers?
29
- (@height / @spacing).times do |x|
30
- offset = @spacing * (x + 1)
31
- @document.move_to [@point.first, (@point.last + offset)]
32
- @document.line_width(0.5)
33
- @document.stroke_line_to([(@point.first + @width), (@point.last + offset)])
34
- end
35
- end
36
- @document.move_to @point
37
- @document.line_width(2)
38
- @document.stroke_line_to([@point.first, @point.last + @height])
39
- @document.move_to @point
40
- @document.line_width(2)
41
- @document.stroke_line_to([(@point.first + @width), @point.last])
42
- @document.move_to @point.first, (@point.last + height)
43
- @document.stroke_color '000000'
44
- @document.line_width(1)
45
- @document.move_to @point
46
- end
47
-
48
- end
49
- end
50
- end
@@ -1,74 +0,0 @@
1
- module Prawn
2
- module Chart
3
-
4
- # Prawn::Chart::Line plots its values as a Line graph, relatively
5
- # sized to fit within the space defined by the Prawn::Chart::Grid
6
- # associated with it.
7
- #
8
- # Call to new will return a new instance of Prawn::Chart::Line ready to
9
- # be rendered.
10
- #
11
- # Takes an Array of +data+, which should contain complete rows of data for
12
- # values to be plotted; a reference to a +document+ which should be an
13
- # instance of Prawn::Document and an +options+ with at least a value for :at
14
- # specified.
15
- #
16
- # Options are:
17
- #
18
- # :at , which should be an Array representing the point at which the graph
19
- # should be drawn.
20
- #
21
- # :title, the title for this graph, wil be rendered centered to the top of
22
- # the Grid.
23
- #
24
- # :label_x, a label to be shown along the X axis of he graph, rendered centered
25
- # on the grid.
26
- #
27
- # :label_y, a label to be shown along the Y axis of he graph, rendered centered
28
- # on the grid and rotated to be perpendicular to the axis.
29
- #
30
- # Data should be formatted like:
31
- #
32
- # [
33
- # [ 'Column Heading', SomeValue ],
34
- # [ 'Column Heading', SomeValue ],
35
- # [ 'Column Heading', SomeValue ],
36
- # [ 'Column Heading', SomeValue ],
37
- # [ 'Column Heading', SomeValue ],
38
- # [ 'Column Heading', SomeValue ]
39
- # ]
40
- #
41
-
42
- class Line < Base
43
-
44
- private
45
-
46
- def plot_values
47
- base_x = @grid.start_x + 1
48
- base_y = @grid.start_y + 1
49
- p = [ [base_x, base_y] ]
50
- bar_width = calculate_bar_width
51
- @document.line_width bar_width
52
- last_position = base_x + bar_width
53
- point_spacing = calculate_plot_spacing
54
- @values.each do |value|
55
- @document.move_to [base_x + last_position, base_y]
56
- bar_height = calculate_point_height_from value
57
- point = [base_x + last_position, base_y + bar_height]
58
- p << point
59
- @document.fill_color @theme.colours.first
60
- @document.fill_circle_at point, :radius => 1
61
- last_position += point_spacing
62
- end
63
- @document.line_width 2
64
- @document.stroke_color @theme.colours.first
65
- p.each_with_index do |point,i|
66
- next if point == p.last
67
- @document.move_to point
68
- @document.stroke_line_to p[i+1]
69
- end
70
- end
71
-
72
- end
73
- end
74
- end
@@ -1,116 +0,0 @@
1
- require 'yaml'
2
-
3
- module Prawn
4
- module Chart
5
-
6
- # Themes serves as a point of interaction between the user and the underlying
7
- # collection of themes made available to Prawn::Graph.
8
- #
9
- class Themes
10
-
11
- # Called once when Prawn::Graph is loaded, initializes the list of
12
- # themes currently bundled. If you have your own custom theme you'd
13
- # like to use instead, use _register_theme and give it the path to
14
- # your theme file.
15
- #
16
- def self.initialize_themes
17
- path = File.expand_path(File.dirname(__FILE__) + '/themes/')
18
- Dir.open(path) do |dir|
19
- dir.each do |file|
20
- _register_theme(path + '/' + file) if file.include?('.yml')
21
- end
22
- end
23
- end
24
-
25
- # Adds the theme defined by the yaml file specified to the mapping of
26
- # registered themes stored in +@@_themes_list+. Converts the YAML object
27
- # into a Theme object for use in the application.
28
- #
29
- def self._register_theme(theme_file_path)
30
- theme = Theme.new(YAML.load(IO.read(File.expand_path(theme_file_path))))
31
- if !defined? @@_themes_list
32
- @@_themes_list = {}
33
- end
34
- @@_themes_list[theme.name.to_sym] = theme
35
- end
36
-
37
- # Returns an array of the themes currently registered.
38
- #
39
- def self.list
40
- @@_themes_list.keys
41
- end
42
-
43
- protected
44
-
45
- # Hook into method_missing to allow us to do things like:
46
- # Prawn::Chart::Themes.theme_name
47
- # To return the theme object being looked for.
48
- #
49
- def self.method_missing(method, *args)
50
- if @@_themes_list.keys.include?(method)
51
- return @@_themes_list[method]
52
- end
53
- end
54
-
55
-
56
- class Theme
57
- attr_accessor :name, :title, :colours, :font_colour, :background_colour, :marker_colour
58
-
59
- # Creates a new theme from a theme hash. The hash comes from the
60
- # library parsing YAML definitions of a theme.
61
- #
62
- def initialize(theme_hash)
63
- @name = theme_hash['name']
64
- @title = theme_hash['title']
65
-
66
- if theme_hash.keys.include?('colours')
67
- @colours = theme_hash['colours']
68
- elsif theme_hash.keys.include?('colors')
69
- @colours = theme_hash['colors']
70
- end
71
-
72
- if theme_hash.keys.include?('font_colour')
73
- @font_colour = theme_hash['font_colour']
74
- elsif theme_hash.keys.include?('font_color')
75
- @font_colour = theme_hash['font_color']
76
- end
77
-
78
- if theme_hash.keys.include?('background_colour')
79
- @background_colour = theme_hash['background_colour']
80
- elsif theme_hash.keys.include?('background_color')
81
- @background_colour = theme_hash['background_color']
82
- end
83
-
84
- if theme_hash.keys.include?('marker_colour')
85
- @marker_colour = theme_hash['marker_colour']
86
- elsif theme_hash.keys.include?('marker_color')
87
- @marker_colour = theme_hash['marker_color']
88
- end
89
-
90
- @stroke_grid_markers = theme_hash['stroke_grid_markers'].to_i
91
- end
92
-
93
- # Returns the next colour in the array of colours associated
94
- # with this theme. If it gets to the end, it starts again from
95
- # the beginning.
96
- #
97
- def next_colour
98
- unless @current_colour
99
- @current_colour = 0
100
- return @colours[0]
101
- end
102
- @current_colour += 1
103
- @current_colour = 0 if @current_colour == @colours.nitems
104
- @colours[@current_colour]
105
- end
106
- alias next_color next_colour
107
-
108
- def stroke_grid_markers?
109
- @stroke_grid_markers == 1
110
- end
111
-
112
- end
113
- end
114
-
115
- end
116
- end