highcharts-rails 4.1.9 → 4.1.10

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