inviton-powerduck 0.0.218 → 0.0.219

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.
@@ -1,507 +1,507 @@
1
- /* Javascript plotting library for jQuery, version 0.8.3.
2
-
3
- Copyright (c) 2007-2014 IOLA and Ole Laursen.
4
- Licensed under the MIT license.
5
-
6
- */
7
- (function ($) {
8
- var REDRAW_ATTEMPTS = 10;
9
- var REDRAW_SHRINK = 0.95;
10
- function init(plot) {
11
- var canvas = null,
12
- target = null,
13
- options = null,
14
- maxRadius = null,
15
- centerLeft = null,
16
- centerTop = null,
17
- processed = false,
18
- ctx = null;
19
- var highlights = [];
20
- plot.hooks.processOptions.push(function (plot, options) {
21
- if (options.series.pie.show) {
22
- options.grid.show = false;
23
- if (options.series.pie.label.show == "auto") {
24
- if (options.legend.show) {
25
- options.series.pie.label.show = false;
26
- } else {
27
- options.series.pie.label.show = true;
28
- }
29
- }
30
- if (options.series.pie.radius == "auto") {
31
- if (options.series.pie.label.show) {
32
- options.series.pie.radius = 3 / 4;
33
- } else {
34
- options.series.pie.radius = 1;
35
- }
36
- }
37
- if (options.series.pie.tilt > 1) {
38
- options.series.pie.tilt = 1;
39
- } else if (options.series.pie.tilt < 0) {
40
- options.series.pie.tilt = 0;
41
- }
42
- }
43
- });
44
- plot.hooks.bindEvents.push(function (plot, eventHolder) {
45
- var options = plot.getOptions();
46
- if (options.series.pie.show) {
47
- if (options.grid.hoverable) {
48
- eventHolder.unbind("mousemove").mousemove(onMouseMove);
49
- }
50
- if (options.grid.clickable) {
51
- eventHolder.unbind("click").click(onClick);
52
- }
53
- }
54
- });
55
- plot.hooks.processDatapoints.push(function (plot, series, data, datapoints) {
56
- var options = plot.getOptions();
57
- if (options.series.pie.show) {
58
- processDatapoints(plot, series, data, datapoints);
59
- }
60
- });
61
- plot.hooks.drawOverlay.push(function (plot, octx) {
62
- var options = plot.getOptions();
63
- if (options.series.pie.show) {
64
- drawOverlay(plot, octx);
65
- }
66
- });
67
- plot.hooks.draw.push(function (plot, newCtx) {
68
- var options = plot.getOptions();
69
- if (options.series.pie.show) {
70
- draw(plot, newCtx);
71
- }
72
- });
73
- function processDatapoints(plot, series, datapoints) {
74
- if (!processed) {
75
- processed = true;
76
- canvas = plot.getCanvas();
77
- target = $(canvas).parent();
78
- options = plot.getOptions();
79
- plot.setData(combine(plot.getData()));
80
- }
81
- }
82
- function combine(data) {
83
- var total = 0,
84
- combined = 0,
85
- numCombined = 0,
86
- color = options.series.pie.combine.color,
87
- newdata = [];
88
- for (var i = 0; i < data.length; ++i) {
89
- var value = data[i].data;
90
- if ($.isArray(value) && value.length == 1) {
91
- value = value[0];
92
- }
93
- if ($.isArray(value)) {
94
- if (!isNaN(parseFloat(value[1])) && isFinite(value[1])) {
95
- value[1] = +value[1];
96
- } else {
97
- value[1] = 0;
98
- }
99
- } else if (!isNaN(parseFloat(value)) && isFinite(value)) {
100
- value = [1, +value];
101
- } else {
102
- value = [1, 0];
103
- }
104
- data[i].data = [value];
105
- }
106
- for (var i = 0; i < data.length; ++i) {
107
- total += data[i].data[0][1];
108
- }
109
- for (var i = 0; i < data.length; ++i) {
110
- var value = data[i].data[0][1];
111
- if (value / total <= options.series.pie.combine.threshold) {
112
- combined += value;
113
- numCombined++;
114
- if (!color) {
115
- color = data[i].color;
116
- }
117
- }
118
- }
119
- for (var i = 0; i < data.length; ++i) {
120
- var value = data[i].data[0][1];
121
- if (numCombined < 2 || value / total > options.series.pie.combine.threshold) {
122
- newdata.push(
123
- $.extend(data[i], {
124
- data: [[1, value]],
125
- color: data[i].color,
126
- label: data[i].label,
127
- angle: (value * Math.PI * 2) / total,
128
- percent: value / (total / 100),
129
- })
130
- );
131
- }
132
- }
133
- if (numCombined > 1) {
134
- newdata.push({
135
- data: [[1, combined]],
136
- color: color,
137
- label: options.series.pie.combine.label,
138
- angle: (combined * Math.PI * 2) / total,
139
- percent: combined / (total / 100),
140
- });
141
- }
142
- return newdata;
143
- }
144
- function draw(plot, newCtx) {
145
- if (!target) {
146
- return;
147
- }
148
- var canvasWidth = plot.getPlaceholder().width(),
149
- canvasHeight = plot.getPlaceholder().height(),
150
- legendWidth = target.children().filter(".legend").children().width() || 0;
151
- ctx = newCtx;
152
- processed = false;
153
- maxRadius = Math.min(canvasWidth, canvasHeight / options.series.pie.tilt) / 2;
154
- centerTop = canvasHeight / 2 + options.series.pie.offset.top;
155
- centerLeft = canvasWidth / 2;
156
- if (options.series.pie.offset.left == "auto") {
157
- if (options.legend.position.match("w")) {
158
- centerLeft += legendWidth / 2;
159
- } else {
160
- centerLeft -= legendWidth / 2;
161
- }
162
- if (centerLeft < maxRadius) {
163
- centerLeft = maxRadius;
164
- } else if (centerLeft > canvasWidth - maxRadius) {
165
- centerLeft = canvasWidth - maxRadius;
166
- }
167
- } else {
168
- centerLeft += options.series.pie.offset.left;
169
- }
170
- var slices = plot.getData(),
171
- attempts = 0;
172
- do {
173
- if (attempts > 0) {
174
- maxRadius *= REDRAW_SHRINK;
175
- }
176
- attempts += 1;
177
- clear();
178
- if (options.series.pie.tilt <= 0.8) {
179
- drawShadow();
180
- }
181
- } while (!drawPie() && attempts < REDRAW_ATTEMPTS);
182
- if (attempts >= REDRAW_ATTEMPTS) {
183
- clear();
184
- target.prepend("<div class='error'>Could not draw pie with labels contained inside canvas</div>");
185
- }
186
- if (plot.setSeries && plot.insertLegend) {
187
- plot.setSeries(slices);
188
- plot.insertLegend();
189
- }
190
- function clear() {
191
- ctx.clearRect(0, 0, canvasWidth, canvasHeight);
192
- target.children().filter(".pieLabel, .pieLabelBackground").remove();
193
- }
194
- function drawShadow() {
195
- var shadowLeft = options.series.pie.shadow.left;
196
- var shadowTop = options.series.pie.shadow.top;
197
- var edge = 10;
198
- var alpha = options.series.pie.shadow.alpha;
199
- var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
200
- if (radius >= canvasWidth / 2 - shadowLeft || radius * options.series.pie.tilt >= canvasHeight / 2 - shadowTop || radius <= edge) {
201
- return;
202
- }
203
- ctx.save();
204
- ctx.translate(shadowLeft, shadowTop);
205
- ctx.globalAlpha = alpha;
206
- ctx.fillStyle = "#000";
207
- ctx.translate(centerLeft, centerTop);
208
- ctx.scale(1, options.series.pie.tilt);
209
- for (var i = 1; i <= edge; i++) {
210
- ctx.beginPath();
211
- ctx.arc(0, 0, radius, 0, Math.PI * 2, false);
212
- ctx.fill();
213
- radius -= i;
214
- }
215
- ctx.restore();
216
- }
217
- function drawPie() {
218
- var startAngle = Math.PI * options.series.pie.startAngle;
219
- var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
220
- ctx.save();
221
- ctx.translate(centerLeft, centerTop);
222
- ctx.scale(1, options.series.pie.tilt);
223
- ctx.save();
224
- var currentAngle = startAngle;
225
- for (var i = 0; i < slices.length; ++i) {
226
- slices[i].startAngle = currentAngle;
227
- drawSlice(slices[i].angle, slices[i].color, true);
228
- }
229
- ctx.restore();
230
- if (options.series.pie.stroke.width > 0) {
231
- ctx.save();
232
- ctx.lineWidth = options.series.pie.stroke.width;
233
- currentAngle = startAngle;
234
- for (var i = 0; i < slices.length; ++i) {
235
- drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
236
- }
237
- ctx.restore();
238
- }
239
- drawDonutHole(ctx);
240
- ctx.restore();
241
- if (options.series.pie.label.show) {
242
- return drawLabels();
243
- } else return true;
244
- function drawSlice(angle, color, fill) {
245
- if (angle <= 0 || isNaN(angle)) {
246
- return;
247
- }
248
- if (fill) {
249
- ctx.fillStyle = color;
250
- } else {
251
- ctx.strokeStyle = color;
252
- ctx.lineJoin = "round";
253
- }
254
- ctx.beginPath();
255
- if (Math.abs(angle - Math.PI * 2) > 1e-9) {
256
- ctx.moveTo(0, 0);
257
- }
258
- ctx.arc(0, 0, radius, currentAngle, currentAngle + angle / 2, false);
259
- ctx.arc(0, 0, radius, currentAngle + angle / 2, currentAngle + angle, false);
260
- ctx.closePath();
261
- currentAngle += angle;
262
- if (fill) {
263
- ctx.fill();
264
- } else {
265
- ctx.stroke();
266
- }
267
- }
268
- function drawLabels() {
269
- var currentAngle = startAngle;
270
- var radius = options.series.pie.label.radius > 1 ? options.series.pie.label.radius : maxRadius * options.series.pie.label.radius;
271
- for (var i = 0; i < slices.length; ++i) {
272
- if (slices[i].percent >= options.series.pie.label.threshold * 100) {
273
- if (!drawLabel(slices[i], currentAngle, i)) {
274
- return false;
275
- }
276
- }
277
- currentAngle += slices[i].angle;
278
- }
279
- return true;
280
- function drawLabel(slice, startAngle, index) {
281
- if (slice.data[0][1] == 0) {
282
- return true;
283
- }
284
- var lf = options.legend.labelFormatter,
285
- text,
286
- plf = options.series.pie.label.formatter;
287
- if (lf) {
288
- text = lf(slice.label, slice);
289
- } else {
290
- text = slice.label;
291
- }
292
- if (plf) {
293
- text = plf(text, slice);
294
- }
295
- var halfAngle = (startAngle + slice.angle + startAngle) / 2;
296
- var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
297
- var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
298
- var html = "<span class='pieLabel' id='pieLabel" + index + "' style='position:absolute;top:" + y + "px;left:" + x + "px;'>" + text + "</span>";
299
- target.append(html);
300
- var label = target.children("#pieLabel" + index);
301
- var labelTop = y - label.height() / 2;
302
- var labelLeft = x - label.width() / 2;
303
- label.css("top", labelTop);
304
- label.css("left", labelLeft);
305
- if (0 - labelTop > 0 || 0 - labelLeft > 0 || canvasHeight - (labelTop + label.height()) < 0 || canvasWidth - (labelLeft + label.width()) < 0) {
306
- return false;
307
- }
308
- if (options.series.pie.label.background.opacity != 0) {
309
- var c = options.series.pie.label.background.color;
310
- if (c == null) {
311
- c = slice.color;
312
- }
313
- var pos = "top:" + labelTop + "px;left:" + labelLeft + "px;";
314
- $("<div class='pieLabelBackground' style='position:absolute;width:" + label.width() + "px;height:" + label.height() + "px;" + pos + "background-color:" + c + ";'></div>")
315
- .css("opacity", options.series.pie.label.background.opacity)
316
- .insertBefore(label);
317
- }
318
- return true;
319
- }
320
- }
321
- }
322
- }
323
- function drawDonutHole(layer) {
324
- if (options.series.pie.innerRadius > 0) {
325
- layer.save();
326
- var innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
327
- layer.globalCompositeOperation = "destination-out";
328
- layer.beginPath();
329
- layer.fillStyle = options.series.pie.stroke.color;
330
- layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false);
331
- layer.fill();
332
- layer.closePath();
333
- layer.restore();
334
- layer.save();
335
- layer.beginPath();
336
- layer.strokeStyle = options.series.pie.stroke.color;
337
- layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false);
338
- layer.stroke();
339
- layer.closePath();
340
- layer.restore();
341
- }
342
- }
343
- function isPointInPoly(poly, pt) {
344
- for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
345
- ((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1] < poly[i][1])) &&
346
- pt[0] < ((poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1])) / (poly[j][1] - poly[i][1]) + poly[i][0] &&
347
- (c = !c);
348
- return c;
349
- }
350
- function findNearbySlice(mouseX, mouseY) {
351
- var slices = plot.getData(),
352
- options = plot.getOptions(),
353
- radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius,
354
- x,
355
- y;
356
- for (var i = 0; i < slices.length; ++i) {
357
- var s = slices[i];
358
- if (s.pie.show) {
359
- ctx.save();
360
- ctx.beginPath();
361
- ctx.moveTo(0, 0);
362
- ctx.arc(0, 0, radius, s.startAngle, s.startAngle + s.angle / 2, false);
363
- ctx.arc(0, 0, radius, s.startAngle + s.angle / 2, s.startAngle + s.angle, false);
364
- ctx.closePath();
365
- x = mouseX - centerLeft;
366
- y = mouseY - centerTop;
367
- if (ctx.isPointInPath) {
368
- if (ctx.isPointInPath(mouseX - centerLeft, mouseY - centerTop)) {
369
- ctx.restore();
370
- return { datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i };
371
- }
372
- } else {
373
- var p1X = radius * Math.cos(s.startAngle),
374
- p1Y = radius * Math.sin(s.startAngle),
375
- p2X = radius * Math.cos(s.startAngle + s.angle / 4),
376
- p2Y = radius * Math.sin(s.startAngle + s.angle / 4),
377
- p3X = radius * Math.cos(s.startAngle + s.angle / 2),
378
- p3Y = radius * Math.sin(s.startAngle + s.angle / 2),
379
- p4X = radius * Math.cos(s.startAngle + s.angle / 1.5),
380
- p4Y = radius * Math.sin(s.startAngle + s.angle / 1.5),
381
- p5X = radius * Math.cos(s.startAngle + s.angle),
382
- p5Y = radius * Math.sin(s.startAngle + s.angle),
383
- arrPoly = [
384
- [0, 0],
385
- [p1X, p1Y],
386
- [p2X, p2Y],
387
- [p3X, p3Y],
388
- [p4X, p4Y],
389
- [p5X, p5Y],
390
- ],
391
- arrPoint = [x, y];
392
- if (isPointInPoly(arrPoly, arrPoint)) {
393
- ctx.restore();
394
- return { datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i };
395
- }
396
- }
397
- ctx.restore();
398
- }
399
- }
400
- return null;
401
- }
402
- function onMouseMove(e) {
403
- triggerClickHoverEvent("plothover", e);
404
- }
405
- function onClick(e) {
406
- triggerClickHoverEvent("plotclick", e);
407
- }
408
- function triggerClickHoverEvent(eventname, e) {
409
- var offset = plot.offset();
410
- var canvasX = parseInt(e.pageX - offset.left);
411
- var canvasY = parseInt(e.pageY - offset.top);
412
- var item = findNearbySlice(canvasX, canvasY);
413
- if (options.grid.autoHighlight) {
414
- for (var i = 0; i < highlights.length; ++i) {
415
- var h = highlights[i];
416
- if (h.auto == eventname && !(item && h.series == item.series)) {
417
- unhighlight(h.series);
418
- }
419
- }
420
- }
421
- if (item) {
422
- highlight(item.series, eventname);
423
- }
424
- var pos = { pageX: e.pageX, pageY: e.pageY };
425
- target.trigger(eventname, [pos, item]);
426
- }
427
- function highlight(s, auto) {
428
- var i = indexOfHighlight(s);
429
- if (i == -1) {
430
- highlights.push({ series: s, auto: auto });
431
- plot.triggerRedrawOverlay();
432
- } else if (!auto) {
433
- highlights[i].auto = false;
434
- }
435
- }
436
- function unhighlight(s) {
437
- if (s == null) {
438
- highlights = [];
439
- plot.triggerRedrawOverlay();
440
- }
441
- var i = indexOfHighlight(s);
442
- if (i != -1) {
443
- highlights.splice(i, 1);
444
- plot.triggerRedrawOverlay();
445
- }
446
- }
447
- function indexOfHighlight(s) {
448
- for (var i = 0; i < highlights.length; ++i) {
449
- var h = highlights[i];
450
- if (h.series == s) return i;
451
- }
452
- return -1;
453
- }
454
- function drawOverlay(plot, octx) {
455
- var options = plot.getOptions();
456
- var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
457
- octx.save();
458
- octx.translate(centerLeft, centerTop);
459
- octx.scale(1, options.series.pie.tilt);
460
- for (var i = 0; i < highlights.length; ++i) {
461
- drawHighlight(highlights[i].series);
462
- }
463
- drawDonutHole(octx);
464
- octx.restore();
465
- function drawHighlight(series) {
466
- if (series.angle <= 0 || isNaN(series.angle)) {
467
- return;
468
- }
469
- octx.fillStyle = "rgba(255, 255, 255, " + options.series.pie.highlight.opacity + ")";
470
- octx.beginPath();
471
- if (Math.abs(series.angle - Math.PI * 2) > 1e-9) {
472
- octx.moveTo(0, 0);
473
- }
474
- octx.arc(0, 0, radius, series.startAngle, series.startAngle + series.angle / 2, false);
475
- octx.arc(0, 0, radius, series.startAngle + series.angle / 2, series.startAngle + series.angle, false);
476
- octx.closePath();
477
- octx.fill();
478
- }
479
- }
480
- }
481
- var options = {
482
- series: {
483
- pie: {
484
- show: false,
485
- radius: "auto",
486
- innerRadius: 0,
487
- startAngle: 3 / 2,
488
- tilt: 1,
489
- shadow: { left: 5, top: 15, alpha: 0.02 },
490
- offset: { top: 0, left: "auto" },
491
- stroke: { color: "#fff", width: 1 },
492
- label: {
493
- show: "auto",
494
- formatter: function (label, slice) {
495
- return "<div style='font-size:x-small;text-align:center;padding:2px;color:" + slice.color + ";'>" + label + "<br/>" + Math.round(slice.percent) + "%</div>";
496
- },
497
- radius: 1,
498
- background: { color: null, opacity: 0 },
499
- threshold: 0,
500
- },
501
- combine: { threshold: -1, color: null, label: "Other" },
502
- highlight: { opacity: 0.5 },
503
- },
504
- },
505
- };
506
- $.plot.plugins.push({ init: init, options: options, name: "pie", version: "1.1" });
507
- })(jQuery);
1
+ /* Javascript plotting library for jQuery, version 0.8.3.
2
+
3
+ Copyright (c) 2007-2014 IOLA and Ole Laursen.
4
+ Licensed under the MIT license.
5
+
6
+ */
7
+ (function ($) {
8
+ var REDRAW_ATTEMPTS = 10;
9
+ var REDRAW_SHRINK = 0.95;
10
+ function init(plot) {
11
+ var canvas = null,
12
+ target = null,
13
+ options = null,
14
+ maxRadius = null,
15
+ centerLeft = null,
16
+ centerTop = null,
17
+ processed = false,
18
+ ctx = null;
19
+ var highlights = [];
20
+ plot.hooks.processOptions.push(function (plot, options) {
21
+ if (options.series.pie.show) {
22
+ options.grid.show = false;
23
+ if (options.series.pie.label.show == "auto") {
24
+ if (options.legend.show) {
25
+ options.series.pie.label.show = false;
26
+ } else {
27
+ options.series.pie.label.show = true;
28
+ }
29
+ }
30
+ if (options.series.pie.radius == "auto") {
31
+ if (options.series.pie.label.show) {
32
+ options.series.pie.radius = 3 / 4;
33
+ } else {
34
+ options.series.pie.radius = 1;
35
+ }
36
+ }
37
+ if (options.series.pie.tilt > 1) {
38
+ options.series.pie.tilt = 1;
39
+ } else if (options.series.pie.tilt < 0) {
40
+ options.series.pie.tilt = 0;
41
+ }
42
+ }
43
+ });
44
+ plot.hooks.bindEvents.push(function (plot, eventHolder) {
45
+ var options = plot.getOptions();
46
+ if (options.series.pie.show) {
47
+ if (options.grid.hoverable) {
48
+ eventHolder.unbind("mousemove").mousemove(onMouseMove);
49
+ }
50
+ if (options.grid.clickable) {
51
+ eventHolder.unbind("click").click(onClick);
52
+ }
53
+ }
54
+ });
55
+ plot.hooks.processDatapoints.push(function (plot, series, data, datapoints) {
56
+ var options = plot.getOptions();
57
+ if (options.series.pie.show) {
58
+ processDatapoints(plot, series, data, datapoints);
59
+ }
60
+ });
61
+ plot.hooks.drawOverlay.push(function (plot, octx) {
62
+ var options = plot.getOptions();
63
+ if (options.series.pie.show) {
64
+ drawOverlay(plot, octx);
65
+ }
66
+ });
67
+ plot.hooks.draw.push(function (plot, newCtx) {
68
+ var options = plot.getOptions();
69
+ if (options.series.pie.show) {
70
+ draw(plot, newCtx);
71
+ }
72
+ });
73
+ function processDatapoints(plot, series, datapoints) {
74
+ if (!processed) {
75
+ processed = true;
76
+ canvas = plot.getCanvas();
77
+ target = $(canvas).parent();
78
+ options = plot.getOptions();
79
+ plot.setData(combine(plot.getData()));
80
+ }
81
+ }
82
+ function combine(data) {
83
+ var total = 0,
84
+ combined = 0,
85
+ numCombined = 0,
86
+ color = options.series.pie.combine.color,
87
+ newdata = [];
88
+ for (var i = 0; i < data.length; ++i) {
89
+ var value = data[i].data;
90
+ if ($.isArray(value) && value.length == 1) {
91
+ value = value[0];
92
+ }
93
+ if ($.isArray(value)) {
94
+ if (!isNaN(parseFloat(value[1])) && isFinite(value[1])) {
95
+ value[1] = +value[1];
96
+ } else {
97
+ value[1] = 0;
98
+ }
99
+ } else if (!isNaN(parseFloat(value)) && isFinite(value)) {
100
+ value = [1, +value];
101
+ } else {
102
+ value = [1, 0];
103
+ }
104
+ data[i].data = [value];
105
+ }
106
+ for (var i = 0; i < data.length; ++i) {
107
+ total += data[i].data[0][1];
108
+ }
109
+ for (var i = 0; i < data.length; ++i) {
110
+ var value = data[i].data[0][1];
111
+ if (value / total <= options.series.pie.combine.threshold) {
112
+ combined += value;
113
+ numCombined++;
114
+ if (!color) {
115
+ color = data[i].color;
116
+ }
117
+ }
118
+ }
119
+ for (var i = 0; i < data.length; ++i) {
120
+ var value = data[i].data[0][1];
121
+ if (numCombined < 2 || value / total > options.series.pie.combine.threshold) {
122
+ newdata.push(
123
+ $.extend(data[i], {
124
+ data: [[1, value]],
125
+ color: data[i].color,
126
+ label: data[i].label,
127
+ angle: (value * Math.PI * 2) / total,
128
+ percent: value / (total / 100),
129
+ })
130
+ );
131
+ }
132
+ }
133
+ if (numCombined > 1) {
134
+ newdata.push({
135
+ data: [[1, combined]],
136
+ color: color,
137
+ label: options.series.pie.combine.label,
138
+ angle: (combined * Math.PI * 2) / total,
139
+ percent: combined / (total / 100),
140
+ });
141
+ }
142
+ return newdata;
143
+ }
144
+ function draw(plot, newCtx) {
145
+ if (!target) {
146
+ return;
147
+ }
148
+ var canvasWidth = plot.getPlaceholder().width(),
149
+ canvasHeight = plot.getPlaceholder().height(),
150
+ legendWidth = target.children().filter(".legend").children().width() || 0;
151
+ ctx = newCtx;
152
+ processed = false;
153
+ maxRadius = Math.min(canvasWidth, canvasHeight / options.series.pie.tilt) / 2;
154
+ centerTop = canvasHeight / 2 + options.series.pie.offset.top;
155
+ centerLeft = canvasWidth / 2;
156
+ if (options.series.pie.offset.left == "auto") {
157
+ if (options.legend.position.match("w")) {
158
+ centerLeft += legendWidth / 2;
159
+ } else {
160
+ centerLeft -= legendWidth / 2;
161
+ }
162
+ if (centerLeft < maxRadius) {
163
+ centerLeft = maxRadius;
164
+ } else if (centerLeft > canvasWidth - maxRadius) {
165
+ centerLeft = canvasWidth - maxRadius;
166
+ }
167
+ } else {
168
+ centerLeft += options.series.pie.offset.left;
169
+ }
170
+ var slices = plot.getData(),
171
+ attempts = 0;
172
+ do {
173
+ if (attempts > 0) {
174
+ maxRadius *= REDRAW_SHRINK;
175
+ }
176
+ attempts += 1;
177
+ clear();
178
+ if (options.series.pie.tilt <= 0.8) {
179
+ drawShadow();
180
+ }
181
+ } while (!drawPie() && attempts < REDRAW_ATTEMPTS);
182
+ if (attempts >= REDRAW_ATTEMPTS) {
183
+ clear();
184
+ target.prepend("<div class='error'>Could not draw pie with labels contained inside canvas</div>");
185
+ }
186
+ if (plot.setSeries && plot.insertLegend) {
187
+ plot.setSeries(slices);
188
+ plot.insertLegend();
189
+ }
190
+ function clear() {
191
+ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
192
+ target.children().filter(".pieLabel, .pieLabelBackground").remove();
193
+ }
194
+ function drawShadow() {
195
+ var shadowLeft = options.series.pie.shadow.left;
196
+ var shadowTop = options.series.pie.shadow.top;
197
+ var edge = 10;
198
+ var alpha = options.series.pie.shadow.alpha;
199
+ var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
200
+ if (radius >= canvasWidth / 2 - shadowLeft || radius * options.series.pie.tilt >= canvasHeight / 2 - shadowTop || radius <= edge) {
201
+ return;
202
+ }
203
+ ctx.save();
204
+ ctx.translate(shadowLeft, shadowTop);
205
+ ctx.globalAlpha = alpha;
206
+ ctx.fillStyle = "#000";
207
+ ctx.translate(centerLeft, centerTop);
208
+ ctx.scale(1, options.series.pie.tilt);
209
+ for (var i = 1; i <= edge; i++) {
210
+ ctx.beginPath();
211
+ ctx.arc(0, 0, radius, 0, Math.PI * 2, false);
212
+ ctx.fill();
213
+ radius -= i;
214
+ }
215
+ ctx.restore();
216
+ }
217
+ function drawPie() {
218
+ var startAngle = Math.PI * options.series.pie.startAngle;
219
+ var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
220
+ ctx.save();
221
+ ctx.translate(centerLeft, centerTop);
222
+ ctx.scale(1, options.series.pie.tilt);
223
+ ctx.save();
224
+ var currentAngle = startAngle;
225
+ for (var i = 0; i < slices.length; ++i) {
226
+ slices[i].startAngle = currentAngle;
227
+ drawSlice(slices[i].angle, slices[i].color, true);
228
+ }
229
+ ctx.restore();
230
+ if (options.series.pie.stroke.width > 0) {
231
+ ctx.save();
232
+ ctx.lineWidth = options.series.pie.stroke.width;
233
+ currentAngle = startAngle;
234
+ for (var i = 0; i < slices.length; ++i) {
235
+ drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
236
+ }
237
+ ctx.restore();
238
+ }
239
+ drawDonutHole(ctx);
240
+ ctx.restore();
241
+ if (options.series.pie.label.show) {
242
+ return drawLabels();
243
+ } else return true;
244
+ function drawSlice(angle, color, fill) {
245
+ if (angle <= 0 || isNaN(angle)) {
246
+ return;
247
+ }
248
+ if (fill) {
249
+ ctx.fillStyle = color;
250
+ } else {
251
+ ctx.strokeStyle = color;
252
+ ctx.lineJoin = "round";
253
+ }
254
+ ctx.beginPath();
255
+ if (Math.abs(angle - Math.PI * 2) > 1e-9) {
256
+ ctx.moveTo(0, 0);
257
+ }
258
+ ctx.arc(0, 0, radius, currentAngle, currentAngle + angle / 2, false);
259
+ ctx.arc(0, 0, radius, currentAngle + angle / 2, currentAngle + angle, false);
260
+ ctx.closePath();
261
+ currentAngle += angle;
262
+ if (fill) {
263
+ ctx.fill();
264
+ } else {
265
+ ctx.stroke();
266
+ }
267
+ }
268
+ function drawLabels() {
269
+ var currentAngle = startAngle;
270
+ var radius = options.series.pie.label.radius > 1 ? options.series.pie.label.radius : maxRadius * options.series.pie.label.radius;
271
+ for (var i = 0; i < slices.length; ++i) {
272
+ if (slices[i].percent >= options.series.pie.label.threshold * 100) {
273
+ if (!drawLabel(slices[i], currentAngle, i)) {
274
+ return false;
275
+ }
276
+ }
277
+ currentAngle += slices[i].angle;
278
+ }
279
+ return true;
280
+ function drawLabel(slice, startAngle, index) {
281
+ if (slice.data[0][1] == 0) {
282
+ return true;
283
+ }
284
+ var lf = options.legend.labelFormatter,
285
+ text,
286
+ plf = options.series.pie.label.formatter;
287
+ if (lf) {
288
+ text = lf(slice.label, slice);
289
+ } else {
290
+ text = slice.label;
291
+ }
292
+ if (plf) {
293
+ text = plf(text, slice);
294
+ }
295
+ var halfAngle = (startAngle + slice.angle + startAngle) / 2;
296
+ var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
297
+ var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
298
+ var html = "<span class='pieLabel' id='pieLabel" + index + "' style='position:absolute;top:" + y + "px;left:" + x + "px;'>" + text + "</span>";
299
+ target.append(html);
300
+ var label = target.children("#pieLabel" + index);
301
+ var labelTop = y - label.height() / 2;
302
+ var labelLeft = x - label.width() / 2;
303
+ label.css("top", labelTop);
304
+ label.css("left", labelLeft);
305
+ if (0 - labelTop > 0 || 0 - labelLeft > 0 || canvasHeight - (labelTop + label.height()) < 0 || canvasWidth - (labelLeft + label.width()) < 0) {
306
+ return false;
307
+ }
308
+ if (options.series.pie.label.background.opacity != 0) {
309
+ var c = options.series.pie.label.background.color;
310
+ if (c == null) {
311
+ c = slice.color;
312
+ }
313
+ var pos = "top:" + labelTop + "px;left:" + labelLeft + "px;";
314
+ $("<div class='pieLabelBackground' style='position:absolute;width:" + label.width() + "px;height:" + label.height() + "px;" + pos + "background-color:" + c + ";'></div>")
315
+ .css("opacity", options.series.pie.label.background.opacity)
316
+ .insertBefore(label);
317
+ }
318
+ return true;
319
+ }
320
+ }
321
+ }
322
+ }
323
+ function drawDonutHole(layer) {
324
+ if (options.series.pie.innerRadius > 0) {
325
+ layer.save();
326
+ var innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
327
+ layer.globalCompositeOperation = "destination-out";
328
+ layer.beginPath();
329
+ layer.fillStyle = options.series.pie.stroke.color;
330
+ layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false);
331
+ layer.fill();
332
+ layer.closePath();
333
+ layer.restore();
334
+ layer.save();
335
+ layer.beginPath();
336
+ layer.strokeStyle = options.series.pie.stroke.color;
337
+ layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false);
338
+ layer.stroke();
339
+ layer.closePath();
340
+ layer.restore();
341
+ }
342
+ }
343
+ function isPointInPoly(poly, pt) {
344
+ for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
345
+ ((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1] < poly[i][1])) &&
346
+ pt[0] < ((poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1])) / (poly[j][1] - poly[i][1]) + poly[i][0] &&
347
+ (c = !c);
348
+ return c;
349
+ }
350
+ function findNearbySlice(mouseX, mouseY) {
351
+ var slices = plot.getData(),
352
+ options = plot.getOptions(),
353
+ radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius,
354
+ x,
355
+ y;
356
+ for (var i = 0; i < slices.length; ++i) {
357
+ var s = slices[i];
358
+ if (s.pie.show) {
359
+ ctx.save();
360
+ ctx.beginPath();
361
+ ctx.moveTo(0, 0);
362
+ ctx.arc(0, 0, radius, s.startAngle, s.startAngle + s.angle / 2, false);
363
+ ctx.arc(0, 0, radius, s.startAngle + s.angle / 2, s.startAngle + s.angle, false);
364
+ ctx.closePath();
365
+ x = mouseX - centerLeft;
366
+ y = mouseY - centerTop;
367
+ if (ctx.isPointInPath) {
368
+ if (ctx.isPointInPath(mouseX - centerLeft, mouseY - centerTop)) {
369
+ ctx.restore();
370
+ return { datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i };
371
+ }
372
+ } else {
373
+ var p1X = radius * Math.cos(s.startAngle),
374
+ p1Y = radius * Math.sin(s.startAngle),
375
+ p2X = radius * Math.cos(s.startAngle + s.angle / 4),
376
+ p2Y = radius * Math.sin(s.startAngle + s.angle / 4),
377
+ p3X = radius * Math.cos(s.startAngle + s.angle / 2),
378
+ p3Y = radius * Math.sin(s.startAngle + s.angle / 2),
379
+ p4X = radius * Math.cos(s.startAngle + s.angle / 1.5),
380
+ p4Y = radius * Math.sin(s.startAngle + s.angle / 1.5),
381
+ p5X = radius * Math.cos(s.startAngle + s.angle),
382
+ p5Y = radius * Math.sin(s.startAngle + s.angle),
383
+ arrPoly = [
384
+ [0, 0],
385
+ [p1X, p1Y],
386
+ [p2X, p2Y],
387
+ [p3X, p3Y],
388
+ [p4X, p4Y],
389
+ [p5X, p5Y],
390
+ ],
391
+ arrPoint = [x, y];
392
+ if (isPointInPoly(arrPoly, arrPoint)) {
393
+ ctx.restore();
394
+ return { datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i };
395
+ }
396
+ }
397
+ ctx.restore();
398
+ }
399
+ }
400
+ return null;
401
+ }
402
+ function onMouseMove(e) {
403
+ triggerClickHoverEvent("plothover", e);
404
+ }
405
+ function onClick(e) {
406
+ triggerClickHoverEvent("plotclick", e);
407
+ }
408
+ function triggerClickHoverEvent(eventname, e) {
409
+ var offset = plot.offset();
410
+ var canvasX = parseInt(e.pageX - offset.left);
411
+ var canvasY = parseInt(e.pageY - offset.top);
412
+ var item = findNearbySlice(canvasX, canvasY);
413
+ if (options.grid.autoHighlight) {
414
+ for (var i = 0; i < highlights.length; ++i) {
415
+ var h = highlights[i];
416
+ if (h.auto == eventname && !(item && h.series == item.series)) {
417
+ unhighlight(h.series);
418
+ }
419
+ }
420
+ }
421
+ if (item) {
422
+ highlight(item.series, eventname);
423
+ }
424
+ var pos = { pageX: e.pageX, pageY: e.pageY };
425
+ target.trigger(eventname, [pos, item]);
426
+ }
427
+ function highlight(s, auto) {
428
+ var i = indexOfHighlight(s);
429
+ if (i == -1) {
430
+ highlights.push({ series: s, auto: auto });
431
+ plot.triggerRedrawOverlay();
432
+ } else if (!auto) {
433
+ highlights[i].auto = false;
434
+ }
435
+ }
436
+ function unhighlight(s) {
437
+ if (s == null) {
438
+ highlights = [];
439
+ plot.triggerRedrawOverlay();
440
+ }
441
+ var i = indexOfHighlight(s);
442
+ if (i != -1) {
443
+ highlights.splice(i, 1);
444
+ plot.triggerRedrawOverlay();
445
+ }
446
+ }
447
+ function indexOfHighlight(s) {
448
+ for (var i = 0; i < highlights.length; ++i) {
449
+ var h = highlights[i];
450
+ if (h.series == s) return i;
451
+ }
452
+ return -1;
453
+ }
454
+ function drawOverlay(plot, octx) {
455
+ var options = plot.getOptions();
456
+ var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
457
+ octx.save();
458
+ octx.translate(centerLeft, centerTop);
459
+ octx.scale(1, options.series.pie.tilt);
460
+ for (var i = 0; i < highlights.length; ++i) {
461
+ drawHighlight(highlights[i].series);
462
+ }
463
+ drawDonutHole(octx);
464
+ octx.restore();
465
+ function drawHighlight(series) {
466
+ if (series.angle <= 0 || isNaN(series.angle)) {
467
+ return;
468
+ }
469
+ octx.fillStyle = "rgba(255, 255, 255, " + options.series.pie.highlight.opacity + ")";
470
+ octx.beginPath();
471
+ if (Math.abs(series.angle - Math.PI * 2) > 1e-9) {
472
+ octx.moveTo(0, 0);
473
+ }
474
+ octx.arc(0, 0, radius, series.startAngle, series.startAngle + series.angle / 2, false);
475
+ octx.arc(0, 0, radius, series.startAngle + series.angle / 2, series.startAngle + series.angle, false);
476
+ octx.closePath();
477
+ octx.fill();
478
+ }
479
+ }
480
+ }
481
+ var options = {
482
+ series: {
483
+ pie: {
484
+ show: false,
485
+ radius: "auto",
486
+ innerRadius: 0,
487
+ startAngle: 3 / 2,
488
+ tilt: 1,
489
+ shadow: { left: 5, top: 15, alpha: 0.02 },
490
+ offset: { top: 0, left: "auto" },
491
+ stroke: { color: "#fff", width: 1 },
492
+ label: {
493
+ show: "auto",
494
+ formatter: function (label, slice) {
495
+ return "<div style='font-size:x-small;text-align:center;padding:2px;color:" + slice.color + ";'>" + label + "<br/>" + Math.round(slice.percent) + "%</div>";
496
+ },
497
+ radius: 1,
498
+ background: { color: null, opacity: 0 },
499
+ threshold: 0,
500
+ },
501
+ combine: { threshold: -1, color: null, label: "Other" },
502
+ highlight: { opacity: 0.5 },
503
+ },
504
+ },
505
+ };
506
+ $.plot.plugins.push({ init: init, options: options, name: "pie", version: "1.1" });
507
+ })(jQuery);