luci2: implement Class.require() and Class.instantiate()
[project/luci2/ui.git] / luci2 / htdocs / luci2 / jquery.peity.js
1 // Peity jQuery plugin version 1.2.0
2 // (c) 2013 Ben Pickles
3 //
4 // http://benpickles.github.com/peity
5 //
6 // Released under MIT license.
7 (function($, document, Math, devicePixelRatio) {
8   var canvasSupported = document.createElement("canvas").getContext
9
10   var peity = $.fn.peity = function(type, options) {
11     if (canvasSupported) {
12       this.each(function() {
13         var $this = $(this)
14         var chart = $this.data("peity")
15
16         if (chart) {
17           if (type) chart.type = type
18           $.extend(chart.opts, options)
19           chart.draw()
20         } else {
21           var defaults = peity.defaults[type]
22           var data = {}
23
24           $.each($this.data(), function(name, value) {
25             if (name in defaults) data[name] = value
26           })
27
28           var opts = $.extend({}, defaults, data, options)
29           var chart = new Peity($this, type, opts)
30           chart.draw()
31
32           $this
33             .change(function() { chart.draw() })
34             .data("peity", chart)
35         }
36       });
37     }
38
39     return this;
40   };
41
42   var Peity = function($el, type, opts) {
43     this.$el = $el
44     this.type = type
45     this.opts = opts
46   }
47
48   var PeityPrototype = Peity.prototype
49
50   PeityPrototype.colours = function() {
51     var colours = this.opts.colours
52     var func = colours
53
54     if (!$.isFunction(func)) {
55       func = function(_, i) {
56         return colours[i % colours.length]
57       }
58     }
59
60     return func
61   }
62
63   PeityPrototype.draw = function() {
64     peity.graphers[this.type].call(this, this.opts)
65   }
66
67   PeityPrototype.prepareCanvas = function(width, height) {
68     var canvas = this.canvas
69     var $canvas
70
71     if (canvas) {
72       this.context.clearRect(0, 0, canvas.width, canvas.height)
73       $canvas = $(canvas)
74     } else {
75       $canvas = $("<canvas>").css({
76         height: height,
77         width: width
78       }).addClass("peity").data("peity", this)
79
80       this.canvas = canvas = $canvas[0]
81       this.context = canvas.getContext("2d")
82       this.$el.hide().after(canvas)
83     }
84
85     canvas.height = $canvas.height() * devicePixelRatio
86     canvas.width = $canvas.width() * devicePixelRatio
87
88     return canvas
89   }
90
91   PeityPrototype.values = function() {
92     return $.map(this.$el.text().split(this.opts.delimiter), function(value) {
93       return parseFloat(value)
94     })
95   }
96
97   peity.defaults = {}
98   peity.graphers = {}
99
100   peity.register = function(type, defaults, grapher) {
101     this.defaults[type] = defaults
102     this.graphers[type] = grapher
103   }
104
105   peity.register(
106     'pie',
107     {
108       colours: ["#ff9900", "#fff4dd", "#ffc66e"],
109       delimiter: null,
110       diameter: 16
111     },
112     function(opts) {
113       if (!opts.delimiter) {
114         var delimiter = this.$el.text().match(/[^0-9\.]/)
115         opts.delimiter = delimiter ? delimiter[0] : ","
116       }
117
118       var values = this.values()
119
120       if (opts.delimiter == "/") {
121         var v1 = values[0]
122         var v2 = values[1]
123         values = [v1, v2 - v1]
124       }
125
126       var i = 0
127       var length = values.length
128       var sum = 0
129
130       for (; i < length; i++) {
131         sum += values[i]
132       }
133
134       var canvas = this.prepareCanvas(opts.width || opts.diameter, opts.height || opts.diameter)
135       var context = this.context
136       var width = canvas.width
137       var height = canvas.height
138       var radius = Math.min(width, height) / 2
139       var pi = Math.PI
140       var colours = this.colours()
141
142       context.save()
143       context.translate(width / 2, height / 2)
144       context.rotate(-pi / 2)
145
146       for (i = 0; i < length; i++) {
147         var value = values[i]
148         var slice = (value / sum) * pi * 2
149
150         context.beginPath()
151         context.moveTo(0, 0)
152         context.arc(0, 0, radius, 0, slice, false)
153         context.fillStyle = colours.call(this, value, i, values)
154         context.fill()
155         context.rotate(slice)
156       }
157
158       context.restore()
159     }
160   )
161
162   peity.register(
163     "line",
164     {
165       colour: "#c6d9fd",
166       strokeColour: "#4d89f9",
167       strokeWidth: 1,
168       delimiter: ",",
169       height: 16,
170       max: null,
171       min: 0,
172       width: 32
173     },
174     function(opts) {
175       var values = this.values()
176       if (values.length == 1) values.push(values[0])
177       var max = Math.max.apply(Math, values.concat([opts.max]));
178       var min = Math.min.apply(Math, values.concat([opts.min]))
179
180       var canvas = this.prepareCanvas(opts.width, opts.height)
181       var context = this.context
182       var width = canvas.width
183       var height = canvas.height
184       var xQuotient = width / (values.length - 1)
185       var yQuotient = height / (max - min)
186
187       var coords = [];
188       var i;
189
190       context.beginPath();
191       context.moveTo(0, height + (min * yQuotient))
192
193       for (i = 0; i < values.length; i++) {
194         var x = i * xQuotient
195         var y = height - (yQuotient * (values[i] - min))
196
197         coords.push({ x: x, y: y });
198         context.lineTo(x, y);
199       }
200
201       context.lineTo(width, height + (min * yQuotient))
202       context.fillStyle = opts.colour;
203       context.fill();
204
205       if (opts.strokeWidth) {
206         context.beginPath();
207         context.moveTo(0, coords[0].y);
208         for (i = 0; i < coords.length; i++) {
209           context.lineTo(coords[i].x, coords[i].y);
210         }
211         context.lineWidth = opts.strokeWidth * devicePixelRatio;
212         context.strokeStyle = opts.strokeColour;
213         context.stroke();
214       }
215     }
216   );
217
218   peity.register(
219     'bar',
220     {
221       colours: ["#4D89F9"],
222       delimiter: ",",
223       height: 16,
224       max: null,
225       min: 0,
226       spacing: devicePixelRatio,
227       width: 32
228     },
229     function(opts) {
230       var values = this.values()
231       var max = Math.max.apply(Math, values.concat([opts.max]));
232       var min = Math.min.apply(Math, values.concat([opts.min]))
233
234       var canvas = this.prepareCanvas(opts.width, opts.height)
235       var context = this.context
236
237       var width = canvas.width
238       var height = canvas.height
239       var yQuotient = height / (max - min)
240       var space = opts.spacing
241       var xQuotient = (width + space) / values.length
242       var colours = this.colours()
243
244       for (var i = 0; i < values.length; i++) {
245         var value = values[i]
246         var y = height - (yQuotient * (value - min))
247         var h
248
249         if (value == 0) {
250           if (min >= 0 || max > 0) y -= 1
251           h = 1
252         } else {
253           h = yQuotient * values[i]
254         }
255
256         context.fillStyle = colours.call(this, value, i, values)
257         context.fillRect(i * xQuotient, y, xQuotient - space, h)
258       }
259     }
260   );
261 })(jQuery, document, Math, window.devicePixelRatio || 1);