pi_charts 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|