highcharts_rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }));