prawn-graph 1.0.0.pre1 → 1.0.1
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/.travis.yml +10 -0
- data/README.md +72 -36
- data/Rakefile +6 -0
- data/lib/prawn-graph.rb +6 -1
- data/lib/prawn/graph/calculations.rb +1 -0
- data/lib/prawn/graph/calculations/layout_calculator.rb +109 -0
- data/lib/prawn/graph/chart_components.rb +4 -0
- data/lib/prawn/graph/chart_components/bar_chart_renderer.rb +94 -0
- data/lib/prawn/graph/chart_components/canvas.rb +128 -0
- data/lib/prawn/graph/chart_components/line_chart_renderer.rb +92 -0
- data/lib/prawn/graph/chart_components/series_renderer.rb +120 -0
- data/lib/prawn/graph/extension.rb +16 -23
- data/lib/prawn/graph/series.rb +57 -8
- data/lib/prawn/graph/theme.rb +23 -6
- data/lib/prawn/graph/version.rb +1 -1
- data/prawn-graph.gemspec +8 -2
- metadata +44 -15
- data/lib/prawn/graph/charts.rb +0 -4
- data/lib/prawn/graph/charts/bar.rb +0 -18
- data/lib/prawn/graph/charts/base.rb +0 -69
- data/lib/prawn/graph/charts/legacy.rb +0 -4
- data/lib/prawn/graph/charts/legacy/bar.rb +0 -28
- data/lib/prawn/graph/charts/legacy/base.rb +0 -195
- data/lib/prawn/graph/charts/legacy/grid.rb +0 -51
- data/lib/prawn/graph/charts/legacy/line.rb +0 -39
- data/lib/prawn/graph/charts/line.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6390e1f2b56cd0e602ed9bad9f9e79d8bf8d24fd
|
4
|
+
data.tar.gz: 5a17ad2247533d9a61a26043521e26c7dd21f1f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
[](https://badge.fury.io/rb/prawn-graph)
|
4
4
|
[](http://sujrd.mit-license.org)
|
5
|
+
[](https://codeclimate.com/github/HHRy/prawn-graph)
|
6
|
+
[](https://codeclimate.com/github/HHRy/prawn-graph/coverage)
|
7
|
+
[](https://travis-ci.org/HHRy/prawn-graph)
|
8
|
+
[](https://hakiri.io/github/HHRy/prawn-graph/master)
|
9
|
+

|
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
|
-
|
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
|
-
|
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
|
-
|
33
|
-
|
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
|
-
|
37
|
-
[a good citizen][2] and [report them][2].
|
46
|
+
## Installation
|
38
47
|
|
39
|
-
To use prawn-graph
|
48
|
+
To use prawn-graph, you can add the following to your `Gemfile`:
|
40
49
|
|
41
50
|
```Gemfile
|
42
|
-
gem 'prawn-graph', '1.0
|
51
|
+
gem 'prawn-graph', ' ~> 1.0'
|
43
52
|
```
|
44
53
|
|
45
|
-
Alternatively, you can use Rubygems directly: `gem install prawn-graph
|
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
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
71
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
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,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
|