highcharts-rails 4.1.9 → 4.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,26 +1,44 @@
1
1
  /**
2
- * @license Highcharts JS v4.1.9 (2015-10-07)
2
+ * @license Highcharts JS v4.1.10 (2015-12-07)
3
3
  *
4
4
  * Standalone Highcharts Framework
5
5
  *
6
6
  * License: MIT License
7
7
  */
8
8
 
9
-
10
- /*global Highcharts */
11
- var HighchartsAdapter = (function () {
9
+ (function (root, factory) {
10
+ if (typeof module === 'object' && module.exports) {
11
+ module.exports = root.document ?
12
+ factory(root) :
13
+ function (w) {
14
+ return factory(w);
15
+ };
16
+ } else {
17
+ root.HighchartsAdapter = factory();
18
+ }
19
+ }(typeof window !== 'undefined' ? window : this, function (w) {
12
20
 
13
21
  var UNDEFINED,
14
- doc = document,
22
+ win = w || window,
23
+ doc = win.document,
15
24
  emptyArray = [],
25
+ _getStyle,
16
26
  timers = [],
17
27
  animSetters = {},
28
+ HighchartsAdapter,
18
29
  Fx;
19
30
 
20
31
  Math.easeInOutSine = function (t, b, c, d) {
21
32
  return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
22
33
  };
23
34
 
35
+ /**
36
+ * Internal method to return CSS value for given element and property
37
+ */
38
+ _getStyle = function (el, prop) {
39
+ var style = win.getComputedStyle(el, undefined);
40
+ return style && style.getPropertyValue(prop);
41
+ };
24
42
 
25
43
 
26
44
  /**
@@ -70,120 +88,118 @@ function augment(obj) {
70
88
  }
71
89
 
72
90
  if (!obj.HCExtended) {
73
- Highcharts.extend(obj, {
74
- HCExtended: true,
91
+ obj.HCExtended = true;
75
92
 
76
- HCEvents: {},
93
+ obj.HCEvents = {};
77
94
 
78
- bind: function (name, fn) {
79
- var el = this,
80
- events = this.HCEvents,
81
- wrappedFn;
95
+ obj.bind = function (name, fn) {
96
+ var el = this,
97
+ events = this.HCEvents,
98
+ wrappedFn;
82
99
 
83
- // handle DOM events in modern browsers
84
- if (el.addEventListener) {
85
- el.addEventListener(name, fn, false);
100
+ // handle DOM events in modern browsers
101
+ if (el.addEventListener) {
102
+ el.addEventListener(name, fn, false);
86
103
 
87
- // handle old IE implementation
88
- } else if (el.attachEvent) {
89
-
90
- wrappedFn = function (e) {
91
- e.target = e.srcElement || window; // #2820
92
- fn.call(el, e);
93
- };
104
+ // handle old IE implementation
105
+ } else if (el.attachEvent) {
106
+
107
+ wrappedFn = function (e) {
108
+ e.target = e.srcElement || win; // #2820
109
+ fn.call(el, e);
110
+ };
94
111
 
95
- if (!el.HCProxiedMethods) {
96
- el.HCProxiedMethods = {};
97
- }
112
+ if (!el.HCProxiedMethods) {
113
+ el.HCProxiedMethods = {};
114
+ }
98
115
 
99
- // link wrapped fn with original fn, so we can get this in removeEvent
100
- el.HCProxiedMethods[fn.toString()] = wrappedFn;
116
+ // link wrapped fn with original fn, so we can get this in removeEvent
117
+ el.HCProxiedMethods[fn.toString()] = wrappedFn;
101
118
 
102
- el.attachEvent('on' + name, wrappedFn);
103
- }
119
+ el.attachEvent('on' + name, wrappedFn);
120
+ }
104
121
 
105
122
 
106
- if (events[name] === UNDEFINED) {
107
- events[name] = [];
108
- }
123
+ if (events[name] === UNDEFINED) {
124
+ events[name] = [];
125
+ }
109
126
 
110
- events[name].push(fn);
111
- },
127
+ events[name].push(fn);
128
+ };
112
129
 
113
- unbind: function (name, fn) {
114
- var events,
115
- index;
116
-
117
- if (name) {
118
- events = this.HCEvents[name] || [];
119
- if (fn) {
120
- index = HighchartsAdapter.inArray(fn, events);
121
- if (index > -1) {
122
- events.splice(index, 1);
123
- this.HCEvents[name] = events;
124
- }
125
- if (this.removeEventListener) {
126
- removeOneEvent(this, name, fn);
127
- } else if (this.attachEvent) {
128
- IERemoveOneEvent(this, name, fn);
129
- }
130
- } else {
131
- removeAllEvents(this, name);
132
- this.HCEvents[name] = [];
130
+ obj.unbind = function (name, fn) {
131
+ var events,
132
+ index;
133
+
134
+ if (name) {
135
+ events = this.HCEvents[name] || [];
136
+ if (fn) {
137
+ index = HighchartsAdapter.inArray(fn, events);
138
+ if (index > -1) {
139
+ events.splice(index, 1);
140
+ this.HCEvents[name] = events;
141
+ }
142
+ if (this.removeEventListener) {
143
+ removeOneEvent(this, name, fn);
144
+ } else if (this.attachEvent) {
145
+ IERemoveOneEvent(this, name, fn);
133
146
  }
134
147
  } else {
135
- removeAllEvents(this);
136
- this.HCEvents = {};
148
+ removeAllEvents(this, name);
149
+ this.HCEvents[name] = [];
137
150
  }
138
- },
151
+ } else {
152
+ removeAllEvents(this);
153
+ this.HCEvents = {};
154
+ }
155
+ };
139
156
 
140
- trigger: function (name, args) {
141
- var events = this.HCEvents[name] || [],
142
- target = this,
143
- len = events.length,
144
- i,
145
- preventDefault,
146
- fn;
147
-
148
- // Attach a simple preventDefault function to skip default handler if called
149
- preventDefault = function () {
150
- args.defaultPrevented = true;
151
- };
152
-
153
- for (i = 0; i < len; i++) {
154
- fn = events[i];
157
+ obj.trigger = function (name, args) {
158
+ var events = this.HCEvents[name] || [],
159
+ target = this,
160
+ len = events.length,
161
+ i,
162
+ preventDefault,
163
+ fn;
164
+
165
+ // Attach a simple preventDefault function to skip default handler if called
166
+ preventDefault = function () {
167
+ args.defaultPrevented = true;
168
+ };
169
+
170
+ for (i = 0; i < len; i++) {
171
+ fn = events[i];
155
172
 
156
- // args is never null here
157
- if (args.stopped) {
158
- return;
159
- }
173
+ // args is never null here
174
+ if (args.stopped) {
175
+ return;
176
+ }
160
177
 
161
- args.preventDefault = preventDefault;
162
- args.target = target;
178
+ args.preventDefault = preventDefault;
179
+ args.target = target;
163
180
 
164
- // If the type is not set, we're running a custom event (#2297). If it is set,
165
- // we're running a browser event, and setting it will cause en error in
166
- // IE8 (#2465).
167
- if (!args.type) {
168
- args.type = name;
169
- }
170
-
181
+ // If the type is not set, we're running a custom event (#2297). If it is set,
182
+ // we're running a browser event, and setting it will cause en error in
183
+ // IE8 (#2465).
184
+ if (!args.type) {
185
+ args.type = name;
186
+ }
187
+
171
188
 
172
-
173
- // If the event handler return false, prevent the default handler from executing
174
- if (fn.call(this, args) === false) {
175
- args.preventDefault();
176
- }
189
+
190
+ // If the event handler return false, prevent the default handler from executing
191
+ if (fn.call(this, args) === false) {
192
+ args.preventDefault();
177
193
  }
178
194
  }
179
- });
195
+ };
180
196
  }
181
197
 
182
198
  return obj;
183
199
  }
184
200
 
185
201
 
186
- return {
202
+ HighchartsAdapter = {
187
203
 
188
204
  /**
189
205
  * Initialize the adapter. This is run once as Highcharts is first run.
@@ -195,34 +211,35 @@ return {
195
211
  * support is not needed.
196
212
  */
197
213
  if (!doc.defaultView) {
198
- this._getStyle = function (el, prop) {
214
+ _getStyle = function (el, prop) {
199
215
  var val;
200
216
  if (el.style[prop]) {
201
217
  return el.style[prop];
202
- } else {
203
- if (prop === 'opacity') {
204
- prop = 'filter';
205
- }
206
- /*jslint unparam: true*/
207
- val = el.currentStyle[prop.replace(/\-(\w)/g, function (a, b) { return b.toUpperCase(); })];
208
- if (prop === 'filter') {
209
- val = val.replace(
210
- /alpha\(opacity=([0-9]+)\)/,
211
- function (a, b) {
212
- return b / 100;
213
- }
214
- );
215
- }
216
- /*jslint unparam: false*/
217
- return val === '' ? 1 : val;
218
- }
218
+ }
219
+ if (prop === 'opacity') {
220
+ prop = 'filter';
221
+ }
222
+
223
+ val = el.currentStyle[prop.replace(/\-(\w)/g, function (a, b) {
224
+ return b.toUpperCase();
225
+ })];
226
+ if (prop === 'filter') {
227
+ val = val.replace(
228
+ /alpha\(opacity=([0-9]+)\)/,
229
+ function (a, b) {
230
+ return b / 100;
231
+ }
232
+ );
233
+ }
234
+
235
+ return val === '' ? 1 : val;
219
236
  };
220
237
  this.adapterRun = function (elem, method) {
221
238
  var alias = { width: 'clientWidth', height: 'clientHeight' }[method];
222
239
 
223
240
  if (alias) {
224
241
  elem.style.zoom = 1;
225
- return elem[alias] - 2 * parseInt(HighchartsAdapter._getStyle(elem, 'padding'), 10);
242
+ return elem[alias] - 2 * parseInt(_getStyle(elem, 'padding'), 10);
226
243
  }
227
244
  };
228
245
  }
@@ -259,13 +276,13 @@ return {
259
276
  }
260
277
 
261
278
  if (!Array.prototype.filter) {
262
- this.grep = function (elements, callback) {
279
+ this.grep = function (elements, fn) {
263
280
  var ret = [],
264
281
  i = 0,
265
282
  length = elements.length;
266
283
 
267
284
  for (; i < length; i++) {
268
- if (!!callback(elements[i], i)) {
285
+ if (!!fn(elements[i], i)) {
269
286
  ret.push(elements[i]);
270
287
  }
271
288
  }
@@ -291,7 +308,8 @@ return {
291
308
  var styles,
292
309
  paths = this.paths,
293
310
  elem = this.elem,
294
- elemelem = elem.element; // if destroyed, it is null
311
+ elemelem = elem.element,
312
+ prop; // if destroyed, it is null
295
313
 
296
314
  // Animation setter defined from outside
297
315
  if (animSetters[this.prop]) {
@@ -307,11 +325,13 @@ return {
307
325
  elem.attr(this.prop, this.now);
308
326
  }
309
327
 
310
- // HTML styles
328
+ // HTML styles, raw HTML content like container size
311
329
  } else {
312
330
  styles = {};
313
331
  styles[this.prop] = this.now + this.unit;
314
- Highcharts.css(elem, styles);
332
+ for (prop in styles) {
333
+ elem.style[prop] = styles[prop];
334
+ }
315
335
  }
316
336
 
317
337
  if (this.options.step) {
@@ -405,6 +425,7 @@ return {
405
425
  fx,
406
426
  args,
407
427
  name,
428
+ key,
408
429
  PX = 'px';
409
430
 
410
431
  if (typeof opt !== 'object' || opt === null) {
@@ -419,7 +440,10 @@ return {
419
440
  opt.duration = 400;
420
441
  }
421
442
  opt.easing = Math[opt.easing] || Math.easeInOutSine;
422
- opt.curAnim = Highcharts.extend({}, prop);
443
+ opt.curAnim = {};
444
+ for (key in prop) {
445
+ opt.curAnim[key] = prop[key];
446
+ }
423
447
 
424
448
  for (name in prop) {
425
449
  fx = new Fx(el, opt, name);
@@ -437,7 +461,7 @@ return {
437
461
  } else if (el.attr) {
438
462
  start = el.attr(name);
439
463
  } else {
440
- start = parseFloat(HighchartsAdapter._getStyle(el, name)) || 0;
464
+ start = parseFloat(_getStyle(el, name)) || 0;
441
465
  if (name !== 'opacity') {
442
466
  unit = PX;
443
467
  }
@@ -454,13 +478,6 @@ return {
454
478
  };
455
479
  },
456
480
 
457
- /**
458
- * Internal method to return CSS value for given element and property
459
- */
460
- _getStyle: function (el, prop) {
461
- return window.getComputedStyle(el, undefined).getPropertyValue(prop);
462
- },
463
-
464
481
  /**
465
482
  * Add an animation setter for a specific property
466
483
  */
@@ -497,7 +514,7 @@ return {
497
514
  * A direct link to adapter methods
498
515
  */
499
516
  adapterRun: function (elem, method) {
500
- return parseInt(HighchartsAdapter._getStyle(elem, method), 10);
517
+ return parseInt(_getStyle(elem, method), 10);
501
518
  },
502
519
 
503
520
  /**
@@ -528,8 +545,8 @@ return {
528
545
  box = el.getBoundingClientRect();
529
546
 
530
547
  return {
531
- top: box.top + (window.pageYOffset || docElem.scrollTop) - (docElem.clientTop || 0),
532
- left: box.left + (window.pageXOffset || docElem.scrollLeft) - (docElem.clientLeft || 0)
548
+ top: box.top + (win.pageYOffset || docElem.scrollTop) - (docElem.clientTop || 0),
549
+ left: box.left + (win.pageXOffset || docElem.scrollLeft) - (docElem.clientLeft || 0)
533
550
  };
534
551
  },
535
552
 
@@ -551,14 +568,17 @@ return {
551
568
  * Fire an event on a custom object
552
569
  */
553
570
  fireEvent: function (el, type, eventArguments, defaultFunction) {
554
- var e;
571
+ var e,
572
+ key;
555
573
 
556
574
  if (doc.createEvent && (el.dispatchEvent || el.fireEvent)) {
557
575
  e = doc.createEvent('Events');
558
576
  e.initEvent(type, true, true);
559
577
  e.target = el;
560
578
 
561
- Highcharts.extend(e, eventArguments);
579
+ for (key in eventArguments) {
580
+ e[key] = eventArguments[key];
581
+ }
562
582
 
563
583
  if (el.dispatchEvent) {
564
584
  el.dispatchEvent(e);
@@ -611,4 +631,5 @@ return {
611
631
  return Array.prototype.forEach.call(arr, fn);
612
632
  }
613
633
  };
614
- }());
634
+ return HighchartsAdapter;
635
+ }));
@@ -2,1569 +2,1710 @@
2
2
  // @compilation_level SIMPLE_OPTIMIZATIONS
3
3
 
4
4
  /**
5
- * @license Highcharts JS v4.1.9 (2015-10-07)
5
+ * @license Highcharts JS v4.1.10 (2015-12-07)
6
6
  *
7
- * (c) 2009-2013 Torstein Hønsi
7
+ * 3D features for Highcharts JS
8
8
  *
9
- * License: www.highcharts.com/license
9
+ * @license: www.highcharts.com/license
10
10
  */
11
11
 
12
- // JSLint options:
13
- /*global Highcharts, HighchartsAdapter, document, window, navigator, setInterval, clearInterval, clearTimeout, setTimeout, location, jQuery, $, console */
14
-
15
- (function (Highcharts) {
16
- /**
17
- Shorthands for often used function
18
- */
19
- /**
20
- * Mathematical Functionility
21
- */
22
- var PI = Math.PI,
23
- deg2rad = (PI / 180), // degrees to radians
24
- sin = Math.sin,
25
- cos = Math.cos,
26
- pick = Highcharts.pick,
27
- round = Math.round;
28
-
29
- /**
30
- * Transforms a given array of points according to the angles in chart.options.
31
- * Parameters:
32
- * - points: the array of points
33
- * - chart: the chart
34
- * - insidePlotArea: wether to verifiy the points are inside the plotArea
35
- * Returns:
36
- * - an array of transformed points
37
- */
38
- function perspective(points, chart, insidePlotArea) {
39
- var options3d = chart.options.chart.options3d,
40
- inverted = false,
41
- origin;
42
-
43
- if (insidePlotArea) {
44
- inverted = chart.inverted;
45
- origin = {
46
- x: chart.plotWidth / 2,
47
- y: chart.plotHeight / 2,
48
- z: options3d.depth / 2,
49
- vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
50
- };
51
- } else {
52
- origin = {
53
- x: chart.plotLeft + (chart.plotWidth / 2),
54
- y: chart.plotTop + (chart.plotHeight / 2),
55
- z: options3d.depth / 2,
56
- vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
57
- };
58
- }
59
-
60
- var result = [],
61
- xe = origin.x,
62
- ye = origin.y,
63
- ze = origin.z,
64
- vd = origin.vd,
65
- angle1 = deg2rad * (inverted ? options3d.beta : -options3d.beta),
66
- angle2 = deg2rad * (inverted ? -options3d.alpha : options3d.alpha),
67
- s1 = sin(angle1),
68
- c1 = cos(angle1),
69
- s2 = sin(angle2),
70
- c2 = cos(angle2);
71
-
72
- var x, y, z, px, py, pz;
73
-
74
- // Transform each point
75
- Highcharts.each(points, function (point) {
76
- x = (inverted ? point.y : point.x) - xe;
77
- y = (inverted ? point.x : point.y) - ye;
78
- z = (point.z || 0) - ze;
79
-
80
- //Apply 3-D rotation
81
- px = c1 * x - s1 * z;
82
- py = -s1 * s2 * x - c1 * s2 * z + c2 * y;
83
- pz = s1 * c2 * x + c1 * c2 * z + s2 * y;
84
-
85
- //Apply perspective
86
- if ((vd > 0) && (vd < Number.POSITIVE_INFINITY)) {
87
- px = px * (vd / (pz + ze + vd));
88
- py = py * (vd / (pz + ze + vd));
89
- }
90
-
91
- //Apply translation
92
- px = px + xe;
93
- py = py + ye;
94
- pz = pz + ze;
95
-
96
- result.push({
97
- x: (inverted ? py : px),
98
- y: (inverted ? px : py),
99
- z: pz
100
- });
101
- });
102
- return result;
103
- }
104
- // Make function acessible to plugins
105
- Highcharts.perspective = perspective;
106
- /***
107
- EXTENSION TO THE SVG-RENDERER TO ENABLE 3D SHAPES
108
- ***/
109
- ////// HELPER METHODS //////
110
- var dFactor = (4 * (Math.sqrt(2) - 1) / 3) / (PI / 2);
111
-
112
- function defined(obj) {
113
- return obj !== undefined && obj !== null;
114
- }
115
-
116
- //Shoelace algorithm -- http://en.wikipedia.org/wiki/Shoelace_formula
117
- function shapeArea(vertexes) {
118
- var area = 0,
119
- i,
120
- j;
121
- for (i = 0; i < vertexes.length; i++) {
122
- j = (i + 1) % vertexes.length;
123
- area += vertexes[i].x * vertexes[j].y - vertexes[j].x * vertexes[i].y;
124
- }
125
- return area / 2;
126
- }
127
-
128
- function averageZ(vertexes) {
129
- var z = 0,
130
- i;
131
- for (i = 0; i < vertexes.length; i++) {
132
- z += vertexes[i].z;
133
- }
134
- return vertexes.length ? z / vertexes.length : 0;
135
- }
136
-
137
- /** Method to construct a curved path
138
- * Can 'wrap' around more then 180 degrees
139
- */
140
- function curveTo(cx, cy, rx, ry, start, end, dx, dy) {
141
- var result = [];
142
- if ((end > start) && (end - start > PI / 2 + 0.0001)) {
143
- result = result.concat(curveTo(cx, cy, rx, ry, start, start + (PI / 2), dx, dy));
144
- result = result.concat(curveTo(cx, cy, rx, ry, start + (PI / 2), end, dx, dy));
145
- return result;
146
- } else if ((end < start) && (start - end > PI / 2 + 0.0001)) {
147
- result = result.concat(curveTo(cx, cy, rx, ry, start, start - (PI / 2), dx, dy));
148
- result = result.concat(curveTo(cx, cy, rx, ry, start - (PI / 2), end, dx, dy));
149
- return result;
150
- } else {
151
- var arcAngle = end - start;
152
- return [
153
- 'C',
154
- cx + (rx * cos(start)) - ((rx * dFactor * arcAngle) * sin(start)) + dx,
155
- cy + (ry * sin(start)) + ((ry * dFactor * arcAngle) * cos(start)) + dy,
156
- cx + (rx * cos(end)) + ((rx * dFactor * arcAngle) * sin(end)) + dx,
157
- cy + (ry * sin(end)) - ((ry * dFactor * arcAngle) * cos(end)) + dy,
158
-
159
- cx + (rx * cos(end)) + dx,
160
- cy + (ry * sin(end)) + dy
161
- ];
162
- }
163
- }
164
-
165
- Highcharts.SVGRenderer.prototype.toLinePath = function (points, closed) {
166
- var result = [];
167
-
168
- // Put "L x y" for each point
169
- Highcharts.each(points, function (point) {
170
- result.push('L', point.x, point.y);
171
- });
172
-
173
- if (points.length) {
174
- // Set the first element to M
175
- result[0] = 'M';
176
-
177
- // If it is a closed line, add Z
178
- if (closed) {
179
- result.push('Z');
180
- }
181
- }
182
-
183
- return result;
184
- };
185
-
186
- ////// CUBOIDS //////
187
- Highcharts.SVGRenderer.prototype.cuboid = function (shapeArgs) {
188
-
189
- var result = this.g(),
190
- paths = this.cuboidPath(shapeArgs);
191
-
192
- // create the 3 sides
193
- result.front = this.path(paths[0]).attr({zIndex: paths[3], 'stroke-linejoin': 'round'}).add(result);
194
- result.top = this.path(paths[1]).attr({zIndex: paths[4], 'stroke-linejoin': 'round'}).add(result);
195
- result.side = this.path(paths[2]).attr({zIndex: paths[5], 'stroke-linejoin': 'round'}).add(result);
196
-
197
- // apply the fill everywhere, the top a bit brighter, the side a bit darker
198
- result.fillSetter = function (color) {
199
- var c0 = color,
200
- c1 = Highcharts.Color(color).brighten(0.1).get(),
201
- c2 = Highcharts.Color(color).brighten(-0.1).get();
202
-
203
- this.front.attr({fill: c0});
204
- this.top.attr({fill: c1});
205
- this.side.attr({fill: c2});
206
-
207
- this.color = color;
208
- return this;
209
- };
210
-
211
- // apply opacaity everywhere
212
- result.opacitySetter = function (opacity) {
213
- this.front.attr({opacity: opacity});
214
- this.top.attr({opacity: opacity});
215
- this.side.attr({opacity: opacity});
216
- return this;
217
- };
218
-
219
- result.attr = function (args) {
220
- if (args.shapeArgs || defined(args.x)) {
221
- var shapeArgs = args.shapeArgs || args;
222
- var paths = this.renderer.cuboidPath(shapeArgs);
223
- this.front.attr({d: paths[0], zIndex: paths[3]});
224
- this.top.attr({d: paths[1], zIndex: paths[4]});
225
- this.side.attr({d: paths[2], zIndex: paths[5]});
226
- } else {
227
- Highcharts.SVGElement.prototype.attr.call(this, args);
228
- }
229
-
230
- return this;
231
- };
232
-
233
- result.animate = function (args, duration, complete) {
234
- if (defined(args.x) && defined(args.y)) {
235
- var paths = this.renderer.cuboidPath(args);
236
- this.front.attr({zIndex: paths[3]}).animate({d: paths[0]}, duration, complete);
237
- this.top.attr({zIndex: paths[4]}).animate({d: paths[1]}, duration, complete);
238
- this.side.attr({zIndex: paths[5]}).animate({d: paths[2]}, duration, complete);
239
- } else if (args.opacity) {
240
- this.front.animate(args, duration, complete);
241
- this.top.animate(args, duration, complete);
242
- this.side.animate(args, duration, complete);
243
- } else {
244
- Highcharts.SVGElement.prototype.animate.call(this, args, duration, complete);
245
- }
246
- return this;
247
- };
248
-
249
- // destroy all children
250
- result.destroy = function () {
251
- this.front.destroy();
252
- this.top.destroy();
253
- this.side.destroy();
254
-
255
- return null;
256
- };
257
-
258
- // Apply the Z index to the cuboid group
259
- result.attr({ zIndex: -paths[3] });
260
-
261
- return result;
262
- };
263
-
12
+ (function (factory) {
13
+ if (typeof module === 'object' && module.exports) {
14
+ module.exports = factory;
15
+ } else {
16
+ factory(Highcharts);
17
+ }
18
+ }(function (Highcharts) {
264
19
  /**
265
- * Generates a cuboid
266
- */
267
- Highcharts.SVGRenderer.prototype.cuboidPath = function (shapeArgs) {
268
- var x = shapeArgs.x,
269
- y = shapeArgs.y,
270
- z = shapeArgs.z,
271
- h = shapeArgs.height,
272
- w = shapeArgs.width,
273
- d = shapeArgs.depth,
274
- chart = Highcharts.charts[this.chartIndex],
275
- map = Highcharts.map;
276
-
277
- // The 8 corners of the cube
278
- var pArr = [
279
- {x: x, y: y, z: z},
280
- {x: x + w, y: y, z: z},
281
- {x: x + w, y: y + h, z: z},
282
- {x: x, y: y + h, z: z},
283
- {x: x, y: y + h, z: z + d},
284
- {x: x + w, y: y + h, z: z + d},
285
- {x: x + w, y: y, z: z + d},
286
- {x: x, y: y, z: z + d}
287
- ];
288
-
289
- // apply perspective
290
- pArr = perspective(pArr, chart, shapeArgs.insidePlotArea);
291
-
292
- // helper method to decide which side is visible
293
- var pickShape = function (path1, path2) {
294
- path1 = map(path1, function (i) { return pArr[i]; });
295
- path2 = map(path2, function (i) { return pArr[i]; });
296
- if (shapeArea(path1) < 0) {
297
- return path1;
298
- } else if (shapeArea(path2) < 0) {
299
- return path2;
300
- } else {
301
- return [];
302
- }
303
- };
304
-
305
- // front or back
306
- var front = [3, 2, 1, 0];
307
- var back = [7, 6, 5, 4];
308
- var path1 = pickShape(front, back);
309
-
310
- // top or bottom
311
- var top = [1, 6, 7, 0];
312
- var bottom = [4, 5, 2, 3];
313
- var path2 = pickShape(top, bottom);
314
-
315
- // side
316
- var right = [1, 2, 5, 6];
317
- var left = [0, 7, 4, 3];
318
- var path3 = pickShape(right, left);
319
-
320
- return [this.toLinePath(path1, true), this.toLinePath(path2, true), this.toLinePath(path3, true), averageZ(path1), averageZ(path2), averageZ(path3)];
321
- };
322
-
323
- ////// SECTORS //////
324
- Highcharts.SVGRenderer.prototype.arc3d = function (shapeArgs) {
325
-
326
- shapeArgs.alpha *= deg2rad;
327
- shapeArgs.beta *= deg2rad;
328
- var result = this.g(),
329
- paths = this.arc3dPath(shapeArgs),
330
- renderer = result.renderer;
331
-
332
- var zIndex = paths.zTop * 100;
333
-
334
- result.shapeArgs = shapeArgs; // Store for later use
335
-
336
- // create the different sub sections of the shape
337
- result.top = renderer.path(paths.top).setRadialReference(shapeArgs.center).attr({zIndex: paths.zTop}).add(result);
338
- result.side1 = renderer.path(paths.side2).attr({zIndex: paths.zSide1});
339
- result.side2 = renderer.path(paths.side1).attr({zIndex: paths.zSide2});
340
- result.inn = renderer.path(paths.inn).attr({zIndex: paths.zInn});
341
- result.out = renderer.path(paths.out).attr({zIndex: paths.zOut});
342
-
343
- // apply the fill to the top and a darker shade to the sides
344
- result.fillSetter = function (color) {
345
- this.color = color;
346
-
347
- var c0 = color,
348
- c2 = Highcharts.Color(color).brighten(-0.1).get();
349
-
350
- this.side1.attr({fill: c2});
351
- this.side2.attr({fill: c2});
352
- this.inn.attr({fill: c2});
353
- this.out.attr({fill: c2});
354
- this.top.attr({fill: c0});
355
- return this;
356
- };
357
-
358
- // apply the translation to all
359
- result.translateXSetter = function (value) {
360
- this.out.attr({translateX: value});
361
- this.inn.attr({translateX: value});
362
- this.side1.attr({translateX: value});
363
- this.side2.attr({translateX: value});
364
- this.top.attr({translateX: value});
365
- };
366
-
367
- result.translateYSetter = function (value) {
368
- this.out.attr({translateY: value});
369
- this.inn.attr({translateY: value});
370
- this.side1.attr({translateY: value});
371
- this.side2.attr({translateY: value});
372
- this.top.attr({translateY: value});
373
- };
374
-
375
- result.animate = function (args, duration, complete) {
376
- if (defined(args.end) || defined(args.start)) {
377
- this._shapeArgs = this.shapeArgs;
378
-
379
- Highcharts.SVGElement.prototype.animate.call(this, {
380
- _args: args
381
- }, {
382
- duration: duration,
383
- start: function () {
384
- var args = arguments,
385
- fx = args[0],
386
- elem = fx.elem,
387
- end = elem._shapeArgs;
388
-
389
- if (end.fill !== elem.color) {
390
- elem.attr({
391
- fill: end.fill
392
- });
393
- }
394
- },
395
- step: function () {
396
- var args = arguments,
397
- fx = args[1],
398
- result = fx.elem,
399
- start = result._shapeArgs,
400
- end = fx.end,
401
- pos = fx.pos,
402
- sA = Highcharts.merge(start, {
403
- x: start.x + ((end.x - start.x) * pos),
404
- y: start.y + ((end.y - start.y) * pos),
405
- r: start.r + ((end.r - start.r) * pos),
406
- innerR: start.innerR + ((end.innerR - start.innerR) * pos),
407
- start: start.start + ((end.start - start.start) * pos),
408
- end: start.end + ((end.end - start.end) * pos)
409
- });
410
-
411
- var paths = result.renderer.arc3dPath(sA);
412
-
413
- result.shapeArgs = sA;
414
-
415
- result.top.attr({d: paths.top, zIndex: paths.zTop});
416
- result.inn.attr({d: paths.inn, zIndex: paths.zInn});
417
- result.out.attr({d: paths.out, zIndex: paths.zOut});
418
- result.side1.attr({d: paths.side1, zIndex: paths.zSide1});
419
- result.side2.attr({d: paths.side2, zIndex: paths.zSide2});
420
-
421
- }
422
- }, complete);
423
- } else {
424
- Highcharts.SVGElement.prototype.animate.call(this, args, duration, complete);
425
- }
426
- return this;
427
- };
428
-
429
- // destroy all children
430
- result.destroy = function () {
431
- this.top.destroy();
432
- this.out.destroy();
433
- this.inn.destroy();
434
- this.side1.destroy();
435
- this.side2.destroy();
436
-
437
- Highcharts.SVGElement.prototype.destroy.call(this);
438
- };
439
- // hide all children
440
- result.hide = function () {
441
- this.top.hide();
442
- this.out.hide();
443
- this.inn.hide();
444
- this.side1.hide();
445
- this.side2.hide();
446
- };
447
- result.show = function () {
448
- this.top.show();
449
- this.out.show();
450
- this.inn.show();
451
- this.side1.show();
452
- this.side2.show();
453
- };
454
- // show all children
455
- result.zIndex = zIndex;
456
- result.attr({zIndex: zIndex});
457
- return result;
458
- };
459
-
460
- /**
461
- * Generate the paths required to draw a 3D arc
462
- */
463
- Highcharts.SVGRenderer.prototype.arc3dPath = function (shapeArgs) {
464
- var cx = shapeArgs.x, // x coordinate of the center
465
- cy = shapeArgs.y, // y coordinate of the center
466
- start = shapeArgs.start, // start angle
467
- end = shapeArgs.end - 0.00001, // end angle
468
- r = shapeArgs.r, // radius
469
- ir = shapeArgs.innerR, // inner radius
470
- d = shapeArgs.depth, // depth
471
- alpha = shapeArgs.alpha, // alpha rotation of the chart
472
- beta = shapeArgs.beta; // beta rotation of the chart
473
-
474
- // Derived Variables
475
- var cs = cos(start), // cosinus of the start angle
476
- ss = sin(start), // sinus of the start angle
477
- ce = cos(end), // cosinus of the end angle
478
- se = sin(end), // sinus of the end angle
479
- rx = r * cos(beta), // x-radius
480
- ry = r * cos(alpha), // y-radius
481
- irx = ir * cos(beta), // x-radius (inner)
482
- iry = ir * cos(alpha), // y-radius (inner)
483
- dx = d * sin(beta), // distance between top and bottom in x
484
- dy = d * sin(alpha); // distance between top and bottom in y
485
-
486
- // TOP
487
- var top = ['M', cx + (rx * cs), cy + (ry * ss)];
488
- top = top.concat(curveTo(cx, cy, rx, ry, start, end, 0, 0));
489
- top = top.concat([
490
- 'L', cx + (irx * ce), cy + (iry * se)
491
- ]);
492
- top = top.concat(curveTo(cx, cy, irx, iry, end, start, 0, 0));
493
- top = top.concat(['Z']);
494
-
495
- // OUTSIDE
496
- var b = (beta > 0 ? PI / 2 : 0),
497
- a = (alpha > 0 ? 0 : PI / 2);
498
-
499
- var start2 = start > -b ? start : (end > -b ? -b : start),
500
- end2 = end < PI - a ? end : (start < PI - a ? PI - a : end);
501
-
502
- var out = ['M', cx + (rx * cos(start2)), cy + (ry * sin(start2))];
503
- out = out.concat(curveTo(cx, cy, rx, ry, start2, end2, 0, 0));
504
-
505
- // When slice goes over middle, need to add both, left and right outer side:
506
- if (end > PI - a && start < PI - a) {
507
- // Go to outer side
508
- out = out.concat([
509
- 'L', cx + (rx * cos(end2)) + dx, cy + (ry * sin(end2)) + dy
510
- ]);
511
- // Curve to the true end of the slice
512
- out = out.concat(curveTo(cx, cy, rx, ry, end2, end, dx, dy));
513
- // Go to the inner side
514
- out = out.concat([
515
- 'L', cx + (rx * cos(end)), cy + (ry * sin(end))
516
- ]);
517
- // Go back to the artifical end2
518
- out = out.concat(curveTo(cx, cy, rx, ry, end, end2, 0, 0));
519
- }
520
-
521
- out = out.concat([
522
- 'L', cx + (rx * cos(end2)) + dx, cy + (ry * sin(end2)) + dy
523
- ]);
524
- out = out.concat(curveTo(cx, cy, rx, ry, end2, start2, dx, dy));
525
- out = out.concat(['Z']);
526
-
527
- // INSIDE
528
- var inn = ['M', cx + (irx * cs), cy + (iry * ss)];
529
- inn = inn.concat(curveTo(cx, cy, irx, iry, start, end, 0, 0));
530
- inn = inn.concat([
531
- 'L', cx + (irx * cos(end)) + dx, cy + (iry * sin(end)) + dy
532
- ]);
533
- inn = inn.concat(curveTo(cx, cy, irx, iry, end, start, dx, dy));
534
- inn = inn.concat(['Z']);
535
-
536
- // SIDES
537
- var side1 = [
538
- 'M', cx + (rx * cs), cy + (ry * ss),
539
- 'L', cx + (rx * cs) + dx, cy + (ry * ss) + dy,
540
- 'L', cx + (irx * cs) + dx, cy + (iry * ss) + dy,
541
- 'L', cx + (irx * cs), cy + (iry * ss),
542
- 'Z'
543
- ];
544
- var side2 = [
545
- 'M', cx + (rx * ce), cy + (ry * se),
546
- 'L', cx + (rx * ce) + dx, cy + (ry * se) + dy,
547
- 'L', cx + (irx * ce) + dx, cy + (iry * se) + dy,
548
- 'L', cx + (irx * ce), cy + (iry * se),
549
- 'Z'
550
- ];
551
-
552
- // correction for changed position of vanishing point caused by alpha and beta rotations
553
- var angleCorr = Math.atan2(dy, -dx),
554
- angleEnd = Math.abs(end + angleCorr),
555
- angleStart = Math.abs(start + angleCorr),
556
- angleMid = Math.abs((start + end) / 2 + angleCorr);
557
-
558
- // set to 0-PI range
559
- function toZeroPIRange(angle) {
560
- angle = angle % (2 * PI);
561
- if (angle > PI) {
562
- angle = 2 * PI - angle;
563
- }
564
- return angle;
565
- }
566
- angleEnd = toZeroPIRange(angleEnd);
567
- angleStart = toZeroPIRange(angleStart);
568
- angleMid = toZeroPIRange(angleMid);
569
-
570
- // *1e5 is to compensate pInt in zIndexSetter
571
- var incPrecision = 1e5,
572
- a1 = angleMid * incPrecision,
573
- a2 = angleStart * incPrecision,
574
- a3 = angleEnd * incPrecision;
575
-
576
- return {
577
- top: top,
578
- zTop: PI * incPrecision + 1, // max angle is PI, so this is allways higher
579
- out: out,
580
- zOut: Math.max(a1, a2, a3),
581
- inn: inn,
582
- zInn: Math.max(a1, a2, a3),
583
- side1: side1,
584
- zSide1: a3 * 0.99, // to keep below zOut and zInn in case of same values
585
- side2: side2,
586
- zSide2: a2 * 0.99
587
- };
588
- };
589
- /***
590
- EXTENSION FOR 3D CHARTS
591
- ***/
592
- // Shorthand to check the is3d flag
593
- Highcharts.Chart.prototype.is3d = function () {
594
- return this.options.chart.options3d && this.options.chart.options3d.enabled; // #4280
595
- };
596
-
597
- Highcharts.wrap(Highcharts.Chart.prototype, 'isInsidePlot', function (proceed) {
598
- if (this.is3d()) {
599
- return true;
600
- } else {
601
- return proceed.apply(this, [].slice.call(arguments, 1));
602
- }
603
- });
604
-
605
- var defaultChartOptions = Highcharts.getOptions();
606
- defaultChartOptions.chart.options3d = {
607
- enabled: false,
608
- alpha: 0,
609
- beta: 0,
610
- depth: 100,
611
- viewDistance: 25,
612
- frame: {
613
- bottom: { size: 1, color: 'rgba(255,255,255,0)' },
614
- side: { size: 1, color: 'rgba(255,255,255,0)' },
615
- back: { size: 1, color: 'rgba(255,255,255,0)' }
616
- }
617
- };
618
-
619
- Highcharts.wrap(Highcharts.Chart.prototype, 'init', function (proceed) {
620
- var args = [].slice.call(arguments, 1),
621
- plotOptions,
622
- pieOptions;
623
-
624
- if (args[0].chart.options3d && args[0].chart.options3d.enabled) {
625
- // Normalize alpha and beta to (-360, 360) range
626
- args[0].chart.options3d.alpha = (args[0].chart.options3d.alpha || 0) % 360;
627
- args[0].chart.options3d.beta = (args[0].chart.options3d.beta || 0) % 360;
628
-
629
- plotOptions = args[0].plotOptions || {};
630
- pieOptions = plotOptions.pie || {};
631
-
632
- pieOptions.borderColor = Highcharts.pick(pieOptions.borderColor, undefined);
633
- }
634
- proceed.apply(this, args);
635
- });
636
-
637
- Highcharts.wrap(Highcharts.Chart.prototype, 'setChartSize', function (proceed) {
638
- proceed.apply(this, [].slice.call(arguments, 1));
639
-
640
- if (this.is3d()) {
641
- var inverted = this.inverted,
642
- clipBox = this.clipBox,
643
- margin = this.margin,
644
- x = inverted ? 'y' : 'x',
645
- y = inverted ? 'x' : 'y',
646
- w = inverted ? 'height' : 'width',
647
- h = inverted ? 'width' : 'height';
648
-
649
- clipBox[x] = -(margin[3] || 0);
650
- clipBox[y] = -(margin[0] || 0);
651
- clipBox[w] = this.chartWidth + (margin[3] || 0) + (margin[1] || 0);
652
- clipBox[h] = this.chartHeight + (margin[0] || 0) + (margin[2] || 0);
653
- }
654
- });
655
-
656
- Highcharts.wrap(Highcharts.Chart.prototype, 'redraw', function (proceed) {
657
- if (this.is3d()) {
658
- // Set to force a redraw of all elements
659
- this.isDirtyBox = true;
660
- }
661
- proceed.apply(this, [].slice.call(arguments, 1));
662
- });
663
-
664
- // Draw the series in the reverse order (#3803, #3917)
665
- Highcharts.wrap(Highcharts.Chart.prototype, 'renderSeries', function (proceed) {
666
- var series,
667
- i = this.series.length;
668
-
669
- if (this.is3d()) {
670
- while (i--) {
671
- series = this.series[i];
672
- series.translate();
673
- series.render();
674
- }
675
- } else {
676
- proceed.call(this);
677
- }
678
- });
679
-
680
- Highcharts.Chart.prototype.retrieveStacks = function (stacking) {
681
- var series = this.series,
682
- stacks = {},
683
- stackNumber,
684
- i = 1;
685
-
686
- Highcharts.each(this.series, function (s) {
687
- stackNumber = pick(s.options.stack, (stacking ? 0 : series.length - 1 - s.index)); // #3841, #4532
688
- if (!stacks[stackNumber]) {
689
- stacks[stackNumber] = { series: [s], position: i};
690
- i++;
691
- } else {
692
- stacks[stackNumber].series.push(s);
693
- }
694
- });
695
-
696
- stacks.totalStacks = i + 1;
697
- return stacks;
698
- };
699
-
700
- /***
701
- EXTENSION TO THE AXIS
702
- ***/
703
- Highcharts.wrap(Highcharts.Axis.prototype, 'setOptions', function (proceed, userOptions) {
704
- var options;
705
- proceed.call(this, userOptions);
706
- if (this.chart.is3d()) {
707
- options = this.options;
708
- options.tickWidth = Highcharts.pick(options.tickWidth, 0);
709
- options.gridLineWidth = Highcharts.pick(options.gridLineWidth, 1);
710
- }
711
- });
712
-
713
- Highcharts.wrap(Highcharts.Axis.prototype, 'render', function (proceed) {
714
- proceed.apply(this, [].slice.call(arguments, 1));
715
-
716
- // Do not do this if the chart is not 3D
717
- if (!this.chart.is3d()) {
718
- return;
719
- }
720
-
721
- var chart = this.chart,
722
- renderer = chart.renderer,
723
- options3d = chart.options.chart.options3d,
724
- frame = options3d.frame,
725
- fbottom = frame.bottom,
726
- fback = frame.back,
727
- fside = frame.side,
728
- depth = options3d.depth,
729
- height = this.height,
730
- width = this.width,
731
- left = this.left,
732
- top = this.top;
733
-
734
- if (this.isZAxis) {
735
- return;
736
- } else if (this.horiz) {
737
- var bottomShape = {
738
- x: left,
739
- y: top + (chart.xAxis[0].opposite ? -fbottom.size : height),
740
- z: 0,
741
- width: width,
742
- height: fbottom.size,
743
- depth: depth,
744
- insidePlotArea: false
745
- };
746
- if (!this.bottomFrame) {
747
- this.bottomFrame = renderer.cuboid(bottomShape).attr({
748
- fill: fbottom.color,
749
- zIndex: (chart.yAxis[0].reversed && options3d.alpha > 0 ? 4 : -1)
750
- })
751
- .css({
752
- stroke: fbottom.color
753
- }).add();
754
- } else {
755
- this.bottomFrame.animate(bottomShape);
756
- }
757
- } else {
758
- // BACK
759
- var backShape = {
760
- x: left + (chart.yAxis[0].opposite ? 0 : -fside.size),
761
- y: top + (chart.xAxis[0].opposite ? -fbottom.size : 0),
762
- z: depth,
763
- width: width + fside.size,
764
- height: height + fbottom.size,
765
- depth: fback.size,
766
- insidePlotArea: false
767
- };
768
- if (!this.backFrame) {
769
- this.backFrame = renderer.cuboid(backShape).attr({
770
- fill: fback.color,
771
- zIndex: -3
772
- }).css({
773
- stroke: fback.color
774
- }).add();
775
- } else {
776
- this.backFrame.animate(backShape);
777
- }
778
- var sideShape = {
779
- x: left + (chart.yAxis[0].opposite ? width : -fside.size),
780
- y: top + (chart.xAxis[0].opposite ? -fbottom.size : 0),
781
- z: 0,
782
- width: fside.size,
783
- height: height + fbottom.size,
784
- depth: depth,
785
- insidePlotArea: false
786
- };
787
- if (!this.sideFrame) {
788
- this.sideFrame = renderer.cuboid(sideShape).attr({
789
- fill: fside.color,
790
- zIndex: -2
791
- }).css({
792
- stroke: fside.color
793
- }).add();
794
- } else {
795
- this.sideFrame.animate(sideShape);
796
- }
797
- }
798
- });
799
-
800
- Highcharts.wrap(Highcharts.Axis.prototype, 'getPlotLinePath', function (proceed) {
801
- var path = proceed.apply(this, [].slice.call(arguments, 1));
802
-
803
- // Do not do this if the chart is not 3D
804
- if (!this.chart.is3d()) {
805
- return path;
806
- }
807
-
808
- if (path === null) { return path; }
809
-
810
- var chart = this.chart,
811
- options3d = chart.options.chart.options3d;
812
-
813
- var d = this.isZAxis ? this.chart.plotWidth : options3d.depth,
814
- opposite = this.opposite;
815
- if (this.horiz) {
816
- opposite = !opposite;
817
- }
818
- var pArr = [
819
- this.swapZ({ x: path[1], y: path[2], z: (opposite ? d : 0)}),
820
- this.swapZ({ x: path[1], y: path[2], z: d }),
821
- this.swapZ({ x: path[4], y: path[5], z: d }),
822
- this.swapZ({ x: path[4], y: path[5], z: (opposite ? 0 : d)})
823
- ];
824
-
825
- pArr = perspective(pArr, this.chart, false);
826
- path = this.chart.renderer.toLinePath(pArr, false);
827
-
828
- return path;
829
- });
830
-
831
- // Do not draw axislines in 3D
832
- Highcharts.wrap(Highcharts.Axis.prototype, 'getLinePath', function (proceed) {
833
- return this.chart.is3d() ? [] : proceed.apply(this, [].slice.call(arguments, 1));
834
- });
835
-
836
- Highcharts.wrap(Highcharts.Axis.prototype, 'getPlotBandPath', function (proceed) {
837
- // Do not do this if the chart is not 3D
838
- if (!this.chart.is3d()) {
839
- return proceed.apply(this, [].slice.call(arguments, 1));
840
- } else {
841
- var args = arguments,
842
- from = args[1],
843
- to = args[2];
844
-
845
- var toPath = this.getPlotLinePath(to),
846
- path = this.getPlotLinePath(from);
847
-
848
- if (path && toPath) {
849
- path.push(
850
- 'L',
851
- toPath[10], // These two do not exist in the regular getPlotLine
852
- toPath[11], // ---- # 3005
853
- 'L',
854
- toPath[7],
855
- toPath[8],
856
- 'L',
857
- toPath[4],
858
- toPath[5],
859
- 'L',
860
- toPath[1],
861
- toPath[2]
862
- );
863
- } else { // outside the axis area
864
- path = null;
865
- }
866
-
867
- return path;
868
- }
869
- });
870
-
871
- /***
872
- EXTENSION TO THE TICKS
873
- ***/
874
-
875
- Highcharts.wrap(Highcharts.Tick.prototype, 'getMarkPath', function (proceed) {
876
- var path = proceed.apply(this, [].slice.call(arguments, 1));
877
-
878
- // Do not do this if the chart is not 3D
879
- if (!this.axis.chart.is3d()) {
880
- return path;
881
- }
882
-
883
- var pArr = [
884
- this.axis.swapZ({x: path[1], y: path[2], z: 0}),
885
- this.axis.swapZ({x: path[4], y: path[5], z: 0})
886
- ];
887
-
888
- pArr = perspective(pArr, this.axis.chart, false);
889
- path = [
890
- 'M', pArr[0].x, pArr[0].y,
891
- 'L', pArr[1].x, pArr[1].y
892
- ];
893
- return path;
894
- });
895
-
896
- Highcharts.wrap(Highcharts.Tick.prototype, 'getLabelPosition', function (proceed) {
897
- var pos = proceed.apply(this, [].slice.call(arguments, 1));
898
-
899
- // Do not do this if the chart is not 3D
900
- if (!this.axis.chart.is3d()) {
901
- return pos;
902
- }
903
-
904
- var new_pos = perspective([this.axis.swapZ({x: pos.x, y: pos.y, z: 0})], this.axis.chart, false)[0];
905
- new_pos.x = new_pos.x - (!this.axis.horiz && this.axis.opposite ? this.axis.transA : 0); //#3788
906
- new_pos.old = pos;
907
- return new_pos;
908
- });
909
-
910
- Highcharts.wrap(Highcharts.Tick.prototype, 'handleOverflow', function (proceed, xy) {
911
- if (this.axis.chart.is3d()) {
912
- xy = xy.old;
913
- }
914
- return proceed.call(this, xy);
915
- });
916
-
917
- Highcharts.wrap(Highcharts.Axis.prototype, 'getTitlePosition', function (proceed) {
918
- var pos = proceed.apply(this, [].slice.call(arguments, 1));
919
-
920
- // Do not do this if the chart is not 3D
921
- if (!this.chart.is3d()) {
922
- return pos;
923
- }
924
-
925
- pos = perspective([this.swapZ({x: pos.x, y: pos.y, z: 0})], this.chart, false)[0];
926
- return pos;
927
- });
928
-
929
- Highcharts.wrap(Highcharts.Axis.prototype, 'drawCrosshair', function (proceed) {
930
- var args = arguments;
931
- if (this.chart.is3d()) {
932
- if (args[2]) {
933
- args[2] = {
934
- plotX: args[2].plotXold || args[2].plotX,
935
- plotY: args[2].plotYold || args[2].plotY
936
- };
937
- }
938
- }
939
- proceed.apply(this, [].slice.call(args, 1));
940
- });
941
-
942
- /***
943
- Z-AXIS
944
- ***/
945
-
946
- Highcharts.Axis.prototype.swapZ = function (p, insidePlotArea) {
947
- if (this.isZAxis) {
948
- var plotLeft = insidePlotArea ? 0 : this.chart.plotLeft;
949
- var chart = this.chart;
950
- return {
951
- x: plotLeft + (chart.yAxis[0].opposite ? p.z : chart.xAxis[0].width - p.z),
952
- y: p.y,
953
- z: p.x - plotLeft
954
- };
955
- } else {
956
- return p;
957
- }
958
- };
959
-
960
- var ZAxis = Highcharts.ZAxis = function () {
961
- this.isZAxis = true;
962
- this.init.apply(this, arguments);
963
- };
964
- Highcharts.extend(ZAxis.prototype, Highcharts.Axis.prototype);
965
- Highcharts.extend(ZAxis.prototype, {
966
- setOptions: function (userOptions) {
967
- userOptions = Highcharts.merge({
968
- offset: 0,
969
- lineWidth: 0
970
- }, userOptions);
971
- Highcharts.Axis.prototype.setOptions.call(this, userOptions);
972
- this.coll = 'zAxis';
973
- },
974
- setAxisSize: function () {
975
- Highcharts.Axis.prototype.setAxisSize.call(this);
976
- this.width = this.len = this.chart.options.chart.options3d.depth;
977
- this.right = this.chart.chartWidth - this.width - this.left;
978
- },
979
- getSeriesExtremes: function () {
980
- var axis = this,
981
- chart = axis.chart;
982
-
983
- axis.hasVisibleSeries = false;
984
-
985
- // Reset properties in case we're redrawing (#3353)
986
- axis.dataMin = axis.dataMax = axis.ignoreMinPadding = axis.ignoreMaxPadding = null;
987
-
988
- if (axis.buildStacks) {
989
- axis.buildStacks();
990
- }
991
-
992
- // loop through this axis' series
993
- Highcharts.each(axis.series, function (series) {
994
-
995
- if (series.visible || !chart.options.chart.ignoreHiddenSeries) {
996
-
997
- var seriesOptions = series.options,
998
- zData,
999
- threshold = seriesOptions.threshold;
1000
-
1001
- axis.hasVisibleSeries = true;
1002
-
1003
- // Validate threshold in logarithmic axes
1004
- if (axis.isLog && threshold <= 0) {
1005
- threshold = null;
1006
- }
1007
-
1008
- zData = series.zData;
1009
- if (zData.length) {
1010
- axis.dataMin = Math.min(pick(axis.dataMin, zData[0]), Math.min.apply(null, zData));
1011
- axis.dataMax = Math.max(pick(axis.dataMax, zData[0]), Math.max.apply(null, zData));
1012
- }
1013
- }
1014
- });
1015
- }
1016
- });
1017
-
1018
-
1019
- /**
1020
- * Extend the chart getAxes method to also get the color axis
1021
- */
1022
- Highcharts.wrap(Highcharts.Chart.prototype, 'getAxes', function (proceed) {
1023
- var chart = this,
1024
- options = this.options,
1025
- zAxisOptions = options.zAxis = Highcharts.splat(options.zAxis || {});
1026
-
1027
- proceed.call(this);
1028
-
1029
- if (!chart.is3d()) {
1030
- return;
1031
- }
1032
- this.zAxis = [];
1033
- Highcharts.each(zAxisOptions, function (axisOptions, i) {
1034
- axisOptions.index = i;
1035
- axisOptions.isX = true; //Z-Axis is shown horizontally, so it's kind of a X-Axis
1036
- var zAxis = new ZAxis(chart, axisOptions);
1037
- zAxis.setScale();
1038
- });
1039
- });
1040
- /***
1041
- EXTENSION FOR 3D COLUMNS
1042
- ***/
1043
- Highcharts.wrap(Highcharts.seriesTypes.column.prototype, 'translate', function (proceed) {
1044
- proceed.apply(this, [].slice.call(arguments, 1));
1045
-
1046
- // Do not do this if the chart is not 3D
1047
- if (!this.chart.is3d()) {
1048
- return;
1049
- }
1050
-
1051
- var series = this,
1052
- chart = series.chart,
1053
- seriesOptions = series.options,
1054
- depth = seriesOptions.depth || 25;
1055
-
1056
- var stack = seriesOptions.stacking ? (seriesOptions.stack || 0) : series._i;
1057
- var z = stack * (depth + (seriesOptions.groupZPadding || 1));
1058
-
1059
- if (seriesOptions.grouping !== false) { z = 0; }
1060
-
1061
- z += (seriesOptions.groupZPadding || 1);
1062
-
1063
- Highcharts.each(series.data, function (point) {
1064
- if (point.y !== null) {
1065
- var shapeArgs = point.shapeArgs,
1066
- tooltipPos = point.tooltipPos;
1067
-
1068
- point.shapeType = 'cuboid';
1069
- shapeArgs.z = z;
1070
- shapeArgs.depth = depth;
1071
- shapeArgs.insidePlotArea = true;
1072
-
1073
- // Translate the tooltip position in 3d space
1074
- tooltipPos = perspective([{ x: tooltipPos[0], y: tooltipPos[1], z: z }], chart, false)[0];
1075
- point.tooltipPos = [tooltipPos.x, tooltipPos.y];
1076
- }
1077
- });
1078
- // store for later use #4067
1079
- series.z = z;
1080
- });
1081
-
1082
- Highcharts.wrap(Highcharts.seriesTypes.column.prototype, 'animate', function (proceed) {
1083
- if (!this.chart.is3d()) {
1084
- proceed.apply(this, [].slice.call(arguments, 1));
1085
- } else {
1086
- var args = arguments,
1087
- init = args[1],
1088
- yAxis = this.yAxis,
1089
- series = this,
1090
- reversed = this.yAxis.reversed;
1091
-
1092
- if (Highcharts.svg) { // VML is too slow anyway
1093
- if (init) {
1094
- Highcharts.each(series.data, function (point) {
1095
- if (point.y !== null) {
1096
- point.height = point.shapeArgs.height;
1097
- point.shapey = point.shapeArgs.y; //#2968
1098
- point.shapeArgs.height = 1;
1099
- if (!reversed) {
1100
- if (point.stackY) {
1101
- point.shapeArgs.y = point.plotY + yAxis.translate(point.stackY);
1102
- } else {
1103
- point.shapeArgs.y = point.plotY + (point.negative ? -point.height : point.height);
1104
- }
1105
- }
1106
- }
1107
- });
1108
-
1109
- } else { // run the animation
1110
- Highcharts.each(series.data, function (point) {
1111
- if (point.y !== null) {
1112
- point.shapeArgs.height = point.height;
1113
- point.shapeArgs.y = point.shapey; //#2968
1114
- // null value do not have a graphic
1115
- if (point.graphic) {
1116
- point.graphic.animate(point.shapeArgs, series.options.animation);
1117
- }
1118
- }
1119
- });
1120
-
1121
- // redraw datalabels to the correct position
1122
- this.drawDataLabels();
1123
-
1124
- // delete this function to allow it only once
1125
- series.animate = null;
1126
- }
1127
- }
1128
- }
1129
- });
1130
-
1131
- Highcharts.wrap(Highcharts.seriesTypes.column.prototype, 'init', function (proceed) {
1132
- proceed.apply(this, [].slice.call(arguments, 1));
1133
-
1134
- if (this.chart.is3d()) {
1135
- var seriesOptions = this.options,
1136
- grouping = seriesOptions.grouping,
1137
- stacking = seriesOptions.stacking,
1138
- z = 0;
1139
-
1140
- if (!(grouping !== undefined && !grouping)) {
1141
- var stacks = this.chart.retrieveStacks(stacking),
1142
- stack = seriesOptions.stack || 0,
1143
- i; // position within the stack
1144
- for (i = 0; i < stacks[stack].series.length; i++) {
1145
- if (stacks[stack].series[i] === this) {
1146
- break;
1147
- }
1148
- }
1149
- z = (stacks.totalStacks * 10) - (10 * (stacks.totalStacks - stacks[stack].position)) - i;
1150
- }
1151
-
1152
- seriesOptions.zIndex = z;
1153
- }
1154
- });
1155
- function draw3DPoints(proceed) {
1156
- // Do not do this if the chart is not 3D
1157
- if (this.chart.is3d()) {
1158
- var grouping = this.chart.options.plotOptions.column.grouping;
1159
- if (grouping !== undefined && !grouping && this.group.zIndex !== undefined && !this.zIndexSet) {
1160
- this.group.attr({zIndex : (this.group.zIndex * 10)});
1161
- this.zIndexSet = true; // #4062 set zindex only once
1162
- }
1163
-
1164
- var options = this.options,
1165
- states = this.options.states;
1166
-
1167
- this.borderWidth = options.borderWidth = defined(options.edgeWidth) ? options.edgeWidth : 1; //#4055
1168
-
1169
- Highcharts.each(this.data, function (point) {
1170
- if (point.y !== null) {
1171
- var pointAttr = point.pointAttr;
1172
-
1173
- // Set the border color to the fill color to provide a smooth edge
1174
- this.borderColor = Highcharts.pick(options.edgeColor, pointAttr[''].fill);
1175
-
1176
- pointAttr[''].stroke = this.borderColor;
1177
- pointAttr.hover.stroke = Highcharts.pick(states.hover.edgeColor, this.borderColor);
1178
- pointAttr.select.stroke = Highcharts.pick(states.select.edgeColor, this.borderColor);
1179
- }
1180
- });
1181
- }
1182
-
1183
- proceed.apply(this, [].slice.call(arguments, 1));
1184
- }
1185
-
1186
- Highcharts.wrap(Highcharts.Series.prototype, 'alignDataLabel', function (proceed) {
1187
-
1188
- // Only do this for 3D columns and columnranges
1189
- if (this.chart.is3d() && (this.type === 'column' || this.type === 'columnrange')) {
1190
- var series = this,
1191
- chart = series.chart;
1192
-
1193
- var args = arguments,
1194
- alignTo = args[4];
1195
-
1196
- var pos = ({x: alignTo.x, y: alignTo.y, z: series.z});
1197
- pos = perspective([pos], chart, true)[0];
1198
- alignTo.x = pos.x;
1199
- alignTo.y = pos.y;
1200
- }
1201
-
1202
- proceed.apply(this, [].slice.call(arguments, 1));
1203
- });
1204
-
1205
- if (Highcharts.seriesTypes.columnrange) {
1206
- Highcharts.wrap(Highcharts.seriesTypes.columnrange.prototype, 'drawPoints', draw3DPoints);
1207
- }
1208
-
1209
- Highcharts.wrap(Highcharts.seriesTypes.column.prototype, 'drawPoints', draw3DPoints);
1210
-
1211
- /***
1212
- EXTENSION FOR 3D CYLINDRICAL COLUMNS
1213
- Not supported
1214
- ***/
1215
- /*
1216
- var defaultOptions = Highcharts.getOptions();
1217
- defaultOptions.plotOptions.cylinder = Highcharts.merge(defaultOptions.plotOptions.column);
1218
- var CylinderSeries = Highcharts.extendClass(Highcharts.seriesTypes.column, {
1219
- type: 'cylinder'
1220
- });
1221
- Highcharts.seriesTypes.cylinder = CylinderSeries;
1222
-
1223
- Highcharts.wrap(Highcharts.seriesTypes.cylinder.prototype, 'translate', function (proceed) {
1224
- proceed.apply(this, [].slice.call(arguments, 1));
1225
-
1226
- // Do not do this if the chart is not 3D
1227
- if (!this.chart.is3d()) {
1228
- return;
1229
- }
1230
-
1231
- var series = this,
1232
- chart = series.chart,
1233
- options = chart.options,
1234
- cylOptions = options.plotOptions.cylinder,
1235
- options3d = options.chart.options3d,
1236
- depth = cylOptions.depth || 0,
1237
- origin = {
1238
- x: chart.inverted ? chart.plotHeight / 2 : chart.plotWidth / 2,
1239
- y: chart.inverted ? chart.plotWidth / 2 : chart.plotHeight / 2,
1240
- z: options3d.depth,
1241
- vd: options3d.viewDistance
1242
- },
1243
- alpha = options3d.alpha;
1244
-
1245
- var z = cylOptions.stacking ? (this.options.stack || 0) * depth : series._i * depth;
1246
- z += depth / 2;
1247
-
1248
- if (cylOptions.grouping !== false) { z = 0; }
1249
-
1250
- Highcharts.each(series.data, function (point) {
1251
- var shapeArgs = point.shapeArgs;
1252
- point.shapeType = 'arc3d';
1253
- shapeArgs.x += depth / 2;
1254
- shapeArgs.z = z;
1255
- shapeArgs.start = 0;
1256
- shapeArgs.end = 2 * PI;
1257
- shapeArgs.r = depth * 0.95;
1258
- shapeArgs.innerR = 0;
1259
- shapeArgs.depth = shapeArgs.height * (1 / sin((90 - alpha) * deg2rad)) - z;
1260
- shapeArgs.alpha = 90 - alpha;
1261
- shapeArgs.beta = 0;
1262
- shapeArgs.origin = origin;
1263
- });
1264
- });
1265
- *//***
1266
- EXTENSION FOR 3D PIES
1267
- ***/
1268
-
1269
- Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'translate', function (proceed) {
1270
- proceed.apply(this, [].slice.call(arguments, 1));
1271
-
1272
- // Do not do this if the chart is not 3D
1273
- if (!this.chart.is3d()) {
1274
- return;
1275
- }
1276
-
1277
- var series = this,
1278
- chart = series.chart,
1279
- options = chart.options,
1280
- seriesOptions = series.options,
1281
- depth = seriesOptions.depth || 0,
1282
- options3d = options.chart.options3d,
1283
- origin = {
1284
- x: chart.plotWidth / 2,
1285
- y: chart.plotHeight / 2,
1286
- z: options3d.depth
1287
- },
1288
- alpha = options3d.alpha,
1289
- beta = options3d.beta,
1290
- z = seriesOptions.stacking ? (seriesOptions.stack || 0) * depth : series._i * depth;
1291
-
1292
- z += depth / 2;
1293
-
1294
- if (seriesOptions.grouping !== false) { z = 0; }
1295
-
1296
- Highcharts.each(series.data, function (point) {
1297
-
1298
- var shapeArgs = point.shapeArgs,
1299
- angle;
1300
-
1301
- point.shapeType = 'arc3d';
1302
-
1303
- shapeArgs.z = z;
1304
- shapeArgs.depth = depth * 0.75;
1305
- shapeArgs.origin = origin;
1306
- shapeArgs.alpha = alpha;
1307
- shapeArgs.beta = beta;
1308
- shapeArgs.center = series.center;
1309
-
1310
- angle = (shapeArgs.end + shapeArgs.start) / 2;
1311
-
1312
- point.slicedTranslation = {
1313
- translateX : round(cos(angle) * seriesOptions.slicedOffset * cos(alpha * deg2rad)),
1314
- translateY : round(sin(angle) * seriesOptions.slicedOffset * cos(alpha * deg2rad))
1315
- };
1316
- });
1317
- });
1318
-
1319
- Highcharts.wrap(Highcharts.seriesTypes.pie.prototype.pointClass.prototype, 'haloPath', function (proceed) {
1320
- var args = arguments;
1321
- return this.series.chart.is3d() ? [] : proceed.call(this, args[1]);
1322
- });
1323
-
1324
- Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'drawPoints', function (proceed) {
1325
-
1326
- var seriesGroup = this.group,
1327
- options = this.options,
1328
- states = options.states;
1329
-
1330
- // Do not do this if the chart is not 3D
1331
- if (this.chart.is3d()) {
1332
- // Set the border color to the fill color to provide a smooth edge
1333
- this.borderWidth = options.borderWidth = options.edgeWidth || 1;
1334
- this.borderColor = options.edgeColor = Highcharts.pick(options.edgeColor, options.borderColor, undefined);
1335
-
1336
- states.hover.borderColor = Highcharts.pick(states.hover.edgeColor, this.borderColor);
1337
- states.hover.borderWidth = Highcharts.pick(states.hover.edgeWidth, this.borderWidth);
1338
- states.select.borderColor = Highcharts.pick(states.select.edgeColor, this.borderColor);
1339
- states.select.borderWidth = Highcharts.pick(states.select.edgeWidth, this.borderWidth);
1340
-
1341
- Highcharts.each(this.data, function (point) {
1342
- var pointAttr = point.pointAttr;
1343
- pointAttr[''].stroke = point.series.borderColor || point.color;
1344
- pointAttr['']['stroke-width'] = point.series.borderWidth;
1345
- pointAttr.hover.stroke = states.hover.borderColor;
1346
- pointAttr.hover['stroke-width'] = states.hover.borderWidth;
1347
- pointAttr.select.stroke = states.select.borderColor;
1348
- pointAttr.select['stroke-width'] = states.select.borderWidth;
1349
- });
1350
- }
1351
-
1352
- proceed.apply(this, [].slice.call(arguments, 1));
1353
-
1354
- if (this.chart.is3d()) {
1355
- Highcharts.each(this.points, function (point) {
1356
- var graphic = point.graphic;
1357
-
1358
- graphic.out.add(seriesGroup);
1359
- graphic.inn.add(seriesGroup);
1360
- graphic.side1.add(seriesGroup);
1361
- graphic.side2.add(seriesGroup);
1362
-
1363
- // Hide null or 0 points (#3006, 3650)
1364
- graphic[point.y ? 'show' : 'hide']();
1365
- });
1366
- }
1367
- });
1368
-
1369
- Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'drawDataLabels', function (proceed) {
1370
- if (this.chart.is3d()) {
1371
- var series = this;
1372
- Highcharts.each(series.data, function (point) {
1373
- var shapeArgs = point.shapeArgs,
1374
- r = shapeArgs.r,
1375
- d = shapeArgs.depth,
1376
- a1 = (shapeArgs.alpha || series.chart.options.chart.options3d.alpha) * deg2rad, //#3240 issue with datalabels for 0 and null values
1377
- a2 = (shapeArgs.start + shapeArgs.end) / 2,
1378
- labelPos = point.labelPos;
1379
-
1380
- labelPos[1] += (-r * (1 - cos(a1)) * sin(a2)) + (sin(a2) > 0 ? sin(a1) * d : 0);
1381
- labelPos[3] += (-r * (1 - cos(a1)) * sin(a2)) + (sin(a2) > 0 ? sin(a1) * d : 0);
1382
- labelPos[5] += (-r * (1 - cos(a1)) * sin(a2)) + (sin(a2) > 0 ? sin(a1) * d : 0);
1383
-
1384
- });
1385
- }
1386
-
1387
- proceed.apply(this, [].slice.call(arguments, 1));
1388
- });
1389
-
1390
- Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'addPoint', function (proceed) {
1391
- proceed.apply(this, [].slice.call(arguments, 1));
1392
- if (this.chart.is3d()) {
1393
- // destroy (and rebuild) everything!!!
1394
- this.update(this.userOptions, true); // #3845 pass the old options
1395
- }
1396
- });
1397
-
1398
- Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'animate', function (proceed) {
1399
- if (!this.chart.is3d()) {
1400
- proceed.apply(this, [].slice.call(arguments, 1));
1401
- } else {
1402
- var args = arguments,
1403
- init = args[1],
1404
- animation = this.options.animation,
1405
- attribs,
1406
- center = this.center,
1407
- group = this.group,
1408
- markerGroup = this.markerGroup;
1409
-
1410
- if (Highcharts.svg) { // VML is too slow anyway
1411
-
1412
- if (animation === true) {
1413
- animation = {};
1414
- }
1415
- // Initialize the animation
1416
- if (init) {
1417
-
1418
- // Scale down the group and place it in the center
1419
- group.oldtranslateX = group.translateX;
1420
- group.oldtranslateY = group.translateY;
1421
- attribs = {
1422
- translateX: center[0],
1423
- translateY: center[1],
1424
- scaleX: 0.001, // #1499
1425
- scaleY: 0.001
1426
- };
1427
-
1428
- group.attr(attribs);
1429
- if (markerGroup) {
1430
- markerGroup.attrSetters = group.attrSetters;
1431
- markerGroup.attr(attribs);
1432
- }
1433
-
1434
- // Run the animation
1435
- } else {
1436
- attribs = {
1437
- translateX: group.oldtranslateX,
1438
- translateY: group.oldtranslateY,
1439
- scaleX: 1,
1440
- scaleY: 1
1441
- };
1442
- group.animate(attribs, animation);
1443
-
1444
- if (markerGroup) {
1445
- markerGroup.animate(attribs, animation);
1446
- }
1447
-
1448
- // Delete this function to allow it only once
1449
- this.animate = null;
1450
- }
1451
-
1452
- }
1453
- }
1454
- });/***
1455
- EXTENSION FOR 3D SCATTER CHART
1456
- ***/
1457
-
1458
- Highcharts.wrap(Highcharts.seriesTypes.scatter.prototype, 'translate', function (proceed) {
1459
- //function translate3d(proceed) {
1460
- proceed.apply(this, [].slice.call(arguments, 1));
1461
-
1462
- if (!this.chart.is3d()) {
1463
- return;
1464
- }
1465
-
1466
- var series = this,
1467
- chart = series.chart,
1468
- zAxis = Highcharts.pick(series.zAxis, chart.options.zAxis[0]),
1469
- rawPoints = [],
1470
- rawPoint,
1471
- projectedPoints,
1472
- projectedPoint,
1473
- zValue,
1474
- i;
1475
-
1476
- for (i = 0; i < series.data.length; i++) {
1477
- rawPoint = series.data[i];
1478
- zValue = zAxis.isLog && zAxis.val2lin ? zAxis.val2lin(rawPoint.z) : rawPoint.z; // #4562
1479
- rawPoint.plotZ = zAxis.translate(zValue);
1480
-
1481
- rawPoint.isInside = rawPoint.isInside ? (zValue >= zAxis.min && zValue <= zAxis.max) : false;
1482
-
1483
- rawPoints.push({
1484
- x: rawPoint.plotX,
1485
- y: rawPoint.plotY,
1486
- z: rawPoint.plotZ
1487
- });
1488
- }
1489
-
1490
- projectedPoints = perspective(rawPoints, chart, true);
1491
-
1492
- for (i = 0; i < series.data.length; i++) {
1493
- rawPoint = series.data[i];
1494
- projectedPoint = projectedPoints[i];
1495
-
1496
- rawPoint.plotXold = rawPoint.plotX;
1497
- rawPoint.plotYold = rawPoint.plotY;
1498
-
1499
- rawPoint.plotX = projectedPoint.x;
1500
- rawPoint.plotY = projectedPoint.y;
1501
- rawPoint.plotZ = projectedPoint.z;
1502
-
1503
-
1504
- }
1505
-
1506
- });
1507
-
1508
- Highcharts.wrap(Highcharts.seriesTypes.scatter.prototype, 'init', function (proceed, chart, options) {
1509
- if (chart.is3d()) {
1510
- // add a third coordinate
1511
- this.axisTypes = ['xAxis', 'yAxis', 'zAxis'];
1512
- this.pointArrayMap = ['x', 'y', 'z'];
1513
- this.parallelArrays = ['x', 'y', 'z'];
1514
- }
1515
-
1516
- var result = proceed.apply(this, [chart, options]);
1517
-
1518
- if (this.chart.is3d()) {
1519
- // Set a new default tooltip formatter
1520
- var default3dScatterTooltip = 'x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>z: <b>{point.z}</b><br/>';
1521
- if (this.userOptions.tooltip) {
1522
- this.tooltipOptions.pointFormat = this.userOptions.tooltip.pointFormat || default3dScatterTooltip;
1523
- } else {
1524
- this.tooltipOptions.pointFormat = default3dScatterTooltip;
1525
- }
1526
- }
1527
- return result;
1528
- });
1529
- /**
1530
- * Extension to the VML Renderer
1531
- */
1532
- if (Highcharts.VMLRenderer) {
1533
-
1534
- Highcharts.setOptions({animate: false});
1535
-
1536
- Highcharts.VMLRenderer.prototype.cuboid = Highcharts.SVGRenderer.prototype.cuboid;
1537
- Highcharts.VMLRenderer.prototype.cuboidPath = Highcharts.SVGRenderer.prototype.cuboidPath;
1538
-
1539
- Highcharts.VMLRenderer.prototype.toLinePath = Highcharts.SVGRenderer.prototype.toLinePath;
1540
-
1541
- Highcharts.VMLRenderer.prototype.createElement3D = Highcharts.SVGRenderer.prototype.createElement3D;
1542
-
1543
- Highcharts.VMLRenderer.prototype.arc3d = function (shapeArgs) {
1544
- var result = Highcharts.SVGRenderer.prototype.arc3d.call(this, shapeArgs);
1545
- result.css({zIndex: result.zIndex});
1546
- return result;
1547
- };
1548
-
1549
- Highcharts.VMLRenderer.prototype.arc3dPath = Highcharts.SVGRenderer.prototype.arc3dPath;
1550
-
1551
- Highcharts.wrap(Highcharts.Axis.prototype, 'render', function (proceed) {
1552
- proceed.apply(this, [].slice.call(arguments, 1));
1553
- // VML doesn't support a negative z-index
1554
- if (this.sideFrame) {
1555
- this.sideFrame.css({zIndex: 0});
1556
- this.sideFrame.front.attr({fill: this.sideFrame.color});
1557
- }
1558
- if (this.bottomFrame) {
1559
- this.bottomFrame.css({zIndex: 1});
1560
- this.bottomFrame.front.attr({fill: this.bottomFrame.color});
1561
- }
1562
- if (this.backFrame) {
1563
- this.backFrame.css({zIndex: 0});
1564
- this.backFrame.front.attr({fill: this.backFrame.color});
1565
- }
1566
- });
1567
-
1568
- }
1569
-
1570
- }(Highcharts));
20
+ Shorthands for often used function
21
+ */
22
+ var each = Highcharts.each,
23
+ extend = Highcharts.extend,
24
+ inArray = Highcharts.inArray,
25
+ merge = Highcharts.merge,
26
+ pick = Highcharts.pick,
27
+ wrap = Highcharts.wrap;
28
+ /**
29
+ * Mathematical Functionility
30
+ */
31
+ var PI = Math.PI,
32
+ deg2rad = (PI / 180), // degrees to radians
33
+ sin = Math.sin,
34
+ cos = Math.cos,
35
+ round = Math.round;
36
+
37
+ /**
38
+ * Transforms a given array of points according to the angles in chart.options.
39
+ * Parameters:
40
+ * - points: the array of points
41
+ * - chart: the chart
42
+ * - insidePlotArea: wether to verifiy the points are inside the plotArea
43
+ * Returns:
44
+ * - an array of transformed points
45
+ */
46
+ function perspective(points, chart, insidePlotArea) {
47
+ var options3d = chart.options.chart.options3d,
48
+ inverted = false,
49
+ origin;
50
+
51
+ if (insidePlotArea) {
52
+ inverted = chart.inverted;
53
+ origin = {
54
+ x: chart.plotWidth / 2,
55
+ y: chart.plotHeight / 2,
56
+ z: options3d.depth / 2,
57
+ vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
58
+ };
59
+ } else {
60
+ origin = {
61
+ x: chart.plotLeft + (chart.plotWidth / 2),
62
+ y: chart.plotTop + (chart.plotHeight / 2),
63
+ z: options3d.depth / 2,
64
+ vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
65
+ };
66
+ }
67
+
68
+ var result = [],
69
+ xe = origin.x,
70
+ ye = origin.y,
71
+ ze = origin.z,
72
+ vd = origin.vd,
73
+ angle1 = deg2rad * (inverted ? options3d.beta : -options3d.beta),
74
+ angle2 = deg2rad * (inverted ? -options3d.alpha : options3d.alpha),
75
+ s1 = sin(angle1),
76
+ c1 = cos(angle1),
77
+ s2 = sin(angle2),
78
+ c2 = cos(angle2);
79
+
80
+ var x, y, z, px, py, pz;
81
+
82
+ // Transform each point
83
+ each(points, function (point) {
84
+ x = (inverted ? point.y : point.x) - xe;
85
+ y = (inverted ? point.x : point.y) - ye;
86
+ z = (point.z || 0) - ze;
87
+
88
+ // Apply 3-D rotation
89
+ // Euler Angles (XYZ): cosA = cos(Alfa|Roll), cosB = cos(Beta|Pitch), cosG = cos(Gamma|Yaw)
90
+ //
91
+ // Composite rotation:
92
+ // | cosB * cosG | cosB * sinG | -sinB |
93
+ // | sinA * sinB * cosG - cosA * sinG | sinA * sinB * sinG + cosA * cosG | sinA * cosB |
94
+ // | cosA * sinB * cosG + sinA * sinG | cosA * sinB * sinG - sinA * cosG | cosA * cosB |
95
+ //
96
+ // Now, Gamma/Yaw is not used (angle=0), so we assume cosG = 1 and sinG = 0, so we get:
97
+ // | cosB | 0 | - sinB |
98
+ // | sinA * sinB | cosA | sinA * cosB |
99
+ // | cosA * sinB | - sinA | cosA * cosB |
100
+ //
101
+ // But in browsers, y is reversed, so we get sinA => -sinA. The general result is:
102
+ // | cosB | 0 | - sinB | | x | | px |
103
+ // | - sinA * sinB | cosA | - sinA * cosB | x | y | = | py |
104
+ // | cosA * sinB | sinA | cosA * cosB | | z | | pz |
105
+ //
106
+ // Result:
107
+ px = c1 * x - s1 * z;
108
+ py = -s1 * s2 * x + c2 * y - c1 * s2 * z;
109
+ pz = s1 * c2 * x + s2 * y + c1 * c2 * z;
110
+
111
+
112
+ // Apply perspective
113
+ if ((vd > 0) && (vd < Number.POSITIVE_INFINITY)) {
114
+ px = px * (vd / (pz + ze + vd));
115
+ py = py * (vd / (pz + ze + vd));
116
+ }
117
+
118
+ //Apply translation
119
+ px = px + xe;
120
+ py = py + ye;
121
+ pz = pz + ze;
122
+
123
+ result.push({
124
+ x: (inverted ? py : px),
125
+ y: (inverted ? px : py),
126
+ z: pz
127
+ });
128
+ });
129
+ return result;
130
+ }
131
+ // Make function acessible to plugins
132
+ Highcharts.perspective = perspective;
133
+ /***
134
+ EXTENSION TO THE SVG-RENDERER TO ENABLE 3D SHAPES
135
+ ***/
136
+ ////// HELPER METHODS //////
137
+
138
+ var dFactor = (4 * (Math.sqrt(2) - 1) / 3) / (PI / 2);
139
+
140
+ function defined(obj) {
141
+ return obj !== undefined && obj !== null;
142
+ }
143
+
144
+ //Shoelace algorithm -- http://en.wikipedia.org/wiki/Shoelace_formula
145
+ function shapeArea(vertexes) {
146
+ var area = 0,
147
+ i,
148
+ j;
149
+ for (i = 0; i < vertexes.length; i++) {
150
+ j = (i + 1) % vertexes.length;
151
+ area += vertexes[i].x * vertexes[j].y - vertexes[j].x * vertexes[i].y;
152
+ }
153
+ return area / 2;
154
+ }
155
+
156
+ function averageZ(vertexes) {
157
+ var z = 0,
158
+ i;
159
+ for (i = 0; i < vertexes.length; i++) {
160
+ z += vertexes[i].z;
161
+ }
162
+ return vertexes.length ? z / vertexes.length : 0;
163
+ }
164
+
165
+ /** Method to construct a curved path
166
+ * Can 'wrap' around more then 180 degrees
167
+ */
168
+ function curveTo(cx, cy, rx, ry, start, end, dx, dy) {
169
+ var result = [];
170
+ if ((end > start) && (end - start > PI / 2 + 0.0001)) {
171
+ result = result.concat(curveTo(cx, cy, rx, ry, start, start + (PI / 2), dx, dy));
172
+ result = result.concat(curveTo(cx, cy, rx, ry, start + (PI / 2), end, dx, dy));
173
+ } else if ((end < start) && (start - end > PI / 2 + 0.0001)) {
174
+ result = result.concat(curveTo(cx, cy, rx, ry, start, start - (PI / 2), dx, dy));
175
+ result = result.concat(curveTo(cx, cy, rx, ry, start - (PI / 2), end, dx, dy));
176
+ } else {
177
+ var arcAngle = end - start;
178
+ result = [
179
+ 'C',
180
+ cx + (rx * cos(start)) - ((rx * dFactor * arcAngle) * sin(start)) + dx,
181
+ cy + (ry * sin(start)) + ((ry * dFactor * arcAngle) * cos(start)) + dy,
182
+ cx + (rx * cos(end)) + ((rx * dFactor * arcAngle) * sin(end)) + dx,
183
+ cy + (ry * sin(end)) - ((ry * dFactor * arcAngle) * cos(end)) + dy,
184
+
185
+ cx + (rx * cos(end)) + dx,
186
+ cy + (ry * sin(end)) + dy
187
+ ];
188
+ }
189
+ return result;
190
+ }
191
+
192
+ Highcharts.SVGRenderer.prototype.toLinePath = function (points, closed) {
193
+ var result = [];
194
+
195
+ // Put "L x y" for each point
196
+ Highcharts.each(points, function (point) {
197
+ result.push('L', point.x, point.y);
198
+ });
199
+
200
+ if (points.length) {
201
+ // Set the first element to M
202
+ result[0] = 'M';
203
+
204
+ // If it is a closed line, add Z
205
+ if (closed) {
206
+ result.push('Z');
207
+ }
208
+ }
209
+
210
+ return result;
211
+ };
212
+
213
+ ////// CUBOIDS //////
214
+ Highcharts.SVGRenderer.prototype.cuboid = function (shapeArgs) {
215
+
216
+ var result = this.g(),
217
+ paths = this.cuboidPath(shapeArgs);
218
+
219
+ // create the 3 sides
220
+ result.front = this.path(paths[0]).attr({ zIndex: paths[3], 'stroke-linejoin': 'round' }).add(result);
221
+ result.top = this.path(paths[1]).attr({ zIndex: paths[4], 'stroke-linejoin': 'round' }).add(result);
222
+ result.side = this.path(paths[2]).attr({ zIndex: paths[5], 'stroke-linejoin': 'round' }).add(result);
223
+
224
+ // apply the fill everywhere, the top a bit brighter, the side a bit darker
225
+ result.fillSetter = function (color) {
226
+ var c0 = color,
227
+ c1 = Highcharts.Color(color).brighten(0.1).get(),
228
+ c2 = Highcharts.Color(color).brighten(-0.1).get();
229
+
230
+ this.front.attr({ fill: c0 });
231
+ this.top.attr({ fill: c1 });
232
+ this.side.attr({ fill: c2 });
233
+
234
+ this.color = color;
235
+ return this;
236
+ };
237
+
238
+ // apply opacaity everywhere
239
+ result.opacitySetter = function (opacity) {
240
+ this.front.attr({ opacity: opacity });
241
+ this.top.attr({ opacity: opacity });
242
+ this.side.attr({ opacity: opacity });
243
+ return this;
244
+ };
245
+
246
+ result.attr = function (args) {
247
+ if (args.shapeArgs || defined(args.x)) {
248
+ var shapeArgs = args.shapeArgs || args;
249
+ var paths = this.renderer.cuboidPath(shapeArgs);
250
+ this.front.attr({ d: paths[0], zIndex: paths[3] });
251
+ this.top.attr({ d: paths[1], zIndex: paths[4] });
252
+ this.side.attr({ d: paths[2], zIndex: paths[5] });
253
+ } else {
254
+ Highcharts.SVGElement.prototype.attr.call(this, args);
255
+ }
256
+
257
+ return this;
258
+ };
259
+
260
+ result.animate = function (args, duration, complete) {
261
+ if (defined(args.x) && defined(args.y)) {
262
+ var paths = this.renderer.cuboidPath(args);
263
+ this.front.attr({ zIndex: paths[3] }).animate({ d: paths[0] }, duration, complete);
264
+ this.top.attr({ zIndex: paths[4] }).animate({ d: paths[1] }, duration, complete);
265
+ this.side.attr({ zIndex: paths[5] }).animate({ d: paths[2] }, duration, complete);
266
+ } else if (args.opacity) {
267
+ this.front.animate(args, duration, complete);
268
+ this.top.animate(args, duration, complete);
269
+ this.side.animate(args, duration, complete);
270
+ } else {
271
+ Highcharts.SVGElement.prototype.animate.call(this, args, duration, complete);
272
+ }
273
+ return this;
274
+ };
275
+
276
+ // destroy all children
277
+ result.destroy = function () {
278
+ this.front.destroy();
279
+ this.top.destroy();
280
+ this.side.destroy();
281
+
282
+ return null;
283
+ };
284
+
285
+ // Apply the Z index to the cuboid group
286
+ result.attr({ zIndex: -paths[3] });
287
+
288
+ return result;
289
+ };
290
+
291
+ /**
292
+ * Generates a cuboid
293
+ */
294
+ Highcharts.SVGRenderer.prototype.cuboidPath = function (shapeArgs) {
295
+ var x = shapeArgs.x,
296
+ y = shapeArgs.y,
297
+ z = shapeArgs.z,
298
+ h = shapeArgs.height,
299
+ w = shapeArgs.width,
300
+ d = shapeArgs.depth,
301
+ chart = Highcharts.charts[this.chartIndex],
302
+ map = Highcharts.map;
303
+
304
+ // The 8 corners of the cube
305
+ var pArr = [
306
+ { x: x, y: y, z: z },
307
+ { x: x + w, y: y, z: z },
308
+ { x: x + w, y: y + h, z: z },
309
+ { x: x, y: y + h, z: z },
310
+ { x: x, y: y + h, z: z + d },
311
+ { x: x + w, y: y + h, z: z + d },
312
+ { x: x + w, y: y, z: z + d },
313
+ { x: x, y: y, z: z + d }
314
+ ];
315
+
316
+ // apply perspective
317
+ pArr = perspective(pArr, chart, shapeArgs.insidePlotArea);
318
+
319
+ // helper method to decide which side is visible
320
+ function mapPath(i) {
321
+ return pArr[i];
322
+ }
323
+ var pickShape = function (path1, path2) {
324
+ var ret;
325
+ path1 = map(path1, mapPath);
326
+ path2 = map(path2, mapPath);
327
+ if (shapeArea(path1) < 0) {
328
+ ret = path1;
329
+ } else if (shapeArea(path2) < 0) {
330
+ ret = path2;
331
+ } else {
332
+ ret = [];
333
+ }
334
+ return ret;
335
+ };
336
+
337
+ // front or back
338
+ var front = [3, 2, 1, 0];
339
+ var back = [7, 6, 5, 4];
340
+ var path1 = pickShape(front, back);
341
+
342
+ // top or bottom
343
+ var top = [1, 6, 7, 0];
344
+ var bottom = [4, 5, 2, 3];
345
+ var path2 = pickShape(top, bottom);
346
+
347
+ // side
348
+ var right = [1, 2, 5, 6];
349
+ var left = [0, 7, 4, 3];
350
+ var path3 = pickShape(right, left);
351
+
352
+ return [this.toLinePath(path1, true), this.toLinePath(path2, true), this.toLinePath(path3, true), averageZ(path1), averageZ(path2), averageZ(path3)];
353
+ };
354
+
355
+ ////// SECTORS //////
356
+ Highcharts.SVGRenderer.prototype.arc3d = function (attribs) {
357
+
358
+ var wrapper = this.g(),
359
+ renderer = wrapper.renderer,
360
+ customAttribs = ['x', 'y', 'r', 'innerR', 'start', 'end'];
361
+
362
+ /**
363
+ * Get custom attributes. Mutate the original object and return an object with only custom attr.
364
+ */
365
+ function suckOutCustom(params) {
366
+ var hasCA = false,
367
+ ca = {};
368
+ for (var key in params) {
369
+ if (inArray(key, customAttribs) !== -1) {
370
+ ca[key] = params[key];
371
+ delete params[key];
372
+ hasCA = true;
373
+ }
374
+ }
375
+ return hasCA ? ca : false;
376
+ }
377
+
378
+ attribs = merge(attribs);
379
+
380
+ attribs.alpha *= deg2rad;
381
+ attribs.beta *= deg2rad;
382
+
383
+ // Create the different sub sections of the shape
384
+ wrapper.top = renderer.path();
385
+ wrapper.side1 = renderer.path();
386
+ wrapper.side2 = renderer.path();
387
+ wrapper.inn = renderer.path();
388
+ wrapper.out = renderer.path();
389
+
390
+ /**
391
+ * Add all faces
392
+ */
393
+ wrapper.onAdd = function () {
394
+ var parent = wrapper.parentGroup;
395
+ wrapper.top.add(wrapper);
396
+ wrapper.out.add(parent);
397
+ wrapper.inn.add(parent);
398
+ wrapper.side1.add(parent);
399
+ wrapper.side2.add(parent);
400
+ };
401
+
402
+ /**
403
+ * Compute the transformed paths and set them to the composite shapes
404
+ */
405
+ wrapper.setPaths = function (attribs) {
406
+
407
+ var paths = wrapper.renderer.arc3dPath(attribs),
408
+ zIndex = paths.zTop * 100;
409
+
410
+ wrapper.attribs = attribs;
411
+
412
+ wrapper.top.attr({ d: paths.top, zIndex: paths.zTop });
413
+ wrapper.inn.attr({ d: paths.inn, zIndex: paths.zInn });
414
+ wrapper.out.attr({ d: paths.out, zIndex: paths.zOut });
415
+ wrapper.side1.attr({ d: paths.side1, zIndex: paths.zSide1 });
416
+ wrapper.side2.attr({ d: paths.side2, zIndex: paths.zSide2 });
417
+
418
+
419
+ // show all children
420
+ wrapper.zIndex = zIndex;
421
+ wrapper.attr({ zIndex: zIndex });
422
+
423
+ // Set the radial gradient center the first time
424
+ if (attribs.center) {
425
+ wrapper.top.setRadialReference(attribs.center);
426
+ delete attribs.center;
427
+ }
428
+ };
429
+ wrapper.setPaths(attribs);
430
+
431
+ // Apply the fill to the top and a darker shade to the sides
432
+ wrapper.fillSetter = function (value) {
433
+ var darker = Highcharts.Color(value).brighten(-0.1).get();
434
+
435
+ this.fill = value;
436
+
437
+ this.side1.attr({ fill: darker });
438
+ this.side2.attr({ fill: darker });
439
+ this.inn.attr({ fill: darker });
440
+ this.out.attr({ fill: darker });
441
+ this.top.attr({ fill: value });
442
+ return this;
443
+ };
444
+
445
+ // Apply the same value to all. These properties cascade down to the children
446
+ // when set to the composite arc3d.
447
+ each(['opacity', 'translateX', 'translateY', 'visibility'], function (setter) {
448
+ wrapper[setter + 'Setter'] = function (value, key) {
449
+ wrapper[key] = value;
450
+ each(['out', 'inn', 'side1', 'side2', 'top'], function (el) {
451
+ wrapper[el].attr(key, value);
452
+ });
453
+ };
454
+ });
455
+
456
+ /**
457
+ * Override attr to remove shape attributes and use those to set child paths
458
+ */
459
+ wrap(wrapper, 'attr', function (proceed, params, val) {
460
+ var ca;
461
+ if (typeof params === 'object') {
462
+ ca = suckOutCustom(params);
463
+ if (ca) {
464
+ extend(wrapper.attribs, ca);
465
+ wrapper.setPaths(wrapper.attribs);
466
+ }
467
+ }
468
+ return proceed.call(this, params, val);
469
+ });
470
+
471
+ /**
472
+ * Override the animate function by sucking out custom parameters related to the shapes directly,
473
+ * and update the shapes from the animation step.
474
+ */
475
+ wrap(wrapper, 'animate', function (proceed, params, animation, complete) {
476
+ var ca,
477
+ from = this.attribs,
478
+ to;
479
+
480
+ // Attribute-line properties connected to 3D. These shouldn't have been in the
481
+ // attribs collection in the first place.
482
+ delete params.center;
483
+ delete params.z;
484
+ delete params.depth;
485
+ delete params.alpha;
486
+ delete params.beta;
487
+
488
+ animation = pick(animation, this.renderer.globalAnimation);
489
+
490
+ if (animation) {
491
+ if (typeof animation !== 'object') {
492
+ animation = {};
493
+ }
494
+
495
+ params = merge(params); // Don't mutate the original object
496
+ ca = suckOutCustom(params);
497
+
498
+ if (ca) {
499
+ to = ca;
500
+ animation.step = function (a, fx) {
501
+ function interpolate(key) {
502
+ return from[key] + (pick(to[key], from[key]) - from[key]) * fx.pos;
503
+ }
504
+ fx.elem.setPaths(merge(from, {
505
+ x: interpolate('x'),
506
+ y: interpolate('y'),
507
+ r: interpolate('r'),
508
+ innerR: interpolate('innerR'),
509
+ start: interpolate('start'),
510
+ end: interpolate('end')
511
+ }));
512
+ };
513
+ }
514
+ }
515
+ return proceed.call(this, params, animation, complete);
516
+ });
517
+
518
+ // destroy all children
519
+ wrapper.destroy = function () {
520
+ this.top.destroy();
521
+ this.out.destroy();
522
+ this.inn.destroy();
523
+ this.side1.destroy();
524
+ this.side2.destroy();
525
+
526
+ Highcharts.SVGElement.prototype.destroy.call(this);
527
+ };
528
+ // hide all children
529
+ wrapper.hide = function () {
530
+ this.top.hide();
531
+ this.out.hide();
532
+ this.inn.hide();
533
+ this.side1.hide();
534
+ this.side2.hide();
535
+ };
536
+ wrapper.show = function () {
537
+ this.top.show();
538
+ this.out.show();
539
+ this.inn.show();
540
+ this.side1.show();
541
+ this.side2.show();
542
+ };
543
+ return wrapper;
544
+ };
545
+
546
+ /**
547
+ * Generate the paths required to draw a 3D arc
548
+ */
549
+ Highcharts.SVGRenderer.prototype.arc3dPath = function (shapeArgs) {
550
+ var cx = shapeArgs.x, // x coordinate of the center
551
+ cy = shapeArgs.y, // y coordinate of the center
552
+ start = shapeArgs.start, // start angle
553
+ end = shapeArgs.end - 0.00001, // end angle
554
+ r = shapeArgs.r, // radius
555
+ ir = shapeArgs.innerR, // inner radius
556
+ d = shapeArgs.depth, // depth
557
+ alpha = shapeArgs.alpha, // alpha rotation of the chart
558
+ beta = shapeArgs.beta; // beta rotation of the chart
559
+
560
+ // Derived Variables
561
+ var cs = cos(start), // cosinus of the start angle
562
+ ss = sin(start), // sinus of the start angle
563
+ ce = cos(end), // cosinus of the end angle
564
+ se = sin(end), // sinus of the end angle
565
+ rx = r * cos(beta), // x-radius
566
+ ry = r * cos(alpha), // y-radius
567
+ irx = ir * cos(beta), // x-radius (inner)
568
+ iry = ir * cos(alpha), // y-radius (inner)
569
+ dx = d * sin(beta), // distance between top and bottom in x
570
+ dy = d * sin(alpha); // distance between top and bottom in y
571
+
572
+ // TOP
573
+ var top = ['M', cx + (rx * cs), cy + (ry * ss)];
574
+ top = top.concat(curveTo(cx, cy, rx, ry, start, end, 0, 0));
575
+ top = top.concat([
576
+ 'L', cx + (irx * ce), cy + (iry * se)
577
+ ]);
578
+ top = top.concat(curveTo(cx, cy, irx, iry, end, start, 0, 0));
579
+ top = top.concat(['Z']);
580
+ // OUTSIDE
581
+ var b = (beta > 0 ? PI / 2 : 0),
582
+ a = (alpha > 0 ? 0 : PI / 2);
583
+
584
+ var start2 = start > -b ? start : (end > -b ? -b : start),
585
+ end2 = end < PI - a ? end : (start < PI - a ? PI - a : end),
586
+ midEnd = 2 * PI - a;
587
+
588
+ // When slice goes over bottom middle, need to add both, left and right outer side.
589
+ // Additionally, when we cross right hand edge, create sharp edge. Outer shape/wall:
590
+ //
591
+ // -------
592
+ // / ^ \
593
+ // 4) / / \ \ 1)
594
+ // / / \ \
595
+ // / / \ \
596
+ // (c)=> ==== ==== <=(d)
597
+ // \ \ / /
598
+ // \ \<=(a)/ /
599
+ // \ \ / / <=(b)
600
+ // 3) \ v / 2)
601
+ // -------
602
+ //
603
+ // (a) - inner side
604
+ // (b) - outer side
605
+ // (c) - left edge (sharp)
606
+ // (d) - right edge (sharp)
607
+ // 1..n - rendering order for startAngle = 0, when set to e.g 90, order changes clockwise (1->2, 2->3, n->1) and counterclockwise for negative startAngle
608
+
609
+ var out = ['M', cx + (rx * cos(start2)), cy + (ry * sin(start2))];
610
+ out = out.concat(curveTo(cx, cy, rx, ry, start2, end2, 0, 0));
611
+
612
+ if (end > midEnd && start < midEnd) { // When shape is wide, it can cross both, (c) and (d) edges, when using startAngle
613
+ // Go to outer side
614
+ out = out.concat([
615
+ 'L', cx + (rx * cos(end2)) + dx, cy + (ry * sin(end2)) + dy
616
+ ]);
617
+ // Curve to the right edge of the slice (d)
618
+ out = out.concat(curveTo(cx, cy, rx, ry, end2, midEnd, dx, dy));
619
+ // Go to the inner side
620
+ out = out.concat([
621
+ 'L', cx + (rx * cos(midEnd)), cy + (ry * sin(midEnd))
622
+ ]);
623
+ // Curve to the true end of the slice
624
+ out = out.concat(curveTo(cx, cy, rx, ry, midEnd, end, 0, 0));
625
+ // Go to the outer side
626
+ out = out.concat([
627
+ 'L', cx + (rx * cos(end)) + dx, cy + (ry * sin(end)) + dy
628
+ ]);
629
+ // Go back to middle (d)
630
+ out = out.concat(curveTo(cx, cy, rx, ry, end, midEnd, dx, dy));
631
+ out = out.concat([
632
+ 'L', cx + (rx * cos(midEnd)), cy + (ry * sin(midEnd))
633
+ ]);
634
+ // Go back to the left edge
635
+ out = out.concat(curveTo(cx, cy, rx, ry, midEnd, end2, 0, 0));
636
+ } else if (end > PI - a && start < PI - a) { // But shape can cross also only (c) edge:
637
+ // Go to outer side
638
+ out = out.concat([
639
+ 'L', cx + (rx * cos(end2)) + dx, cy + (ry * sin(end2)) + dy
640
+ ]);
641
+ // Curve to the true end of the slice
642
+ out = out.concat(curveTo(cx, cy, rx, ry, end2, end, dx, dy));
643
+ // Go to the inner side
644
+ out = out.concat([
645
+ 'L', cx + (rx * cos(end)), cy + (ry * sin(end))
646
+ ]);
647
+ // Go back to the artifical end2
648
+ out = out.concat(curveTo(cx, cy, rx, ry, end, end2, 0, 0));
649
+ }
650
+
651
+ out = out.concat([
652
+ 'L', cx + (rx * cos(end2)) + dx, cy + (ry * sin(end2)) + dy
653
+ ]);
654
+ out = out.concat(curveTo(cx, cy, rx, ry, end2, start2, dx, dy));
655
+ out = out.concat(['Z']);
656
+
657
+ // INSIDE
658
+ var inn = ['M', cx + (irx * cs), cy + (iry * ss)];
659
+ inn = inn.concat(curveTo(cx, cy, irx, iry, start, end, 0, 0));
660
+ inn = inn.concat([
661
+ 'L', cx + (irx * cos(end)) + dx, cy + (iry * sin(end)) + dy
662
+ ]);
663
+ inn = inn.concat(curveTo(cx, cy, irx, iry, end, start, dx, dy));
664
+ inn = inn.concat(['Z']);
665
+
666
+ // SIDES
667
+ var side1 = [
668
+ 'M', cx + (rx * cs), cy + (ry * ss),
669
+ 'L', cx + (rx * cs) + dx, cy + (ry * ss) + dy,
670
+ 'L', cx + (irx * cs) + dx, cy + (iry * ss) + dy,
671
+ 'L', cx + (irx * cs), cy + (iry * ss),
672
+ 'Z'
673
+ ];
674
+ var side2 = [
675
+ 'M', cx + (rx * ce), cy + (ry * se),
676
+ 'L', cx + (rx * ce) + dx, cy + (ry * se) + dy,
677
+ 'L', cx + (irx * ce) + dx, cy + (iry * se) + dy,
678
+ 'L', cx + (irx * ce), cy + (iry * se),
679
+ 'Z'
680
+ ];
681
+
682
+ // correction for changed position of vanishing point caused by alpha and beta rotations
683
+ var angleCorr = Math.atan2(dy, -dx),
684
+ angleEnd = Math.abs(end + angleCorr),
685
+ angleStart = Math.abs(start + angleCorr),
686
+ angleMid = Math.abs((start + end) / 2 + angleCorr);
687
+
688
+ // set to 0-PI range
689
+ function toZeroPIRange(angle) {
690
+ angle = angle % (2 * PI);
691
+ if (angle > PI) {
692
+ angle = 2 * PI - angle;
693
+ }
694
+ return angle;
695
+ }
696
+ angleEnd = toZeroPIRange(angleEnd);
697
+ angleStart = toZeroPIRange(angleStart);
698
+ angleMid = toZeroPIRange(angleMid);
699
+
700
+ // *1e5 is to compensate pInt in zIndexSetter
701
+ var incPrecision = 1e5,
702
+ a1 = angleMid * incPrecision,
703
+ a2 = angleStart * incPrecision,
704
+ a3 = angleEnd * incPrecision;
705
+
706
+ return {
707
+ top: top,
708
+ zTop: PI * incPrecision + 1, // max angle is PI, so this is allways higher
709
+ out: out,
710
+ zOut: Math.max(a1, a2, a3),
711
+ inn: inn,
712
+ zInn: Math.max(a1, a2, a3),
713
+ side1: side1,
714
+ zSide1: a3 * 0.99, // to keep below zOut and zInn in case of same values
715
+ side2: side2,
716
+ zSide2: a2 * 0.99
717
+ };
718
+ };
719
+ /***
720
+ EXTENSION FOR 3D CHARTS
721
+ ***/
722
+ // Shorthand to check the is3d flag
723
+ Highcharts.Chart.prototype.is3d = function () {
724
+ return this.options.chart.options3d && this.options.chart.options3d.enabled; // #4280
725
+ };
726
+
727
+ Highcharts.wrap(Highcharts.Chart.prototype, 'isInsidePlot', function (proceed) {
728
+ return this.is3d() || proceed.apply(this, [].slice.call(arguments, 1));
729
+ });
730
+
731
+ var defaultChartOptions = Highcharts.getOptions();
732
+ defaultChartOptions.chart.options3d = {
733
+ enabled: false,
734
+ alpha: 0,
735
+ beta: 0,
736
+ depth: 100,
737
+ viewDistance: 25,
738
+ frame: {
739
+ bottom: { size: 1, color: 'rgba(255,255,255,0)' },
740
+ side: { size: 1, color: 'rgba(255,255,255,0)' },
741
+ back: { size: 1, color: 'rgba(255,255,255,0)' }
742
+ }
743
+ };
744
+
745
+ Highcharts.wrap(Highcharts.Chart.prototype, 'init', function (proceed) {
746
+ var args = [].slice.call(arguments, 1),
747
+ plotOptions,
748
+ pieOptions;
749
+
750
+ if (args[0].chart.options3d && args[0].chart.options3d.enabled) {
751
+ // Normalize alpha and beta to (-360, 360) range
752
+ args[0].chart.options3d.alpha = (args[0].chart.options3d.alpha || 0) % 360;
753
+ args[0].chart.options3d.beta = (args[0].chart.options3d.beta || 0) % 360;
754
+
755
+ plotOptions = args[0].plotOptions || {};
756
+ pieOptions = plotOptions.pie || {};
757
+
758
+ pieOptions.borderColor = Highcharts.pick(pieOptions.borderColor, undefined);
759
+ }
760
+ proceed.apply(this, args);
761
+ });
762
+
763
+ Highcharts.wrap(Highcharts.Chart.prototype, 'setChartSize', function (proceed) {
764
+ proceed.apply(this, [].slice.call(arguments, 1));
765
+
766
+ if (this.is3d()) {
767
+ var inverted = this.inverted,
768
+ clipBox = this.clipBox,
769
+ margin = this.margin,
770
+ x = inverted ? 'y' : 'x',
771
+ y = inverted ? 'x' : 'y',
772
+ w = inverted ? 'height' : 'width',
773
+ h = inverted ? 'width' : 'height';
774
+
775
+ clipBox[x] = -(margin[3] || 0);
776
+ clipBox[y] = -(margin[0] || 0);
777
+ clipBox[w] = this.chartWidth + (margin[3] || 0) + (margin[1] || 0);
778
+ clipBox[h] = this.chartHeight + (margin[0] || 0) + (margin[2] || 0);
779
+ }
780
+ });
781
+
782
+ Highcharts.wrap(Highcharts.Chart.prototype, 'redraw', function (proceed) {
783
+ if (this.is3d()) {
784
+ // Set to force a redraw of all elements
785
+ this.isDirtyBox = true;
786
+ }
787
+ proceed.apply(this, [].slice.call(arguments, 1));
788
+ });
789
+
790
+ // Draw the series in the reverse order (#3803, #3917)
791
+ Highcharts.wrap(Highcharts.Chart.prototype, 'renderSeries', function (proceed) {
792
+ var series,
793
+ i = this.series.length;
794
+
795
+ if (this.is3d()) {
796
+ while (i--) {
797
+ series = this.series[i];
798
+ series.translate();
799
+ series.render();
800
+ }
801
+ } else {
802
+ proceed.call(this);
803
+ }
804
+ });
805
+
806
+ Highcharts.Chart.prototype.retrieveStacks = function (stacking) {
807
+ var series = this.series,
808
+ stacks = {},
809
+ stackNumber,
810
+ i = 1;
811
+
812
+ Highcharts.each(this.series, function (s) {
813
+ stackNumber = pick(s.options.stack, (stacking ? 0 : series.length - 1 - s.index)); // #3841, #4532
814
+ if (!stacks[stackNumber]) {
815
+ stacks[stackNumber] = { series: [s], position: i };
816
+ i++;
817
+ } else {
818
+ stacks[stackNumber].series.push(s);
819
+ }
820
+ });
821
+
822
+ stacks.totalStacks = i + 1;
823
+ return stacks;
824
+ };
825
+
826
+ /***
827
+ EXTENSION TO THE AXIS
828
+ ***/
829
+ Highcharts.wrap(Highcharts.Axis.prototype, 'setOptions', function (proceed, userOptions) {
830
+ var options;
831
+ proceed.call(this, userOptions);
832
+ if (this.chart.is3d()) {
833
+ options = this.options;
834
+ options.tickWidth = Highcharts.pick(options.tickWidth, 0);
835
+ options.gridLineWidth = Highcharts.pick(options.gridLineWidth, 1);
836
+ }
837
+ });
838
+
839
+ Highcharts.wrap(Highcharts.Axis.prototype, 'render', function (proceed) {
840
+ proceed.apply(this, [].slice.call(arguments, 1));
841
+
842
+ // Do not do this if the chart is not 3D
843
+ if (!this.chart.is3d()) {
844
+ return;
845
+ }
846
+
847
+ var chart = this.chart,
848
+ renderer = chart.renderer,
849
+ options3d = chart.options.chart.options3d,
850
+ frame = options3d.frame,
851
+ fbottom = frame.bottom,
852
+ fback = frame.back,
853
+ fside = frame.side,
854
+ depth = options3d.depth,
855
+ height = this.height,
856
+ width = this.width,
857
+ left = this.left,
858
+ top = this.top;
859
+
860
+ if (this.isZAxis) {
861
+ return;
862
+ }
863
+ if (this.horiz) {
864
+ var bottomShape = {
865
+ x: left,
866
+ y: top + (chart.xAxis[0].opposite ? -fbottom.size : height),
867
+ z: 0,
868
+ width: width,
869
+ height: fbottom.size,
870
+ depth: depth,
871
+ insidePlotArea: false
872
+ };
873
+ if (!this.bottomFrame) {
874
+ this.bottomFrame = renderer.cuboid(bottomShape).attr({
875
+ fill: fbottom.color,
876
+ zIndex: (chart.yAxis[0].reversed && options3d.alpha > 0 ? 4 : -1)
877
+ })
878
+ .css({
879
+ stroke: fbottom.color
880
+ }).add();
881
+ } else {
882
+ this.bottomFrame.animate(bottomShape);
883
+ }
884
+ } else {
885
+ // BACK
886
+ var backShape = {
887
+ x: left + (chart.yAxis[0].opposite ? 0 : -fside.size),
888
+ y: top + (chart.xAxis[0].opposite ? -fbottom.size : 0),
889
+ z: depth,
890
+ width: width + fside.size,
891
+ height: height + fbottom.size,
892
+ depth: fback.size,
893
+ insidePlotArea: false
894
+ };
895
+ if (!this.backFrame) {
896
+ this.backFrame = renderer.cuboid(backShape).attr({
897
+ fill: fback.color,
898
+ zIndex: -3
899
+ }).css({
900
+ stroke: fback.color
901
+ }).add();
902
+ } else {
903
+ this.backFrame.animate(backShape);
904
+ }
905
+ var sideShape = {
906
+ x: left + (chart.yAxis[0].opposite ? width : -fside.size),
907
+ y: top + (chart.xAxis[0].opposite ? -fbottom.size : 0),
908
+ z: 0,
909
+ width: fside.size,
910
+ height: height + fbottom.size,
911
+ depth: depth,
912
+ insidePlotArea: false
913
+ };
914
+ if (!this.sideFrame) {
915
+ this.sideFrame = renderer.cuboid(sideShape).attr({
916
+ fill: fside.color,
917
+ zIndex: -2
918
+ }).css({
919
+ stroke: fside.color
920
+ }).add();
921
+ } else {
922
+ this.sideFrame.animate(sideShape);
923
+ }
924
+ }
925
+ });
926
+
927
+ Highcharts.wrap(Highcharts.Axis.prototype, 'getPlotLinePath', function (proceed) {
928
+ var path = proceed.apply(this, [].slice.call(arguments, 1));
929
+
930
+ // Do not do this if the chart is not 3D
931
+ if (!this.chart.is3d()) {
932
+ return path;
933
+ }
934
+
935
+ if (path === null) {
936
+ return path;
937
+ }
938
+
939
+ var chart = this.chart,
940
+ options3d = chart.options.chart.options3d,
941
+ d = this.isZAxis ? chart.plotWidth : options3d.depth,
942
+ opposite = this.opposite;
943
+ if (this.horiz) {
944
+ opposite = !opposite;
945
+ }
946
+ var pArr = [
947
+ this.swapZ({ x: path[1], y: path[2], z: (opposite ? d : 0) }),
948
+ this.swapZ({ x: path[1], y: path[2], z: d }),
949
+ this.swapZ({ x: path[4], y: path[5], z: d }),
950
+ this.swapZ({ x: path[4], y: path[5], z: (opposite ? 0 : d) })
951
+ ];
952
+
953
+ pArr = perspective(pArr, this.chart, false);
954
+ path = this.chart.renderer.toLinePath(pArr, false);
955
+
956
+ return path;
957
+ });
958
+
959
+ // Do not draw axislines in 3D
960
+ Highcharts.wrap(Highcharts.Axis.prototype, 'getLinePath', function (proceed) {
961
+ return this.chart.is3d() ? [] : proceed.apply(this, [].slice.call(arguments, 1));
962
+ });
963
+
964
+ Highcharts.wrap(Highcharts.Axis.prototype, 'getPlotBandPath', function (proceed) {
965
+ // Do not do this if the chart is not 3D
966
+ if (!this.chart.is3d()) {
967
+ return proceed.apply(this, [].slice.call(arguments, 1));
968
+ }
969
+
970
+ var args = arguments,
971
+ from = args[1],
972
+ to = args[2],
973
+ toPath = this.getPlotLinePath(to),
974
+ path = this.getPlotLinePath(from);
975
+
976
+ if (path && toPath) {
977
+ path.push(
978
+ 'L',
979
+ toPath[10], // These two do not exist in the regular getPlotLine
980
+ toPath[11], // ---- # 3005
981
+ 'L',
982
+ toPath[7],
983
+ toPath[8],
984
+ 'L',
985
+ toPath[4],
986
+ toPath[5],
987
+ 'L',
988
+ toPath[1],
989
+ toPath[2]
990
+ );
991
+ } else { // outside the axis area
992
+ path = null;
993
+ }
994
+
995
+ return path;
996
+ });
997
+
998
+ /***
999
+ EXTENSION TO THE TICKS
1000
+ ***/
1001
+
1002
+ Highcharts.wrap(Highcharts.Tick.prototype, 'getMarkPath', function (proceed) {
1003
+ var path = proceed.apply(this, [].slice.call(arguments, 1));
1004
+
1005
+ // Do not do this if the chart is not 3D
1006
+ if (!this.axis.chart.is3d()) {
1007
+ return path;
1008
+ }
1009
+
1010
+ var pArr = [
1011
+ this.axis.swapZ({ x: path[1], y: path[2], z: 0 }),
1012
+ this.axis.swapZ({ x: path[4], y: path[5], z: 0 })
1013
+ ];
1014
+
1015
+ pArr = perspective(pArr, this.axis.chart, false);
1016
+ path = [
1017
+ 'M', pArr[0].x, pArr[0].y,
1018
+ 'L', pArr[1].x, pArr[1].y
1019
+ ];
1020
+ return path;
1021
+ });
1022
+
1023
+ Highcharts.wrap(Highcharts.Tick.prototype, 'getLabelPosition', function (proceed) {
1024
+ var pos = proceed.apply(this, [].slice.call(arguments, 1));
1025
+
1026
+ // Do not do this if the chart is not 3D
1027
+ if (!this.axis.chart.is3d()) {
1028
+ return pos;
1029
+ }
1030
+
1031
+ var newPos = perspective([this.axis.swapZ({ x: pos.x, y: pos.y, z: 0 })], this.axis.chart, false)[0];
1032
+ newPos.x = newPos.x - (!this.axis.horiz && this.axis.opposite ? this.axis.transA : 0); //#3788
1033
+ newPos.old = pos;
1034
+ return newPos;
1035
+ });
1036
+
1037
+ Highcharts.wrap(Highcharts.Tick.prototype, 'handleOverflow', function (proceed, xy) {
1038
+ if (this.axis.chart.is3d()) {
1039
+ xy = xy.old;
1040
+ }
1041
+ return proceed.call(this, xy);
1042
+ });
1043
+
1044
+ Highcharts.wrap(Highcharts.Axis.prototype, 'getTitlePosition', function (proceed) {
1045
+ var is3d = this.chart.is3d(),
1046
+ pos,
1047
+ axisTitleMargin;
1048
+
1049
+ // Pull out the axis title margin, that is not subject to the perspective
1050
+ if (is3d) {
1051
+ axisTitleMargin = this.axisTitleMargin;
1052
+ this.axisTitleMargin = 0;
1053
+ }
1054
+
1055
+ pos = proceed.apply(this, [].slice.call(arguments, 1));
1056
+
1057
+ if (is3d) {
1058
+ pos = perspective([this.swapZ({ x: pos.x, y: pos.y, z: 0 })], this.chart, false)[0];
1059
+
1060
+ // Re-apply the axis title margin outside the perspective
1061
+ pos[this.horiz ? 'y' : 'x'] += (this.horiz ? 1 : -1) * // horizontal axis reverses the margin ...
1062
+ (this.opposite ? -1 : 1) * // ... so does opposite axes
1063
+ axisTitleMargin;
1064
+ this.axisTitleMargin = axisTitleMargin;
1065
+ }
1066
+ return pos;
1067
+ });
1068
+
1069
+ Highcharts.wrap(Highcharts.Axis.prototype, 'drawCrosshair', function (proceed) {
1070
+ var args = arguments;
1071
+ if (this.chart.is3d()) {
1072
+ if (args[2]) {
1073
+ args[2] = {
1074
+ plotX: args[2].plotXold || args[2].plotX,
1075
+ plotY: args[2].plotYold || args[2].plotY
1076
+ };
1077
+ }
1078
+ }
1079
+ proceed.apply(this, [].slice.call(args, 1));
1080
+ });
1081
+
1082
+ /***
1083
+ Z-AXIS
1084
+ ***/
1085
+
1086
+ Highcharts.Axis.prototype.swapZ = function (p, insidePlotArea) {
1087
+ if (this.isZAxis) {
1088
+ var plotLeft = insidePlotArea ? 0 : this.chart.plotLeft;
1089
+ var chart = this.chart;
1090
+ return {
1091
+ x: plotLeft + (chart.yAxis[0].opposite ? p.z : chart.xAxis[0].width - p.z),
1092
+ y: p.y,
1093
+ z: p.x - plotLeft
1094
+ };
1095
+ }
1096
+ return p;
1097
+ };
1098
+
1099
+ var ZAxis = Highcharts.ZAxis = function () {
1100
+ this.isZAxis = true;
1101
+ this.init.apply(this, arguments);
1102
+ };
1103
+ Highcharts.extend(ZAxis.prototype, Highcharts.Axis.prototype);
1104
+ Highcharts.extend(ZAxis.prototype, {
1105
+ setOptions: function (userOptions) {
1106
+ userOptions = Highcharts.merge({
1107
+ offset: 0,
1108
+ lineWidth: 0
1109
+ }, userOptions);
1110
+ Highcharts.Axis.prototype.setOptions.call(this, userOptions);
1111
+ this.coll = 'zAxis';
1112
+ },
1113
+ setAxisSize: function () {
1114
+ Highcharts.Axis.prototype.setAxisSize.call(this);
1115
+ this.width = this.len = this.chart.options.chart.options3d.depth;
1116
+ this.right = this.chart.chartWidth - this.width - this.left;
1117
+ },
1118
+ getSeriesExtremes: function () {
1119
+ var axis = this,
1120
+ chart = axis.chart;
1121
+
1122
+ axis.hasVisibleSeries = false;
1123
+
1124
+ // Reset properties in case we're redrawing (#3353)
1125
+ axis.dataMin = axis.dataMax = axis.ignoreMinPadding = axis.ignoreMaxPadding = null;
1126
+
1127
+ if (axis.buildStacks) {
1128
+ axis.buildStacks();
1129
+ }
1130
+
1131
+ // loop through this axis' series
1132
+ Highcharts.each(axis.series, function (series) {
1133
+
1134
+ if (series.visible || !chart.options.chart.ignoreHiddenSeries) {
1135
+
1136
+ var seriesOptions = series.options,
1137
+ zData,
1138
+ threshold = seriesOptions.threshold;
1139
+
1140
+ axis.hasVisibleSeries = true;
1141
+
1142
+ // Validate threshold in logarithmic axes
1143
+ if (axis.isLog && threshold <= 0) {
1144
+ threshold = null;
1145
+ }
1146
+
1147
+ zData = series.zData;
1148
+ if (zData.length) {
1149
+ axis.dataMin = Math.min(pick(axis.dataMin, zData[0]), Math.min.apply(null, zData));
1150
+ axis.dataMax = Math.max(pick(axis.dataMax, zData[0]), Math.max.apply(null, zData));
1151
+ }
1152
+ }
1153
+ });
1154
+ }
1155
+ });
1156
+
1157
+
1158
+ /**
1159
+ * Extend the chart getAxes method to also get the color axis
1160
+ */
1161
+ Highcharts.wrap(Highcharts.Chart.prototype, 'getAxes', function (proceed) {
1162
+ var chart = this,
1163
+ options = this.options,
1164
+ zAxisOptions = options.zAxis = Highcharts.splat(options.zAxis || {});
1165
+
1166
+ proceed.call(this);
1167
+
1168
+ if (!chart.is3d()) {
1169
+ return;
1170
+ }
1171
+ this.zAxis = [];
1172
+ Highcharts.each(zAxisOptions, function (axisOptions, i) {
1173
+ axisOptions.index = i;
1174
+ axisOptions.isX = true; //Z-Axis is shown horizontally, so it's kind of a X-Axis
1175
+ var zAxis = new ZAxis(chart, axisOptions);
1176
+ zAxis.setScale();
1177
+ });
1178
+ });
1179
+ /***
1180
+ EXTENSION FOR 3D COLUMNS
1181
+ ***/
1182
+ Highcharts.wrap(Highcharts.seriesTypes.column.prototype, 'translate', function (proceed) {
1183
+ proceed.apply(this, [].slice.call(arguments, 1));
1184
+
1185
+ // Do not do this if the chart is not 3D
1186
+ if (!this.chart.is3d()) {
1187
+ return;
1188
+ }
1189
+
1190
+ var series = this,
1191
+ chart = series.chart,
1192
+ seriesOptions = series.options,
1193
+ depth = seriesOptions.depth || 25;
1194
+
1195
+ var stack = seriesOptions.stacking ? (seriesOptions.stack || 0) : series._i;
1196
+ var z = stack * (depth + (seriesOptions.groupZPadding || 1));
1197
+
1198
+ if (seriesOptions.grouping !== false) {
1199
+ z = 0;
1200
+ }
1201
+
1202
+ z += (seriesOptions.groupZPadding || 1);
1203
+
1204
+ Highcharts.each(series.data, function (point) {
1205
+ if (point.y !== null) {
1206
+ var shapeArgs = point.shapeArgs,
1207
+ tooltipPos = point.tooltipPos;
1208
+
1209
+ point.shapeType = 'cuboid';
1210
+ shapeArgs.z = z;
1211
+ shapeArgs.depth = depth;
1212
+ shapeArgs.insidePlotArea = true;
1213
+
1214
+ // Translate the tooltip position in 3d space
1215
+ tooltipPos = perspective([{ x: tooltipPos[0], y: tooltipPos[1], z: z }], chart, false)[0];
1216
+ point.tooltipPos = [tooltipPos.x, tooltipPos.y];
1217
+ }
1218
+ });
1219
+ // store for later use #4067
1220
+ series.z = z;
1221
+ });
1222
+
1223
+ Highcharts.wrap(Highcharts.seriesTypes.column.prototype, 'animate', function (proceed) {
1224
+ if (!this.chart.is3d()) {
1225
+ proceed.apply(this, [].slice.call(arguments, 1));
1226
+ } else {
1227
+ var args = arguments,
1228
+ init = args[1],
1229
+ yAxis = this.yAxis,
1230
+ series = this,
1231
+ reversed = this.yAxis.reversed;
1232
+
1233
+ if (Highcharts.svg) { // VML is too slow anyway
1234
+ if (init) {
1235
+ Highcharts.each(series.data, function (point) {
1236
+ if (point.y !== null) {
1237
+ point.height = point.shapeArgs.height;
1238
+ point.shapey = point.shapeArgs.y; //#2968
1239
+ point.shapeArgs.height = 1;
1240
+ if (!reversed) {
1241
+ if (point.stackY) {
1242
+ point.shapeArgs.y = point.plotY + yAxis.translate(point.stackY);
1243
+ } else {
1244
+ point.shapeArgs.y = point.plotY + (point.negative ? -point.height : point.height);
1245
+ }
1246
+ }
1247
+ }
1248
+ });
1249
+
1250
+ } else { // run the animation
1251
+ Highcharts.each(series.data, function (point) {
1252
+ if (point.y !== null) {
1253
+ point.shapeArgs.height = point.height;
1254
+ point.shapeArgs.y = point.shapey; //#2968
1255
+ // null value do not have a graphic
1256
+ if (point.graphic) {
1257
+ point.graphic.animate(point.shapeArgs, series.options.animation);
1258
+ }
1259
+ }
1260
+ });
1261
+
1262
+ // redraw datalabels to the correct position
1263
+ this.drawDataLabels();
1264
+
1265
+ // delete this function to allow it only once
1266
+ series.animate = null;
1267
+ }
1268
+ }
1269
+ }
1270
+ });
1271
+
1272
+ Highcharts.wrap(Highcharts.seriesTypes.column.prototype, 'init', function (proceed) {
1273
+ proceed.apply(this, [].slice.call(arguments, 1));
1274
+
1275
+ if (this.chart.is3d()) {
1276
+ var seriesOptions = this.options,
1277
+ grouping = seriesOptions.grouping,
1278
+ stacking = seriesOptions.stacking,
1279
+ reversedStacks = pick(this.yAxis.options.reversedStacks, true),
1280
+ z = 0;
1281
+
1282
+ if (!(grouping !== undefined && !grouping)) {
1283
+ var stacks = this.chart.retrieveStacks(stacking),
1284
+ stack = seriesOptions.stack || 0,
1285
+ i; // position within the stack
1286
+ for (i = 0; i < stacks[stack].series.length; i++) {
1287
+ if (stacks[stack].series[i] === this) {
1288
+ break;
1289
+ }
1290
+ }
1291
+ z = (10 * (stacks.totalStacks - stacks[stack].position)) + (reversedStacks ? i : -i); // #4369
1292
+
1293
+ // In case when axis is reversed, columns are also reversed inside the group (#3737)
1294
+ if (!this.xAxis.reversed) {
1295
+ z = (stacks.totalStacks * 10) - z;
1296
+ }
1297
+ }
1298
+
1299
+ seriesOptions.zIndex = z;
1300
+ }
1301
+ });
1302
+ function draw3DPoints(proceed) {
1303
+ // Do not do this if the chart is not 3D
1304
+ if (this.chart.is3d()) {
1305
+ var grouping = this.chart.options.plotOptions.column.grouping;
1306
+ if (grouping !== undefined && !grouping && this.group.zIndex !== undefined && !this.zIndexSet) {
1307
+ this.group.attr({ zIndex: this.group.zIndex * 10 });
1308
+ this.zIndexSet = true; // #4062 set zindex only once
1309
+ }
1310
+
1311
+ var options = this.options,
1312
+ states = this.options.states;
1313
+
1314
+ this.borderWidth = options.borderWidth = defined(options.edgeWidth) ? options.edgeWidth : 1; //#4055
1315
+
1316
+ Highcharts.each(this.data, function (point) {
1317
+ if (point.y !== null) {
1318
+ var pointAttr = point.pointAttr;
1319
+
1320
+ // Set the border color to the fill color to provide a smooth edge
1321
+ this.borderColor = Highcharts.pick(options.edgeColor, pointAttr[''].fill);
1322
+
1323
+ pointAttr[''].stroke = this.borderColor;
1324
+ pointAttr.hover.stroke = Highcharts.pick(states.hover.edgeColor, this.borderColor);
1325
+ pointAttr.select.stroke = Highcharts.pick(states.select.edgeColor, this.borderColor);
1326
+ }
1327
+ });
1328
+ }
1329
+
1330
+ proceed.apply(this, [].slice.call(arguments, 1));
1331
+ }
1332
+
1333
+ Highcharts.wrap(Highcharts.Series.prototype, 'alignDataLabel', function (proceed) {
1334
+
1335
+ // Only do this for 3D columns and columnranges
1336
+ if (this.chart.is3d() && (this.type === 'column' || this.type === 'columnrange')) {
1337
+ var series = this,
1338
+ chart = series.chart;
1339
+
1340
+ var args = arguments,
1341
+ alignTo = args[4];
1342
+
1343
+ var pos = ({ x: alignTo.x, y: alignTo.y, z: series.z });
1344
+ pos = perspective([pos], chart, true)[0];
1345
+ alignTo.x = pos.x;
1346
+ alignTo.y = pos.y;
1347
+ }
1348
+
1349
+ proceed.apply(this, [].slice.call(arguments, 1));
1350
+ });
1351
+
1352
+ if (Highcharts.seriesTypes.columnrange) {
1353
+ Highcharts.wrap(Highcharts.seriesTypes.columnrange.prototype, 'drawPoints', draw3DPoints);
1354
+ }
1355
+
1356
+ Highcharts.wrap(Highcharts.seriesTypes.column.prototype, 'drawPoints', draw3DPoints);
1357
+
1358
+ /***
1359
+ EXTENSION FOR 3D CYLINDRICAL COLUMNS
1360
+ Not supported
1361
+ ***/
1362
+ /*
1363
+ var defaultOptions = Highcharts.getOptions();
1364
+ defaultOptions.plotOptions.cylinder = Highcharts.merge(defaultOptions.plotOptions.column);
1365
+ var CylinderSeries = Highcharts.extendClass(Highcharts.seriesTypes.column, {
1366
+ type: 'cylinder'
1367
+ });
1368
+ Highcharts.seriesTypes.cylinder = CylinderSeries;
1369
+
1370
+ Highcharts.wrap(Highcharts.seriesTypes.cylinder.prototype, 'translate', function (proceed) {
1371
+ proceed.apply(this, [].slice.call(arguments, 1));
1372
+
1373
+ // Do not do this if the chart is not 3D
1374
+ if (!this.chart.is3d()) {
1375
+ return;
1376
+ }
1377
+
1378
+ var series = this,
1379
+ chart = series.chart,
1380
+ options = chart.options,
1381
+ cylOptions = options.plotOptions.cylinder,
1382
+ options3d = options.chart.options3d,
1383
+ depth = cylOptions.depth || 0,
1384
+ alpha = options3d.alpha;
1385
+
1386
+ var z = cylOptions.stacking ? (this.options.stack || 0) * depth : series._i * depth;
1387
+ z += depth / 2;
1388
+
1389
+ if (cylOptions.grouping !== false) { z = 0; }
1390
+
1391
+ Highcharts.each(series.data, function (point) {
1392
+ var shapeArgs = point.shapeArgs;
1393
+ point.shapeType = 'arc3d';
1394
+ shapeArgs.x += depth / 2;
1395
+ shapeArgs.z = z;
1396
+ shapeArgs.start = 0;
1397
+ shapeArgs.end = 2 * PI;
1398
+ shapeArgs.r = depth * 0.95;
1399
+ shapeArgs.innerR = 0;
1400
+ shapeArgs.depth = shapeArgs.height * (1 / sin((90 - alpha) * deg2rad)) - z;
1401
+ shapeArgs.alpha = 90 - alpha;
1402
+ shapeArgs.beta = 0;
1403
+ });
1404
+ });
1405
+ */
1406
+ /***
1407
+ EXTENSION FOR 3D PIES
1408
+ ***/
1409
+
1410
+ Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'translate', function (proceed) {
1411
+ proceed.apply(this, [].slice.call(arguments, 1));
1412
+
1413
+ // Do not do this if the chart is not 3D
1414
+ if (!this.chart.is3d()) {
1415
+ return;
1416
+ }
1417
+
1418
+ var series = this,
1419
+ chart = series.chart,
1420
+ options = chart.options,
1421
+ seriesOptions = series.options,
1422
+ depth = seriesOptions.depth || 0,
1423
+ options3d = options.chart.options3d,
1424
+ alpha = options3d.alpha,
1425
+ beta = options3d.beta,
1426
+ z = seriesOptions.stacking ? (seriesOptions.stack || 0) * depth : series._i * depth;
1427
+
1428
+ z += depth / 2;
1429
+
1430
+ if (seriesOptions.grouping !== false) {
1431
+ z = 0;
1432
+ }
1433
+
1434
+ each(series.data, function (point) {
1435
+
1436
+ var shapeArgs = point.shapeArgs,
1437
+ angle;
1438
+
1439
+ point.shapeType = 'arc3d';
1440
+
1441
+ shapeArgs.z = z;
1442
+ shapeArgs.depth = depth * 0.75;
1443
+ shapeArgs.alpha = alpha;
1444
+ shapeArgs.beta = beta;
1445
+ shapeArgs.center = series.center;
1446
+
1447
+ angle = (shapeArgs.end + shapeArgs.start) / 2;
1448
+
1449
+ point.slicedTranslation = {
1450
+ translateX: round(cos(angle) * seriesOptions.slicedOffset * cos(alpha * deg2rad)),
1451
+ translateY: round(sin(angle) * seriesOptions.slicedOffset * cos(alpha * deg2rad))
1452
+ };
1453
+ });
1454
+ });
1455
+
1456
+ Highcharts.wrap(Highcharts.seriesTypes.pie.prototype.pointClass.prototype, 'haloPath', function (proceed) {
1457
+ var args = arguments;
1458
+ return this.series.chart.is3d() ? [] : proceed.call(this, args[1]);
1459
+ });
1460
+
1461
+ Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'drawPoints', function (proceed) {
1462
+
1463
+ var options = this.options,
1464
+ states = options.states;
1465
+
1466
+ // Do not do this if the chart is not 3D
1467
+ if (this.chart.is3d()) {
1468
+ // Set the border color to the fill color to provide a smooth edge
1469
+ this.borderWidth = options.borderWidth = options.edgeWidth || 1;
1470
+ this.borderColor = options.edgeColor = Highcharts.pick(options.edgeColor, options.borderColor, undefined);
1471
+
1472
+ states.hover.borderColor = Highcharts.pick(states.hover.edgeColor, this.borderColor);
1473
+ states.hover.borderWidth = Highcharts.pick(states.hover.edgeWidth, this.borderWidth);
1474
+ states.select.borderColor = Highcharts.pick(states.select.edgeColor, this.borderColor);
1475
+ states.select.borderWidth = Highcharts.pick(states.select.edgeWidth, this.borderWidth);
1476
+
1477
+ each(this.data, function (point) {
1478
+ var pointAttr = point.pointAttr;
1479
+ pointAttr[''].stroke = point.series.borderColor || point.color;
1480
+ pointAttr['']['stroke-width'] = point.series.borderWidth;
1481
+ pointAttr.hover.stroke = states.hover.borderColor;
1482
+ pointAttr.hover['stroke-width'] = states.hover.borderWidth;
1483
+ pointAttr.select.stroke = states.select.borderColor;
1484
+ pointAttr.select['stroke-width'] = states.select.borderWidth;
1485
+ });
1486
+ }
1487
+
1488
+ proceed.apply(this, [].slice.call(arguments, 1));
1489
+
1490
+ if (this.chart.is3d()) {
1491
+ each(this.points, function (point) {
1492
+ var graphic = point.graphic;
1493
+
1494
+ // #4584 Check if has graphic - null points don't have it
1495
+ if (graphic) {
1496
+ // Hide null or 0 points (#3006, 3650)
1497
+ graphic[point.y ? 'show' : 'hide']();
1498
+ }
1499
+ });
1500
+ }
1501
+ });
1502
+
1503
+ Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'drawDataLabels', function (proceed) {
1504
+ if (this.chart.is3d()) {
1505
+ var series = this,
1506
+ chart = series.chart,
1507
+ options3d = chart.options.chart.options3d;
1508
+ each(series.data, function (point) {
1509
+ var shapeArgs = point.shapeArgs,
1510
+ r = shapeArgs.r,
1511
+ a1 = (shapeArgs.alpha || options3d.alpha) * deg2rad, //#3240 issue with datalabels for 0 and null values
1512
+ b1 = (shapeArgs.beta || options3d.beta) * deg2rad,
1513
+ a2 = (shapeArgs.start + shapeArgs.end) / 2,
1514
+ labelPos = point.labelPos,
1515
+ labelIndexes = [0, 2, 4], // [x1, y1, x2, y2, x3, y3]
1516
+ yOffset = (-r * (1 - cos(a1)) * sin(a2)), // + (sin(a2) > 0 ? sin(a1) * d : 0)
1517
+ xOffset = r * (cos(b1) - 1) * cos(a2);
1518
+
1519
+ // Apply perspective on label positions
1520
+ each(labelIndexes, function (index) {
1521
+ labelPos[index] += xOffset;
1522
+ labelPos[index + 1] += yOffset;
1523
+ });
1524
+ });
1525
+ }
1526
+
1527
+ proceed.apply(this, [].slice.call(arguments, 1));
1528
+ });
1529
+
1530
+ Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'addPoint', function (proceed) {
1531
+ proceed.apply(this, [].slice.call(arguments, 1));
1532
+ if (this.chart.is3d()) {
1533
+ // destroy (and rebuild) everything!!!
1534
+ this.update(this.userOptions, true); // #3845 pass the old options
1535
+ }
1536
+ });
1537
+
1538
+ Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'animate', function (proceed) {
1539
+ if (!this.chart.is3d()) {
1540
+ proceed.apply(this, [].slice.call(arguments, 1));
1541
+ } else {
1542
+ var args = arguments,
1543
+ init = args[1],
1544
+ animation = this.options.animation,
1545
+ attribs,
1546
+ center = this.center,
1547
+ group = this.group,
1548
+ markerGroup = this.markerGroup;
1549
+
1550
+ if (Highcharts.svg) { // VML is too slow anyway
1551
+
1552
+ if (animation === true) {
1553
+ animation = {};
1554
+ }
1555
+ // Initialize the animation
1556
+ if (init) {
1557
+
1558
+ // Scale down the group and place it in the center
1559
+ group.oldtranslateX = group.translateX;
1560
+ group.oldtranslateY = group.translateY;
1561
+ attribs = {
1562
+ translateX: center[0],
1563
+ translateY: center[1],
1564
+ scaleX: 0.001, // #1499
1565
+ scaleY: 0.001
1566
+ };
1567
+
1568
+ group.attr(attribs);
1569
+ if (markerGroup) {
1570
+ markerGroup.attrSetters = group.attrSetters;
1571
+ markerGroup.attr(attribs);
1572
+ }
1573
+
1574
+ // Run the animation
1575
+ } else {
1576
+ attribs = {
1577
+ translateX: group.oldtranslateX,
1578
+ translateY: group.oldtranslateY,
1579
+ scaleX: 1,
1580
+ scaleY: 1
1581
+ };
1582
+ group.animate(attribs, animation);
1583
+
1584
+ if (markerGroup) {
1585
+ markerGroup.animate(attribs, animation);
1586
+ }
1587
+
1588
+ // Delete this function to allow it only once
1589
+ this.animate = null;
1590
+ }
1591
+
1592
+ }
1593
+ }
1594
+ });
1595
+ /***
1596
+ EXTENSION FOR 3D SCATTER CHART
1597
+ ***/
1598
+
1599
+ Highcharts.wrap(Highcharts.seriesTypes.scatter.prototype, 'translate', function (proceed) {
1600
+ //function translate3d(proceed) {
1601
+ proceed.apply(this, [].slice.call(arguments, 1));
1602
+
1603
+ if (!this.chart.is3d()) {
1604
+ return;
1605
+ }
1606
+
1607
+ var series = this,
1608
+ chart = series.chart,
1609
+ zAxis = Highcharts.pick(series.zAxis, chart.options.zAxis[0]),
1610
+ rawPoints = [],
1611
+ rawPoint,
1612
+ projectedPoints,
1613
+ projectedPoint,
1614
+ zValue,
1615
+ i;
1616
+
1617
+ for (i = 0; i < series.data.length; i++) {
1618
+ rawPoint = series.data[i];
1619
+ zValue = zAxis.isLog && zAxis.val2lin ? zAxis.val2lin(rawPoint.z) : rawPoint.z; // #4562
1620
+ rawPoint.plotZ = zAxis.translate(zValue);
1621
+
1622
+ rawPoint.isInside = rawPoint.isInside ? (zValue >= zAxis.min && zValue <= zAxis.max) : false;
1623
+
1624
+ rawPoints.push({
1625
+ x: rawPoint.plotX,
1626
+ y: rawPoint.plotY,
1627
+ z: rawPoint.plotZ
1628
+ });
1629
+ }
1630
+
1631
+ projectedPoints = perspective(rawPoints, chart, true);
1632
+
1633
+ for (i = 0; i < series.data.length; i++) {
1634
+ rawPoint = series.data[i];
1635
+ projectedPoint = projectedPoints[i];
1636
+
1637
+ rawPoint.plotXold = rawPoint.plotX;
1638
+ rawPoint.plotYold = rawPoint.plotY;
1639
+
1640
+ rawPoint.plotX = projectedPoint.x;
1641
+ rawPoint.plotY = projectedPoint.y;
1642
+ rawPoint.plotZ = projectedPoint.z;
1643
+
1644
+
1645
+ }
1646
+
1647
+ });
1648
+
1649
+ Highcharts.wrap(Highcharts.seriesTypes.scatter.prototype, 'init', function (proceed, chart, options) {
1650
+ if (chart.is3d()) {
1651
+ // add a third coordinate
1652
+ this.axisTypes = ['xAxis', 'yAxis', 'zAxis'];
1653
+ this.pointArrayMap = ['x', 'y', 'z'];
1654
+ this.parallelArrays = ['x', 'y', 'z'];
1655
+ }
1656
+
1657
+ var result = proceed.apply(this, [chart, options]);
1658
+
1659
+ if (this.chart.is3d()) {
1660
+ // Set a new default tooltip formatter
1661
+ var default3dScatterTooltip = 'x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>z: <b>{point.z}</b><br/>';
1662
+ if (this.userOptions.tooltip) {
1663
+ this.tooltipOptions.pointFormat = this.userOptions.tooltip.pointFormat || default3dScatterTooltip;
1664
+ } else {
1665
+ this.tooltipOptions.pointFormat = default3dScatterTooltip;
1666
+ }
1667
+ }
1668
+ return result;
1669
+ });
1670
+ /**
1671
+ * Extension to the VML Renderer
1672
+ */
1673
+ if (Highcharts.VMLRenderer) {
1674
+
1675
+ Highcharts.setOptions({ animate: false });
1676
+
1677
+ Highcharts.VMLRenderer.prototype.cuboid = Highcharts.SVGRenderer.prototype.cuboid;
1678
+ Highcharts.VMLRenderer.prototype.cuboidPath = Highcharts.SVGRenderer.prototype.cuboidPath;
1679
+
1680
+ Highcharts.VMLRenderer.prototype.toLinePath = Highcharts.SVGRenderer.prototype.toLinePath;
1681
+
1682
+ Highcharts.VMLRenderer.prototype.createElement3D = Highcharts.SVGRenderer.prototype.createElement3D;
1683
+
1684
+ Highcharts.VMLRenderer.prototype.arc3d = function (shapeArgs) {
1685
+ var result = Highcharts.SVGRenderer.prototype.arc3d.call(this, shapeArgs);
1686
+ result.css({ zIndex: result.zIndex });
1687
+ return result;
1688
+ };
1689
+
1690
+ Highcharts.VMLRenderer.prototype.arc3dPath = Highcharts.SVGRenderer.prototype.arc3dPath;
1691
+
1692
+ Highcharts.wrap(Highcharts.Axis.prototype, 'render', function (proceed) {
1693
+ proceed.apply(this, [].slice.call(arguments, 1));
1694
+ // VML doesn't support a negative z-index
1695
+ if (this.sideFrame) {
1696
+ this.sideFrame.css({ zIndex: 0 });
1697
+ this.sideFrame.front.attr({ fill: this.sideFrame.color });
1698
+ }
1699
+ if (this.bottomFrame) {
1700
+ this.bottomFrame.css({ zIndex: 1 });
1701
+ this.bottomFrame.front.attr({ fill: this.bottomFrame.color });
1702
+ }
1703
+ if (this.backFrame) {
1704
+ this.backFrame.css({ zIndex: 0 });
1705
+ this.backFrame.front.attr({ fill: this.backFrame.color });
1706
+ }
1707
+ });
1708
+
1709
+ }
1710
+
1711
+ }));