highcharts_rails 0.1.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.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +106 -0
  9. data/Rakefile +6 -0
  10. data/highcharts_rails.gemspec +27 -0
  11. data/lib/highcharts_rails/version.rb +3 -0
  12. data/lib/highcharts_rails.rb +8 -0
  13. data/vendor/assets/javascripts/highcharts-3d.src.js +2139 -0
  14. data/vendor/assets/javascripts/highcharts-more.src.js +2982 -0
  15. data/vendor/assets/javascripts/highcharts.src.js +22947 -0
  16. data/vendor/assets/javascripts/js/highcharts-3d.src.js +2085 -0
  17. data/vendor/assets/javascripts/js/highcharts-more.src.js +2820 -0
  18. data/vendor/assets/javascripts/js/highcharts.src.js +20917 -0
  19. data/vendor/assets/javascripts/js/modules/accessibility.src.js +1072 -0
  20. data/vendor/assets/javascripts/js/modules/annotations.src.js +408 -0
  21. data/vendor/assets/javascripts/js/modules/boost.src.js +652 -0
  22. data/vendor/assets/javascripts/js/modules/broken-axis.src.js +338 -0
  23. data/vendor/assets/javascripts/js/modules/data.src.js +981 -0
  24. data/vendor/assets/javascripts/js/modules/drilldown.src.js +756 -0
  25. data/vendor/assets/javascripts/js/modules/exporting.src.js +953 -0
  26. data/vendor/assets/javascripts/js/modules/funnel.src.js +290 -0
  27. data/vendor/assets/javascripts/js/modules/gantt.src.js +791 -0
  28. data/vendor/assets/javascripts/js/modules/grid-axis.src.js +545 -0
  29. data/vendor/assets/javascripts/js/modules/heatmap.src.js +798 -0
  30. data/vendor/assets/javascripts/js/modules/no-data-to-display.src.js +150 -0
  31. data/vendor/assets/javascripts/js/modules/offline-exporting.src.js +492 -0
  32. data/vendor/assets/javascripts/js/modules/overlapping-datalabels.src.js +164 -0
  33. data/vendor/assets/javascripts/js/modules/series-label.src.js +606 -0
  34. data/vendor/assets/javascripts/js/modules/solid-gauge.src.js +305 -0
  35. data/vendor/assets/javascripts/js/modules/treemap.src.js +881 -0
  36. data/vendor/assets/javascripts/js/modules/xrange-series.src.js +254 -0
  37. data/vendor/assets/javascripts/js/themes/dark-blue.js +317 -0
  38. data/vendor/assets/javascripts/js/themes/dark-green.js +314 -0
  39. data/vendor/assets/javascripts/js/themes/dark-unica.js +243 -0
  40. data/vendor/assets/javascripts/js/themes/gray.js +326 -0
  41. data/vendor/assets/javascripts/js/themes/grid-light.js +99 -0
  42. data/vendor/assets/javascripts/js/themes/grid.js +131 -0
  43. data/vendor/assets/javascripts/js/themes/sand-signika.js +129 -0
  44. data/vendor/assets/javascripts/js/themes/skies.js +112 -0
  45. data/vendor/assets/javascripts/lib/canvg.src.js +3073 -0
  46. data/vendor/assets/javascripts/lib/jspdf.src.js +3031 -0
  47. data/vendor/assets/javascripts/lib/rgbcolor.src.js +299 -0
  48. data/vendor/assets/javascripts/lib/svg2pdf.src.js +1451 -0
  49. data/vendor/assets/javascripts/modules/accessibility.src.js +1072 -0
  50. data/vendor/assets/javascripts/modules/annotations.src.js +408 -0
  51. data/vendor/assets/javascripts/modules/boost.src.js +652 -0
  52. data/vendor/assets/javascripts/modules/broken-axis.src.js +338 -0
  53. data/vendor/assets/javascripts/modules/data.src.js +981 -0
  54. data/vendor/assets/javascripts/modules/drilldown.src.js +797 -0
  55. data/vendor/assets/javascripts/modules/exporting.src.js +882 -0
  56. data/vendor/assets/javascripts/modules/funnel.src.js +304 -0
  57. data/vendor/assets/javascripts/modules/gantt.src.js +815 -0
  58. data/vendor/assets/javascripts/modules/grid-axis.src.js +547 -0
  59. data/vendor/assets/javascripts/modules/heatmap.src.js +810 -0
  60. data/vendor/assets/javascripts/modules/no-data-to-display.src.js +161 -0
  61. data/vendor/assets/javascripts/modules/offline-exporting.src.js +492 -0
  62. data/vendor/assets/javascripts/modules/overlapping-datalabels.src.js +164 -0
  63. data/vendor/assets/javascripts/modules/series-label.src.js +606 -0
  64. data/vendor/assets/javascripts/modules/solid-gauge.src.js +316 -0
  65. data/vendor/assets/javascripts/modules/treemap.src.js +935 -0
  66. data/vendor/assets/javascripts/modules/xrange-series.src.js +276 -0
  67. data/vendor/assets/javascripts/themes/dark-blue.js +317 -0
  68. data/vendor/assets/javascripts/themes/dark-green.js +314 -0
  69. data/vendor/assets/javascripts/themes/dark-unica.js +243 -0
  70. data/vendor/assets/javascripts/themes/gray.js +326 -0
  71. data/vendor/assets/javascripts/themes/grid-light.js +99 -0
  72. data/vendor/assets/javascripts/themes/grid.js +131 -0
  73. data/vendor/assets/javascripts/themes/sand-signika.js +129 -0
  74. data/vendor/assets/javascripts/themes/skies.js +112 -0
  75. data/vendor/assets/stylesheets/highcharts.scss +610 -0
  76. metadata +161 -0
