Subversion-Projekte lars-tiefland.ci

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
776 lars 1
// ==ClosureCompiler==
2
// @compilation_level SIMPLE_OPTIMIZATIONS
3
 
4
/**
5
 * @license Highcharts JS v4.1.9 (2015-10-07)
6
 *
7
 * (c) 2009-2013 Torstein Hønsi
8
 *
9
 * License: www.highcharts.com/license
10
 */
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
 
264
/**
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));