prawn-graph 1.0.0.pre1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 84da9cfac88ce76e053409afd8ea057d8fb165b6
4
- data.tar.gz: 0dc84a38ede9e63fae98301613f57c89c9d4970b
3
+ metadata.gz: 6390e1f2b56cd0e602ed9bad9f9e79d8bf8d24fd
4
+ data.tar.gz: 5a17ad2247533d9a61a26043521e26c7dd21f1f8
5
5
  SHA512:
6
- metadata.gz: 2d7a8b4568f6cd91c062d2811cca83d077b086ea76d71e38ac0c5f2cb660636fd1043f2f3c68b3fb1bedd204629fb746a368daa3074afee9088b1c964d361a1c
7
- data.tar.gz: 98609b55fe0f6cca079bf8b3421ee6fbd9315f1737c2278c0ec4c6e099ecdae658a9f8c37b8e9411c3198830695311eea9b682fca7bd6c44fcb17742549f6b8e
6
+ metadata.gz: 18a28570e31af7e7d7dce328cfd1277d50e13c255d47afa015ef3a8fc0e06d76f64e43c726b0c5a67afb885ed2ede934d5f73e7f16d52d18ae8136fabcfbdf5e
7
+ data.tar.gz: 8dd7705229fa6450dd46f8a679560299a9feba69a7356f9c7f60e4326e9ba65eade94c5f77cb1d94679477de849cc48da21dbd2ff4355848ad9cb324c14dc8e9
data/.travis.yml CHANGED
@@ -1,7 +1,17 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.0.0
4
+ - 2.1.0-p0
4
5
  - 2.1.8
6
+ - 2.2.0-p0
5
7
  - 2.2.4
6
8
  - 2.3.0
9
+ - jruby-9.0.5.0
10
+ - rbx-3.19
11
+ matrix:
12
+ allow_failures:
13
+ - rvm: rbx-3.19
7
14
  before_install: gem install bundler -v 1.11.2