@@ -0,0 +1,2820 @@
1
+ /**
2
+ * @license Highcharts JS v5.0.6 (2016-12-07)
3
+ *
4
+ * (c) 2009-2016 Torstein Honsi
5
+ *
6
+ * License: www.highcharts.com/license
7
+ */
8
+ (function(factory) {
9
+ if (typeof module === 'object' && module.exports) {
10
+ module.exports = factory;
11
+ } else {
12
+ factory(Highcharts);
13
+ }
14
+ }(function(Highcharts) {
15
+ (function(H) {
16
+ /**
17
+ * (c) 2010-2016 Torstein Honsi
18
+ *
19
+ * License: www.highcharts.com/license
20
+ */
21
+ 'use strict';
22
+ var each = H.each,
23
+ extend = H.extend,
24
+ merge = H.merge,
25
+ splat = H.splat;
26
+ /**
27
+ * The Pane object allows options that are common to a set of X and Y axes.
28
+ *
29
+ * In the future, this can be extended to basic Highcharts and Highstock.
30
+ */
31
+ function Pane(options, chart, firstAxis) {
32
+ this.init(options, chart, firstAxis);
33
+ }
34
+
35
+ // Extend the Pane prototype
36
+ extend(Pane.prototype, {
37
+
38
+ /**
39
+ * Initiate the Pane object
40
+ */
41
+ init: function(options, chart, firstAxis) {
42
+ var pane = this,
43
+ backgroundOption,
44
+ defaultOptions = pane.defaultOptions;
45
+
46
+ pane.chart = chart;
47
+
48
+ // Set options. Angular charts have a default background (#3318)
49
+ pane.options = options = merge(defaultOptions, chart.angular ? {
50
+ background: {}
51
+ } : undefined, options);
52
+
53
+ backgroundOption = options.background;
54
+
55
+ // To avoid having weighty logic to place, update and remove the backgrounds,
56
+ // push them to the first axis' plot bands and borrow the existing logic there.
57
+ if (backgroundOption) {
58
+ each([].concat(splat(backgroundOption)).reverse(), function(config) {
59
+ var mConfig,
60
+ axisUserOptions = firstAxis.userOptions;
61
+ mConfig = merge(pane.defaultBackgroundOptions, config);
62
+
63
+
64
+
65
+ firstAxis.options.plotBands.unshift(mConfig);
66
+ axisUserOptions.plotBands = axisUserOptions.plotBands || []; // #3176
67
+ if (axisUserOptions.plotBands !== firstAxis.options.plotBands) {
68
+ axisUserOptions.plotBands.unshift(mConfig);
69
+ }
70
+ });
71
+ }
72
+ },
73
+
74
+ /**
75
+ * The default options object
76
+ */
77
+ defaultOptions: {
78
+ // background: {conditional},
79
+ center: ['50%', '50%'],
80
+ size: '85%',
81
+ startAngle: 0
82
+ //endAngle: startAngle + 360
83
+ },
84
+
85
+ /**
86
+ * The default background options
87
+ */
88
+ defaultBackgroundOptions: {
89
+ className: 'highcharts-pane',
90
+ shape: 'circle',
91
+
92
+ from: -Number.MAX_VALUE, // corrected to axis min
93
+ innerRadius: 0,
94
+ to: Number.MAX_VALUE, // corrected to axis max
95
+ outerRadius: '105%'
96
+ }
97
+
98
+ });
99
+
100
+ H.Pane = Pane;
101
+
102
+ }(Highcharts));
103
+ (function(H) {
104
+ /**
105
+ * (c) 2010-2016 Torstein Honsi
106
+ *
107
+ * License: www.highcharts.com/license
108
+ */
109
+ 'use strict';
110
+ var Axis = H.Axis,
111
+ CenteredSeriesMixin = H.CenteredSeriesMixin,
112
+ each = H.each,
113
+ extend = H.extend,
114
+ map = H.map,
115
+ merge = H.merge,
116
+ noop = H.noop,
117
+ Pane = H.Pane,
118
+ pick = H.pick,
119
+ pInt = H.pInt,
120
+ Tick = H.Tick,
121
+ splat = H.splat,
122
+ wrap = H.wrap,
123
+
124
+
125
+ hiddenAxisMixin, // @todo Extract this to a new file
126
+ radialAxisMixin, // @todo Extract this to a new file
127
+ axisProto = Axis.prototype,
128
+ tickProto = Tick.prototype;
129
+
130
+ /**
131
+ * Augmented methods for the x axis in order to hide it completely, used for the X axis in gauges
132
+ */
133
+ hiddenAxisMixin = {
134
+ getOffset: noop,
135
+ redraw: function() {
136
+ this.isDirty = false; // prevent setting Y axis dirty
137
+ },
138
+ render: function() {
139
+ this.isDirty = false; // prevent setting Y axis dirty
140
+ },
141
+ setScale: noop,
142
+ setCategories: noop,
143
+ setTitle: noop
144
+ };
145
+
146
+ /**
147
+ * Augmented methods for the value axis
148
+ */
149
+ radialAxisMixin = {
150
+
151
+ /**
152
+ * The default options extend defaultYAxisOptions
153
+ */
154
+ defaultRadialGaugeOptions: {
155
+ labels: {
156
+ align: 'center',
157
+ x: 0,
158
+ y: null // auto
159
+ },
160
+ minorGridLineWidth: 0,
161
+ minorTickInterval: 'auto',
162
+ minorTickLength: 10,
163
+ minorTickPosition: 'inside',
164
+ minorTickWidth: 1,
165
+ tickLength: 10,
166
+ tickPosition: 'inside',
167
+ tickWidth: 2,
168
+ title: {
169
+ rotation: 0
170
+ },
171
+ zIndex: 2 // behind dials, points in the series group
172
+ },
173
+
174
+ // Circular axis around the perimeter of a polar chart
175
+ defaultRadialXOptions: {
176
+ gridLineWidth: 1, // spokes
177
+ labels: {
178
+ align: null, // auto
179
+ distance: 15,
180
+ x: 0,
181
+ y: null // auto
182
+ },
183
+ maxPadding: 0,
184
+ minPadding: 0,
185
+ showLastLabel: false,
186
+ tickLength: 0
187
+ },
188
+
189
+ // Radial axis, like a spoke in a polar chart
190
+ defaultRadialYOptions: {
191
+ gridLineInterpolation: 'circle',
192
+ labels: {
193
+ align: 'right',
194
+ x: -3,
195
+ y: -2
196
+ },
197
+ showLastLabel: false,
198
+ title: {
199
+ x: 4,
200
+ text: null,
201
+ rotation: 90
202
+ }
203
+ },
204
+
205
+ /**
206
+ * Merge and set options
207
+ */
208
+ setOptions: function(userOptions) {
209
+
210
+ var options = this.options = merge(
211
+ this.defaultOptions,
212
+ this.defaultRadialOptions,
213
+ userOptions
214
+ );
215
+
216
+ // Make sure the plotBands array is instanciated for each Axis (#2649)
217
+ if (!options.plotBands) {
218
+ options.plotBands = [];
219
+ }
220
+
221
+ },
222
+
223
+ /**
224
+ * Wrap the getOffset method to return zero offset for title or labels in a radial
225
+ * axis
226
+ */
227
+ getOffset: function() {
228
+ // Call the Axis prototype method (the method we're in now is on the instance)
229
+ axisProto.getOffset.call(this);
230
+
231
+ // Title or label offsets are not counted
232
+ this.chart.axisOffset[this.side] = 0;
233
+
234
+ // Set the center array
235
+ this.center = this.pane.center = CenteredSeriesMixin.getCenter.call(this.pane);
236
+ },
237
+
238
+
239
+ /**
240
+ * Get the path for the axis line. This method is also referenced in the getPlotLinePath
241
+ * method.
242
+ */
243
+ getLinePath: function(lineWidth, radius) {
244
+ var center = this.center,
245
+ end,
246
+ chart = this.chart,
247
+ r = pick(radius, center[2] / 2 - this.offset),
248
+ path;
249
+
250
+ if (this.isCircular || radius !== undefined) {
251
+ path = this.chart.renderer.symbols.arc(
252
+ this.left + center[0],
253
+ this.top + center[1],
254
+ r,
255
+ r, {
256
+ start: this.startAngleRad,
257
+ end: this.endAngleRad,
258
+ open: true,
259
+ innerR: 0
260
+ }
261
+ );
262
+ } else {
263
+ end = this.postTranslate(this.angleRad, r);
264
+ path = ['M', center[0] + chart.plotLeft, center[1] + chart.plotTop, 'L', end.x, end.y];
265
+ }
266
+ return path;
267
+ },
268
+
269
+ /**
270
+ * Override setAxisTranslation by setting the translation to the difference
271
+ * in rotation. This allows the translate method to return angle for
272
+ * any given value.
273
+ */
274
+ setAxisTranslation: function() {
275
+
276
+ // Call uber method
277
+ axisProto.setAxisTranslation.call(this);
278
+
279
+ // Set transA and minPixelPadding
280
+ if (this.center) { // it's not defined the first time
281
+ if (this.isCircular) {
282
+
283
+ this.transA = (this.endAngleRad - this.startAngleRad) /
284
+ ((this.max - this.min) || 1);
285
+
286
+
287
+ } else {
288
+ this.transA = (this.center[2] / 2) / ((this.max - this.min) || 1);
289
+ }
290
+
291
+ if (this.isXAxis) {
292
+ this.minPixelPadding = this.transA * this.minPointOffset;
293
+ } else {
294
+ // This is a workaround for regression #2593, but categories still don't position correctly.
295
+ this.minPixelPadding = 0;
296
+ }
297
+ }
298
+ },
299
+
300
+ /**
301
+ * In case of auto connect, add one closestPointRange to the max value right before
302
+ * tickPositions are computed, so that ticks will extend passed the real max.
303
+ */
304
+ beforeSetTickPositions: function() {
305
+ // If autoConnect is true, polygonal grid lines are connected, and one closestPointRange
306
+ // is added to the X axis to prevent the last point from overlapping the first.
307
+ this.autoConnect = this.isCircular && pick(this.userMax, this.options.max) === undefined &&
308
+ this.endAngleRad - this.startAngleRad === 2 * Math.PI;
309
+
310
+ if (this.autoConnect) {
311
+ this.max += (this.categories && 1) || this.pointRange || this.closestPointRange || 0; // #1197, #2260
312
+ }
313
+ },
314
+
315
+ /**
316
+ * Override the setAxisSize method to use the arc's circumference as length. This
317
+ * allows tickPixelInterval to apply to pixel lengths along the perimeter
318
+ */
319
+ setAxisSize: function() {
320
+
321
+ axisProto.setAxisSize.call(this);
322
+
323
+ if (this.isRadial) {
324
+
325
+ // Set the center array
326
+ this.center = this.pane.center = CenteredSeriesMixin.getCenter.call(this.pane);
327
+
328
+ // The sector is used in Axis.translate to compute the translation of reversed axis points (#2570)
329
+ if (this.isCircular) {
330
+ this.sector = this.endAngleRad - this.startAngleRad;
331
+ }
332
+
333
+ // Axis len is used to lay out the ticks
334
+ this.len = this.width = this.height = this.center[2] * pick(this.sector, 1) / 2;
335
+
336
+
337
+ }
338
+ },
339
+
340
+ /**
341
+ * Returns the x, y coordinate of a point given by a value and a pixel distance
342
+ * from center
343
+ */
344
+ getPosition: function(value, length) {
345
+ return this.postTranslate(
346
+ this.isCircular ? this.translate(value) : this.angleRad, // #2848
347
+ pick(this.isCircular ? length : this.translate(value), this.center[2] / 2) - this.offset
348
+ );
349
+ },
350
+
351
+ /**
352
+ * Translate from intermediate plotX (angle), plotY (axis.len - radius) to final chart coordinates.
353
+ */
354
+ postTranslate: function(angle, radius) {
355
+
356
+ var chart = this.chart,
357
+ center = this.center;
358
+
359
+ angle = this.startAngleRad + angle;
360
+
361
+ return {
362
+ x: chart.plotLeft + center[0] + Math.cos(angle) * radius,
363
+ y: chart.plotTop + center[1] + Math.sin(angle) * radius
364
+ };
365
+
366
+ },
367
+
368
+ /**
369
+ * Find the path for plot bands along the radial axis
370
+ */
371
+ getPlotBandPath: function(from, to, options) {
372
+ var center = this.center,
373
+ startAngleRad = this.startAngleRad,
374
+ fullRadius = center[2] / 2,
375
+ radii = [
376
+ pick(options.outerRadius, '100%'),
377
+ options.innerRadius,
378
+ pick(options.thickness, 10)
379
+ ],
380
+ offset = Math.min(this.offset, 0),
381
+ percentRegex = /%$/,
382
+ start,
383
+ end,
384
+ open,
385
+ isCircular = this.isCircular, // X axis in a polar chart
386
+ ret;
387
+
388
+ // Polygonal plot bands
389
+ if (this.options.gridLineInterpolation === 'polygon') {
390
+ ret = this.getPlotLinePath(from).concat(this.getPlotLinePath(to, true));
391
+
392
+ // Circular grid bands
393
+ } else {
394
+
395
+ // Keep within bounds
396
+ from = Math.max(from, this.min);
397
+ to = Math.min(to, this.max);
398
+
399
+ // Plot bands on Y axis (radial axis) - inner and outer radius depend on to and from
400
+ if (!isCircular) {
401
+ radii[0] = this.translate(from);
402
+ radii[1] = this.translate(to);
403
+ }
404
+
405
+ // Convert percentages to pixel values
406
+ radii = map(radii, function(radius) {
407
+ if (percentRegex.test(radius)) {
408
+ radius = (pInt(radius, 10) * fullRadius) / 100;
409
+ }
410
+ return radius;
411
+ });
412
+
413
+ // Handle full circle
414
+ if (options.shape === 'circle' || !isCircular) {
415
+ start = -Math.PI / 2;
416
+ end = Math.PI * 1.5;
417
+ open = true;
418
+ } else {
419
+ start = startAngleRad + this.translate(from);
420
+ end = startAngleRad + this.translate(to);
421
+ }
422
+
423
+ radii[0] -= offset; // #5283
424
+ radii[2] -= offset; // #5283
425
+
426
+ ret = this.chart.renderer.symbols.arc(
427
+ this.left + center[0],
428
+ this.top + center[1],
429
+ radii[0],
430
+ radii[0], {
431
+ start: Math.min(start, end), // Math is for reversed yAxis (#3606)
432
+ end: Math.max(start, end),
433
+ innerR: pick(radii[1], radii[0] - radii[2]),
434
+ open: open
435
+ }
436
+ );
437
+ }
438
+
439
+ return ret;
440
+ },
441
+
442
+ /**
443
+ * Find the path for plot lines perpendicular to the radial axis.
444
+ */
445
+ getPlotLinePath: function(value, reverse) {
446
+ var axis = this,
447
+ center = axis.center,
448
+ chart = axis.chart,
449
+ end = axis.getPosition(value),
450
+ xAxis,
451
+ xy,
452
+ tickPositions,
453
+ ret;
454
+
455
+ // Spokes
456
+ if (axis.isCircular) {
457
+ ret = ['M', center[0] + chart.plotLeft, center[1] + chart.plotTop, 'L', end.x, end.y];
458
+
459
+ // Concentric circles
460
+ } else if (axis.options.gridLineInterpolation === 'circle') {
461
+ value = axis.translate(value);
462
+ if (value) { // a value of 0 is in the center
463
+ ret = axis.getLinePath(0, value);
464
+ }
465
+ // Concentric polygons
466
+ } else {
467
+ // Find the X axis in the same pane
468
+ each(chart.xAxis, function(a) {
469
+ if (a.pane === axis.pane) {
470
+ xAxis = a;
471
+ }
472
+ });
473
+ ret = [];
474
+ value = axis.translate(value);
475
+ tickPositions = xAxis.tickPositions;
476
+ if (xAxis.autoConnect) {
477
+ tickPositions = tickPositions.concat([tickPositions[0]]);
478
+ }
479
+ // Reverse the positions for concatenation of polygonal plot bands
480
+ if (reverse) {
481
+ tickPositions = [].concat(tickPositions).reverse();
482
+ }
483
+
484
+ each(tickPositions, function(pos, i) {
485
+ xy = xAxis.getPosition(pos, value);
486
+ ret.push(i ? 'L' : 'M', xy.x, xy.y);
487
+ });
488
+
489
+ }
490
+ return ret;
491
+ },
492
+
493
+ /**
494
+ * Find the position for the axis title, by default inside the gauge
495
+ */
496
+ getTitlePosition: function() {
497
+ var center = this.center,
498
+ chart = this.chart,
499
+ titleOptions = this.options.title;
500
+
501
+ return {
502
+ x: chart.plotLeft + center[0] + (titleOptions.x || 0),
503
+ y: chart.plotTop + center[1] - ({
504
+ high: 0.5,
505
+ middle: 0.25,
506
+ low: 0
507
+ }[titleOptions.align] *
508
+ center[2]) + (titleOptions.y || 0)
509
+ };
510
+ }
511
+
512
+ };
513
+
514
+ /**
515
+ * Override axisProto.init to mix in special axis instance functions and function overrides
516
+ */
517
+ wrap(axisProto, 'init', function(proceed, chart, userOptions) {
518
+ var axis = this,
519
+ angular = chart.angular,
520
+ polar = chart.polar,
521
+ isX = userOptions.isX,
522
+ isHidden = angular && isX,
523
+ isCircular,
524
+ options,
525
+ chartOptions = chart.options,
526
+ paneIndex = userOptions.pane || 0,
527
+ pane,
528
+ paneOptions;
529
+
530
+ // Before prototype.init
531
+ if (angular) {
532
+ extend(this, isHidden ? hiddenAxisMixin : radialAxisMixin);
533
+ isCircular = !isX;
534
+ if (isCircular) {
535
+ this.defaultRadialOptions = this.defaultRadialGaugeOptions;
536
+ }
537
+
538
+ } else if (polar) {
539
+ extend(this, radialAxisMixin);
540
+ isCircular = isX;
541
+ this.defaultRadialOptions = isX ? this.defaultRadialXOptions : merge(this.defaultYAxisOptions, this.defaultRadialYOptions);
542
+
543
+ }
544
+
545
+ // Disable certain features on angular and polar axes
546
+ if (angular || polar) {
547
+ this.isRadial = true;
548
+ chart.inverted = false;
549
+ chartOptions.chart.zoomType = null;
550
+ } else {
551
+ this.isRadial = false;
552
+ }
553
+
554
+ // Run prototype.init
555
+ proceed.call(this, chart, userOptions);
556
+
557
+ if (!isHidden && (angular || polar)) {
558
+ options = this.options;
559
+
560
+ // Create the pane and set the pane options.
561
+ if (!chart.panes) {
562
+ chart.panes = [];
563
+ }
564
+ this.pane = pane = chart.panes[paneIndex] = chart.panes[paneIndex] || new Pane(
565
+ splat(chartOptions.pane)[paneIndex],
566
+ chart,
567
+ axis
568
+ );
569
+ paneOptions = pane.options;
570
+
571
+ // Start and end angle options are
572
+ // given in degrees relative to top, while internal computations are
573
+ // in radians relative to right (like SVG).
574
+ this.angleRad = (options.angle || 0) * Math.PI / 180; // Y axis in polar charts
575
+ this.startAngleRad = (paneOptions.startAngle - 90) * Math.PI / 180; // Gauges
576
+ this.endAngleRad = (pick(paneOptions.endAngle, paneOptions.startAngle + 360) - 90) * Math.PI / 180; // Gauges
577
+ this.offset = options.offset || 0;
578
+
579
+ this.isCircular = isCircular;
580
+
581
+ }
582
+
583
+ });
584
+
585
+ /**
586
+ * Wrap auto label align to avoid setting axis-wide rotation on radial axes (#4920)
587
+ * @param {Function} proceed
588
+ * @returns {String} Alignment
589
+ */
590
+ wrap(axisProto, 'autoLabelAlign', function(proceed) {
591
+ if (!this.isRadial) {
592
+ return proceed.apply(this, [].slice.call(arguments, 1));
593
+ } // else return undefined
594
+ });
595
+
596
+ /**
597
+ * Add special cases within the Tick class' methods for radial axes.
598
+ */
599
+ wrap(tickProto, 'getPosition', function(proceed, horiz, pos, tickmarkOffset, old) {
600
+ var axis = this.axis;
601
+
602
+ return axis.getPosition ?
603
+ axis.getPosition(pos) :
604
+ proceed.call(this, horiz, pos, tickmarkOffset, old);
605
+ });
606
+
607
+ /**
608
+ * Wrap the getLabelPosition function to find the center position of the label
609
+ * based on the distance option
610
+ */
611
+ wrap(tickProto, 'getLabelPosition', function(proceed, x, y, label, horiz, labelOptions, tickmarkOffset, index, step) {
612
+ var axis = this.axis,
613
+ optionsY = labelOptions.y,
614
+ ret,
615
+ centerSlot = 20, // 20 degrees to each side at the top and bottom
616
+ align = labelOptions.align,
617
+ angle = ((axis.translate(this.pos) + axis.startAngleRad + Math.PI / 2) / Math.PI * 180) % 360;
618
+
619
+ if (axis.isRadial) { // Both X and Y axes in a polar chart
620
+ ret = axis.getPosition(this.pos, (axis.center[2] / 2) + pick(labelOptions.distance, -25));
621
+
622
+ // Automatically rotated
623
+ if (labelOptions.rotation === 'auto') {
624
+ label.attr({
625
+ rotation: angle
626
+ });
627
+
628
+ // Vertically centered
629
+ } else if (optionsY === null) {
630
+ optionsY = axis.chart.renderer.fontMetrics(label.styles.fontSize).b - label.getBBox().height / 2;
631
+ }
632
+
633
+ // Automatic alignment
634
+ if (align === null) {
635
+ if (axis.isCircular) { // Y axis
636
+ if (this.label.getBBox().width > axis.len * axis.tickInterval / (axis.max - axis.min)) { // #3506
637
+ centerSlot = 0;
638
+ }
639
+ if (angle > centerSlot && angle < 180 - centerSlot) {
640
+ align = 'left'; // right hemisphere
641
+ } else if (angle > 180 + centerSlot && angle < 360 - centerSlot) {
642
+ align = 'right'; // left hemisphere
643
+ } else {
644
+ align = 'center'; // top or bottom
645
+ }
646
+ } else {
647
+ align = 'center';
648
+ }
649
+ label.attr({
650
+ align: align
651
+ });
652
+ }
653
+
654
+ ret.x += labelOptions.x;
655
+ ret.y += optionsY;
656
+
657
+ } else {
658
+ ret = proceed.call(this, x, y, label, horiz, labelOptions, tickmarkOffset, index, step);
659
+ }
660
+ return ret;
661
+ });
662
+
663
+ /**
664
+ * Wrap the getMarkPath function to return the path of the radial marker
665
+ */
666
+ wrap(tickProto, 'getMarkPath', function(proceed, x, y, tickLength, tickWidth, horiz, renderer) {
667
+ var axis = this.axis,
668
+ endPoint,
669
+ ret;
670
+
671
+ if (axis.isRadial) {
672
+ endPoint = axis.getPosition(this.pos, axis.center[2] / 2 + tickLength);
673
+ ret = [
674
+ 'M',
675
+ x,
676
+ y,
677
+ 'L',
678
+ endPoint.x,
679
+ endPoint.y
680
+ ];
681
+ } else {
682
+ ret = proceed.call(this, x, y, tickLength, tickWidth, horiz, renderer);
683
+ }
684
+ return ret;
685
+ });
686
+
687
+ }(Highcharts));
688
+ (function(H) {
689
+ /**
690
+ * (c) 2010-2016 Torstein Honsi
691
+ *
692
+ * License: www.highcharts.com/license
693
+ */
694
+ 'use strict';
695
+ var each = H.each,
696
+ noop = H.noop,
697
+ pick = H.pick,
698
+ Series = H.Series,
699
+ seriesType = H.seriesType,
700
+ seriesTypes = H.seriesTypes;
701
+ /*
702
+ * The arearangeseries series type
703
+ */
704
+ seriesType('arearange', 'area', {
705
+
706
+ marker: null,
707
+ threshold: null,
708
+ tooltip: {
709
+
710
+ pointFormat: '<span class="highcharts-color-{series.colorIndex}">\u25CF</span> {series.name}: <b>{point.low}</b> - <b>{point.high}</b><br/>'
711
+
712
+ },
713
+ trackByArea: true,
714
+ dataLabels: {
715
+ align: null,
716
+ verticalAlign: null,
717
+ xLow: 0,
718
+ xHigh: 0,
719
+ yLow: 0,
720
+ yHigh: 0
721
+ },
722
+ states: {
723
+ hover: {
724
+ halo: false
725
+ }
726
+ }
727
+
728
+ // Prototype members
729
+ }, {
730
+ pointArrayMap: ['low', 'high'],
731
+ dataLabelCollections: ['dataLabel', 'dataLabelUpper'],
732
+ toYData: function(point) {
733
+ return [point.low, point.high];
734
+ },
735
+ pointValKey: 'low',
736
+ deferTranslatePolar: true,
737
+
738
+ /**
739
+ * Translate a point's plotHigh from the internal angle and radius measures to
740
+ * true plotHigh coordinates. This is an addition of the toXY method found in
741
+ * Polar.js, because it runs too early for arearanges to be considered (#3419).
742
+ */
743
+ highToXY: function(point) {
744
+ // Find the polar plotX and plotY
745
+ var chart = this.chart,
746
+ xy = this.xAxis.postTranslate(point.rectPlotX, this.yAxis.len - point.plotHigh);
747
+ point.plotHighX = xy.x - chart.plotLeft;
748
+ point.plotHigh = xy.y - chart.plotTop;
749
+ },
750
+
751
+ /**
752
+ * Translate data points from raw values x and y to plotX and plotY
753
+ */
754
+ translate: function() {
755
+ var series = this,
756
+ yAxis = series.yAxis,
757
+ hasModifyValue = !!series.modifyValue;
758
+
759
+ seriesTypes.area.prototype.translate.apply(series);
760
+
761
+ // Set plotLow and plotHigh
762
+ each(series.points, function(point) {
763
+
764
+ var low = point.low,
765
+ high = point.high,
766
+ plotY = point.plotY;
767
+
768
+ if (high === null || low === null) {
769
+ point.isNull = true;
770
+ } else {
771
+ point.plotLow = plotY;
772
+ point.plotHigh = yAxis.translate(
773
+ hasModifyValue ? series.modifyValue(high, point) : high,
774
+ 0,
775
+ 1,
776
+ 0,
777
+ 1
778
+ );
779
+ if (hasModifyValue) {
780
+ point.yBottom = point.plotHigh;
781
+ }
782
+ }
783
+ });
784
+
785
+ // Postprocess plotHigh
786
+ if (this.chart.polar) {
787
+ each(this.points, function(point) {
788
+ series.highToXY(point);
789
+ });
790
+ }
791
+ },
792
+
793
+ /**
794
+ * Extend the line series' getSegmentPath method by applying the segment
795
+ * path to both lower and higher values of the range
796
+ */
797
+ getGraphPath: function(points) {
798
+
799
+ var highPoints = [],
800
+ highAreaPoints = [],
801
+ i,
802
+ getGraphPath = seriesTypes.area.prototype.getGraphPath,
803
+ point,
804
+ pointShim,
805
+ linePath,
806
+ lowerPath,
807
+ options = this.options,
808
+ step = options.step,
809
+ higherPath,
810
+ higherAreaPath;
811
+
812
+ points = points || this.points;
813
+ i = points.length;
814
+
815
+ // Create the top line and the top part of the area fill. The area fill compensates for
816
+ // null points by drawing down to the lower graph, moving across the null gap and
817
+ // starting again at the lower graph.
818
+ i = points.length;
819
+ while (i--) {
820
+ point = points[i];
821
+
822
+ if (!point.isNull && !options.connectEnds && (!points[i + 1] || points[i + 1].isNull)) {
823
+ highAreaPoints.push({
824
+ plotX: point.plotX,
825
+ plotY: point.plotY,
826
+ doCurve: false // #5186, gaps in areasplinerange fill
827
+ });
828
+ }
829
+
830
+ pointShim = {
831
+ polarPlotY: point.polarPlotY,
832
+ rectPlotX: point.rectPlotX,
833
+ yBottom: point.yBottom,
834
+ plotX: pick(point.plotHighX, point.plotX), // plotHighX is for polar charts
835
+ plotY: point.plotHigh,
836
+ isNull: point.isNull
837
+ };
838
+ highAreaPoints.push(pointShim);
839
+ highPoints.push(pointShim);
840
+ if (!point.isNull && !options.connectEnds && (!points[i - 1] || points[i - 1].isNull)) {
841
+ highAreaPoints.push({
842
+ plotX: point.plotX,
843
+ plotY: point.plotY,
844
+ doCurve: false // #5186, gaps in areasplinerange fill
845
+ });
846
+ }
847
+ }
848
+
849
+ // Get the paths
850
+ lowerPath = getGraphPath.call(this, points);
851
+ if (step) {
852
+ if (step === true) {
853
+ step = 'left';
854
+ }
855
+ options.step = {
856
+ left: 'right',
857
+ center: 'center',
858
+ right: 'left'
859
+ }[step]; // swap for reading in getGraphPath
860
+ }
861
+ higherPath = getGraphPath.call(this, highPoints);
862
+ higherAreaPath = getGraphPath.call(this, highAreaPoints);
863
+ options.step = step;
864
+
865
+ // Create a line on both top and bottom of the range
866
+ linePath = [].concat(lowerPath, higherPath);
867
+
868
+ // For the area path, we need to change the 'move' statement into 'lineTo' or 'curveTo'
869
+ if (!this.chart.polar && higherAreaPath[0] === 'M') {
870
+ higherAreaPath[0] = 'L'; // this probably doesn't work for spline
871
+ }
872
+
873
+ this.graphPath = linePath;
874
+ this.areaPath = this.areaPath.concat(lowerPath, higherAreaPath);
875
+
876
+ // Prepare for sideways animation
877
+ linePath.isArea = true;
878
+ linePath.xMap = lowerPath.xMap;
879
+ this.areaPath.xMap = lowerPath.xMap;
880
+
881
+ return linePath;
882
+ },
883
+
884
+ /**
885
+ * Extend the basic drawDataLabels method by running it for both lower and higher
886
+ * values.
887
+ */
888
+ drawDataLabels: function() {
889
+
890
+ var data = this.data,
891
+ length = data.length,
892
+ i,
893
+ originalDataLabels = [],
894
+ seriesProto = Series.prototype,
895
+ dataLabelOptions = this.options.dataLabels,
896
+ align = dataLabelOptions.align,
897
+ verticalAlign = dataLabelOptions.verticalAlign,
898
+ inside = dataLabelOptions.inside,
899
+ point,
900
+ up,
901
+ inverted = this.chart.inverted;
902
+
903
+ if (dataLabelOptions.enabled || this._hasPointLabels) {
904
+
905
+ // Step 1: set preliminary values for plotY and dataLabel and draw the upper labels
906
+ i = length;
907
+ while (i--) {
908
+ point = data[i];
909
+ if (point) {
910
+ up = inside ? point.plotHigh < point.plotLow : point.plotHigh > point.plotLow;
911
+
912
+ // Set preliminary values
913
+ point.y = point.high;
914
+ point._plotY = point.plotY;
915
+ point.plotY = point.plotHigh;
916
+
917
+ // Store original data labels and set preliminary label objects to be picked up
918
+ // in the uber method
919
+ originalDataLabels[i] = point.dataLabel;
920
+ point.dataLabel = point.dataLabelUpper;
921
+
922
+ // Set the default offset
923
+ point.below = up;
924
+ if (inverted) {
925
+ if (!align) {
926
+ dataLabelOptions.align = up ? 'right' : 'left';
927
+ }
928
+ } else {
929
+ if (!verticalAlign) {
930
+ dataLabelOptions.verticalAlign = up ? 'top' : 'bottom';
931
+ }
932
+ }
933
+
934
+ dataLabelOptions.x = dataLabelOptions.xHigh;
935
+ dataLabelOptions.y = dataLabelOptions.yHigh;
936
+ }
937
+ }
938
+
939
+ if (seriesProto.drawDataLabels) {
940
+ seriesProto.drawDataLabels.apply(this, arguments); // #1209
941
+ }
942
+
943
+ // Step 2: reorganize and handle data labels for the lower values
944
+ i = length;
945
+ while (i--) {
946
+ point = data[i];
947
+ if (point) {
948
+ up = inside ? point.plotHigh < point.plotLow : point.plotHigh > point.plotLow;
949
+
950
+ // Move the generated labels from step 1, and reassign the original data labels
951
+ point.dataLabelUpper = point.dataLabel;
952
+ point.dataLabel = originalDataLabels[i];
953
+
954
+ // Reset values
955
+ point.y = point.low;
956
+ point.plotY = point._plotY;
957
+
958
+ // Set the default offset
959
+ point.below = !up;
960
+ if (inverted) {
961
+ if (!align) {
962
+ dataLabelOptions.align = up ? 'left' : 'right';
963
+ }
964
+ } else {
965
+ if (!verticalAlign) {
966
+ dataLabelOptions.verticalAlign = up ? 'bottom' : 'top';
967
+ }
968
+
969
+ }
970
+
971
+ dataLabelOptions.x = dataLabelOptions.xLow;
972
+ dataLabelOptions.y = dataLabelOptions.yLow;
973
+ }
974
+ }
975
+ if (seriesProto.drawDataLabels) {
976
+ seriesProto.drawDataLabels.apply(this, arguments);
977
+ }
978
+ }
979
+
980
+ dataLabelOptions.align = align;
981
+ dataLabelOptions.verticalAlign = verticalAlign;
982
+ },
983
+
984
+ alignDataLabel: function() {
985
+ seriesTypes.column.prototype.alignDataLabel.apply(this, arguments);
986
+ },
987
+
988
+ setStackedPoints: noop,
989
+
990
+ getSymbol: noop,
991
+
992
+ drawPoints: noop
993
+ });
994
+
995
+ }(Highcharts));
996
+ (function(H) {
997
+ /**
998
+ * (c) 2010-2016 Torstein Honsi
999
+ *
1000
+ * License: www.highcharts.com/license
1001
+ */
1002
+ 'use strict';
1003
+
1004
+ var seriesType = H.seriesType,
1005
+ seriesTypes = H.seriesTypes;
1006
+
1007
+ /**
1008
+ * The areasplinerange series type
1009
+ */
1010
+ seriesType('areasplinerange', 'arearange', null, {
1011
+ getPointSpline: seriesTypes.spline.prototype.getPointSpline
1012
+ });
1013
+
1014
+ }(Highcharts));
1015
+ (function(H) {
1016
+ /**
1017
+ * (c) 2010-2016 Torstein Honsi
1018
+ *
1019
+ * License: www.highcharts.com/license
1020
+ */
1021
+ 'use strict';
1022
+ var defaultPlotOptions = H.defaultPlotOptions,
1023
+ each = H.each,
1024
+ merge = H.merge,
1025
+ noop = H.noop,
1026
+ pick = H.pick,
1027
+ seriesType = H.seriesType,
1028
+ seriesTypes = H.seriesTypes;
1029
+
1030
+ var colProto = seriesTypes.column.prototype;
1031
+
1032
+ /**
1033
+ * The ColumnRangeSeries class
1034
+ */
1035
+ seriesType('columnrange', 'arearange', merge(defaultPlotOptions.column, defaultPlotOptions.arearange, {
1036
+ lineWidth: 1,
1037
+ pointRange: null
1038
+
1039
+ // Prototype members
1040
+ }), {
1041
+ /**
1042
+ * Translate data points from raw values x and y to plotX and plotY
1043
+ */
1044
+ translate: function() {
1045
+ var series = this,
1046
+ yAxis = series.yAxis,
1047
+ xAxis = series.xAxis,
1048
+ startAngleRad = xAxis.startAngleRad,
1049
+ start,
1050
+ chart = series.chart,
1051
+ isRadial = series.xAxis.isRadial,
1052
+ plotHigh;
1053
+
1054
+ colProto.translate.apply(series);
1055
+
1056
+ // Set plotLow and plotHigh
1057
+ each(series.points, function(point) {
1058
+ var shapeArgs = point.shapeArgs,
1059
+ minPointLength = series.options.minPointLength,
1060
+ heightDifference,
1061
+ height,
1062
+ y;
1063
+
1064
+ point.plotHigh = plotHigh = yAxis.translate(point.high, 0, 1, 0, 1);
1065
+ point.plotLow = point.plotY;
1066
+
1067
+ // adjust shape
1068
+ y = plotHigh;
1069
+ height = pick(point.rectPlotY, point.plotY) - plotHigh;
1070
+
1071
+ // Adjust for minPointLength
1072
+ if (Math.abs(height) < minPointLength) {
1073
+ heightDifference = (minPointLength - height);
1074
+ height += heightDifference;
1075
+ y -= heightDifference / 2;
1076
+
1077
+ // Adjust for negative ranges or reversed Y axis (#1457)
1078
+ } else if (height < 0) {
1079
+ height *= -1;
1080
+ y -= height;
1081
+ }
1082
+
1083
+ if (isRadial) {
1084
+
1085
+ start = point.barX + startAngleRad;
1086
+ point.shapeType = 'path';
1087
+ point.shapeArgs = {
1088
+ d: series.polarArc(y + height, y, start, start + point.pointWidth)
1089
+ };
1090
+ } else {
1091
+ shapeArgs.height = height;
1092
+ shapeArgs.y = y;
1093
+
1094
+ point.tooltipPos = chart.inverted ? [
1095
+ yAxis.len + yAxis.pos - chart.plotLeft - y - height / 2,
1096
+ xAxis.len + xAxis.pos - chart.plotTop - shapeArgs.x - shapeArgs.width / 2,
1097
+ height
1098
+ ] : [
1099
+ xAxis.left - chart.plotLeft + shapeArgs.x + shapeArgs.width / 2,
1100
+ yAxis.pos - chart.plotTop + y + height / 2,
1101
+ height
1102
+ ]; // don't inherit from column tooltip position - #3372
1103
+ }
1104
+ });
1105
+ },
1106
+ directTouch: true,
1107
+ trackerGroups: ['group', 'dataLabelsGroup'],
1108
+ drawGraph: noop,
1109
+ crispCol: colProto.crispCol,
1110
+ drawPoints: colProto.drawPoints,
1111
+ drawTracker: colProto.drawTracker,
1112
+ getColumnMetrics: colProto.getColumnMetrics,
1113
+ animate: function() {
1114
+ return colProto.animate.apply(this, arguments);
1115
+ },
1116
+ polarArc: function() {
1117
+ return colProto.polarArc.apply(this, arguments);
1118
+ },
1119
+ pointAttribs: colProto.pointAttribs
1120
+ });
1121
+
1122
+ }(Highcharts));
1123
+ (function(H) {
1124
+ /**
1125
+ * (c) 2010-2016 Torstein Honsi
1126
+ *
1127
+ * License: www.highcharts.com/license
1128
+ */
1129
+ 'use strict';
1130
+ var each = H.each,
1131
+ isNumber = H.isNumber,
1132
+ merge = H.merge,
1133
+ noop = H.noop,
1134
+ pick = H.pick,
1135
+ pInt = H.pInt,
1136
+ Series = H.Series,
1137
+ seriesType = H.seriesType,
1138
+ TrackerMixin = H.TrackerMixin;
1139
+ /*
1140
+ * The GaugeSeries class
1141
+ */
1142
+ seriesType('gauge', 'line', {
1143
+ dataLabels: {
1144
+ enabled: true,
1145
+ defer: false,
1146
+ y: 15,
1147
+ borderRadius: 3,
1148
+ crop: false,
1149
+ verticalAlign: 'top',
1150
+ zIndex: 2
1151
+
1152
+ },
1153
+ dial: {
1154
+ // radius: '80%',
1155
+ // baseWidth: 3,
1156
+ // topWidth: 1,
1157
+ // baseLength: '70%' // of radius
1158
+ // rearLength: '10%'
1159
+
1160
+
1161
+ },
1162
+ pivot: {
1163
+ //radius: 5
1164
+
1165
+ },
1166
+ tooltip: {
1167
+ headerFormat: ''
1168
+ },
1169
+ showInLegend: false
1170
+
1171
+ // Prototype members
1172
+ }, {
1173
+ // chart.angular will be set to true when a gauge series is present, and this will
1174
+ // be used on the axes
1175
+ angular: true,
1176
+ directTouch: true, // #5063
1177
+ drawGraph: noop,
1178
+ fixedBox: true,
1179
+ forceDL: true,
1180
+ noSharedTooltip: true,
1181
+ trackerGroups: ['group', 'dataLabelsGroup'],
1182
+
1183
+ /**
1184
+ * Calculate paths etc
1185
+ */
1186
+ translate: function() {
1187
+
1188
+ var series = this,
1189
+ yAxis = series.yAxis,
1190
+ options = series.options,
1191
+ center = yAxis.center;
1192
+
1193
+ series.generatePoints();
1194
+
1195
+ each(series.points, function(point) {
1196
+
1197
+ var dialOptions = merge(options.dial, point.dial),
1198
+ radius = (pInt(pick(dialOptions.radius, 80)) * center[2]) / 200,
1199
+ baseLength = (pInt(pick(dialOptions.baseLength, 70)) * radius) / 100,
1200
+ rearLength = (pInt(pick(dialOptions.rearLength, 10)) * radius) / 100,
1201
+ baseWidth = dialOptions.baseWidth || 3,
1202
+ topWidth = dialOptions.topWidth || 1,
1203
+ overshoot = options.overshoot,
1204
+ rotation = yAxis.startAngleRad + yAxis.translate(point.y, null, null, null, true);
1205
+
1206
+ // Handle the wrap and overshoot options
1207
+ if (isNumber(overshoot)) {
1208
+ overshoot = overshoot / 180 * Math.PI;
1209
+ rotation = Math.max(yAxis.startAngleRad - overshoot, Math.min(yAxis.endAngleRad + overshoot, rotation));
1210
+
1211
+ } else if (options.wrap === false) {
1212
+ rotation = Math.max(yAxis.startAngleRad, Math.min(yAxis.endAngleRad, rotation));
1213
+ }
1214
+
1215
+ rotation = rotation * 180 / Math.PI;
1216
+
1217
+ point.shapeType = 'path';
1218
+ point.shapeArgs = {
1219
+ d: dialOptions.path || [
1220
+ 'M', -rearLength, -baseWidth / 2,
1221
+ 'L',
1222
+ baseLength, -baseWidth / 2,
1223
+ radius, -topWidth / 2,
1224
+ radius, topWidth / 2,
1225
+ baseLength, baseWidth / 2, -rearLength, baseWidth / 2,
1226
+ 'z'
1227
+ ],
1228
+ translateX: center[0],
1229
+ translateY: center[1],
1230
+ rotation: rotation
1231
+ };
1232
+
1233
+ // Positions for data label
1234
+ point.plotX = center[0];
1235
+ point.plotY = center[1];
1236
+ });
1237
+ },
1238
+
1239
+ /**
1240
+ * Draw the points where each point is one needle
1241
+ */
1242
+ drawPoints: function() {
1243
+
1244
+ var series = this,
1245
+ center = series.yAxis.center,
1246
+ pivot = series.pivot,
1247
+ options = series.options,
1248
+ pivotOptions = options.pivot,
1249
+ renderer = series.chart.renderer;
1250
+
1251
+ each(series.points, function(point) {
1252
+
1253
+ var graphic = point.graphic,
1254
+ shapeArgs = point.shapeArgs,
1255
+ d = shapeArgs.d,
1256
+ dialOptions = merge(options.dial, point.dial); // #1233
1257
+
1258
+ if (graphic) {
1259
+ graphic.animate(shapeArgs);
1260
+ shapeArgs.d = d; // animate alters it
1261
+ } else {
1262
+ point.graphic = renderer[point.shapeType](shapeArgs)
1263
+ .attr({
1264
+ rotation: shapeArgs.rotation, // required by VML when animation is false
1265
+ zIndex: 1
1266
+ })
1267
+ .addClass('highcharts-dial')
1268
+ .add(series.group);
1269
+
1270
+
1271
+ }
1272
+ });
1273
+
1274
+ // Add or move the pivot
1275
+ if (pivot) {
1276
+ pivot.animate({ // #1235
1277
+ translateX: center[0],
1278
+ translateY: center[1]
1279
+ });
1280
+ } else {
1281
+ series.pivot = renderer.circle(0, 0, pick(pivotOptions.radius, 5))
1282
+ .attr({
1283
+ zIndex: 2
1284
+ })
1285
+ .addClass('highcharts-pivot')
1286
+ .translate(center[0], center[1])
1287
+ .add(series.group);
1288
+
1289
+
1290
+ }
1291
+ },
1292
+
1293
+ /**
1294
+ * Animate the arrow up from startAngle
1295
+ */
1296
+ animate: function(init) {
1297
+ var series = this;
1298
+
1299
+ if (!init) {
1300
+ each(series.points, function(point) {
1301
+ var graphic = point.graphic;
1302
+
1303
+ if (graphic) {
1304
+ // start value
1305
+ graphic.attr({
1306
+ rotation: series.yAxis.startAngleRad * 180 / Math.PI
1307
+ });
1308
+
1309
+ // animate
1310
+ graphic.animate({
1311
+ rotation: point.shapeArgs.rotation
1312
+ }, series.options.animation);
1313
+ }
1314
+ });
1315
+
1316
+ // delete this function to allow it only once
1317
+ series.animate = null;
1318
+ }
1319
+ },
1320
+
1321
+ render: function() {
1322
+ this.group = this.plotGroup(
1323
+ 'group',
1324
+ 'series',
1325
+ this.visible ? 'visible' : 'hidden',
1326
+ this.options.zIndex,
1327
+ this.chart.seriesGroup
1328
+ );
1329
+ Series.prototype.render.call(this);
1330
+ this.group.clip(this.chart.clipRect);
1331
+ },
1332
+
1333
+ /**
1334
+ * Extend the basic setData method by running processData and generatePoints immediately,
1335
+ * in order to access the points from the legend.
1336
+ */
1337
+ setData: function(data, redraw) {
1338
+ Series.prototype.setData.call(this, data, false);
1339
+ this.processData();
1340
+ this.generatePoints();
1341
+ if (pick(redraw, true)) {
1342
+ this.chart.redraw();
1343
+ }
1344
+ },
1345
+
1346
+ /**
1347
+ * If the tracking module is loaded, add the point tracker
1348
+ */
1349
+ drawTracker: TrackerMixin && TrackerMixin.drawTrackerPoint
1350
+
1351
+ // Point members
1352
+ }, {
1353
+ /**
1354
+ * Don't do any hover colors or anything
1355
+ */
1356
+ setState: function(state) {
1357
+ this.state = state;
1358
+ }
1359
+ });
1360
+
1361
+ }(Highcharts));
1362
+ (function(H) {
1363
+ /**
1364
+ * (c) 2010-2016 Torstein Honsi
1365
+ *
1366
+ * License: www.highcharts.com/license
1367
+ */
1368
+ 'use strict';
1369
+ var each = H.each,
1370
+ noop = H.noop,
1371
+ pick = H.pick,
1372
+ seriesType = H.seriesType,
1373
+ seriesTypes = H.seriesTypes;
1374
+
1375
+ /**
1376
+ * The boxplot series type.
1377
+ *
1378
+ * @constructor seriesTypes.boxplot
1379
+ * @augments seriesTypes.column
1380
+ */
1381
+ seriesType('boxplot', 'column', {
1382
+ threshold: null,
1383
+ tooltip: {
1384
+
1385
+ pointFormat: '<span class="highcharts-color-{point.colorIndex}">\u25CF</span> <b> {series.name}</b><br/>' +
1386
+ 'Maximum: {point.high}<br/>' +
1387
+ 'Upper quartile: {point.q3}<br/>' +
1388
+ 'Median: {point.median}<br/>' +
1389
+ 'Lower quartile: {point.q1}<br/>' +
1390
+ 'Minimum: {point.low}<br/>'
1391
+
1392
+ },
1393
+ whiskerLength: '50%'
1394
+
1395
+
1396
+ }, /** @lends seriesTypes.boxplot */ {
1397
+ pointArrayMap: ['low', 'q1', 'median', 'q3', 'high'], // array point configs are mapped to this
1398
+ toYData: function(point) { // return a plain array for speedy calculation
1399
+ return [point.low, point.q1, point.median, point.q3, point.high];
1400
+ },
1401
+ pointValKey: 'high', // defines the top of the tracker
1402
+
1403
+
1404
+
1405
+ /**
1406
+ * Disable data labels for box plot
1407
+ */
1408
+ drawDataLabels: noop,
1409
+
1410
+ /**
1411
+ * Translate data points from raw values x and y to plotX and plotY
1412
+ */
1413
+ translate: function() {
1414
+ var series = this,
1415
+ yAxis = series.yAxis,
1416
+ pointArrayMap = series.pointArrayMap;
1417
+
1418
+ seriesTypes.column.prototype.translate.apply(series);
1419
+
1420
+ // do the translation on each point dimension
1421
+ each(series.points, function(point) {
1422
+ each(pointArrayMap, function(key) {
1423
+ if (point[key] !== null) {
1424
+ point[key + 'Plot'] = yAxis.translate(point[key], 0, 1, 0, 1);
1425
+ }
1426
+ });
1427
+ });
1428
+ },
1429
+
1430
+ /**
1431
+ * Draw the data points
1432
+ */
1433
+ drawPoints: function() {
1434
+ var series = this, //state = series.state,
1435
+ points = series.points,
1436
+ options = series.options,
1437
+ chart = series.chart,
1438
+ renderer = chart.renderer,
1439
+ q1Plot,
1440
+ q3Plot,
1441
+ highPlot,
1442
+ lowPlot,
1443
+ medianPlot,
1444
+ medianPath,
1445
+ crispCorr,
1446
+ crispX = 0,
1447
+ boxPath,
1448
+ width,
1449
+ left,
1450
+ right,
1451
+ halfWidth,
1452
+ doQuartiles = series.doQuartiles !== false, // error bar inherits this series type but doesn't do quartiles
1453
+ pointWiskerLength,
1454
+ whiskerLength = series.options.whiskerLength;
1455
+
1456
+
1457
+ each(points, function(point) {
1458
+
1459
+ var graphic = point.graphic,
1460
+ verb = graphic ? 'animate' : 'attr',
1461
+ shapeArgs = point.shapeArgs; // the box
1462
+
1463
+
1464
+
1465
+ if (point.plotY !== undefined) {
1466
+
1467
+ // crisp vector coordinates
1468
+ width = shapeArgs.width;
1469
+ left = Math.floor(shapeArgs.x);
1470
+ right = left + width;
1471
+ halfWidth = Math.round(width / 2);
1472
+ q1Plot = Math.floor(doQuartiles ? point.q1Plot : point.lowPlot);
1473
+ q3Plot = Math.floor(doQuartiles ? point.q3Plot : point.lowPlot);
1474
+ highPlot = Math.floor(point.highPlot);
1475
+ lowPlot = Math.floor(point.lowPlot);
1476
+
1477
+ if (!graphic) {
1478
+ point.graphic = graphic = renderer.g('point')
1479
+ .add(series.group);
1480
+
1481
+ point.stem = renderer.path()
1482
+ .addClass('highcharts-boxplot-stem')
1483
+ .add(graphic);
1484
+
1485
+ if (whiskerLength) {
1486
+ point.whiskers = renderer.path()
1487
+ .addClass('highcharts-boxplot-whisker')
1488
+ .add(graphic);
1489
+ }
1490
+ if (doQuartiles) {
1491
+ point.box = renderer.path(boxPath)
1492
+ .addClass('highcharts-boxplot-box')
1493
+ .add(graphic);
1494
+ }
1495
+ point.medianShape = renderer.path(medianPath)
1496
+ .addClass('highcharts-boxplot-median')
1497
+ .add(graphic);
1498
+
1499
+
1500
+
1501
+ }
1502
+
1503
+
1504
+
1505
+ // The stem
1506
+ crispCorr = (point.stem.strokeWidth() % 2) / 2;
1507
+ crispX = left + halfWidth + crispCorr;
1508
+ point.stem[verb]({
1509
+ d: [
1510
+ // stem up
1511
+ 'M',
1512
+ crispX, q3Plot,
1513
+ 'L',
1514
+ crispX, highPlot,
1515
+
1516
+ // stem down
1517
+ 'M',
1518
+ crispX, q1Plot,
1519
+ 'L',
1520
+ crispX, lowPlot
1521
+ ]
1522
+ });
1523
+
1524
+ // The box
1525
+ if (doQuartiles) {
1526
+ crispCorr = (point.box.strokeWidth() % 2) / 2;
1527
+ q1Plot = Math.floor(q1Plot) + crispCorr;
1528
+ q3Plot = Math.floor(q3Plot) + crispCorr;
1529
+ left += crispCorr;
1530
+ right += crispCorr;
1531
+ point.box[verb]({
1532
+ d: [
1533
+ 'M',
1534
+ left, q3Plot,
1535
+ 'L',
1536
+ left, q1Plot,
1537
+ 'L',
1538
+ right, q1Plot,
1539
+ 'L',
1540
+ right, q3Plot,
1541
+ 'L',
1542
+ left, q3Plot,
1543
+ 'z'
1544
+ ]
1545
+ });
1546
+ }
1547
+
1548
+ // The whiskers
1549
+ if (whiskerLength) {
1550
+ crispCorr = (point.whiskers.strokeWidth() % 2) / 2;
1551
+ highPlot = highPlot + crispCorr;
1552
+ lowPlot = lowPlot + crispCorr;
1553
+ pointWiskerLength = (/%$/).test(whiskerLength) ? halfWidth * parseFloat(whiskerLength) / 100 : whiskerLength / 2;
1554
+ point.whiskers[verb]({
1555
+ d: [
1556
+ // High whisker
1557
+ 'M',
1558
+ crispX - pointWiskerLength,
1559
+ highPlot,
1560
+ 'L',
1561
+ crispX + pointWiskerLength,
1562
+ highPlot,
1563
+
1564
+ // Low whisker
1565
+ 'M',
1566
+ crispX - pointWiskerLength,
1567
+ lowPlot,
1568
+ 'L',
1569
+ crispX + pointWiskerLength,
1570
+ lowPlot
1571
+ ]
1572
+ });
1573
+ }
1574
+
1575
+ // The median
1576
+ medianPlot = Math.round(point.medianPlot);
1577
+ crispCorr = (point.medianShape.strokeWidth() % 2) / 2;
1578
+ medianPlot = medianPlot + crispCorr;
1579
+
1580
+ point.medianShape[verb]({
1581
+ d: [
1582
+ 'M',
1583
+ left,
1584
+ medianPlot,
1585
+ 'L',
1586
+ right,
1587
+ medianPlot
1588
+ ]
1589
+ });
1590
+ }
1591
+ });
1592
+
1593
+ },
1594
+ setStackedPoints: noop // #3890
1595
+
1596
+
1597
+ });
1598
+
1599
+ /* ****************************************************************************
1600
+ * End Box plot series code *
1601
+ *****************************************************************************/
1602
+
1603
+ }(Highcharts));
1604
+ (function(H) {
1605
+ /**
1606
+ * (c) 2010-2016 Torstein Honsi
1607
+ *
1608
+ * License: www.highcharts.com/license
1609
+ */
1610
+ 'use strict';
1611
+ var each = H.each,
1612
+ noop = H.noop,
1613
+ seriesType = H.seriesType,
1614
+ seriesTypes = H.seriesTypes;
1615
+
1616
+
1617
+ /* ****************************************************************************
1618
+ * Start error bar series code *
1619
+ *****************************************************************************/
1620
+ seriesType('errorbar', 'boxplot', {
1621
+
1622
+ grouping: false,
1623
+ linkedTo: ':previous',
1624
+ tooltip: {
1625
+ pointFormat: '<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.low}</b> - <b>{point.high}</b><br/>'
1626
+ },
1627
+ whiskerWidth: null
1628
+
1629
+ // Prototype members
1630
+ }, {
1631
+ type: 'errorbar',
1632
+ pointArrayMap: ['low', 'high'], // array point configs are mapped to this
1633
+ toYData: function(point) { // return a plain array for speedy calculation
1634
+ return [point.low, point.high];
1635
+ },
1636
+ pointValKey: 'high', // defines the top of the tracker
1637
+ doQuartiles: false,
1638
+ drawDataLabels: seriesTypes.arearange ? function() {
1639
+ var valKey = this.pointValKey;
1640
+ seriesTypes.arearange.prototype.drawDataLabels.call(this);
1641
+ // Arearange drawDataLabels does not reset point.y to high, but to low after drawing. #4133
1642
+ each(this.data, function(point) {
1643
+ point.y = point[valKey];
1644
+ });
1645
+ } : noop,
1646
+
1647
+ /**
1648
+ * Get the width and X offset, either on top of the linked series column
1649
+ * or standalone
1650
+ */
1651
+ getColumnMetrics: function() {
1652
+ return (this.linkedParent && this.linkedParent.columnMetrics) ||
1653
+ seriesTypes.column.prototype.getColumnMetrics.call(this);
1654
+ }
1655
+ });
1656
+
1657
+ /* ****************************************************************************
1658
+ * End error bar series code *
1659
+ *****************************************************************************/
1660
+
1661
+ }(Highcharts));
1662
+ (function(H) {
1663
+ /**
1664
+ * (c) 2010-2016 Torstein Honsi
1665
+ *
1666
+ * License: www.highcharts.com/license
1667
+ */
1668
+ 'use strict';
1669
+ var correctFloat = H.correctFloat,
1670
+ isNumber = H.isNumber,
1671
+ noop = H.noop,
1672
+ pick = H.pick,
1673
+ Point = H.Point,
1674
+ Series = H.Series,
1675
+ seriesType = H.seriesType,
1676
+ seriesTypes = H.seriesTypes;
1677
+
1678
+ /* ****************************************************************************
1679
+ * Start Waterfall series code *
1680
+ *****************************************************************************/
1681
+ seriesType('waterfall', 'column', {
1682
+ dataLabels: {
1683
+ inside: true
1684
+ },
1685
+
1686
+
1687
+ // Prototype members
1688
+ }, {
1689
+ pointValKey: 'y',
1690
+
1691
+ /**
1692
+ * Translate data points from raw values
1693
+ */
1694
+ translate: function() {
1695
+ var series = this,
1696
+ options = series.options,
1697
+ yAxis = series.yAxis,
1698
+ len,
1699
+ i,
1700
+ points,
1701
+ point,
1702
+ shapeArgs,
1703
+ stack,
1704
+ y,
1705
+ yValue,
1706
+ previousY,
1707
+ previousIntermediate,
1708
+ range,
1709
+ minPointLength = pick(options.minPointLength, 5),
1710
+ threshold = options.threshold,
1711
+ stacking = options.stacking,
1712
+ // Separate offsets for negative and positive columns:
1713
+ positiveOffset = 0,
1714
+ negativeOffset = 0,
1715
+ stackIndicator,
1716
+ tooltipY;
1717
+
1718
+ // run column series translate
1719
+ seriesTypes.column.prototype.translate.apply(this);
1720
+
1721
+ previousY = previousIntermediate = threshold;
1722
+ points = series.points;
1723
+
1724
+ for (i = 0, len = points.length; i < len; i++) {
1725
+ // cache current point object
1726
+ point = points[i];
1727
+ yValue = this.processedYData[i];
1728
+ shapeArgs = point.shapeArgs;
1729
+
1730
+ // get current stack
1731
+ stack = stacking && yAxis.stacks[(series.negStacks && yValue < threshold ? '-' : '') + series.stackKey];
1732
+ stackIndicator = series.getStackIndicator(stackIndicator, point.x);
1733
+ range = stack ?
1734
+ stack[point.x].points[series.index + ',' + i + ',' + stackIndicator.index] : [0, yValue];
1735
+
1736
+ // override point value for sums
1737
+ // #3710 Update point does not propagate to sum
1738
+ if (point.isSum) {
1739
+ point.y = correctFloat(yValue);
1740
+ } else if (point.isIntermediateSum) {
1741
+ point.y = correctFloat(yValue - previousIntermediate); // #3840
1742
+ }
1743
+ // up points
1744
+ y = Math.max(previousY, previousY + point.y) + range[0];
1745
+ shapeArgs.y = yAxis.toPixels(y, true);
1746
+
1747
+
1748
+ // sum points
1749
+ if (point.isSum) {
1750
+ shapeArgs.y = yAxis.toPixels(range[1], true);
1751
+ shapeArgs.height = Math.min(yAxis.toPixels(range[0], true), yAxis.len) -
1752
+ shapeArgs.y + positiveOffset + negativeOffset; // #4256
1753
+
1754
+ } else if (point.isIntermediateSum) {
1755
+ shapeArgs.y = yAxis.toPixels(range[1], true);
1756
+ shapeArgs.height = Math.min(yAxis.toPixels(previousIntermediate, true), yAxis.len) -
1757
+ shapeArgs.y + positiveOffset + negativeOffset;
1758
+ previousIntermediate = range[1];
1759
+
1760
+ // If it's not the sum point, update previous stack end position and get
1761
+ // shape height (#3886)
1762
+ } else {
1763
+ shapeArgs.height = yValue > 0 ?
1764
+ yAxis.toPixels(previousY, true) - shapeArgs.y :
1765
+ yAxis.toPixels(previousY, true) - yAxis.toPixels(previousY - yValue, true);
1766
+ previousY += yValue;
1767
+ }
1768
+ // #3952 Negative sum or intermediate sum not rendered correctly
1769
+ if (shapeArgs.height < 0) {
1770
+ shapeArgs.y += shapeArgs.height;
1771
+ shapeArgs.height *= -1;
1772
+ }
1773
+
1774
+ point.plotY = shapeArgs.y = Math.round(shapeArgs.y) - (series.borderWidth % 2) / 2;
1775
+ shapeArgs.height = Math.max(Math.round(shapeArgs.height), 0.001); // #3151
1776
+ point.yBottom = shapeArgs.y + shapeArgs.height;
1777
+
1778
+ // Before minPointLength, apply negative offset:
1779
+ shapeArgs.y -= negativeOffset;
1780
+
1781
+
1782
+ if (shapeArgs.height <= minPointLength && !point.isNull) {
1783
+ shapeArgs.height = minPointLength;
1784
+ if (point.y < 0) {
1785
+ negativeOffset -= minPointLength;
1786
+ } else {
1787
+ positiveOffset += minPointLength;
1788
+ }
1789
+ }
1790
+
1791
+ // After minPointLength is updated, apply positive offset:
1792
+ shapeArgs.y -= positiveOffset;
1793
+
1794
+ // Correct tooltip placement (#3014)
1795
+ tooltipY = point.plotY - negativeOffset - positiveOffset +
1796
+ (point.negative && negativeOffset >= 0 ? shapeArgs.height : 0);
1797
+ if (series.chart.inverted) {
1798
+ point.tooltipPos[0] = yAxis.len - tooltipY;
1799
+ } else {
1800
+ point.tooltipPos[1] = tooltipY;
1801
+ }
1802
+ }
1803
+ },
1804
+
1805
+ /**
1806
+ * Call default processData then override yData to reflect waterfall's extremes on yAxis
1807
+ */
1808
+ processData: function(force) {
1809
+ var series = this,
1810
+ options = series.options,
1811
+ yData = series.yData,
1812
+ points = series.options.data, // #3710 Update point does not propagate to sum
1813
+ point,
1814
+ dataLength = yData.length,
1815
+ threshold = options.threshold || 0,
1816
+ subSum,
1817
+ sum,
1818
+ dataMin,
1819
+ dataMax,
1820
+ y,
1821
+ i;
1822
+
1823
+ sum = subSum = dataMin = dataMax = threshold;
1824
+
1825
+ for (i = 0; i < dataLength; i++) {
1826
+ y = yData[i];
1827
+ point = points && points[i] ? points[i] : {};
1828
+
1829
+ if (y === 'sum' || point.isSum) {
1830
+ yData[i] = correctFloat(sum);
1831
+ } else if (y === 'intermediateSum' || point.isIntermediateSum) {
1832
+ yData[i] = correctFloat(subSum);
1833
+ } else {
1834
+ sum += y;
1835
+ subSum += y;
1836
+ }
1837
+ dataMin = Math.min(sum, dataMin);
1838
+ dataMax = Math.max(sum, dataMax);
1839
+ }
1840
+
1841
+ Series.prototype.processData.call(this, force);
1842
+
1843
+ // Record extremes
1844
+ series.dataMin = dataMin;
1845
+ series.dataMax = dataMax;
1846
+ },
1847
+
1848
+ /**
1849
+ * Return y value or string if point is sum
1850
+ */
1851
+ toYData: function(pt) {
1852
+ if (pt.isSum) {
1853
+ return (pt.x === 0 ? null : 'sum'); //#3245 Error when first element is Sum or Intermediate Sum
1854
+ }
1855
+ if (pt.isIntermediateSum) {
1856
+ return (pt.x === 0 ? null : 'intermediateSum'); //#3245
1857
+ }
1858
+ return pt.y;
1859
+ },
1860
+
1861
+
1862
+
1863
+ /**
1864
+ * Return an empty path initially, because we need to know the stroke-width in order
1865
+ * to set the final path.
1866
+ */
1867
+ getGraphPath: function() {
1868
+ return ['M', 0, 0];
1869
+ },
1870
+
1871
+ /**
1872
+ * Draw columns' connector lines
1873
+ */
1874
+ getCrispPath: function() {
1875
+
1876
+ var data = this.data,
1877
+ length = data.length,
1878
+ lineWidth = this.graph.strokeWidth() + this.borderWidth,
1879
+ normalizer = Math.round(lineWidth) % 2 / 2,
1880
+ path = [],
1881
+ prevArgs,
1882
+ pointArgs,
1883
+ i,
1884
+ d;
1885
+
1886
+ for (i = 1; i < length; i++) {
1887
+ pointArgs = data[i].shapeArgs;
1888
+ prevArgs = data[i - 1].shapeArgs;
1889
+
1890
+ d = [
1891
+ 'M',
1892
+ prevArgs.x + prevArgs.width, prevArgs.y + normalizer,
1893
+ 'L',
1894
+ pointArgs.x, prevArgs.y + normalizer
1895
+ ];
1896
+
1897
+ if (data[i - 1].y < 0) {
1898
+ d[2] += prevArgs.height;
1899
+ d[5] += prevArgs.height;
1900
+ }
1901
+
1902
+ path = path.concat(d);
1903
+ }
1904
+
1905
+ return path;
1906
+ },
1907
+
1908
+ /**
1909
+ * The graph is initally drawn with an empty definition, then updated with
1910
+ * crisp rendering.
1911
+ */
1912
+ drawGraph: function() {
1913
+ Series.prototype.drawGraph.call(this);
1914
+ this.graph.attr({
1915
+ d: this.getCrispPath()
1916
+ });
1917
+ },
1918
+
1919
+ /**
1920
+ * Extremes are recorded in processData
1921
+ */
1922
+ getExtremes: noop
1923
+
1924
+ // Point members
1925
+ }, {
1926
+ getClassName: function() {
1927
+ var className = Point.prototype.getClassName.call(this);
1928
+
1929
+ if (this.isSum) {
1930
+ className += ' highcharts-sum';
1931
+ } else if (this.isIntermediateSum) {
1932
+ className += ' highcharts-intermediate-sum';
1933
+ }
1934
+ return className;
1935
+ },
1936
+ /**
1937
+ * Pass the null test in ColumnSeries.translate.
1938
+ */
1939
+ isValid: function() {
1940
+ return isNumber(this.y, true) || this.isSum || this.isIntermediateSum;
1941
+ }
1942
+
1943
+ });
1944
+
1945
+ /* ****************************************************************************
1946
+ * End Waterfall series code *
1947
+ *****************************************************************************/
1948
+
1949
+ }(Highcharts));
1950
+ (function(H) {
1951
+ /**
1952
+ * (c) 2010-2016 Torstein Honsi
1953
+ *
1954
+ * License: www.highcharts.com/license
1955
+ */
1956
+ 'use strict';
1957
+ var LegendSymbolMixin = H.LegendSymbolMixin,
1958
+ noop = H.noop,
1959
+ Series = H.Series,
1960
+ seriesType = H.seriesType,
1961
+ seriesTypes = H.seriesTypes;
1962
+ /**
1963
+ * The polygon series prototype
1964
+ */
1965
+ seriesType('polygon', 'scatter', {
1966
+ marker: {
1967
+ enabled: false,
1968
+ states: {
1969
+ hover: {
1970
+ enabled: false
1971
+ }
1972
+ }
1973
+ },
1974
+ stickyTracking: false,
1975
+ tooltip: {
1976
+ followPointer: true,
1977
+ pointFormat: ''
1978
+ },
1979
+ trackByArea: true
1980
+
1981
+ // Prototype members
1982
+ }, {
1983
+ type: 'polygon',
1984
+ getGraphPath: function() {
1985
+
1986
+ var graphPath = Series.prototype.getGraphPath.call(this),
1987
+ i = graphPath.length + 1;
1988
+
1989
+ // Close all segments
1990
+ while (i--) {
1991
+ if ((i === graphPath.length || graphPath[i] === 'M') && i > 0) {
1992
+ graphPath.splice(i, 0, 'z');
1993
+ }
1994
+ }
1995
+ this.areaPath = graphPath;
1996
+ return graphPath;
1997
+ },
1998
+ drawGraph: function() {
1999
+
2000
+ seriesTypes.area.prototype.drawGraph.call(this);
2001
+ },
2002
+ drawLegendSymbol: LegendSymbolMixin.drawRectangle,
2003
+ drawTracker: Series.prototype.drawTracker,
2004
+ setStackedPoints: noop // No stacking points on polygons (#5310)
2005
+ });
2006
+
2007
+ }(Highcharts));
2008
+ (function(H) {
2009
+ /**
2010
+ * (c) 2010-2016 Torstein Honsi
2011
+ *
2012
+ * License: www.highcharts.com/license
2013
+ */
2014
+ 'use strict';
2015
+ var arrayMax = H.arrayMax,
2016
+ arrayMin = H.arrayMin,
2017
+ Axis = H.Axis,
2018
+ color = H.color,
2019
+ each = H.each,
2020
+ isNumber = H.isNumber,
2021
+ noop = H.noop,
2022
+ pick = H.pick,
2023
+ pInt = H.pInt,
2024
+ Point = H.Point,
2025
+ Series = H.Series,
2026
+ seriesType = H.seriesType,
2027
+ seriesTypes = H.seriesTypes;
2028
+
2029
+ /* ****************************************************************************
2030
+ * Start Bubble series code *
2031
+ *****************************************************************************/
2032
+
2033
+ seriesType('bubble', 'scatter', {
2034
+ dataLabels: {
2035
+ formatter: function() { // #2945
2036
+ return this.point.z;
2037
+ },
2038
+ inside: true,
2039
+ verticalAlign: 'middle'
2040
+ },
2041
+ // displayNegative: true,
2042
+ marker: {
2043
+
2044
+ // Avoid offset in Point.setState
2045
+ radius: null,
2046
+ states: {
2047
+ hover: {
2048
+ radiusPlus: 0
2049
+ }
2050
+ }
2051
+ },
2052
+ minSize: 8,
2053
+ maxSize: '20%',
2054
+ // negativeColor: null,
2055
+ // sizeBy: 'area'
2056
+ softThreshold: false,
2057
+ states: {
2058
+ hover: {
2059
+ halo: {
2060
+ size: 5
2061
+ }
2062
+ }
2063
+ },
2064
+ tooltip: {
2065
+ pointFormat: '({point.x}, {point.y}), Size: {point.z}'
2066
+ },
2067
+ turboThreshold: 0,
2068
+ zThreshold: 0,
2069
+ zoneAxis: 'z'
2070
+
2071
+ // Prototype members
2072
+ }, {
2073
+ pointArrayMap: ['y', 'z'],
2074
+ parallelArrays: ['x', 'y', 'z'],
2075
+ trackerGroups: ['group', 'dataLabelsGroup'],
2076
+ bubblePadding: true,
2077
+ zoneAxis: 'z',
2078
+ markerAttribs: null,
2079
+
2080
+
2081
+
2082
+ /**
2083
+ * Get the radius for each point based on the minSize, maxSize and each point's Z value. This
2084
+ * must be done prior to Series.translate because the axis needs to add padding in
2085
+ * accordance with the point sizes.
2086
+ */
2087
+ getRadii: function(zMin, zMax, minSize, maxSize) {
2088
+ var len,
2089
+ i,
2090
+ pos,
2091
+ zData = this.zData,
2092
+ radii = [],
2093
+ options = this.options,
2094
+ sizeByArea = options.sizeBy !== 'width',
2095
+ zThreshold = options.zThreshold,
2096
+ zRange = zMax - zMin,
2097
+ value,
2098
+ radius;
2099
+
2100
+ // Set the shape type and arguments to be picked up in drawPoints
2101
+ for (i = 0, len = zData.length; i < len; i++) {
2102
+
2103
+ value = zData[i];
2104
+
2105
+ // When sizing by threshold, the absolute value of z determines the size
2106
+ // of the bubble.
2107
+ if (options.sizeByAbsoluteValue && value !== null) {
2108
+ value = Math.abs(value - zThreshold);
2109
+ zMax = Math.max(zMax - zThreshold, Math.abs(zMin - zThreshold));
2110
+ zMin = 0;
2111
+ }
2112
+
2113
+ if (value === null) {
2114
+ radius = null;
2115
+ // Issue #4419 - if value is less than zMin, push a radius that's always smaller than the minimum size
2116
+ } else if (value < zMin) {
2117
+ radius = minSize / 2 - 1;
2118
+ } else {
2119
+ // Relative size, a number between 0 and 1
2120
+ pos = zRange > 0 ? (value - zMin) / zRange : 0.5;
2121
+
2122
+ if (sizeByArea && pos >= 0) {
2123
+ pos = Math.sqrt(pos);
2124
+ }
2125
+ radius = Math.ceil(minSize + pos * (maxSize - minSize)) / 2;
2126
+ }
2127
+ radii.push(radius);
2128
+ }
2129
+ this.radii = radii;
2130
+ },
2131
+
2132
+ /**
2133
+ * Perform animation on the bubbles
2134
+ */
2135
+ animate: function(init) {
2136
+ var animation = this.options.animation;
2137
+
2138
+ if (!init) { // run the animation
2139
+ each(this.points, function(point) {
2140
+ var graphic = point.graphic,
2141
+ shapeArgs = point.shapeArgs;
2142
+
2143
+ if (graphic && shapeArgs) {
2144
+ // start values
2145
+ graphic.attr('r', 1);
2146
+
2147
+ // animate
2148
+ graphic.animate({
2149
+ r: shapeArgs.r
2150
+ }, animation);
2151
+ }
2152
+ });
2153
+
2154
+ // delete this function to allow it only once
2155
+ this.animate = null;
2156
+ }
2157
+ },
2158
+
2159
+ /**
2160
+ * Extend the base translate method to handle bubble size
2161
+ */
2162
+ translate: function() {
2163
+
2164
+ var i,
2165
+ data = this.data,
2166
+ point,
2167
+ radius,
2168
+ radii = this.radii;
2169
+
2170
+ // Run the parent method
2171
+ seriesTypes.scatter.prototype.translate.call(this);
2172
+
2173
+ // Set the shape type and arguments to be picked up in drawPoints
2174
+ i = data.length;
2175
+
2176
+ while (i--) {
2177
+ point = data[i];
2178
+ radius = radii ? radii[i] : 0; // #1737
2179
+
2180
+ if (isNumber(radius) && radius >= this.minPxSize / 2) {
2181
+ // Shape arguments
2182
+ point.shapeType = 'circle';
2183
+ point.shapeArgs = {
2184
+ x: point.plotX,
2185
+ y: point.plotY,
2186
+ r: radius
2187
+ };
2188
+
2189
+ // Alignment box for the data label
2190
+ point.dlBox = {
2191
+ x: point.plotX - radius,
2192
+ y: point.plotY - radius,
2193
+ width: 2 * radius,
2194
+ height: 2 * radius
2195
+ };
2196
+ } else { // below zThreshold
2197
+ point.shapeArgs = point.plotY = point.dlBox = undefined; // #1691
2198
+ }
2199
+ }
2200
+ },
2201
+
2202
+ /**
2203
+ * Get the series' symbol in the legend
2204
+ *
2205
+ * @param {Object} legend The legend object
2206
+ * @param {Object} item The series (this) or point
2207
+ */
2208
+ drawLegendSymbol: function(legend, item) {
2209
+ var renderer = this.chart.renderer,
2210
+ radius = renderer.fontMetrics(
2211
+ legend.itemStyle && legend.itemStyle.fontSize,
2212
+ item.legendItem
2213
+ ).f / 2;
2214
+
2215
+ item.legendSymbol = renderer.circle(
2216
+ radius,
2217
+ legend.baseline - radius,
2218
+ radius
2219
+ ).attr({
2220
+ zIndex: 3
2221
+ }).add(item.legendGroup);
2222
+ item.legendSymbol.isMarker = true;
2223
+
2224
+ },
2225
+
2226
+ drawPoints: seriesTypes.column.prototype.drawPoints,
2227
+ alignDataLabel: seriesTypes.column.prototype.alignDataLabel,
2228
+ buildKDTree: noop,
2229
+ applyZones: noop
2230
+
2231
+ // Point class
2232
+ }, {
2233
+ haloPath: function(size) {
2234
+ return Point.prototype.haloPath.call(
2235
+ this,
2236
+ size === 0 ? 0 : this.shapeArgs.r + size // #6067
2237
+ );
2238
+ },
2239
+ ttBelow: false
2240
+ });
2241
+
2242
+ /**
2243
+ * Add logic to pad each axis with the amount of pixels
2244
+ * necessary to avoid the bubbles to overflow.
2245
+ */
2246
+ Axis.prototype.beforePadding = function() {
2247
+ var axis = this,
2248
+ axisLength = this.len,
2249
+ chart = this.chart,
2250
+ pxMin = 0,
2251
+ pxMax = axisLength,
2252
+ isXAxis = this.isXAxis,
2253
+ dataKey = isXAxis ? 'xData' : 'yData',
2254
+ min = this.min,
2255
+ extremes = {},
2256
+ smallestSize = Math.min(chart.plotWidth, chart.plotHeight),
2257
+ zMin = Number.MAX_VALUE,
2258
+ zMax = -Number.MAX_VALUE,
2259
+ range = this.max - min,
2260
+ transA = axisLength / range,
2261
+ activeSeries = [];
2262
+
2263
+ // Handle padding on the second pass, or on redraw
2264
+ each(this.series, function(series) {
2265
+
2266
+ var seriesOptions = series.options,
2267
+ zData;
2268
+
2269
+ if (series.bubblePadding && (series.visible || !chart.options.chart.ignoreHiddenSeries)) {
2270
+
2271
+ // Correction for #1673
2272
+ axis.allowZoomOutside = true;
2273
+
2274
+ // Cache it
2275
+ activeSeries.push(series);
2276
+
2277
+ if (isXAxis) { // because X axis is evaluated first
2278
+
2279
+ // For each series, translate the size extremes to pixel values
2280
+ each(['minSize', 'maxSize'], function(prop) {
2281
+ var length = seriesOptions[prop],
2282
+ isPercent = /%$/.test(length);
2283
+
2284
+ length = pInt(length);
2285
+ extremes[prop] = isPercent ?
2286
+ smallestSize * length / 100 :
2287
+ length;
2288
+
2289
+ });
2290
+ series.minPxSize = extremes.minSize;
2291
+ // Prioritize min size if conflict to make sure bubbles are
2292
+ // always visible. #5873
2293
+ series.maxPxSize = Math.max(extremes.maxSize, extremes.minSize);
2294
+
2295
+ // Find the min and max Z
2296
+ zData = series.zData;
2297
+ if (zData.length) { // #1735
2298
+ zMin = pick(seriesOptions.zMin, Math.min(
2299
+ zMin,
2300
+ Math.max(
2301
+ arrayMin(zData),
2302
+ seriesOptions.displayNegative === false ? seriesOptions.zThreshold : -Number.MAX_VALUE
2303
+ )
2304
+ ));
2305
+ zMax = pick(seriesOptions.zMax, Math.max(zMax, arrayMax(zData)));
2306
+ }
2307
+ }
2308
+ }
2309
+ });
2310
+
2311
+ each(activeSeries, function(series) {
2312
+
2313
+ var data = series[dataKey],
2314
+ i = data.length,
2315
+ radius;
2316
+
2317
+ if (isXAxis) {
2318
+ series.getRadii(zMin, zMax, series.minPxSize, series.maxPxSize);
2319
+ }
2320
+
2321
+ if (range > 0) {
2322
+ while (i--) {
2323
+ if (isNumber(data[i]) && axis.dataMin <= data[i] && data[i] <= axis.dataMax) {
2324
+ radius = series.radii[i];
2325
+ pxMin = Math.min(((data[i] - min) * transA) - radius, pxMin);
2326
+ pxMax = Math.max(((data[i] - min) * transA) + radius, pxMax);
2327
+ }
2328
+ }
2329
+ }
2330
+ });
2331
+
2332
+ if (activeSeries.length && range > 0 && !this.isLog) {
2333
+ pxMax -= axisLength;
2334
+ transA *= (axisLength + pxMin - pxMax) / axisLength;
2335
+ each([
2336
+ ['min', 'userMin', pxMin],
2337
+ ['max', 'userMax', pxMax]
2338
+ ], function(keys) {
2339
+ if (pick(axis.options[keys[0]], axis[keys[1]]) === undefined) {
2340
+ axis[keys[0]] += keys[2] / transA;
2341
+ }
2342
+ });
2343
+ }
2344
+ };
2345
+
2346
+ /* ****************************************************************************
2347
+ * End Bubble series code *
2348
+ *****************************************************************************/
2349
+
2350
+ }(Highcharts));
2351
+ (function(H) {
2352
+ /**
2353
+ * (c) 2010-2016 Torstein Honsi
2354
+ *
2355
+ * License: www.highcharts.com/license
2356
+ */
2357
+ 'use strict';
2358
+
2359
+ /**
2360
+ * Extensions for polar charts. Additionally, much of the geometry required for polar charts is
2361
+ * gathered in RadialAxes.js.
2362
+ *
2363
+ */
2364
+
2365
+ var each = H.each,
2366
+ pick = H.pick,
2367
+ Pointer = H.Pointer,
2368
+ Series = H.Series,
2369
+ seriesTypes = H.seriesTypes,
2370
+ wrap = H.wrap,
2371
+
2372
+ seriesProto = Series.prototype,
2373
+ pointerProto = Pointer.prototype,
2374
+ colProto;
2375
+
2376
+ /**
2377
+ * Search a k-d tree by the point angle, used for shared tooltips in polar charts
2378
+ */
2379
+ seriesProto.searchPointByAngle = function(e) {
2380
+ var series = this,
2381
+ chart = series.chart,
2382
+ xAxis = series.xAxis,
2383
+ center = xAxis.pane.center,
2384
+ plotX = e.chartX - center[0] - chart.plotLeft,
2385
+ plotY = e.chartY - center[1] - chart.plotTop;
2386
+
2387
+ return this.searchKDTree({
2388
+ clientX: 180 + (Math.atan2(plotX, plotY) * (-180 / Math.PI))
2389
+ });
2390
+
2391
+ };
2392
+
2393
+ /**
2394
+ * Wrap the buildKDTree function so that it searches by angle (clientX) in case of shared tooltip,
2395
+ * and by two dimensional distance in case of non-shared.
2396
+ */
2397
+ wrap(seriesProto, 'buildKDTree', function(proceed) {
2398
+ if (this.chart.polar) {
2399
+ if (this.kdByAngle) {
2400
+ this.searchPoint = this.searchPointByAngle;
2401
+ } else {
2402
+ this.kdDimensions = 2;
2403
+ }
2404
+ }
2405
+ proceed.apply(this);
2406
+ });
2407
+
2408
+ /**
2409
+ * Translate a point's plotX and plotY from the internal angle and radius measures to
2410
+ * true plotX, plotY coordinates
2411
+ */
2412
+ seriesProto.toXY = function(point) {
2413
+ var xy,
2414
+ chart = this.chart,
2415
+ plotX = point.plotX,
2416
+ plotY = point.plotY,
2417
+ clientX;
2418
+
2419
+ // Save rectangular plotX, plotY for later computation
2420
+ point.rectPlotX = plotX;
2421
+ point.rectPlotY = plotY;
2422
+
2423
+ // Find the polar plotX and plotY
2424
+ xy = this.xAxis.postTranslate(point.plotX, this.yAxis.len - plotY);
2425
+ point.plotX = point.polarPlotX = xy.x - chart.plotLeft;
2426
+ point.plotY = point.polarPlotY = xy.y - chart.plotTop;
2427
+
2428
+ // If shared tooltip, record the angle in degrees in order to align X points. Otherwise,
2429
+ // use a standard k-d tree to get the nearest point in two dimensions.
2430
+ if (this.kdByAngle) {
2431
+ clientX = ((plotX / Math.PI * 180) + this.xAxis.pane.options.startAngle) % 360;
2432
+ if (clientX < 0) { // #2665
2433
+ clientX += 360;
2434
+ }
2435
+ point.clientX = clientX;
2436
+ } else {
2437
+ point.clientX = point.plotX;
2438
+ }
2439
+ };
2440
+
2441
+ if (seriesTypes.spline) {
2442
+ /**
2443
+ * Overridden method for calculating a spline from one point to the next
2444
+ */
2445
+ wrap(seriesTypes.spline.prototype, 'getPointSpline', function(proceed, segment, point, i) {
2446
+
2447
+ var ret,
2448
+ smoothing = 1.5, // 1 means control points midway between points, 2 means 1/3 from the point, 3 is 1/4 etc;
2449
+ denom = smoothing + 1,
2450
+ plotX,
2451
+ plotY,
2452
+ lastPoint,
2453
+ nextPoint,
2454
+ lastX,
2455
+ lastY,
2456
+ nextX,
2457
+ nextY,
2458
+ leftContX,
2459
+ leftContY,
2460
+ rightContX,
2461
+ rightContY,
2462
+ distanceLeftControlPoint,
2463
+ distanceRightControlPoint,
2464
+ leftContAngle,
2465
+ rightContAngle,
2466
+ jointAngle;
2467
+
2468
+
2469
+ if (this.chart.polar) {
2470
+
2471
+ plotX = point.plotX;
2472
+ plotY = point.plotY;
2473
+ lastPoint = segment[i - 1];
2474
+ nextPoint = segment[i + 1];
2475
+
2476
+ // Connect ends
2477
+ if (this.connectEnds) {
2478
+ if (!lastPoint) {
2479
+ lastPoint = segment[segment.length - 2]; // not the last but the second last, because the segment is already connected
2480
+ }
2481
+ if (!nextPoint) {
2482
+ nextPoint = segment[1];
2483
+ }
2484
+ }
2485
+
2486
+ // find control points
2487
+ if (lastPoint && nextPoint) {
2488
+
2489
+ lastX = lastPoint.plotX;
2490
+ lastY = lastPoint.plotY;
2491
+ nextX = nextPoint.plotX;
2492
+ nextY = nextPoint.plotY;
2493
+ leftContX = (smoothing * plotX + lastX) / denom;
2494
+ leftContY = (smoothing * plotY + lastY) / denom;
2495
+ rightContX = (smoothing * plotX + nextX) / denom;
2496
+ rightContY = (smoothing * plotY + nextY) / denom;
2497
+ distanceLeftControlPoint = Math.sqrt(Math.pow(leftContX - plotX, 2) + Math.pow(leftContY - plotY, 2));
2498
+ distanceRightControlPoint = Math.sqrt(Math.pow(rightContX - plotX, 2) + Math.pow(rightContY - plotY, 2));
2499
+ leftContAngle = Math.atan2(leftContY - plotY, leftContX - plotX);
2500
+ rightContAngle = Math.atan2(rightContY - plotY, rightContX - plotX);
2501
+ jointAngle = (Math.PI / 2) + ((leftContAngle + rightContAngle) / 2);
2502
+
2503
+
2504
+ // Ensure the right direction, jointAngle should be in the same quadrant as leftContAngle
2505
+ if (Math.abs(leftContAngle - jointAngle) > Math.PI / 2) {
2506
+ jointAngle -= Math.PI;
2507
+ }
2508
+
2509
+ // Find the corrected control points for a spline straight through the point
2510
+ leftContX = plotX + Math.cos(jointAngle) * distanceLeftControlPoint;
2511
+ leftContY = plotY + Math.sin(jointAngle) * distanceLeftControlPoint;
2512
+ rightContX = plotX + Math.cos(Math.PI + jointAngle) * distanceRightControlPoint;
2513
+ rightContY = plotY + Math.sin(Math.PI + jointAngle) * distanceRightControlPoint;
2514
+
2515
+ // Record for drawing in next point
2516
+ point.rightContX = rightContX;
2517
+ point.rightContY = rightContY;
2518
+
2519
+ }
2520
+
2521
+
2522
+ // moveTo or lineTo
2523
+ if (!i) {
2524
+ ret = ['M', plotX, plotY];
2525
+ } else { // curve from last point to this
2526
+ ret = [
2527
+ 'C',
2528
+ lastPoint.rightContX || lastPoint.plotX,
2529
+ lastPoint.rightContY || lastPoint.plotY,
2530
+ leftContX || plotX,
2531
+ leftContY || plotY,
2532
+ plotX,
2533
+ plotY
2534
+ ];
2535
+ lastPoint.rightContX = lastPoint.rightContY = null; // reset for updating series later
2536
+ }
2537
+
2538
+
2539
+ } else {
2540
+ ret = proceed.call(this, segment, point, i);
2541
+ }
2542
+ return ret;
2543
+ });
2544
+ }
2545
+
2546
+ /**
2547
+ * Extend translate. The plotX and plotY values are computed as if the polar chart were a
2548
+ * cartesian plane, where plotX denotes the angle in radians and (yAxis.len - plotY) is the pixel distance from
2549
+ * center.
2550
+ */
2551
+ wrap(seriesProto, 'translate', function(proceed) {
2552
+ var chart = this.chart,
2553
+ points,
2554
+ i;
2555
+
2556
+ // Run uber method
2557
+ proceed.call(this);
2558
+
2559
+ // Postprocess plot coordinates
2560
+ if (chart.polar) {
2561
+ this.kdByAngle = chart.tooltip && chart.tooltip.shared;
2562
+
2563
+ if (!this.preventPostTranslate) {
2564
+ points = this.points;
2565
+ i = points.length;
2566
+
2567
+ while (i--) {
2568
+ // Translate plotX, plotY from angle and radius to true plot coordinates
2569
+ this.toXY(points[i]);
2570
+ }
2571
+ }
2572
+ }
2573
+ });
2574
+
2575
+ /**
2576
+ * Extend getSegmentPath to allow connecting ends across 0 to provide a closed circle in
2577
+ * line-like series.
2578
+ */
2579
+ wrap(seriesProto, 'getGraphPath', function(proceed, points) {
2580
+ var series = this,
2581
+ i,
2582
+ firstValid;
2583
+
2584
+ // Connect the path
2585
+ if (this.chart.polar) {
2586
+ points = points || this.points;
2587
+
2588
+ // Append first valid point in order to connect the ends
2589
+ for (i = 0; i < points.length; i++) {
2590
+ if (!points[i].isNull) {
2591
+ firstValid = i;
2592
+ break;
2593
+ }
2594
+ }
2595
+ if (this.options.connectEnds !== false && firstValid !== undefined) {
2596
+ this.connectEnds = true; // re-used in splines
2597
+ points.splice(points.length, 0, points[firstValid]);
2598
+ }
2599
+
2600
+ // For area charts, pseudo points are added to the graph, now we need to translate these
2601
+ each(points, function(point) {
2602
+ if (point.polarPlotY === undefined) {
2603
+ series.toXY(point);
2604
+ }
2605
+ });
2606
+ }
2607
+
2608
+ // Run uber method
2609
+ return proceed.apply(this, [].slice.call(arguments, 1));
2610
+
2611
+ });
2612
+
2613
+
2614
+ function polarAnimate(proceed, init) {
2615
+ var chart = this.chart,
2616
+ animation = this.options.animation,
2617
+ group = this.group,
2618
+ markerGroup = this.markerGroup,
2619
+ center = this.xAxis.center,
2620
+ plotLeft = chart.plotLeft,
2621
+ plotTop = chart.plotTop,
2622
+ attribs;
2623
+
2624
+ // Specific animation for polar charts
2625
+ if (chart.polar) {
2626
+
2627
+ // Enable animation on polar charts only in SVG. In VML, the scaling is different, plus animation
2628
+ // would be so slow it would't matter.
2629
+ if (chart.renderer.isSVG) {
2630
+
2631
+ if (animation === true) {
2632
+ animation = {};
2633
+ }
2634
+
2635
+ // Initialize the animation
2636
+ if (init) {
2637
+
2638
+ // Scale down the group and place it in the center
2639
+ attribs = {
2640
+ translateX: center[0] + plotLeft,
2641
+ translateY: center[1] + plotTop,
2642
+ scaleX: 0.001, // #1499
2643
+ scaleY: 0.001
2644
+ };
2645
+
2646
+ group.attr(attribs);
2647
+ if (markerGroup) {
2648
+ //markerGroup.attrSetters = group.attrSetters;
2649
+ markerGroup.attr(attribs);
2650
+ }
2651
+
2652
+ // Run the animation
2653
+ } else {
2654
+ attribs = {
2655
+ translateX: plotLeft,
2656
+ translateY: plotTop,
2657
+ scaleX: 1,
2658
+ scaleY: 1
2659
+ };
2660
+ group.animate(attribs, animation);
2661
+ if (markerGroup) {
2662
+ markerGroup.animate(attribs, animation);
2663
+ }
2664
+
2665
+ // Delete this function to allow it only once
2666
+ this.animate = null;
2667
+ }
2668
+ }
2669
+
2670
+ // For non-polar charts, revert to the basic animation
2671
+ } else {
2672
+ proceed.call(this, init);
2673
+ }
2674
+ }
2675
+
2676
+ // Define the animate method for regular series
2677
+ wrap(seriesProto, 'animate', polarAnimate);
2678
+
2679
+
2680
+ if (seriesTypes.column) {
2681
+
2682
+ colProto = seriesTypes.column.prototype;
2683
+
2684
+ colProto.polarArc = function(low, high, start, end) {
2685
+ var center = this.xAxis.center,
2686
+ len = this.yAxis.len;
2687
+
2688
+ return this.chart.renderer.symbols.arc(
2689
+ center[0],
2690
+ center[1],
2691
+ len - high,
2692
+ null, {
2693
+ start: start,
2694
+ end: end,
2695
+ innerR: len - pick(low, len)
2696
+ }
2697
+ );
2698
+ };
2699
+
2700
+ /**
2701
+ * Define the animate method for columnseries
2702
+ */
2703
+ wrap(colProto, 'animate', polarAnimate);
2704
+
2705
+
2706
+ /**
2707
+ * Extend the column prototype's translate method
2708
+ */
2709
+ wrap(colProto, 'translate', function(proceed) {
2710
+
2711
+ var xAxis = this.xAxis,
2712
+ startAngleRad = xAxis.startAngleRad,
2713
+ start,
2714
+ points,
2715
+ point,
2716
+ i;
2717
+
2718
+ this.preventPostTranslate = true;
2719
+
2720
+ // Run uber method
2721
+ proceed.call(this);
2722
+
2723
+ // Postprocess plot coordinates
2724
+ if (xAxis.isRadial) {
2725
+ points = this.points;
2726
+ i = points.length;
2727
+ while (i--) {
2728
+ point = points[i];
2729
+ start = point.barX + startAngleRad;
2730
+ point.shapeType = 'path';
2731
+ point.shapeArgs = {
2732
+ d: this.polarArc(point.yBottom, point.plotY, start, start + point.pointWidth)
2733
+ };
2734
+ // Provide correct plotX, plotY for tooltip
2735
+ this.toXY(point);
2736
+ point.tooltipPos = [point.plotX, point.plotY];
2737
+ point.ttBelow = point.plotY > xAxis.center[1];
2738
+ }
2739
+ }
2740
+ });
2741
+
2742
+
2743
+ /**
2744
+ * Align column data labels outside the columns. #1199.
2745
+ */
2746
+ wrap(colProto, 'alignDataLabel', function(proceed, point, dataLabel, options, alignTo, isNew) {
2747
+
2748
+ if (this.chart.polar) {
2749
+ var angle = point.rectPlotX / Math.PI * 180,
2750
+ align,
2751
+ verticalAlign;
2752
+
2753
+ // Align nicely outside the perimeter of the columns
2754
+ if (options.align === null) {
2755
+ if (angle > 20 && angle < 160) {
2756
+ align = 'left'; // right hemisphere
2757
+ } else if (angle > 200 && angle < 340) {
2758
+ align = 'right'; // left hemisphere
2759
+ } else {
2760
+ align = 'center'; // top or bottom
2761
+ }
2762
+ options.align = align;
2763
+ }
2764
+ if (options.verticalAlign === null) {
2765
+ if (angle < 45 || angle > 315) {
2766
+ verticalAlign = 'bottom'; // top part
2767
+ } else if (angle > 135 && angle < 225) {
2768
+ verticalAlign = 'top'; // bottom part
2769
+ } else {
2770
+ verticalAlign = 'middle'; // left or right
2771
+ }
2772
+ options.verticalAlign = verticalAlign;
2773
+ }
2774
+
2775
+ seriesProto.alignDataLabel.call(this, point, dataLabel, options, alignTo, isNew);
2776
+ } else {
2777
+ proceed.call(this, point, dataLabel, options, alignTo, isNew);
2778
+ }
2779
+
2780
+ });
2781
+ }
2782
+
2783
+ /**
2784
+ * Extend getCoordinates to prepare for polar axis values
2785
+ */
2786
+ wrap(pointerProto, 'getCoordinates', function(proceed, e) {
2787
+ var chart = this.chart,
2788
+ ret = {
2789
+ xAxis: [],
2790
+ yAxis: []
2791
+ };
2792
+
2793
+ if (chart.polar) {
2794
+
2795
+ each(chart.axes, function(axis) {
2796
+ var isXAxis = axis.isXAxis,
2797
+ center = axis.center,
2798
+ x = e.chartX - center[0] - chart.plotLeft,
2799
+ y = e.chartY - center[1] - chart.plotTop;
2800
+
2801
+ ret[isXAxis ? 'xAxis' : 'yAxis'].push({
2802
+ axis: axis,
2803
+ value: axis.translate(
2804
+ isXAxis ?
2805
+ Math.PI - Math.atan2(x, y) : // angle
2806
+ Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)), // distance from center
2807
+ true
2808
+ )
2809
+ });
2810
+ });
2811
+
2812
+ } else {
2813
+ ret = proceed.call(this, e);
2814
+ }
2815
+
2816
+ return ret;
2817
+ });
2818
+
2819
+ }(Highcharts));
2820
+ }));