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