15
+ addons:
16
+ code_climate:
17
+ repo_token: 9646aae52d1d1670d545c46bd94f5d86b92d516c5e3cb9890fcef62acc3a34b6
data/README.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/prawn-graph.svg)](https://badge.fury.io/rb/prawn-graph)
4
4
  [![License](http://img.shields.io/:license-mit-blue.svg)](http://sujrd.mit-license.org)
5
+ [![Code Climate](https://codeclimate.com/github/HHRy/prawn-graph/badges/gpa.svg)](https://codeclimate.com/github/HHRy/prawn-graph)
6
+ [![Test Coverage](https://codeclimate.com/github/HHRy/prawn-graph/badges/coverage.svg)](https://codeclimate.com/github/HHRy/prawn-graph/coverage)
7
+ [![Build Status](https://travis-ci.org/HHRy/prawn-graph.svg?branch=master)](https://travis-ci.org/HHRy/prawn-graph)
8
+ [![security](https://hakiri.io/github/HHRy/prawn-graph/master.svg)](https://hakiri.io/github/HHRy/prawn-graph/master)
9
+ ![Maintained: yes](https://img.shields.io/badge/maintained-yes-brightgreen.png)
10
+
11
+ **This readme reflects the state of _master_ which is not the released version of prawn-graph.**
12
+
13
+ **The code being used to cut gems for release is the `stable` Branch, please make pull requests for**
14
+ **bug fixes from that branch.**
5
15
 
6
16
  An extension for the [prawn pdf library][5] which adds the ability to draw graphs (or charts if
7
17
  you perfer) in PDF documents.
@@ -13,42 +23,43 @@ are dramatic.
13
23
 
14
24
  By default, graphs are drawn in monochrome, as that's likely how they will be printed.
15
25
 
26
+ This is free and open source software released under ther terms of the [MIT Licence](http://opensource.org/licenses/MIT).
27
+
28
+ Its copyright is held by Ryan Stenhouse and the [other contributors][8] and it was first released in
29
+ 2010.
30
+
16
31
  ## Compatibility
17
32
 
18
- The gem is only tested against Ruby version 2.0 and greater. Older Ruby versions may work but are not
33
+ This gem is built assuming a Ruby version of 2.0 or higher. Older Ruby versions may work but are not
19
34
  officially supported. We aim for compatibilty with 1.x and 2.x series of prawn. Any incomaptibilities
20
- should be treated as bugs and added to the [issue tracker][2].
21
-
22
- Unlike previous version of prawn-graph, this version does not at this time include a theme api or the
23
- ability to change the colors used to render the graph.
35
+ with prawn versions should be treated as bugs and added to the [issue tracker][2].
24
36
 
37
+ We build automatically using Travis CI. Our [.travis.yml][9] file targets the same Ruby versions as
38
+ [prawn itself][5] does.
25
39
 
26
- ## IMPORTANT - READ THIS BEFORE USING
27
40
 
28
- prawn-graph is currently being rewritten to have its internal components replaced with new, properly
29
- test-driven bits of code to draw the various cool graphs and charts that people would like to use in
30
- their PDFs.
41
+ ### Removed features:
31
42
 
32
- Right now, the "legacy" drawing code is what is ultimately being used to render any graphs being
33
- generated. The newness instead is that project is compatible with all modern versions of prawn and
34
- therefore are useful again.
43
+ Unlike previous versions of `prawn-graph`, this version does not at this time include a theme api or the
44
+ ability to change the colors used to render the graph.
35
45
 
36
- This means that for now any existing rendering bugs still remain. If you find any, please be
37
- [a good citizen][2] and [report them][2].
46
+ ## Installation
38
47
 
39
- To use prawn-graph with these caveats, you can add the following to your `Gemfile`:
48
+ To use prawn-graph, you can add the following to your `Gemfile`:
40
49
 
41
50
  ```Gemfile
42
- gem 'prawn-graph', '1.0.0.pre1'
51
+ gem 'prawn-graph', ' ~> 1.0'
43
52
  ```
44
53
 
45
- Alternatively, you can use Rubygems directly: `gem install prawn-graph --pre`.
54
+ Alternatively, you can use Rubygems directly: `gem install prawn-graph`.
46
55
 
47
56
  ## Acknowledgements
48
57
 
49
58
  With thanks to [株式会社アルム][3] ([Allm Inc][4]) for allowing Ryan Stenhouse the time to rebuild this version of
50
59
  prawn-graph. This updated version of prawn-graph was inspired and guided by [prawn-svg][1] by [Roger Nesbitt][6].
51
- It also uses some of [prawn-svg][1]'s document size calculation code.
60
+
61
+ Prawn Graph was originally sponsored by and built for use at [Purchasing Card Consultancy Ltd][7] while
62
+ Ryan Stenhouse was employed there.
52
63
 
53
64
  ## Supported graph / chart types
54
65
 
@@ -62,39 +73,64 @@ adventurous - please add it!
62
73
 
63
74
  ## Using prawn-graph
64
75
 
65
- ```ruby
66
- require 'prawn-graph'
67
-
68
- data = [ ['A', 10], ['B', 11], ['C', 12] ]
76
+ Graphs can be created by calling the `graph` or its alias, `chart` method with an array of
77
+ `Prawn::Graph::Series` objects representing the data you would like to plot and how it should
78
+ be displayed. It will also take a hash of options, and block which will have the graph yeilded
79
+ to it.
69
80
 
70
- Prawn::Document.generate('test.pdf') do
71
- text 'Graph Example'
72
- bar_graph data
73
- end
81
+ ```ruby
82
+ graph data, options = {}, &block.
74
83
  ```
75
84
 
76
85
  When called with just a set of data, prawn-graph will do its best to make the graph fit in the
77
86
  available space. For a little more control over how the graphs are rendered in the document
78
- you can pass the following options:
87
+ you can pass the following options to `graph` or `chart`:
79
88
 
80
89
  Option | Data type | Description
81
90
  ----------- | --------- | -----------
82
91
  :at | [integer, integer] | Specify the location on the page you want the graph to appear.
83
92
  :width | integer | Desired width of the graph. Defaults to horizontal space available.
84
93
  :height | integer | Desired height of the graph. Defaults to vertical space available.
94
+ :title | string | The overall title for your chart
95
+ :series_key | boolean | Should we render the series key for multi series graphs? Defaults to true.
96
+
97
+ The `data` passed to `graph` or `chart` should be an `Array` of `Prawn::Graph::Series` objects, which
98
+ themselves are made up of an array of data points to plot, and a series of options.
99
+
100
+ ```ruby
101
+ Prawn::Graph::Series.new [1,2,3,4], options = {}
102
+ ```
85
103
 
86
- ### Example
104
+ Valid `options` are:
105
+
106
+ Option | Data type | Description
107
+ ------------- | --------- | -----------
108
+ :mark_average | boolean | Should we mark a line showing the average value of the series? Defaults to false.
109
+ :mark_minimum | boolean | Should we mark the minimum value of the series? Defaults to false.
110
+ :mark_maximum | boolean | Should we mark the maximum value of the series? Defaults to false.
111
+ :title | string | The title of this series, which will be shown in the series key.
112
+ :type | symbol | How this series should be rendered. Defaults to `:bar`, valid options are `:bar`, `:line`.
113
+
114
+ ### Show me some code!
87
115
 
88
116
  ```ruby
89
117
  require 'prawn-graph'
90
118
 
91
- data = [ ['A', 10], ['B', 11], ['C', 12] ]
119
+ series = []
120
+ series << Prawn::Graph::Series.new([4,9,3,2,1,6,2,8,2,3,4,9,2], title: "A label for a series", type: :bar)
121
+ series << Prawn::Graph::Series.new([5,4,3,2,7,9,2,8,7,5,4,9,2], title: "Another label", type: :line, mark_average: true, mark_minimum: true)
122
+ series << Prawn::Graph::Series.new([1,2,3,4,5,9,6,4,5,6,3,2,11], title: "Yet another label", type: :bar)
123
+ series << Prawn::Graph::Series.new([1,2,3,4,5,12,6,4,5,6,3,2,9].shuffle, title: "One final label", type: :line, mark_average: true, mark_maximum: true)
124
+
125
+ xaxis_labels = ['0900', '1000', '1100', '1200', '1300', '1400', '1500', '1600', '1700', '1800', '1900', '2000', '2100']
92
126
 
93
127
  Prawn::Document.generate('test.pdf') do
94
- text 'Graph Example'
95
- bar_graph data, at: [10,20], width: 200
128
+ graph series, width: 500, height: 200, title: "A Title for the chart", at: [10,700], xaxis_labels: xaxis_labels
96
129
  end
97
- ```
130
+ ```
131
+
132
+ ### Output
133
+ <img src="http://prawn-graph.ryanstenhouse.jp/img/prawn-graph-output.png" alt="Prawn Graph Example Output" width="933" height="420">
98
134
 
99
135
  ## Development
100
136
 
@@ -111,9 +147,6 @@ Bug reports and pull requests are welcome [on GitHub][2]. This project is intend
111
147
  safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org)
112
148
  code of conduct.
113
149
 
114
- ## License
115
-
116
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
117
150
 
118
151
 
119
152
  [1]: https://github.com/mogest/prawn-svg/
@@ -121,4 +154,7 @@ The gem is available as open source under the terms of the [MIT License](http://
121
154
  [3]: http://www.allm.net/
122
155
  [4]: http://www.allm.net/en/
123
156
  [5]: http://github.com/prawnpdf/prawn/
124
- [6]: https://github.com/mogest/
157
+ [6]: https://github.com/mogest/
158
+ [7]: http://www.pccl.co.uk/
159
+ [8]: https://github.com/HHRy/prawn-graph/blob/master/CONTRIBUTORS.md
160
+ [9]: https://github.com/HHRy/prawn-graph/blob/master/.travis.yml
data/Rakefile CHANGED
@@ -1,5 +1,11 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
+ require 'yard'
4
+
5
+
6
+ YARD::Rake::YardocTask.new do |t|
7
+ t.files = ['lib/**/*.rb', '-', '*.md']
8
+ end
3
9
 
4
10
  RSpec::Core::RakeTask.new(:spec)
5
11
 
data/lib/prawn-graph.rb CHANGED
@@ -1,8 +1,13 @@
1
+ require "ostruct"
2
+ require "bigdecimal"
1
3
  require "prawn"
2
4
  require "prawn/graph/version"
5
+ require "prawn/graph/calculations"
6
+
7
+ require "prawn/graph/chart_components"
8
+
3
9
  require "prawn/graph/theme"
4
10
  require "prawn/graph/series"
5
- require "prawn/graph/charts"
6
11
 
7
12
  require "prawn/graph/extension"
8
13
 
@@ -0,0 +1 @@
1
+ require_relative "calculations/layout_calculator"
@@ -0,0 +1,109 @@
1
+ module Prawn
2
+ module Graph
3
+ module Calculations
4
+
5
+ class LayoutCalculator
6
+ attr_reader :bounds
7
+ attr_reader :series_key_area, :title_area, :graph_area, :canvas_width, :canvas_height
8
+
9
+ class Dimensions < OpenStruct
10
+ def renderable?
11
+ width > 0 && height > 0
12
+ end
13
+
14
+ def point
15
+ [x, y]
16
+ end
17
+ end
18
+
19
+ def initialize(bounds, attributes = nil, theme = Prawn::Graph::Theme::Default)
20
+ @bounds = bounds
21
+ @graph_area = Dimensions.new({ width: 0, height: 0, x: 0, y: 0 })
22
+ @title_area = Dimensions.new({ width: 0, height: 0, x: 0, y: 0 })
23
+ @series_key_area = Dimensions.new({ width: 0, height: 0, x: 0, y: 0 })
24
+ @theme = theme
25
+ set_from_attributes(attributes) if attributes
26
+ end
27
+
28
+ def calculate
29
+ calculate_width_and_height_of_canvas
30
+ calculate_key_area
31
+ calculate_title_area
32
+ calculate_graph_area
33
+
34
+ self
35
+ end
36
+
37
+ def hpadding
38
+ ((BigDecimal(canvas_width) / 100) * 2).round
39
+ end
40
+
41
+ def vpadding
42
+ ((BigDecimal(canvas_height) / 100) * 2).round
43
+ end
44
+
45
+ def invalid?
46
+ canvas_width > bounds[0] || canvas_height > bounds[1]
47
+ end
48
+
49
+ private
50
+
51
+ def set_from_attributes(attributes)
52
+ @canvas_width = BigDecimal(attributes[:width], 10) rescue 0
53
+ @canvas_height = BigDecimal(attributes[:height], 10) rescue 0
54
+ @num_series = attributes[:series_count] || 1
55
+ @title = attributes[:title]
56
+ @show_series_key = !attributes[:show_series_key].nil? ? attributes[:show_series_key] : true
57
+ end
58
+
59
+ def calculate_width_and_height_of_canvas
60
+ if @canvas_width.zero? && @canvas_height.zero?
61
+ @canvas_width = BigDecimal(bounds[0], 10)
62
+ @canvas_height = BigDecimal(bounds[1], 10)
63
+ elsif !@canvas_width.zero? && @canvas_height.zero?
64
+ @canvas_height = (@canvas_width / bounds_aspect_ratio).round
65
+ elsif !@canvas_height.zero? && @canvas_width.zero?
66
+ @canvas_width = (@canvas_height * bounds_aspect_ratio).round
67
+ end
68
+ end
69
+
70
+ def bounds_aspect_ratio
71
+ BigDecimal(bounds[0], 10) / BigDecimal(bounds[1], 10)
72
+ end
73
+
74
+ def calculate_title_area
75
+ unless @title.nil?
76
+ @title_area[:width] = (canvas_width - @series_key_area[:width] - (2*hpadding))
77
+ @title_area[:x] = hpadding
78
+ @title_area[:height] = @theme.font_sizes.main_title + vpadding
79
+ @title_area[:y] = canvas_height + vpadding
80
+ end
81
+ end
82
+
83
+ def calculate_key_area
84
+ if @num_series > 1 && @show_series_key
85
+ @series_key_area[:width] = ( (canvas_width / 100) * 25 ).round
86
+ @series_key_area[:x] = (canvas_width - @series_key_area[:width] - hpadding)
87
+ @series_key_area[:y] = canvas_height + vpadding
88
+ @series_key_area[:height] = (canvas_height - vpadding)
89
+ end
90
+ end
91
+
92
+ def calculate_graph_area
93
+ @graph_area[:width] = (canvas_width - @series_key_area[:width] - (2*hpadding))
94
+ @graph_area[:x] = hpadding
95
+
96
+ if !@title_area.renderable?
97
+ @graph_area[:y] = canvas_height + vpadding
98
+ @graph_area[:height] = (canvas_height - vpadding)
99
+ else
100
+ @graph_area[:y] = (@title_area[:y] - @title_area[:height])
101
+ @graph_area[:height] = (canvas_height - vpadding - @title_area[:height])
102
+ end
103
+ end
104
+
105
+ end
106
+
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,4 @@
1
+ require_relative "chart_components/series_renderer"
2
+ require_relative "chart_components/bar_chart_renderer"
3
+ require_relative "chart_components/line_chart_renderer"
4
+ require_relative "chart_components/canvas"
@@ -0,0 +1,94 @@
1
+ module Prawn
2
+ module Graph
3
+ module ChartComponents
4
+ # The Prawn::Graph::ChartComponents::BarChartRenderer is used to plot one or more bar charts
5
+ # in a sensible way on a a Prawn::Graph::ChartComponents::Canvas and its associated
6
+ # Prawn::Document.
7
+ #
8
+ class BarChartRenderer < SeriesRenderer
9
+ def render
10
+ render_the_chart
11
+ end
12
+
13
+ private
14
+
15
+ def mark_average_line(series_index)
16
+ if @series[series_index].mark_average?
17
+ average_y_coordinate = (point_height_percentage(@series[series_index].avg) * @plot_area_height) - 5
18
+ prawn.line_width = 1
19
+ prawn.stroke_color = @color[series_index]
20
+ prawn.dash(2)
21
+ prawn.stroke_line([0, average_y_coordinate], [ @plot_area_width, average_y_coordinate ])
22
+ prawn.undash
23
+ end
24
+ end
25
+
26
+ def mark_maximum_point(series_index, point, max_marked, x_position, y_position)
27
+ if @series[series_index].mark_maximum? && max_marked == false && @series[series_index].values[point] == @series[series_index].max
28
+ max_marked = draw_marker_point(@canvas.theme.max, x_position, y_position)
29
+ end
30
+
31
+ max_marked
32
+ end
33
+
34
+ def mark_minimum_point(series_index, point, min_marked, x_position, y_position)
35
+ if @series[series_index].mark_minimum? && min_marked == false && !@series[series_index].values[point].zero? && @series[series_index].values[point] == @series[series_index].min
36
+ min_marked = draw_marker_point(@canvas.theme.min, x_position, y_position)
37
+ end
38
+
39
+ min_marked
40
+ end
41
+
42
+ def render_the_chart
43
+ prawn.bounding_box [@graph_area.point[0] + 5, @graph_area.point[1] - 20], width: @plot_area_width, height: @plot_area_height do
44
+
45
+ prawn.save_graphics_state do
46
+ num_points = @series[0].size
47
+ width_per_point = (@plot_area_width / num_points)
48
+ width = (((width_per_point * 0.9) / @series.size).round(2)).to_f
49
+ min_marked = false
50
+ max_marked = false
51
+
52
+ num_points.times do |point|
53
+
54
+ @series.size.times do |series_index|
55
+ series_offset = series_index + 1
56
+ prawn.fill_color = @color[series_index]
57
+ prawn.stroke_color = @color[series_index]
58
+ prawn.line_width = width
59
+
60
+ starting = (prawn.bounds.left + (point * width_per_point))
61
+
62
+ x_position = ( (starting + (series_offset * width) ).to_f - (width / 2.0))
63
+ y_position = ((point_height_percentage(@series[series_index].values[point]) * @plot_area_height) - 5).to_f
64
+
65
+ prawn.fill_and_stroke_line([ x_position ,0], [x_position ,y_position]) unless @series[series_index].values[point].zero?
66
+
67
+ mark_average_line(series_index)
68
+ max_marked = mark_maximum_point(series_index, point, max_marked, x_position, y_position)
69
+ min_marked = mark_minimum_point(series_index, point, min_marked, x_position, y_position)
70
+ end
71
+
72
+ end
73
+
74
+ end
75
+ render_axes
76
+ end
77
+ end
78
+
79
+ def max
80
+ @series.collect(&:max).max || 0
81
+ end
82
+
83
+ def min
84
+ @series.collect(&:min).min || 0
85
+ end
86
+
87
+ def avg
88
+ @series.collect(&:avg).inject(:+) / @series.size rescue 0
89
+ end
90
+
91
+ end
92
+ end
93
+ end
94
+ end