highcharts-3d.src.js 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327
  1. // ==ClosureCompiler==
  2. // @compilation_level SIMPLE_OPTIMIZATIONS
  3. /**
  4. * @license Highcharts JS v4.1.5 (2015-04-13)
  5. *
  6. * (c) 2009-2013 Torstein Hønsi
  7. *
  8. * License: www.highcharts.com/license
  9. */
  10. // JSLint options:
  11. /*global Highcharts, HighchartsAdapter, document, window, navigator, setInterval, clearInterval, clearTimeout, setTimeout, location, jQuery, $, console */
  12. (function (Highcharts) {
  13. /**
  14. Shorthands for often used function
  15. */
  16. /**
  17. * Mathematical Functionility
  18. */
  19. var PI = Math.PI,
  20. deg2rad = (PI / 180), // degrees to radians
  21. sin = Math.sin,
  22. cos = Math.cos,
  23. pick = Highcharts.pick,
  24. round = Math.round;
  25. function perspective(points, chart, insidePlotArea) {
  26. var options3d = chart.options.chart.options3d,
  27. inverted = false,
  28. origin;
  29. if (insidePlotArea) {
  30. inverted = chart.inverted;
  31. origin = {
  32. x: chart.plotWidth / 2,
  33. y: chart.plotHeight / 2,
  34. z: options3d.depth / 2,
  35. vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
  36. };
  37. } else {
  38. origin = {
  39. x: chart.plotLeft + (chart.plotWidth / 2),
  40. y: chart.plotTop + (chart.plotHeight / 2),
  41. z: options3d.depth / 2,
  42. vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
  43. };
  44. }
  45. var result = [],
  46. xe = origin.x,
  47. ye = origin.y,
  48. ze = origin.z,
  49. vd = origin.vd,
  50. angle1 = deg2rad * (inverted ? options3d.beta : -options3d.beta),
  51. angle2 = deg2rad * (inverted ? -options3d.alpha : options3d.alpha),
  52. s1 = sin(angle1),
  53. c1 = cos(angle1),
  54. s2 = sin(angle2),
  55. c2 = cos(angle2);
  56. var x, y, z, px, py, pz;
  57. Highcharts.each(points, function (point) {
  58. x = (inverted ? point.y : point.x) - xe;
  59. y = (inverted ? point.x : point.y) - ye;
  60. z = (point.z || 0) - ze;
  61. //Apply 3-D rotation
  62. px = c1 * x - s1 * z;
  63. py = -s1 * s2 * x - c1 * s2 * z + c2 * y;
  64. pz = s1 * c2 * x + c1 * c2 * z + s2 * y;
  65. //Apply perspective
  66. if ((vd > 0) && (vd < Number.POSITIVE_INFINITY)) {
  67. px = px * (vd / (pz + ze + vd));
  68. py = py * (vd / (pz + ze + vd));
  69. }
  70. //Apply translation
  71. px = px + xe;
  72. py = py + ye;
  73. pz = pz + ze;
  74. result.push({
  75. x: (inverted ? py : px),
  76. y: (inverted ? px : py),
  77. z: pz
  78. });
  79. });
  80. return result;
  81. }
  82. // Make function acessible to plugins
  83. Highcharts.perspective = perspective;
  84. /***
  85. EXTENSION TO THE SVG-RENDERER TO ENABLE 3D SHAPES
  86. ***/
  87. ////// HELPER METHODS //////
  88. var dFactor = (4 * (Math.sqrt(2) - 1) / 3) / (PI / 2);
  89. function defined(obj) {
  90. return obj !== undefined && obj !== null;
  91. }
  92. //Shoelace algorithm -- http://en.wikipedia.org/wiki/Shoelace_formula
  93. function shapeArea(vertexes) {
  94. var area = 0,
  95. i,
  96. j;
  97. for (i = 0; i < vertexes.length; i++) {
  98. j = (i + 1) % vertexes.length;
  99. area += vertexes[i].x * vertexes[j].y - vertexes[j].x * vertexes[i].y;
  100. }
  101. return area / 2;
  102. }
  103. function averageZ(vertexes) {
  104. var z = 0,
  105. i;
  106. for (i = 0; i < vertexes.length; i++) {
  107. z += vertexes[i].z;
  108. }
  109. return vertexes.length ? z / vertexes.length : 0;
  110. }
  111. function curveTo(cx, cy, rx, ry, start, end, dx, dy) {
  112. var result = [];
  113. if ((end > start) && (end - start > PI / 2 + 0.0001)) {
  114. result = result.concat(curveTo(cx, cy, rx, ry, start, start + (PI / 2), dx, dy));
  115. result = result.concat(curveTo(cx, cy, rx, ry, start + (PI / 2), end, dx, dy));
  116. return result;
  117. } else if ((end < start) && (start - end > PI / 2 + 0.0001)) {
  118. result = result.concat(curveTo(cx, cy, rx, ry, start, start - (PI / 2), dx, dy));
  119. result = result.concat(curveTo(cx, cy, rx, ry, start - (PI / 2), end, dx, dy));
  120. return result;
  121. } else {
  122. var arcAngle = end - start;
  123. return [
  124. 'C',
  125. cx + (rx * cos(start)) - ((rx * dFactor * arcAngle) * sin(start)) + dx,
  126. cy + (ry * sin(start)) + ((ry * dFactor * arcAngle) * cos(start)) + dy,
  127. cx + (rx * cos(end)) + ((rx * dFactor * arcAngle) * sin(end)) + dx,
  128. cy + (ry * sin(end)) - ((ry * dFactor * arcAngle) * cos(end)) + dy,
  129. cx + (rx * cos(end)) + dx,
  130. cy + (ry * sin(end)) + dy
  131. ];
  132. }
  133. }
  134. Highcharts.SVGRenderer.prototype.toLinePath = function (points, closed) {
  135. var result = [];
  136. // Put "L x y" for each point
  137. Highcharts.each(points, function (point) {
  138. result.push('L', point.x, point.y);
  139. });
  140. if (points.length) {
  141. // Set the first element to M
  142. result[0] = 'M';
  143. // If it is a closed line, add Z
  144. if (closed) {
  145. result.push('Z');
  146. }
  147. }
  148. return result;
  149. };
  150. ////// CUBOIDS //////
  151. Highcharts.SVGRenderer.prototype.cuboid = function (shapeArgs) {
  152. var result = this.g(),
  153. paths = this.cuboidPath(shapeArgs);
  154. result.front = this.path(paths[0]).attr({zIndex: paths[3], 'stroke-linejoin': 'round'}).add(result);
  155. result.top = this.path(paths[1]).attr({zIndex: paths[4], 'stroke-linejoin': 'round'}).add(result);
  156. result.side = this.path(paths[2]).attr({zIndex: paths[5], 'stroke-linejoin': 'round'}).add(result);
  157. result.fillSetter = function (color) {
  158. var c0 = color,
  159. c1 = Highcharts.Color(color).brighten(0.1).get(),
  160. c2 = Highcharts.Color(color).brighten(-0.1).get();
  161. this.front.attr({fill: c0});
  162. this.top.attr({fill: c1});
  163. this.side.attr({fill: c2});
  164. this.color = color;
  165. return this;
  166. };
  167. result.opacitySetter = function (opacity) {
  168. this.front.attr({opacity: opacity});
  169. this.top.attr({opacity: opacity});
  170. this.side.attr({opacity: opacity});
  171. return this;
  172. };
  173. result.attr = function (args) {
  174. if (args.shapeArgs || defined(args.x)) {
  175. var shapeArgs = args.shapeArgs || args;
  176. var paths = this.renderer.cuboidPath(shapeArgs);
  177. this.front.attr({d: paths[0], zIndex: paths[3]});
  178. this.top.attr({d: paths[1], zIndex: paths[4]});
  179. this.side.attr({d: paths[2], zIndex: paths[5]});
  180. } else {
  181. Highcharts.SVGElement.prototype.attr.call(this, args);
  182. }
  183. return this;
  184. };
  185. result.animate = function (args, duration, complete) {
  186. if (defined(args.x) && defined(args.y)) {
  187. var paths = this.renderer.cuboidPath(args);
  188. this.front.attr({zIndex: paths[3]}).animate({d: paths[0]}, duration, complete);
  189. this.top.attr({zIndex: paths[4]}).animate({d: paths[1]}, duration, complete);
  190. this.side.attr({zIndex: paths[5]}).animate({d: paths[2]}, duration, complete);
  191. } else if (args.opacity) {
  192. this.front.animate(args, duration, complete);
  193. this.top.animate(args, duration, complete);
  194. this.side.animate(args, duration, complete);
  195. } else {
  196. Highcharts.SVGElement.prototype.animate.call(this, args, duration, complete);
  197. }
  198. return this;
  199. };
  200. result.destroy = function () {
  201. this.front.destroy();
  202. this.top.destroy();
  203. this.side.destroy();
  204. return null;
  205. };
  206. // Apply the Z index to the cuboid group
  207. result.attr({ zIndex: -paths[3] });
  208. return result;
  209. };
  210. Highcharts.SVGRenderer.prototype.cuboidPath = function (shapeArgs) {
  211. var x = shapeArgs.x,
  212. y = shapeArgs.y,
  213. z = shapeArgs.z,
  214. h = shapeArgs.height,
  215. w = shapeArgs.width,
  216. d = shapeArgs.depth,
  217. chart = Highcharts.charts[this.chartIndex],
  218. map = Highcharts.map;
  219. var pArr = [
  220. {x: x, y: y, z: z},
  221. {x: x + w, y: y, z: z},
  222. {x: x + w, y: y + h, z: z},
  223. {x: x, y: y + h, z: z},
  224. {x: x, y: y + h, z: z + d},
  225. {x: x + w, y: y + h, z: z + d},
  226. {x: x + w, y: y, z: z + d},
  227. {x: x, y: y, z: z + d}
  228. ];
  229. pArr = perspective(pArr, chart, shapeArgs.insidePlotArea);
  230. var pickShape = function (path1, path2) {
  231. path1 = map(path1, function (i) { return pArr[i]; });
  232. path2 = map(path2, function (i) { return pArr[i]; });
  233. if (shapeArea(path1) < 0) {
  234. return path1;
  235. } else if (shapeArea(path2) < 0) {
  236. return path2;
  237. } else {
  238. return [];
  239. }
  240. };
  241. // front or back
  242. var front = [3, 2, 1, 0];
  243. var back = [7, 6, 5, 4];
  244. var path1 = pickShape(front, back);
  245. // top or bottom
  246. var top = [1, 6, 7, 0];
  247. var bottom = [4, 5, 2, 3];
  248. var path2 = pickShape(top, bottom);
  249. // side
  250. var right = [1, 2, 5, 6];
  251. var left = [0, 7, 4, 3];
  252. var path3 = pickShape(right, left);
  253. return [this.toLinePath(path1, true), this.toLinePath(path2, true), this.toLinePath(path3, true), averageZ(path1), averageZ(path2), averageZ(path3)];
  254. };
  255. ////// SECTORS //////
  256. Highcharts.SVGRenderer.prototype.arc3d = function (shapeArgs) {
  257. shapeArgs.alpha *= deg2rad;
  258. shapeArgs.beta *= deg2rad;
  259. var result = this.g(),
  260. paths = this.arc3dPath(shapeArgs),
  261. renderer = result.renderer;
  262. var zIndex = paths.zTop * 100;
  263. result.shapeArgs = shapeArgs; // Store for later use
  264. result.top = renderer.path(paths.top).attr({zIndex: paths.zTop}).add(result);
  265. result.side1 = renderer.path(paths.side2).attr({zIndex: paths.zSide1});
  266. result.side2 = renderer.path(paths.side1).attr({zIndex: paths.zSide2});
  267. result.inn = renderer.path(paths.inn).attr({zIndex: paths.zInn});
  268. result.out = renderer.path(paths.out).attr({zIndex: paths.zOut});
  269. result.fillSetter = function (color) {
  270. this.color = color;
  271. var c0 = color,
  272. c2 = Highcharts.Color(color).brighten(-0.1).get();
  273. this.side1.attr({fill: c2});
  274. this.side2.attr({fill: c2});
  275. this.inn.attr({fill: c2});
  276. this.out.attr({fill: c2});
  277. this.top.attr({fill: c0});
  278. return this;
  279. };
  280. result.translateXSetter = function (value) {
  281. this.out.attr({translateX: value});
  282. this.inn.attr({translateX: value});
  283. this.side1.attr({translateX: value});
  284. this.side2.attr({translateX: value});
  285. this.top.attr({translateX: value});
  286. };
  287. result.translateYSetter = function (value) {
  288. this.out.attr({translateY: value});
  289. this.inn.attr({translateY: value});
  290. this.side1.attr({translateY: value});
  291. this.side2.attr({translateY: value});
  292. this.top.attr({translateY: value});
  293. };
  294. result.animate = function (args, duration, complete) {
  295. if (defined(args.end) || defined(args.start)) {
  296. this._shapeArgs = this.shapeArgs;
  297. Highcharts.SVGElement.prototype.animate.call(this, {
  298. _args: args
  299. }, {
  300. duration: duration,
  301. step: function () {
  302. var args = arguments,
  303. fx = args[1],
  304. result = fx.elem,
  305. start = result._shapeArgs,
  306. end = fx.end,
  307. pos = fx.pos,
  308. sA = Highcharts.merge(start, {
  309. x: start.x + ((end.x - start.x) * pos),
  310. y: start.y + ((end.y - start.y) * pos),
  311. r: start.r + ((end.r - start.r) * pos),
  312. innerR: start.innerR + ((end.innerR - start.innerR) * pos),
  313. start: start.start + ((end.start - start.start) * pos),
  314. end: start.end + ((end.end - start.end) * pos)
  315. });
  316. var paths = result.renderer.arc3dPath(sA);
  317. result.shapeArgs = sA;
  318. result.top.attr({d: paths.top, zIndex: paths.zTop});
  319. result.inn.attr({d: paths.inn, zIndex: paths.zInn});
  320. result.out.attr({d: paths.out, zIndex: paths.zOut});
  321. result.side1.attr({d: paths.side1, zIndex: paths.zSide1});
  322. result.side2.attr({d: paths.side2, zIndex: paths.zSide2});
  323. }
  324. }, complete);
  325. } else {
  326. Highcharts.SVGElement.prototype.animate.call(this, args, duration, complete);
  327. }
  328. return this;
  329. };
  330. result.destroy = function () {
  331. this.top.destroy();
  332. this.out.destroy();
  333. this.inn.destroy();
  334. this.side1.destroy();
  335. this.side2.destroy();
  336. Highcharts.SVGElement.prototype.destroy.call(this);
  337. };
  338. result.hide = function () {
  339. this.top.hide();
  340. this.out.hide();
  341. this.inn.hide();
  342. this.side1.hide();
  343. this.side2.hide();
  344. };
  345. result.show = function () {
  346. this.top.show();
  347. this.out.show();
  348. this.inn.show();
  349. this.side1.show();
  350. this.side2.show();
  351. };
  352. result.zIndex = zIndex;
  353. result.attr({zIndex: zIndex});
  354. return result;
  355. };
  356. Highcharts.SVGRenderer.prototype.arc3dPath = function (shapeArgs) {
  357. var cx = shapeArgs.x,
  358. cy = shapeArgs.y,
  359. start = shapeArgs.start,
  360. end = shapeArgs.end - 0.00001,
  361. r = shapeArgs.r,
  362. ir = shapeArgs.innerR,
  363. d = shapeArgs.depth,
  364. alpha = shapeArgs.alpha,
  365. beta = shapeArgs.beta;
  366. // Some Variables
  367. var cs = cos(start),
  368. ss = sin(start),
  369. ce = cos(end),
  370. se = sin(end),
  371. rx = r * cos(beta),
  372. ry = r * cos(alpha),
  373. irx = ir * cos(beta),
  374. iry = ir * cos(alpha),
  375. dx = d * sin(beta),
  376. dy = d * sin(alpha);
  377. // TOP
  378. var top = ['M', cx + (rx * cs), cy + (ry * ss)];
  379. top = top.concat(curveTo(cx, cy, rx, ry, start, end, 0, 0));
  380. top = top.concat([
  381. 'L', cx + (irx * ce), cy + (iry * se)
  382. ]);
  383. top = top.concat(curveTo(cx, cy, irx, iry, end, start, 0, 0));
  384. top = top.concat(['Z']);
  385. // OUTSIDE
  386. var b = (beta > 0 ? PI / 2 : 0),
  387. a = (alpha > 0 ? 0 : PI / 2);
  388. var start2 = start > -b ? start : (end > -b ? -b : start),
  389. end2 = end < PI - a ? end : (start < PI - a ? PI - a : end);
  390. var out = ['M', cx + (rx * cos(start2)), cy + (ry * sin(start2))];
  391. out = out.concat(curveTo(cx, cy, rx, ry, start2, end2, 0, 0));
  392. out = out.concat([
  393. 'L', cx + (rx * cos(end2)) + dx, cy + (ry * sin(end2)) + dy
  394. ]);
  395. out = out.concat(curveTo(cx, cy, rx, ry, end2, start2, dx, dy));
  396. out = out.concat(['Z']);
  397. // INSIDE
  398. var inn = ['M', cx + (irx * cs), cy + (iry * ss)];
  399. inn = inn.concat(curveTo(cx, cy, irx, iry, start, end, 0, 0));
  400. inn = inn.concat([
  401. 'L', cx + (irx * cos(end)) + dx, cy + (iry * sin(end)) + dy
  402. ]);
  403. inn = inn.concat(curveTo(cx, cy, irx, iry, end, start, dx, dy));
  404. inn = inn.concat(['Z']);
  405. // SIDES
  406. var side1 = [
  407. 'M', cx + (rx * cs), cy + (ry * ss),
  408. 'L', cx + (rx * cs) + dx, cy + (ry * ss) + dy,
  409. 'L', cx + (irx * cs) + dx, cy + (iry * ss) + dy,
  410. 'L', cx + (irx * cs), cy + (iry * ss),
  411. 'Z'
  412. ];
  413. var side2 = [
  414. 'M', cx + (rx * ce), cy + (ry * se),
  415. 'L', cx + (rx * ce) + dx, cy + (ry * se) + dy,
  416. 'L', cx + (irx * ce) + dx, cy + (iry * se) + dy,
  417. 'L', cx + (irx * ce), cy + (iry * se),
  418. 'Z'
  419. ];
  420. var a1 = sin((start + end) / 2),
  421. a2 = sin(start),
  422. a3 = sin(end);
  423. return {
  424. top: top,
  425. zTop: r,
  426. out: out,
  427. zOut: Math.max(a1, a2, a3) * r,
  428. inn: inn,
  429. zInn: Math.max(a1, a2, a3) * r,
  430. side1: side1,
  431. zSide1: a2 * (r * 0.99),
  432. side2: side2,
  433. zSide2: a3 * (r * 0.99)
  434. };
  435. };
  436. /***
  437. EXTENSION FOR 3D CHARTS
  438. ***/
  439. // Shorthand to check the is3d flag
  440. Highcharts.Chart.prototype.is3d = function () {
  441. return this.options.chart.options3d && this.options.chart.options3d.enabled;
  442. };
  443. Highcharts.wrap(Highcharts.Chart.prototype, 'isInsidePlot', function (proceed) {
  444. if (this.is3d()) {
  445. return true;
  446. } else {
  447. return proceed.apply(this, [].slice.call(arguments, 1));
  448. }
  449. });
  450. var defaultChartOptions = Highcharts.getOptions();
  451. defaultChartOptions.chart.options3d = {
  452. enabled: false,
  453. alpha: 0,
  454. beta: 0,
  455. depth: 100,
  456. viewDistance: 25,
  457. frame: {
  458. bottom: { size: 1, color: 'rgba(255,255,255,0)' },
  459. side: { size: 1, color: 'rgba(255,255,255,0)' },
  460. back: { size: 1, color: 'rgba(255,255,255,0)' }
  461. }
  462. };
  463. Highcharts.wrap(Highcharts.Chart.prototype, 'init', function (proceed) {
  464. var args = [].slice.call(arguments, 1),
  465. plotOptions,
  466. pieOptions;
  467. if (args[0].chart.options3d && args[0].chart.options3d.enabled) {
  468. plotOptions = args[0].plotOptions || {};
  469. pieOptions = plotOptions.pie || {};
  470. pieOptions.borderColor = Highcharts.pick(pieOptions.borderColor, undefined);
  471. }
  472. proceed.apply(this, args);
  473. });
  474. Highcharts.wrap(Highcharts.Chart.prototype, 'setChartSize', function (proceed) {
  475. proceed.apply(this, [].slice.call(arguments, 1));
  476. if (this.is3d()) {
  477. var inverted = this.inverted,
  478. clipBox = this.clipBox,
  479. margin = this.margin,
  480. x = inverted ? 'y' : 'x',
  481. y = inverted ? 'x' : 'y',
  482. w = inverted ? 'height' : 'width',
  483. h = inverted ? 'width' : 'height';
  484. clipBox[x] = -(margin[3] || 0);
  485. clipBox[y] = -(margin[0] || 0);
  486. clipBox[w] = this.chartWidth + (margin[3] || 0) + (margin[1] || 0);
  487. clipBox[h] = this.chartHeight + (margin[0] || 0) + (margin[2] || 0);
  488. }
  489. });
  490. Highcharts.wrap(Highcharts.Chart.prototype, 'redraw', function (proceed) {
  491. if (this.is3d()) {
  492. // Set to force a redraw of all elements
  493. this.isDirtyBox = true;
  494. }
  495. proceed.apply(this, [].slice.call(arguments, 1));
  496. });
  497. // Draw the series in the reverse order (#3803, #3917)
  498. Highcharts.wrap(Highcharts.Chart.prototype, 'renderSeries', function (proceed) {
  499. var series,
  500. i = this.series.length;
  501. if (this.is3d()) {
  502. while (i--) {
  503. series = this.series[i];
  504. series.translate();
  505. series.render();
  506. }
  507. } else {
  508. proceed.call(this);
  509. }
  510. });
  511. Highcharts.Chart.prototype.retrieveStacks = function (stacking) {
  512. var series = this.series,
  513. stacks = {},
  514. stackNumber,
  515. i = 1;
  516. Highcharts.each(this.series, function (S) {
  517. stackNumber = stacking ? (S.options.stack || 0) : series.length - 1 - S.index; // #3841
  518. if (!stacks[stackNumber]) {
  519. stacks[stackNumber] = { series: [S], position: i};
  520. i++;
  521. } else {
  522. stacks[stackNumber].series.push(S);
  523. }
  524. });
  525. stacks.totalStacks = i + 1;
  526. return stacks;
  527. };
  528. /***
  529. EXTENSION TO THE AXIS
  530. ***/
  531. Highcharts.wrap(Highcharts.Axis.prototype, 'init', function (proceed) {
  532. var args = arguments;
  533. if (args[1].is3d()) {
  534. args[2].tickWidth = Highcharts.pick(args[2].tickWidth, 0);
  535. args[2].gridLineWidth = Highcharts.pick(args[2].gridLineWidth, 1);
  536. }
  537. proceed.apply(this, [].slice.call(arguments, 1));
  538. });
  539. Highcharts.wrap(Highcharts.Axis.prototype, 'render', function (proceed) {
  540. proceed.apply(this, [].slice.call(arguments, 1));
  541. // Do not do this if the chart is not 3D
  542. if (!this.chart.is3d()) {
  543. return;
  544. }
  545. var chart = this.chart,
  546. renderer = chart.renderer,
  547. options3d = chart.options.chart.options3d,
  548. frame = options3d.frame,
  549. fbottom = frame.bottom,
  550. fback = frame.back,
  551. fside = frame.side,
  552. depth = options3d.depth,
  553. height = this.height,
  554. width = this.width,
  555. left = this.left,
  556. top = this.top;
  557. if (this.horiz) {
  558. /// BOTTOM
  559. if (this.axisLine) {
  560. this.axisLine.hide();
  561. }
  562. var bottomShape = {
  563. x: left,
  564. y: top + (chart.yAxis[0].reversed ? -fbottom.size : height),
  565. z: 0,
  566. width: width,
  567. height: fbottom.size,
  568. depth: depth,
  569. insidePlotArea: false
  570. };
  571. if (!this.bottomFrame) {
  572. this.bottomFrame = renderer.cuboid(bottomShape).attr({fill: fbottom.color, zIndex: (chart.yAxis[0].reversed && options3d.alpha > 0 ? 4 : -1)}).css({stroke: fbottom.color}).add();
  573. } else {
  574. this.bottomFrame.animate(bottomShape);
  575. }
  576. } else {
  577. // BACK
  578. var backShape = {
  579. x: left,
  580. y: top,
  581. z: depth + 1,
  582. width: width,
  583. height: height + fbottom.size,
  584. depth: fback.size,
  585. insidePlotArea: false
  586. };
  587. if (!this.backFrame) {
  588. this.backFrame = renderer.cuboid(backShape).attr({fill: fback.color, zIndex: -3}).css({stroke: fback.color}).add();
  589. } else {
  590. this.backFrame.animate(backShape);
  591. }
  592. // SIDE
  593. if (this.axisLine) {
  594. this.axisLine.hide();
  595. }
  596. var sideShape = {
  597. x: (chart.yAxis[0].opposite ? width : 0) + left - fside.size,
  598. y: top,
  599. z: 0,
  600. width: fside.size,
  601. height: height + fbottom.size,
  602. depth: depth + fback.size,
  603. insidePlotArea: false
  604. };
  605. if (!this.sideFrame) {
  606. this.sideFrame = renderer.cuboid(sideShape).attr({fill: fside.color, zIndex: -2}).css({stroke: fside.color}).add();
  607. } else {
  608. this.sideFrame.animate(sideShape);
  609. }
  610. }
  611. });
  612. Highcharts.wrap(Highcharts.Axis.prototype, 'getPlotLinePath', function (proceed) {
  613. var path = proceed.apply(this, [].slice.call(arguments, 1));
  614. // Do not do this if the chart is not 3D
  615. if (!this.chart.is3d()) {
  616. return path;
  617. }
  618. if (path === null) { return path; }
  619. var chart = this.chart,
  620. options3d = chart.options.chart.options3d;
  621. var d = options3d.depth;
  622. var pArr = [
  623. { x: path[1], y: path[2], z : (this.horiz || this.opposite ? d : 0)},
  624. { x: path[1], y: path[2], z : d },
  625. { x: path[4], y: path[5], z : d },
  626. { x: path[4], y: path[5], z : (this.horiz || this.opposite ? 0 : d)}
  627. ];
  628. pArr = perspective(pArr, this.chart, false);
  629. path = this.chart.renderer.toLinePath(pArr, false);
  630. return path;
  631. });
  632. Highcharts.wrap(Highcharts.Axis.prototype, 'getPlotBandPath', function (proceed) {
  633. // Do not do this if the chart is not 3D
  634. if (!this.chart.is3d()) {
  635. return proceed.apply(this, [].slice.call(arguments, 1));
  636. } else {
  637. var args = arguments,
  638. from = args[1],
  639. to = args[2];
  640. var toPath = this.getPlotLinePath(to),
  641. path = this.getPlotLinePath(from);
  642. if (path && toPath) {
  643. path.push(
  644. toPath[7], // These two do not exist in the regular getPlotLine
  645. toPath[8], // ---- # 3005
  646. toPath[4],
  647. toPath[5],
  648. toPath[1],
  649. toPath[2]
  650. );
  651. } else { // outside the axis area
  652. path = null;
  653. }
  654. return path;
  655. }
  656. });
  657. /***
  658. EXTENSION TO THE TICKS
  659. ***/
  660. Highcharts.wrap(Highcharts.Tick.prototype, 'getMarkPath', function (proceed) {
  661. var path = proceed.apply(this, [].slice.call(arguments, 1));
  662. // Do not do this if the chart is not 3D
  663. if (!this.axis.chart.is3d()) {
  664. return path;
  665. }
  666. var pArr = [
  667. {x: path[1], y: path[2], z: 0},
  668. {x: path[4], y: path[5], z: 0}
  669. ];
  670. pArr = perspective(pArr, this.axis.chart, false);
  671. path = [
  672. 'M', pArr[0].x, pArr[0].y,
  673. 'L', pArr[1].x, pArr[1].y
  674. ];
  675. return path;
  676. });
  677. Highcharts.wrap(Highcharts.Tick.prototype, 'getLabelPosition', function (proceed) {
  678. var pos = proceed.apply(this, [].slice.call(arguments, 1));
  679. // Do not do this if the chart is not 3D
  680. if (!this.axis.chart.is3d()) {
  681. return pos;
  682. }
  683. pos = perspective([{x: pos.x, y: pos.y, z: 0}], this.axis.chart, false)[0];
  684. pos.x = pos.x - (!this.axis.horiz && this.axis.opposite ? this.axis.transA : 0); //#3788
  685. return pos;
  686. });
  687. Highcharts.wrap(Highcharts.Axis.prototype, 'drawCrosshair', function (proceed) {
  688. var args = arguments;
  689. if (this.chart.is3d()) {
  690. if (args[2]) {
  691. args[2] = {
  692. plotX: args[2].plotXold || args[2].plotX,
  693. plotY: args[2].plotYold || args[2].plotY
  694. };
  695. }
  696. }
  697. proceed.apply(this, [].slice.call(args, 1));
  698. });
  699. /***
  700. EXTENSION FOR 3D COLUMNS
  701. ***/
  702. Highcharts.wrap(Highcharts.seriesTypes.column.prototype, 'translate', function (proceed) {
  703. proceed.apply(this, [].slice.call(arguments, 1));
  704. // Do not do this if the chart is not 3D
  705. if (!this.chart.is3d()) {
  706. return;
  707. }
  708. var series = this,
  709. chart = series.chart,
  710. seriesOptions = series.options,
  711. depth = seriesOptions.depth || 25;
  712. var stack = seriesOptions.stacking ? (seriesOptions.stack || 0) : series._i;
  713. var z = stack * (depth + (seriesOptions.groupZPadding || 1));
  714. if (seriesOptions.grouping !== false) { z = 0; }
  715. z += (seriesOptions.groupZPadding || 1);
  716. Highcharts.each(series.data, function (point) {
  717. if (point.y !== null) {
  718. var shapeArgs = point.shapeArgs,
  719. tooltipPos = point.tooltipPos;
  720. point.shapeType = 'cuboid';
  721. shapeArgs.z = z;
  722. shapeArgs.depth = depth;
  723. shapeArgs.insidePlotArea = true;
  724. // Translate the tooltip position in 3d space
  725. tooltipPos = perspective([{ x: tooltipPos[0], y: tooltipPos[1], z: z }], chart, false)[0];
  726. point.tooltipPos = [tooltipPos.x, tooltipPos.y];
  727. }
  728. });
  729. // store for later use #4067
  730. series.z = z;
  731. });
  732. Highcharts.wrap(Highcharts.seriesTypes.column.prototype, 'animate', function (proceed) {
  733. if (!this.chart.is3d()) {
  734. proceed.apply(this, [].slice.call(arguments, 1));
  735. } else {
  736. var args = arguments,
  737. init = args[1],
  738. yAxis = this.yAxis,
  739. series = this,
  740. reversed = this.yAxis.reversed;
  741. if (Highcharts.svg) { // VML is too slow anyway
  742. if (init) {
  743. Highcharts.each(series.data, function (point) {
  744. if (point.y !== null) {
  745. point.height = point.shapeArgs.height;
  746. point.shapey = point.shapeArgs.y; //#2968
  747. point.shapeArgs.height = 1;
  748. if (!reversed) {
  749. if (point.stackY) {
  750. point.shapeArgs.y = point.plotY + yAxis.translate(point.stackY);
  751. } else {
  752. point.shapeArgs.y = point.plotY + (point.negative ? -point.height : point.height);
  753. }
  754. }
  755. }
  756. });
  757. } else { // run the animation
  758. Highcharts.each(series.data, function (point) {
  759. if (point.y !== null) {
  760. point.shapeArgs.height = point.height;
  761. point.shapeArgs.y = point.shapey; //#2968
  762. // null value do not have a graphic
  763. if (point.graphic) {
  764. point.graphic.animate(point.shapeArgs, series.options.animation);
  765. }
  766. }
  767. });
  768. // redraw datalabels to the correct position
  769. this.drawDataLabels();
  770. // delete this function to allow it only once
  771. series.animate = null;
  772. }
  773. }
  774. }
  775. });
  776. Highcharts.wrap(Highcharts.seriesTypes.column.prototype, 'init', function (proceed) {
  777. proceed.apply(this, [].slice.call(arguments, 1));
  778. if (this.chart.is3d()) {
  779. var seriesOptions = this.options,
  780. grouping = seriesOptions.grouping,
  781. stacking = seriesOptions.stacking,
  782. z = 0;
  783. if (!(grouping !== undefined && !grouping)) {
  784. var stacks = this.chart.retrieveStacks(stacking),
  785. stack = seriesOptions.stack || 0,
  786. i; // position within the stack
  787. for (i = 0; i < stacks[stack].series.length; i++) {
  788. if (stacks[stack].series[i] === this) {
  789. break;
  790. }
  791. }
  792. z = (stacks.totalStacks * 10) - (10 * (stacks.totalStacks - stacks[stack].position)) - i;
  793. }
  794. seriesOptions.zIndex = z;
  795. }
  796. });
  797. function draw3DPoints(proceed) {
  798. // Do not do this if the chart is not 3D
  799. if (this.chart.is3d()) {
  800. var grouping = this.chart.options.plotOptions.column.grouping;
  801. if (grouping !== undefined && !grouping && this.group.zIndex !== undefined && !this.zIndexSet) {
  802. this.group.attr({zIndex : (this.group.zIndex * 10)});
  803. this.zIndexSet = true; // #4062 set zindex only once
  804. }
  805. var options = this.options,
  806. states = this.options.states;
  807. this.borderWidth = options.borderWidth = defined(options.edgeWidth) ? options.edgeWidth : 1; //#4055
  808. Highcharts.each(this.data, function (point) {
  809. if (point.y !== null) {
  810. var pointAttr = point.pointAttr;
  811. // Set the border color to the fill color to provide a smooth edge
  812. this.borderColor = Highcharts.pick(options.edgeColor, pointAttr[''].fill);
  813. pointAttr[''].stroke = this.borderColor;
  814. pointAttr.hover.stroke = Highcharts.pick(states.hover.edgeColor, this.borderColor);
  815. pointAttr.select.stroke = Highcharts.pick(states.select.edgeColor, this.borderColor);
  816. }
  817. });
  818. }
  819. proceed.apply(this, [].slice.call(arguments, 1));
  820. }
  821. Highcharts.wrap(Highcharts.Series.prototype, 'alignDataLabel', function (proceed) {
  822. // Only do this for 3D columns and columnranges
  823. if (this.chart.is3d() && (this.type === 'column' || this.type === 'columnrange')) {
  824. var series = this,
  825. chart = series.chart;
  826. var args = arguments,
  827. alignTo = args[4];
  828. var pos = ({x: alignTo.x, y: alignTo.y, z: series.z});
  829. pos = perspective([pos], chart, true)[0];
  830. alignTo.x = pos.x;
  831. alignTo.y = pos.y;
  832. }
  833. proceed.apply(this, [].slice.call(arguments, 1));
  834. });
  835. if (Highcharts.seriesTypes.columnrange) {
  836. Highcharts.wrap(Highcharts.seriesTypes.columnrange.prototype, 'drawPoints', draw3DPoints);
  837. }
  838. Highcharts.wrap(Highcharts.seriesTypes.column.prototype, 'drawPoints', draw3DPoints);
  839. /***
  840. EXTENSION FOR 3D CYLINDRICAL COLUMNS
  841. Not supported
  842. ***/
  843. var defaultOptions = Highcharts.getOptions();
  844. defaultOptions.plotOptions.cylinder = Highcharts.merge(defaultOptions.plotOptions.column);
  845. var CylinderSeries = Highcharts.extendClass(Highcharts.seriesTypes.column, {
  846. type: 'cylinder'
  847. });
  848. Highcharts.seriesTypes.cylinder = CylinderSeries;
  849. Highcharts.wrap(Highcharts.seriesTypes.cylinder.prototype, 'translate', function (proceed) {
  850. proceed.apply(this, [].slice.call(arguments, 1));
  851. // Do not do this if the chart is not 3D
  852. if (!this.chart.is3d()) {
  853. return;
  854. }
  855. var series = this,
  856. chart = series.chart,
  857. options = chart.options,
  858. cylOptions = options.plotOptions.cylinder,
  859. options3d = options.chart.options3d,
  860. depth = cylOptions.depth || 0,
  861. origin = {
  862. x: chart.inverted ? chart.plotHeight / 2 : chart.plotWidth / 2,
  863. y: chart.inverted ? chart.plotWidth / 2 : chart.plotHeight / 2,
  864. z: options3d.depth,
  865. vd: options3d.viewDistance
  866. },
  867. alpha = options3d.alpha;
  868. var z = cylOptions.stacking ? (this.options.stack || 0) * depth : series._i * depth;
  869. z += depth / 2;
  870. if (cylOptions.grouping !== false) { z = 0; }
  871. Highcharts.each(series.data, function (point) {
  872. var shapeArgs = point.shapeArgs;
  873. point.shapeType = 'arc3d';
  874. shapeArgs.x += depth / 2;
  875. shapeArgs.z = z;
  876. shapeArgs.start = 0;
  877. shapeArgs.end = 2 * PI;
  878. shapeArgs.r = depth * 0.95;
  879. shapeArgs.innerR = 0;
  880. shapeArgs.depth = shapeArgs.height * (1 / sin((90 - alpha) * deg2rad)) - z;
  881. shapeArgs.alpha = 90 - alpha;
  882. shapeArgs.beta = 0;
  883. shapeArgs.origin = origin;
  884. });
  885. });
  886. /***
  887. EXTENSION FOR 3D PIES
  888. ***/
  889. Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'translate', function (proceed) {
  890. proceed.apply(this, [].slice.call(arguments, 1));
  891. // Do not do this if the chart is not 3D
  892. if (!this.chart.is3d()) {
  893. return;
  894. }
  895. var series = this,
  896. chart = series.chart,
  897. options = chart.options,
  898. seriesOptions = series.options,
  899. depth = seriesOptions.depth || 0,
  900. options3d = options.chart.options3d,
  901. origin = {
  902. x: chart.plotWidth / 2,
  903. y: chart.plotHeight / 2,
  904. z: options3d.depth
  905. },
  906. alpha = options3d.alpha,
  907. beta = options3d.beta;
  908. var z = seriesOptions.stacking ? (seriesOptions.stack || 0) * depth : series._i * depth;
  909. z += depth / 2;
  910. if (seriesOptions.grouping !== false) { z = 0; }
  911. Highcharts.each(series.data, function (point) {
  912. point.shapeType = 'arc3d';
  913. var shapeArgs = point.shapeArgs;
  914. if (point.y) { // will be false if null or 0 #3006
  915. shapeArgs.z = z;
  916. shapeArgs.depth = depth * 0.75;
  917. shapeArgs.origin = origin;
  918. shapeArgs.alpha = alpha;
  919. shapeArgs.beta = beta;
  920. var angle = (shapeArgs.end + shapeArgs.start) / 2;
  921. point.slicedTranslation = {
  922. translateX : round(cos(angle) * series.options.slicedOffset * cos(alpha * deg2rad)),
  923. translateY : round(sin(angle) * series.options.slicedOffset * cos(alpha * deg2rad))
  924. };
  925. } else {
  926. shapeArgs = null;
  927. }
  928. });
  929. });
  930. Highcharts.wrap(Highcharts.seriesTypes.pie.prototype.pointClass.prototype, 'haloPath', function (proceed) {
  931. var args = arguments;
  932. return this.series.chart.is3d() ? [] : proceed.call(this, args[1]);
  933. });
  934. Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'drawPoints', function (proceed) {
  935. // Do not do this if the chart is not 3D
  936. if (this.chart.is3d()) {
  937. var options = this.options,
  938. states = this.options.states;
  939. // Set the border color to the fill color to provide a smooth edge
  940. this.borderWidth = options.borderWidth = options.edgeWidth || 1;
  941. this.borderColor = options.edgeColor = Highcharts.pick(options.edgeColor, options.borderColor, undefined);
  942. states.hover.borderColor = Highcharts.pick(states.hover.edgeColor, this.borderColor);
  943. states.hover.borderWidth = Highcharts.pick(states.hover.edgeWidth, this.borderWidth);
  944. states.select.borderColor = Highcharts.pick(states.select.edgeColor, this.borderColor);
  945. states.select.borderWidth = Highcharts.pick(states.select.edgeWidth, this.borderWidth);
  946. Highcharts.each(this.data, function (point) {
  947. var pointAttr = point.pointAttr;
  948. pointAttr[''].stroke = point.series.borderColor || point.color;
  949. pointAttr['']['stroke-width'] = point.series.borderWidth;
  950. pointAttr.hover.stroke = states.hover.borderColor;
  951. pointAttr.hover['stroke-width'] = states.hover.borderWidth;
  952. pointAttr.select.stroke = states.select.borderColor;
  953. pointAttr.select['stroke-width'] = states.select.borderWidth;
  954. });
  955. }
  956. proceed.apply(this, [].slice.call(arguments, 1));
  957. if (this.chart.is3d()) {
  958. var seriesGroup = this.group;
  959. Highcharts.each(this.points, function (point) {
  960. point.graphic.out.add(seriesGroup);
  961. point.graphic.inn.add(seriesGroup);
  962. point.graphic.side1.add(seriesGroup);
  963. point.graphic.side2.add(seriesGroup);
  964. });
  965. }
  966. });
  967. Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'drawDataLabels', function (proceed) {
  968. if (this.chart.is3d()) {
  969. var series = this;
  970. Highcharts.each(series.data, function (point) {
  971. var shapeArgs = point.shapeArgs,
  972. r = shapeArgs.r,
  973. d = shapeArgs.depth,
  974. a1 = (shapeArgs.alpha || series.chart.options.chart.options3d.alpha) * deg2rad, //#3240 issue with datalabels for 0 and null values
  975. a2 = (shapeArgs.start + shapeArgs.end) / 2,
  976. labelPos = point.labelPos;
  977. labelPos[1] += (-r * (1 - cos(a1)) * sin(a2)) + (sin(a2) > 0 ? sin(a1) * d : 0);
  978. labelPos[3] += (-r * (1 - cos(a1)) * sin(a2)) + (sin(a2) > 0 ? sin(a1) * d : 0);
  979. labelPos[5] += (-r * (1 - cos(a1)) * sin(a2)) + (sin(a2) > 0 ? sin(a1) * d : 0);
  980. });
  981. }
  982. proceed.apply(this, [].slice.call(arguments, 1));
  983. });
  984. Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'addPoint', function (proceed) {
  985. proceed.apply(this, [].slice.call(arguments, 1));
  986. if (this.chart.is3d()) {
  987. // destroy (and rebuild) everything!!!
  988. this.update(this.userOptions, true); // #3845 pass the old options
  989. }
  990. });
  991. Highcharts.wrap(Highcharts.seriesTypes.pie.prototype, 'animate', function (proceed) {
  992. if (!this.chart.is3d()) {
  993. proceed.apply(this, [].slice.call(arguments, 1));
  994. } else {
  995. var args = arguments,
  996. init = args[1],
  997. animation = this.options.animation,
  998. attribs,
  999. center = this.center,
  1000. group = this.group,
  1001. markerGroup = this.markerGroup;
  1002. if (Highcharts.svg) { // VML is too slow anyway
  1003. if (animation === true) {
  1004. animation = {};
  1005. }
  1006. // Initialize the animation
  1007. if (init) {
  1008. // Scale down the group and place it in the center
  1009. group.oldtranslateX = group.translateX;
  1010. group.oldtranslateY = group.translateY;
  1011. attribs = {
  1012. translateX: center[0],
  1013. translateY: center[1],
  1014. scaleX: 0.001, // #1499
  1015. scaleY: 0.001
  1016. };
  1017. group.attr(attribs);
  1018. if (markerGroup) {
  1019. markerGroup.attrSetters = group.attrSetters;
  1020. markerGroup.attr(attribs);
  1021. }
  1022. // Run the animation
  1023. } else {
  1024. attribs = {
  1025. translateX: group.oldtranslateX,
  1026. translateY: group.oldtranslateY,
  1027. scaleX: 1,
  1028. scaleY: 1
  1029. };
  1030. group.animate(attribs, animation);
  1031. if (markerGroup) {
  1032. markerGroup.animate(attribs, animation);
  1033. }
  1034. // Delete this function to allow it only once
  1035. this.animate = null;
  1036. }
  1037. }
  1038. }
  1039. });/***
  1040. EXTENSION FOR 3D SCATTER CHART
  1041. ***/
  1042. Highcharts.wrap(Highcharts.seriesTypes.scatter.prototype, 'translate', function (proceed) {
  1043. //function translate3d(proceed) {
  1044. proceed.apply(this, [].slice.call(arguments, 1));
  1045. if (!this.chart.is3d()) {
  1046. return;
  1047. }
  1048. var series = this,
  1049. chart = series.chart,
  1050. depth = chart.options.chart.options3d.depth,
  1051. zAxis = chart.options.zAxis || { min : 0, max: depth };
  1052. var rangeModifier = depth / (zAxis.max - zAxis.min),
  1053. raw_points = [],
  1054. raw_point,
  1055. projected_points,
  1056. projected_point,
  1057. i;
  1058. for (i = 0; i < series.data.length; i++) {
  1059. raw_point = series.data[i];
  1060. raw_points.push({
  1061. x: raw_point.plotX,
  1062. y: raw_point.plotY,
  1063. z: (raw_point.z - zAxis.min) * rangeModifier
  1064. });
  1065. }
  1066. projected_points = perspective(raw_points, chart, true);
  1067. for (i = 0; i < series.data.length; i++) {
  1068. raw_point = series.data[i];
  1069. projected_point = projected_points[i];
  1070. raw_point.plotXold = raw_point.plotX;
  1071. raw_point.plotYold = raw_point.plotY;
  1072. raw_point.plotX = projected_point.x;
  1073. raw_point.plotY = projected_point.y;
  1074. raw_point.plotZ = projected_point.z;
  1075. }
  1076. });
  1077. Highcharts.wrap(Highcharts.seriesTypes.scatter.prototype, 'init', function (proceed) {
  1078. var result = proceed.apply(this, [].slice.call(arguments, 1));
  1079. if (this.chart.is3d()) {
  1080. // Add a third coordinate
  1081. this.pointArrayMap = ['x', 'y', 'z'];
  1082. // Set a new default tooltip formatter
  1083. var default3dScatterTooltip = 'x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>z: <b>{point.z}</b><br/>';
  1084. if (this.userOptions.tooltip) {
  1085. this.tooltipOptions.pointFormat = this.userOptions.tooltip.pointFormat || default3dScatterTooltip;
  1086. } else {
  1087. this.tooltipOptions.pointFormat = default3dScatterTooltip;
  1088. }
  1089. }
  1090. return result;
  1091. });
  1092. /**
  1093. * Extension to the VML Renderer
  1094. */
  1095. if (Highcharts.VMLRenderer) {
  1096. Highcharts.setOptions({animate: false});
  1097. Highcharts.VMLRenderer.prototype.cuboid = Highcharts.SVGRenderer.prototype.cuboid;
  1098. Highcharts.VMLRenderer.prototype.cuboidPath = Highcharts.SVGRenderer.prototype.cuboidPath;
  1099. Highcharts.VMLRenderer.prototype.toLinePath = Highcharts.SVGRenderer.prototype.toLinePath;
  1100. Highcharts.VMLRenderer.prototype.createElement3D = Highcharts.SVGRenderer.prototype.createElement3D;
  1101. Highcharts.VMLRenderer.prototype.arc3d = function (shapeArgs) {
  1102. var result = Highcharts.SVGRenderer.prototype.arc3d.call(this, shapeArgs);
  1103. result.css({zIndex: result.zIndex});
  1104. return result;
  1105. };
  1106. Highcharts.VMLRenderer.prototype.arc3dPath = Highcharts.SVGRenderer.prototype.arc3dPath;
  1107. Highcharts.wrap(Highcharts.Axis.prototype, 'render', function (proceed) {
  1108. proceed.apply(this, [].slice.call(arguments, 1));
  1109. // VML doesn't support a negative z-index
  1110. if (this.sideFrame) {
  1111. this.sideFrame.css({zIndex: 0});
  1112. this.sideFrame.front.attr({fill: this.sideFrame.color});
  1113. }
  1114. if (this.bottomFrame) {
  1115. this.bottomFrame.css({zIndex: 1});
  1116. this.bottomFrame.front.attr({fill: this.bottomFrame.color});
  1117. }
  1118. if (this.backFrame) {
  1119. this.backFrame.css({zIndex: 0});
  1120. this.backFrame.front.attr({fill: this.backFrame.color});
  1121. }
  1122. });
  1123. }
  1124. }(Highcharts));