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.
@@ -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 }
@@ -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>" }
@@ -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