highcharts-rails 4.2.7 → 5.0.0

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