pi_charts 1.0.0
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 +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +40 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/bar_chart.rb +20 -0
- data/examples/bar_chart_hidden_legend.rb +22 -0
- data/examples/bar_chart_stacked.rb +23 -0
- data/examples/debug.rb +5 -0
- data/examples/doughnut_chart.rb +25 -0
- data/examples/doughnut_chart_hidden_legened.rb +28 -0
- data/examples/line_chart.rb +20 -0
- data/examples/line_chart_border.rb +23 -0
- data/examples/line_chart_hidden_legend.rb +23 -0
- data/examples/line_chart_no_line.rb +24 -0
- data/examples/line_chart_tension.rb +23 -0
- data/examples/pie_chart.rb +22 -0
- data/examples/pie_chart_hidden_legend.rb +19 -0
- data/examples/readme_serve_pie.rb +35 -0
- data/examples/sinatra.rb +55 -0
- data/examples/sinatra_line_chart.rb +25 -0
- data/lib/pi_charts.rb +19 -0
- data/lib/pi_charts/bar_chart.rb +125 -0
- data/lib/pi_charts/base.rb +98 -0
- data/lib/pi_charts/config.rb +40 -0
- data/lib/pi_charts/doughnut_chart.rb +27 -0
- data/lib/pi_charts/line_chart.rb +187 -0
- data/lib/pi_charts/pie_chart.rb +52 -0
- data/lib/pi_charts/utils.rb +21 -0
- data/lib/pi_charts/version.rb +3 -0
- data/pi_charts.gemspec +28 -0
- metadata +123 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require "pi_charts"
|
3
|
+
|
4
|
+
# create a new pie chart
|
5
|
+
chart = PiCharts::Pie.new
|
6
|
+
|
7
|
+
# add datasets
|
8
|
+
chart.add_dataset(label: "cats", data: 80)
|
9
|
+
chart.add_dataset(label: "dogs", data: 20)
|
10
|
+
|
11
|
+
# make cats 90
|
12
|
+
chart.add_dataset(label: "cats", data: 10, add: true)
|
13
|
+
|
14
|
+
# make dogs 10, not adding
|
15
|
+
chart.add_dataset(label: "dogs", data: 10)
|
16
|
+
|
17
|
+
# neat 'lil configurations
|
18
|
+
chart.hover
|
19
|
+
chart.responsive
|
20
|
+
|
21
|
+
# generate html / js for chart
|
22
|
+
puts chart.html
|
@@ -0,0 +1,19 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require "pi_charts"
|
3
|
+
|
4
|
+
# create a new pie chart
|
5
|
+
chart = PiCharts::Pie.new
|
6
|
+
|
7
|
+
# add datasets
|
8
|
+
chart.add_dataset(label: "cats", data: 80)
|
9
|
+
chart.add_dataset(label: "dogs", data: 20)
|
10
|
+
|
11
|
+
# hide legend
|
12
|
+
chart.legend(hidden: true)
|
13
|
+
|
14
|
+
# neat 'lil configurations
|
15
|
+
chart.hover
|
16
|
+
chart.responsive
|
17
|
+
|
18
|
+
# generate html / js for chart
|
19
|
+
puts chart.html
|
@@ -0,0 +1,35 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'sinatra'
|
3
|
+
require 'pi_charts'
|
4
|
+
|
5
|
+
# whatever sinatra configurations you want
|
6
|
+
set :bind, '0.0.0.0'
|
7
|
+
set :port, 4567
|
8
|
+
|
9
|
+
# create a new line chart
|
10
|
+
chart = PiCharts::Line.new
|
11
|
+
|
12
|
+
# add labels ( x values )
|
13
|
+
chart.add_labels(["January", "February", "March", "April", "May"])
|
14
|
+
|
15
|
+
# add datasets
|
16
|
+
chart.add_dataset(label: "cats", data: [3, 1, 3, 3, 7])
|
17
|
+
chart.add_dataset(label: "dogs", data: [7, 3, 3, 1, 3])
|
18
|
+
|
19
|
+
# neat 'lil configurations
|
20
|
+
chart.hover
|
21
|
+
chart.responsive
|
22
|
+
|
23
|
+
# generate html / js for chart
|
24
|
+
# and serve it up, on the house ( localhost )
|
25
|
+
|
26
|
+
def bake_pie
|
27
|
+
chart = PiCharts::Pie.new
|
28
|
+
chart.add_dataset(label: "cats", data: 80)
|
29
|
+
chart.add_dataset(label: "dogs", data: 50)
|
30
|
+
chart.hover
|
31
|
+
chart.responsive
|
32
|
+
"<head>" + chart.cdn + "</head>" + "<body>" + chart.html(width: 100) + "</body>"
|
33
|
+
end
|
34
|
+
|
35
|
+
get('/serve_pie') { bake_pie }
|
data/examples/sinatra.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'pi_charts'
|
3
|
+
require 'sinatra'
|
4
|
+
|
5
|
+
# whatever sinatra configurations you want
|
6
|
+
set :bind, '0.0.0.0'
|
7
|
+
set :port, 4567
|
8
|
+
|
9
|
+
utils = PiCharts::Utils.new
|
10
|
+
|
11
|
+
get('/') { "try /line or /pie or /bar" }
|
12
|
+
|
13
|
+
def line
|
14
|
+
chart = PiCharts::Line.new
|
15
|
+
chart.add_labels(["January", "February", "March", "April", "May"])
|
16
|
+
chart.add_dataset(label: "cats", data: [3, 1, 3, 3, 7])
|
17
|
+
chart.add_dataset(label: "dogs", data: [7, 3, 3, 1, 3])
|
18
|
+
chart.hover
|
19
|
+
chart.responsive
|
20
|
+
chart.html(width: 100)
|
21
|
+
end
|
22
|
+
get('/line') { "<head>" + utils.cdn + "</head>" + "<body>" + line + "</body>" }
|
23
|
+
|
24
|
+
def bake_pie
|
25
|
+
chart = PiCharts::Pie.new
|
26
|
+
chart.add_dataset(label: "cats", data: 80)
|
27
|
+
chart.add_dataset(label: "dogs", data: 50)
|
28
|
+
chart.hover
|
29
|
+
chart.responsive
|
30
|
+
chart.html(width: 100)
|
31
|
+
end
|
32
|
+
get('/pie') { "<head>" + utils.cdn + "</head>" + "<body>" + bake_pie + "</body>" }
|
33
|
+
|
34
|
+
def bar
|
35
|
+
chart = PiCharts::Bar.new
|
36
|
+
chart.add_labels(["January", "February", "March", "April", "May"])
|
37
|
+
chart.add_dataset(label: "cats", data: [ 2, 0, 4, 7, 3 ])
|
38
|
+
chart.add_dataset(label: "dogs", data: [ 4, 6, 3, 9, 2 ])
|
39
|
+
chart.stack
|
40
|
+
chart.hover
|
41
|
+
chart.responsive
|
42
|
+
chart.html(width: 100)
|
43
|
+
end
|
44
|
+
get('/bar') { "<head>" + utils.cdn + "</head>" + "<body>" + bar + "</body>" }
|
45
|
+
|
46
|
+
def get_doughnuts
|
47
|
+
chart = PiCharts::Doughnut.new
|
48
|
+
chart.add_dataset(label: "cats", data: 7)
|
49
|
+
chart.add_dataset(label: "dogs", data: 13)
|
50
|
+
chart.hover
|
51
|
+
chart.responsive
|
52
|
+
chart.html(width: 100)
|
53
|
+
end
|
54
|
+
get('/doughnut') { "<head>" + utils.cdn + "</head>" + "<body>" + get_doughnuts + "</body>" }
|
55
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'pi_charts'
|
3
|
+
require 'sinatra'
|
4
|
+
|
5
|
+
# whatever sinatra configurations you want
|
6
|
+
set :bind, '0.0.0.0'
|
7
|
+
set :port, 4567
|
8
|
+
|
9
|
+
# create a new line chart
|
10
|
+
chart = PiCharts::Line.new
|
11
|
+
|
12
|
+
# add labels ( x values )
|
13
|
+
chart.add_labels(["January", "February", "March", "April", "May"])
|
14
|
+
|
15
|
+
# add datasets
|
16
|
+
chart.add_dataset(label: "cats", data: [3, 1, 3, 3, 7])
|
17
|
+
chart.add_dataset(label: "dogs", data: [7, 3, 3, 1, 3])
|
18
|
+
|
19
|
+
# neat 'lil configurations
|
20
|
+
chart.hover
|
21
|
+
chart.responsive
|
22
|
+
|
23
|
+
# generate html / js for chart
|
24
|
+
# and serve it up, on the house ( localhost )
|
25
|
+
get('/') { "<head>" + chart.cdn + "</head>" + "<body>" + chart.html(width: 100) + "</body>" }
|
data/lib/pi_charts.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# I guess I could do a loop, jah feel?
|
2
|
+
# Or any other way I guess.
|
3
|
+
require "pi_charts/version"
|
4
|
+
require "pi_charts/base"
|
5
|
+
require "pi_charts/utils"
|
6
|
+
require "pi_charts/config"
|
7
|
+
require "pi_charts/line_chart"
|
8
|
+
require "pi_charts/pie_chart"
|
9
|
+
require "pi_charts/bar_chart"
|
10
|
+
require "pi_charts/doughnut_chart"
|
11
|
+
|
12
|
+
# Lil' extra spice.
|
13
|
+
require "securerandom"
|
14
|
+
require "json"
|
15
|
+
|
16
|
+
module PiCharts
|
17
|
+
# I'll put my code where I want to put my code, thank you very much.
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module PiCharts
|
2
|
+
|
3
|
+
class Bar < Base
|
4
|
+
|
5
|
+
def add_labels(labels)
|
6
|
+
@config.data[:data][:labels] = labels
|
7
|
+
end
|
8
|
+
|
9
|
+
def title(args={})
|
10
|
+
if args.keys.empty? or ! args.keys.include? [:title]
|
11
|
+
raise "need to specify title with {title: 'name', display: true/false }"
|
12
|
+
end
|
13
|
+
@config.data[:data][:options][:title] = {}
|
14
|
+
@config.data[:data][:options][:title][:text] = args[:title] || ""
|
15
|
+
@config.data[:data][:options][:title][:display] = true unless args[:display] == false
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def create(args={})
|
20
|
+
@config.data[:type] = 'bar'
|
21
|
+
@config.data[:data][:datasets] = []
|
22
|
+
@config.data[:data][:labels] = []
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def stack(args={})
|
27
|
+
@config.data[:options][:scales] = {} unless @config.data[:options][:scales]
|
28
|
+
@config.data[:options][:scales][:xAxes] = [] unless @config.data[:options][:scales][:xAxes]
|
29
|
+
@config.data[:options][:scales][:yAxes] = [] unless @config.data[:options][:scales][:yAxes]
|
30
|
+
if args.keys.empty?
|
31
|
+
@config.data[:options][:scales][:xAxes] << { stacked: true }
|
32
|
+
@config.data[:options][:scales][:yAxes] << { stacked: true }
|
33
|
+
else
|
34
|
+
@config.data[:options][:scales][:xAxes] << { stacked: true } if args[:x]
|
35
|
+
@config.data[:options][:scales][:yAxes] << { stacked: true } if args[:y]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_dataset(args={})
|
40
|
+
if args.keys.empty?
|
41
|
+
raise "need to specify dataset"
|
42
|
+
end
|
43
|
+
label = args[:label]
|
44
|
+
data = args[:data]
|
45
|
+
color = args[:color] || random_color
|
46
|
+
index = dataset_index(label)
|
47
|
+
if index
|
48
|
+
if data.kind_of?(Array)
|
49
|
+
data.each { |d| @config.data[:data][:datasets][index][:data] << d }
|
50
|
+
else
|
51
|
+
@config.data[:data][:datasets][index][:data] << data
|
52
|
+
end
|
53
|
+
else
|
54
|
+
dataset = {}
|
55
|
+
dataset[:label] = label
|
56
|
+
dataset[:borderColor] = color
|
57
|
+
dataset[:backgroundColor] = color
|
58
|
+
dataset[:data] = []
|
59
|
+
if data.kind_of?(Array)
|
60
|
+
data.each { |d| dataset[:data] << d }
|
61
|
+
else
|
62
|
+
dataset[:data] << data
|
63
|
+
end
|
64
|
+
@config.data[:data][:datasets] << dataset
|
65
|
+
end
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
def border(args={})
|
70
|
+
if args.keys.empty?
|
71
|
+
false
|
72
|
+
else
|
73
|
+
if args[:dataset]
|
74
|
+
index = dataset_index(args[:dataset])
|
75
|
+
if index
|
76
|
+
@config.data[:data][:datasets][index][:borderColor] = args[:color] if args[:color]
|
77
|
+
@config.data[:data][:datasets][index][:borderWidth] = args[:width] if args[:width]
|
78
|
+
@config.data[:data][:datasets][index][:borderSkipped] = args[:skipped] if args[:skipped]
|
79
|
+
@config.data[:data][:datasets][index][:borderDash] = args[:dash] if args[:dash]
|
80
|
+
else
|
81
|
+
raise "dataset doesn't seem to exist"
|
82
|
+
end
|
83
|
+
else
|
84
|
+
raise "need to specify a dataset"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def hover(args={})
|
90
|
+
if args.keys.empty?
|
91
|
+
false
|
92
|
+
else
|
93
|
+
if args[:dataset]
|
94
|
+
index = dataset_index(args[:dataset])
|
95
|
+
if index
|
96
|
+
@config.data[:data][:datasets][index][:hoverBackgroundColor] = args[:color] if args[:color]
|
97
|
+
@config.data[:data][:datasets][index][:hoverBorderColor] = args[:border] if args[:border]
|
98
|
+
@config.data[:data][:datasets][index][:hoverBorderWidth] = args[:width] if args[:width]
|
99
|
+
else
|
100
|
+
raise "dataset doesn't seem to exist"
|
101
|
+
end
|
102
|
+
else
|
103
|
+
raise "need to specify a dataset"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def dataset_index(label=false)
|
111
|
+
if label
|
112
|
+
@config.data[:data][:datasets].each_with_index do |set, index|
|
113
|
+
if set[:label] == label
|
114
|
+
return index
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
false
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module PiCharts
|
2
|
+
# The Base class is responsible for providing the boiler plate
|
3
|
+
# code for all of the different types of +PiCharts+ that someone
|
4
|
+
# can create with this gem. That's its job.
|
5
|
+
class Base
|
6
|
+
attr_accessor :config # Configuration base for all charts.
|
7
|
+
attr_accessor :cdn # Content distribution network, for the lulz.
|
8
|
+
|
9
|
+
# Every class has a +config+ and, depending on the type
|
10
|
+
# the +create+ method will help with setting up the +config+
|
11
|
+
# for that specific type of chart.
|
12
|
+
def initialize(args = {})
|
13
|
+
@config = Config.new
|
14
|
+
create
|
15
|
+
end
|
16
|
+
|
17
|
+
# The responsive() method will make any chart responsive.
|
18
|
+
def responsive(responsive = true)
|
19
|
+
if responsive
|
20
|
+
config.data[:options][:responsive] = true
|
21
|
+
else
|
22
|
+
config.data[:options][:responsive] = false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# The cdn() method will generate a bit of html magic to create
|
27
|
+
# a cloudflare cdn link for the needed javascript.
|
28
|
+
def cdn(args = {})
|
29
|
+
version = args[:version] || '2.4.0'
|
30
|
+
min = false || args[:min]
|
31
|
+
if min
|
32
|
+
"<script src=\"https://cdnjs.cloudflare.com/ajax/libs/Chart.js/#{version}/Chart.min.js\"></script>"
|
33
|
+
else
|
34
|
+
"<script src=\"https://cdnjs.cloudflare.com/ajax/libs/Chart.js/#{version}/Chart.js\"></script>"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# The legend() provides an interface to set options for the legend for any chart.
|
39
|
+
def legend(args = {})
|
40
|
+
config.data[:options][:legend] = {} unless config.data[:options][:legend]
|
41
|
+
config.data[:options][:legend][:position] = args[:position] if args [:position]
|
42
|
+
config.data[:options][:legend][:display] = true if args[:display]
|
43
|
+
config.data[:options][:legend][:display] = false if args[:hidden]
|
44
|
+
config.data[:options][:legend][:fullWidth] = true if args[:full]
|
45
|
+
config.data[:options][:legend][:reverse] = true if args[:reverse]
|
46
|
+
# legend labels
|
47
|
+
config.data[:options][:legend][:labels][:boxWidth] = args[:width] if args[:width]
|
48
|
+
config.data[:options][:legend][:labels][:fontSize] = args[:size] if args[:size]
|
49
|
+
config.data[:options][:legend][:labels][:fontStyle] = args[:style] if args[:style]
|
50
|
+
config.data[:options][:legend][:labels][:padding] = args[:padding] if args[:padding]
|
51
|
+
end
|
52
|
+
|
53
|
+
# The hover() method provides an interface +that is currently incomplete+ to the hover options for a chart.
|
54
|
+
def hover(args = {})
|
55
|
+
config.data[:options][:hover] = {}
|
56
|
+
if args.keys.empty?
|
57
|
+
config.data[:options][:hover][:mode] = 'nearest'
|
58
|
+
config.data[:options][:hover][:intersect] = true
|
59
|
+
else
|
60
|
+
config.data[:options][:hover][:mode] = 'nearest' if args[:nearest]
|
61
|
+
config.data[:options][:hover][:intersect] = true if args[:intersect]
|
62
|
+
config.data[:options][:hover][:animationDuration] = args[:animation] if args[:animation]
|
63
|
+
end
|
64
|
+
# TODO: add support for onHover configuration option
|
65
|
+
true
|
66
|
+
end
|
67
|
+
|
68
|
+
# Sometimes you just need a random color.
|
69
|
+
def random_color
|
70
|
+
"##{SecureRandom.hex(3)}"
|
71
|
+
end
|
72
|
+
|
73
|
+
# The create() method helps with the main boiler-plate
|
74
|
+
# buisness that goes behind the Base class.
|
75
|
+
def create
|
76
|
+
# helps with boilerplateness
|
77
|
+
end
|
78
|
+
|
79
|
+
# The html() method helps build the relevant html for the chart.
|
80
|
+
def html(args = {})
|
81
|
+
id = SecureRandom.uuid
|
82
|
+
width = args[:width] || "50"
|
83
|
+
config = args[:config] || @config.json
|
84
|
+
type = @config.type
|
85
|
+
|
86
|
+
"<div id=\"canvas-holder\" style=\"width:#{width}%\">
|
87
|
+
<canvas id=\"#{id}\" />
|
88
|
+
</div>
|
89
|
+
<script>
|
90
|
+
var config = #{config}
|
91
|
+
window.onload = function() {
|
92
|
+
var ctx = document.getElementById(\"#{id}\").getContext(\"2d\");
|
93
|
+
new Chart(ctx, config);
|
94
|
+
};
|
95
|
+
</script>"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module PiCharts
|
2
|
+
|
3
|
+
# The Config class provides the interface to the config
|
4
|
+
# for a chart. This is basically the skeleton of the
|
5
|
+
# infromation that drives the infromation for the chart
|
6
|
+
# that can be rendered into json. This information is
|
7
|
+
# constructed with its +data+ which actually provides
|
8
|
+
# the blueprints.
|
9
|
+
class Config
|
10
|
+
attr_accessor :data # The main brain and butter of what makes the co
|
11
|
+
|
12
|
+
# The initialize() method handles the creation of what defines
|
13
|
+
# the +data+ for a +config+, which sets up the relevant base.
|
14
|
+
def initialize(args={})
|
15
|
+
@data = {}
|
16
|
+
@data[:type] = ''
|
17
|
+
@data[:data] = {}
|
18
|
+
@data[:data][:datasets] = []
|
19
|
+
@data[:options] = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
# type?() helps determine if a type has been set or not.
|
23
|
+
def type?
|
24
|
+
@data[:type].empty? ? false : true
|
25
|
+
end
|
26
|
+
|
27
|
+
# type() returns the the type set in the config, or false
|
28
|
+
# if a type has not yet been set.
|
29
|
+
def type
|
30
|
+
@data[:type].empty? ? false : @data[:type]
|
31
|
+
end
|
32
|
+
|
33
|
+
# json() returns the +json+ representation of the +config+ data
|
34
|
+
# in a javascript friendly form. Magic!
|
35
|
+
def json
|
36
|
+
@data.to_json
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|