highcharts-rails 5.0.11 → 5.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.markdown +32 -0
  3. data/app/assets/javascripts/highcharts.js +1199 -379
  4. data/app/assets/javascripts/highcharts/highcharts-3d.js +1542 -209
  5. data/app/assets/javascripts/highcharts/highcharts-more.js +6 -1
  6. data/app/assets/javascripts/highcharts/modules/accessibility.js +13 -6
  7. data/app/assets/javascripts/highcharts/modules/annotations.js +1 -1
  8. data/app/assets/javascripts/highcharts/modules/boost.js +66 -24
  9. data/app/assets/javascripts/highcharts/modules/broken-axis.js +1 -1
  10. data/app/assets/javascripts/highcharts/modules/data.js +1 -1
  11. data/app/assets/javascripts/highcharts/modules/drilldown.js +6 -44
  12. data/app/assets/javascripts/highcharts/modules/exporting.js +8 -4
  13. data/app/assets/javascripts/highcharts/modules/funnel.js +1 -8
  14. data/app/assets/javascripts/highcharts/modules/grid-axis.js +1 -1
  15. data/app/assets/javascripts/highcharts/modules/heatmap.js +17 -51
  16. data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +19 -10
  17. data/app/assets/javascripts/highcharts/modules/offline-exporting.js +7 -2
  18. data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +1 -1
  19. data/app/assets/javascripts/highcharts/modules/series-label.js +1 -1
  20. data/app/assets/javascripts/highcharts/modules/solid-gauge.js +7 -51
  21. data/app/assets/javascripts/highcharts/modules/stock.js +82 -9
  22. data/app/assets/javascripts/highcharts/modules/treemap.js +1 -1
  23. data/app/assets/javascripts/highcharts/modules/xrange-series.js +1 -1
  24. data/lib/highcharts/version.rb +1 -1
  25. metadata +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.11 (2017-05-04)
2
+ * @license Highcharts JS v5.0.12 (2017-05-24)
3
3
  *
4
4
  * 3D features for Highcharts JS
5
5
  *
@@ -134,6 +134,29 @@
134
134
  return distance;
135
135
  };
136
136
 
137
+ /**
138
+ * Calculate area of a 2D polygon using Shoelace algorithm
139
+ * http://en.wikipedia.org/wiki/Shoelace_formula
140
+ */
141
+ H.shapeArea = function(vertexes) {
142
+ var area = 0,
143
+ i,
144
+ j;
145
+ for (i = 0; i < vertexes.length; i++) {
146
+ j = (i + 1) % vertexes.length;
147
+ area += vertexes[i].x * vertexes[j].y - vertexes[j].x * vertexes[i].y;
148
+ }
149
+ return area / 2;
150
+ };
151
+
152
+ /**
153
+ * Calculate area of a 3D polygon after perspective projection
154
+ */
155
+ H.shapeArea3d = function(vertexes, chart, insidePlotArea) {
156
+ return H.shapeArea(H.perspective(vertexes, chart, insidePlotArea));
157
+ };
158
+
159
+
137
160
  }(Highcharts));
138
161
  (function(H) {
139
162
  /**
@@ -168,19 +191,6 @@
168
191
 
169
192
  var dFactor = (4 * (Math.sqrt(2) - 1) / 3) / (PI / 2);
170
193
 
171
-
172
- //Shoelace algorithm -- http://en.wikipedia.org/wiki/Shoelace_formula
173
- function shapeArea(vertexes) {
174
- var area = 0,
175
- i,
176
- j;
177
- for (i = 0; i < vertexes.length; i++) {
178
- j = (i + 1) % vertexes.length;
179
- area += vertexes[i].x * vertexes[j].y - vertexes[j].x * vertexes[i].y;
180
- }
181
- return area / 2;
182
- }
183
-
184
194
  /** Method to construct a curved path
185
195
  * Can 'wrap' around more then 180 degrees
186
196
  */
@@ -232,6 +242,139 @@
232
242
  return result;
233
243
  };
234
244
 
245
+ SVGRenderer.prototype.toLineSegments = function(points) {
246
+ var result = [];
247
+
248
+ var m = true;
249
+ each(points, function(point) {
250
+ result.push(m ? 'M' : 'L', point.x, point.y);
251
+ m = !m;
252
+ });
253
+
254
+ return result;
255
+ };
256
+
257
+ /**
258
+ * A 3-D Face is defined by it's 3D vertexes, and is only
259
+ * visible if it's vertexes are counter-clockwise (Back-face culling).
260
+ * It is used as a polyhedron Element
261
+ */
262
+ SVGRenderer.prototype.face3d = function(args) {
263
+ var renderer = this,
264
+ ret = this.createElement('path');
265
+ ret.vertexes = [];
266
+ ret.insidePlotArea = false;
267
+ ret.enabled = true;
268
+
269
+ wrap(ret, 'attr', function(proceed, hash) {
270
+ if (typeof hash === 'object' &&
271
+ (defined(hash.enabled) || defined(hash.vertexes) || defined(hash.insidePlotArea))) {
272
+ this.enabled = pick(hash.enabled, this.enabled);
273
+ this.vertexes = pick(hash.vertexes, this.vertexes);
274
+ this.insidePlotArea = pick(hash.insidePlotArea, this.insidePlotArea);
275
+ delete hash.enabled;
276
+ delete hash.vertexes;
277
+ delete hash.insidePlotArea;
278
+
279
+ var chart = charts[renderer.chartIndex],
280
+ vertexes2d = perspective(this.vertexes, chart, this.insidePlotArea),
281
+ path = renderer.toLinePath(vertexes2d, true),
282
+ area = H.shapeArea(vertexes2d),
283
+ visibility = (this.enabled && area > 0) ? 'visible' : 'hidden';
284
+
285
+ hash.d = path;
286
+ hash.visibility = visibility;
287
+ }
288
+ return proceed.apply(this, [].slice.call(arguments, 1));
289
+ });
290
+
291
+ wrap(ret, 'animate', function(proceed, params) {
292
+ if (typeof params === 'object' &&
293
+ (defined(params.enabled) || defined(params.vertexes) || defined(params.insidePlotArea))) {
294
+ this.enabled = pick(params.enabled, this.enabled);
295
+ this.vertexes = pick(params.vertexes, this.vertexes);
296
+ this.insidePlotArea = pick(params.insidePlotArea, this.insidePlotArea);
297
+ delete params.enabled;
298
+ delete params.vertexes;
299
+ delete params.insidePlotArea;
300
+
301
+ var chart = charts[renderer.chartIndex],
302
+ vertexes2d = perspective(this.vertexes, chart, this.insidePlotArea),
303
+ path = renderer.toLinePath(vertexes2d, true),
304
+ area = H.shapeArea(vertexes2d),
305
+ visibility = (this.enabled && area > 0) ? 'visible' : 'hidden';
306
+
307
+ params.d = path;
308
+ this.attr('visibility', visibility);
309
+ }
310
+
311
+ return proceed.apply(this, [].slice.call(arguments, 1));
312
+ });
313
+
314
+ return ret.attr(args);
315
+ };
316
+
317
+ /**
318
+ * A Polyhedron is a handy way of defining a group of 3-D faces.
319
+ * It's only attribute is `faces`, an array of attributes of each one of it's Face3D instances.
320
+ */
321
+ SVGRenderer.prototype.polyhedron = function(args) {
322
+ var renderer = this,
323
+ result = this.g(),
324
+ destroy = result.destroy;
325
+
326
+
327
+ result.attr({
328
+ 'stroke-linejoin': 'round'
329
+ });
330
+
331
+
332
+ result.faces = [];
333
+
334
+
335
+ // destroy all children
336
+ result.destroy = function() {
337
+ for (var i = 0; i < result.faces.length; i++) {
338
+ result.faces[i].destroy();
339
+ }
340
+ return destroy.call(this);
341
+ };
342
+
343
+ wrap(result, 'attr', function(proceed, hash, val, complete, continueAnimation) {
344
+ if (typeof hash === 'object' && defined(hash.faces)) {
345
+ while (result.faces.length > hash.faces.length) {
346
+ result.faces.pop().destroy();
347
+ }
348
+ while (result.faces.length < hash.faces.length) {
349
+ result.faces.push(renderer.face3d().add(result));
350
+ }
351
+ for (var i = 0; i < hash.faces.length; i++) {
352
+ result.faces[i].attr(hash.faces[i], null, complete, continueAnimation);
353
+ }
354
+ delete hash.faces;
355
+ }
356
+ return proceed.apply(this, [].slice.call(arguments, 1));
357
+ });
358
+
359
+ wrap(result, 'animate', function(proceed, params, duration, complete) {
360
+ if (params && params.faces) {
361
+ while (result.faces.length > params.faces.length) {
362
+ result.faces.pop().destroy();
363
+ }
364
+ while (result.faces.length < params.faces.length) {
365
+ result.faces.push(renderer.face3d().add(result));
366
+ }
367
+ for (var i = 0; i < params.faces.length; i++) {
368
+ result.faces[i].animate(params.faces[i], duration, complete);
369
+ }
370
+ delete params.faces;
371
+ }
372
+ return proceed.apply(this, [].slice.call(arguments, 1));
373
+ });
374
+
375
+ return result.attr(args);
376
+ };
377
+
235
378
  ////// CUBOIDS //////
236
379
  SVGRenderer.prototype.cuboid = function(shapeArgs) {
237
380
 
@@ -445,9 +588,9 @@
445
588
  ];
446
589
  path1 = map(path1, mapPath);
447
590
  path2 = map(path2, mapPath);
448
- if (shapeArea(path1) < 0) {
591
+ if (H.shapeArea(path1) < 0) {
449
592
  ret = [path1, 0];
450
- } else if (shapeArea(path2) < 0) {
593
+ } else if (H.shapeArea(path2) < 0) {
451
594
  ret = [path2, 1];
452
595
  }
453
596
  return ret;
@@ -1049,16 +1192,16 @@
1049
1192
  depth: 100,
1050
1193
  fitToPlot: true,
1051
1194
  viewDistance: 25,
1195
+ axisLabelPosition: 'default',
1052
1196
  frame: {
1053
- bottom: {
1054
- size: 1
1055
- },
1056
- side: {
1057
- size: 1
1058
- },
1059
- back: {
1060
- size: 1
1061
- }
1197
+ visible: 'default',
1198
+ size: 1,
1199
+ bottom: {},
1200
+ top: {},
1201
+ left: {},
1202
+ right: {},
1203
+ back: {},
1204
+ front: {}
1062
1205
  }
1063
1206
  }
1064
1207
  }
@@ -1106,6 +1249,14 @@
1106
1249
  if (this.is3d()) {
1107
1250
  // Set to force a redraw of all elements
1108
1251
  this.isDirtyBox = true;
1252
+ this.frame3d = this.get3dFrame();
1253
+ }
1254
+ proceed.apply(this, [].slice.call(arguments, 1));
1255
+ });
1256
+
1257
+ wrap(Chart.prototype, 'render', function(proceed) {
1258
+ if (this.is3d()) {
1259
+ this.frame3d = this.get3dFrame();
1109
1260
  }
1110
1261
  proceed.apply(this, [].slice.call(arguments, 1));
1111
1262
  });
@@ -1126,6 +1277,830 @@
1126
1277
  }
1127
1278
  });
1128
1279
 
1280
+ wrap(Chart.prototype, 'drawChartBox', function(proceed) {
1281
+ if (this.is3d()) {
1282
+ var chart = this,
1283
+ renderer = chart.renderer,
1284
+ options3d = this.options.chart.options3d,
1285
+ frame = chart.get3dFrame(),
1286
+ xm = this.plotLeft,
1287
+ xp = this.plotLeft + this.plotWidth,
1288
+ ym = this.plotTop,
1289
+ yp = this.plotTop + this.plotHeight,
1290
+ zm = 0,
1291
+ zp = options3d.depth,
1292
+ xmm = xm - (frame.left.visible ? frame.left.size : 0),
1293
+ xpp = xp + (frame.right.visible ? frame.right.size : 0),
1294
+ ymm = ym - (frame.top.visible ? frame.top.size : 0),
1295
+ ypp = yp + (frame.bottom.visible ? frame.bottom.size : 0),
1296
+ zmm = zm - (frame.front.visible ? frame.front.size : 0),
1297
+ zpp = zp + (frame.back.visible ? frame.back.size : 0),
1298
+ verb = chart.hasRendered ? 'animate' : 'attr';
1299
+
1300
+ this.frame3d = frame;
1301
+
1302
+ if (!this.frameShapes) {
1303
+ this.frameShapes = {
1304
+ bottom: renderer.polyhedron().add(),
1305
+ top: renderer.polyhedron().add(),
1306
+ left: renderer.polyhedron().add(),
1307
+ right: renderer.polyhedron().add(),
1308
+ back: renderer.polyhedron().add(),
1309
+ front: renderer.polyhedron().add()
1310
+ };
1311
+ }
1312
+
1313
+ this.frameShapes.bottom[verb]({
1314
+ 'class': 'highcharts-3d-frame highcharts-3d-frame-bottom',
1315
+ zIndex: frame.bottom.frontFacing ? -1000 : 1000,
1316
+ faces: [{ //bottom
1317
+ fill: H.color(frame.bottom.color).brighten(0.1).get(),
1318
+ vertexes: [{
1319
+ x: xmm,
1320
+ y: ypp,
1321
+ z: zmm
1322
+ }, {
1323
+ x: xpp,
1324
+ y: ypp,
1325
+ z: zmm
1326
+ }, {
1327
+ x: xpp,
1328
+ y: ypp,
1329
+ z: zpp
1330
+ }, {
1331
+ x: xmm,
1332
+ y: ypp,
1333
+ z: zpp
1334
+ }],
1335
+ enabled: frame.bottom.visible
1336
+ },
1337
+ { //top
1338
+ fill: H.color(frame.bottom.color).brighten(0.1).get(),
1339
+ vertexes: [{
1340
+ x: xm,
1341
+ y: yp,
1342
+ z: zp
1343
+ }, {
1344
+ x: xp,
1345
+ y: yp,
1346
+ z: zp
1347
+ }, {
1348
+ x: xp,
1349
+ y: yp,
1350
+ z: zm
1351
+ }, {
1352
+ x: xm,
1353
+ y: yp,
1354
+ z: zm
1355
+ }],
1356
+ enabled: frame.bottom.visible
1357
+ },
1358
+ { //left
1359
+ fill: H.color(frame.bottom.color).brighten(-0.1).get(),
1360
+ vertexes: [{
1361
+ x: xmm,
1362
+ y: ypp,
1363
+ z: zmm
1364
+ }, {
1365
+ x: xmm,
1366
+ y: ypp,
1367
+ z: zpp
1368
+ }, {
1369
+ x: xm,
1370
+ y: yp,
1371
+ z: zp
1372
+ }, {
1373
+ x: xm,
1374
+ y: yp,
1375
+ z: zm
1376
+ }],
1377
+ enabled: frame.bottom.visible && !frame.left.visible
1378
+ },
1379
+ { //right
1380
+ fill: H.color(frame.bottom.color).brighten(-0.1).get(),
1381
+ vertexes: [{
1382
+ x: xpp,
1383
+ y: ypp,
1384
+ z: zpp
1385
+ }, {
1386
+ x: xpp,
1387
+ y: ypp,
1388
+ z: zmm
1389
+ }, {
1390
+ x: xp,
1391
+ y: yp,
1392
+ z: zm
1393
+ }, {
1394
+ x: xp,
1395
+ y: yp,
1396
+ z: zp
1397
+ }],
1398
+ enabled: frame.bottom.visible && !frame.right.visible
1399
+ },
1400
+ { //front
1401
+ fill: H.color(frame.bottom.color).get(),
1402
+ vertexes: [{
1403
+ x: xpp,
1404
+ y: ypp,
1405
+ z: zmm
1406
+ }, {
1407
+ x: xmm,
1408
+ y: ypp,
1409
+ z: zmm
1410
+ }, {
1411
+ x: xm,
1412
+ y: yp,
1413
+ z: zm
1414
+ }, {
1415
+ x: xp,
1416
+ y: yp,
1417
+ z: zm
1418
+ }],
1419
+ enabled: frame.bottom.visible && !frame.front.visible
1420
+ },
1421
+ { //back
1422
+ fill: H.color(frame.bottom.color).get(),
1423
+ vertexes: [{
1424
+ x: xmm,
1425
+ y: ypp,
1426
+ z: zpp
1427
+ }, {
1428
+ x: xpp,
1429
+ y: ypp,
1430
+ z: zpp
1431
+ }, {
1432
+ x: xp,
1433
+ y: yp,
1434
+ z: zp
1435
+ }, {
1436
+ x: xm,
1437
+ y: yp,
1438
+ z: zp
1439
+ }],
1440
+ enabled: frame.bottom.visible && !frame.back.visible
1441
+ }
1442
+ ]
1443
+ });
1444
+ this.frameShapes.top[verb]({
1445
+ 'class': 'highcharts-3d-frame highcharts-3d-frame-top',
1446
+ zIndex: frame.top.frontFacing ? -1000 : 1000,
1447
+ faces: [{ //bottom
1448
+ fill: H.color(frame.top.color).brighten(0.1).get(),
1449
+ vertexes: [{
1450
+ x: xmm,
1451
+ y: ymm,
1452
+ z: zpp
1453
+ }, {
1454
+ x: xpp,
1455
+ y: ymm,
1456
+ z: zpp
1457
+ }, {
1458
+ x: xpp,
1459
+ y: ymm,
1460
+ z: zmm
1461
+ }, {
1462
+ x: xmm,
1463
+ y: ymm,
1464
+ z: zmm
1465
+ }],
1466
+ enabled: frame.top.visible
1467
+ },
1468
+ { //top
1469
+ fill: H.color(frame.top.color).brighten(0.1).get(),
1470
+ vertexes: [{
1471
+ x: xm,
1472
+ y: ym,
1473
+ z: zm
1474
+ }, {
1475
+ x: xp,
1476
+ y: ym,
1477
+ z: zm
1478
+ }, {
1479
+ x: xp,
1480
+ y: ym,
1481
+ z: zp
1482
+ }, {
1483
+ x: xm,
1484
+ y: ym,
1485
+ z: zp
1486
+ }],
1487
+ enabled: frame.top.visible
1488
+ },
1489
+ { //left
1490
+ fill: H.color(frame.top.color).brighten(-0.1).get(),
1491
+ vertexes: [{
1492
+ x: xmm,
1493
+ y: ymm,
1494
+ z: zpp
1495
+ }, {
1496
+ x: xmm,
1497
+ y: ymm,
1498
+ z: zmm
1499
+ }, {
1500
+ x: xm,
1501
+ y: ym,
1502
+ z: zm
1503
+ }, {
1504
+ x: xm,
1505
+ y: ym,
1506
+ z: zp
1507
+ }],
1508
+ enabled: frame.top.visible && !frame.left.visible
1509
+ },
1510
+ { //right
1511
+ fill: H.color(frame.top.color).brighten(-0.1).get(),
1512
+ vertexes: [{
1513
+ x: xpp,
1514
+ y: ymm,
1515
+ z: zmm
1516
+ }, {
1517
+ x: xpp,
1518
+ y: ymm,
1519
+ z: zpp
1520
+ }, {
1521
+ x: xp,
1522
+ y: ym,
1523
+ z: zp
1524
+ }, {
1525
+ x: xp,
1526
+ y: ym,
1527
+ z: zm
1528
+ }],
1529
+ enabled: frame.top.visible && !frame.right.visible
1530
+ },
1531
+ { //front
1532
+ fill: H.color(frame.top.color).get(),
1533
+ vertexes: [{
1534
+ x: xmm,
1535
+ y: ymm,
1536
+ z: zmm
1537
+ }, {
1538
+ x: xpp,
1539
+ y: ymm,
1540
+ z: zmm
1541
+ }, {
1542
+ x: xp,
1543
+ y: ym,
1544
+ z: zm
1545
+ }, {
1546
+ x: xm,
1547
+ y: ym,
1548
+ z: zm
1549
+ }],
1550
+ enabled: frame.top.visible && !frame.front.visible
1551
+ },
1552
+ { //back
1553
+ fill: H.color(frame.top.color).get(),
1554
+ vertexes: [{
1555
+ x: xpp,
1556
+ y: ymm,
1557
+ z: zpp
1558
+ }, {
1559
+ x: xmm,
1560
+ y: ymm,
1561
+ z: zpp
1562
+ }, {
1563
+ x: xm,
1564
+ y: ym,
1565
+ z: zp
1566
+ }, {
1567
+ x: xp,
1568
+ y: ym,
1569
+ z: zp
1570
+ }],
1571
+ enabled: frame.top.visible && !frame.back.visible
1572
+ }
1573
+ ]
1574
+ });
1575
+ this.frameShapes.left[verb]({
1576
+ 'class': 'highcharts-3d-frame highcharts-3d-frame-left',
1577
+ zIndex: frame.left.frontFacing ? -1000 : 1000,
1578
+ faces: [{ //bottom
1579
+ fill: H.color(frame.left.color).brighten(0.1).get(),
1580
+ vertexes: [{
1581
+ x: xmm,
1582
+ y: ypp,
1583
+ z: zmm
1584
+ }, {
1585
+ x: xm,
1586
+ y: yp,
1587
+ z: zm
1588
+ }, {
1589
+ x: xm,
1590
+ y: yp,
1591
+ z: zp
1592
+ }, {
1593
+ x: xmm,
1594
+ y: ypp,
1595
+ z: zpp
1596
+ }],
1597
+ enabled: frame.left.visible && !frame.bottom.visible
1598
+ },
1599
+ { //top
1600
+ fill: H.color(frame.left.color).brighten(0.1).get(),
1601
+ vertexes: [{
1602
+ x: xmm,
1603
+ y: ymm,
1604
+ z: zpp
1605
+ }, {
1606
+ x: xm,
1607
+ y: ym,
1608
+ z: zp
1609
+ }, {
1610
+ x: xm,
1611
+ y: ym,
1612
+ z: zm
1613
+ }, {
1614
+ x: xmm,
1615
+ y: ymm,
1616
+ z: zmm
1617
+ }],
1618
+ enabled: frame.left.visible && !frame.top.visible
1619
+ },
1620
+ { //left
1621
+ fill: H.color(frame.left.color).brighten(-0.1).get(),
1622
+ vertexes: [{
1623
+ x: xmm,
1624
+ y: ypp,
1625
+ z: zpp
1626
+ }, {
1627
+ x: xmm,
1628
+ y: ymm,
1629
+ z: zpp
1630
+ }, {
1631
+ x: xmm,
1632
+ y: ymm,
1633
+ z: zmm
1634
+ }, {
1635
+ x: xmm,
1636
+ y: ypp,
1637
+ z: zmm
1638
+ }],
1639
+ enabled: frame.left.visible
1640
+ },
1641
+ { //right
1642
+ fill: H.color(frame.left.color).brighten(-0.1).get(),
1643
+ vertexes: [{
1644
+ x: xm,
1645
+ y: ym,
1646
+ z: zp
1647
+ }, {
1648
+ x: xm,
1649
+ y: yp,
1650
+ z: zp
1651
+ }, {
1652
+ x: xm,
1653
+ y: yp,
1654
+ z: zm
1655
+ }, {
1656
+ x: xm,
1657
+ y: ym,
1658
+ z: zm
1659
+ }],
1660
+ enabled: frame.left.visible
1661
+ },
1662
+ { //front
1663
+ fill: H.color(frame.left.color).get(),
1664
+ vertexes: [{
1665
+ x: xmm,
1666
+ y: ypp,
1667
+ z: zmm
1668
+ }, {
1669
+ x: xmm,
1670
+ y: ymm,
1671
+ z: zmm
1672
+ }, {
1673
+ x: xm,
1674
+ y: ym,
1675
+ z: zm
1676
+ }, {
1677
+ x: xm,
1678
+ y: yp,
1679
+ z: zm
1680
+ }],
1681
+ enabled: frame.left.visible && !frame.front.visible
1682
+ },
1683
+ { //back
1684
+ fill: H.color(frame.left.color).get(),
1685
+ vertexes: [{
1686
+ x: xmm,
1687
+ y: ymm,
1688
+ z: zpp
1689
+ }, {
1690
+ x: xmm,
1691
+ y: ypp,
1692
+ z: zpp
1693
+ }, {
1694
+ x: xm,
1695
+ y: yp,
1696
+ z: zp
1697
+ }, {
1698
+ x: xm,
1699
+ y: ym,
1700
+ z: zp
1701
+ }],
1702
+ enabled: frame.left.visible && !frame.back.visible
1703
+ }
1704
+ ]
1705
+ });
1706
+ this.frameShapes.right[verb]({
1707
+ 'class': 'highcharts-3d-frame highcharts-3d-frame-right',
1708
+ zIndex: frame.right.frontFacing ? -1000 : 1000,
1709
+ faces: [{ //bottom
1710
+ fill: H.color(frame.right.color).brighten(0.1).get(),
1711
+ vertexes: [{
1712
+ x: xpp,
1713
+ y: ypp,
1714
+ z: zpp
1715
+ }, {
1716
+ x: xp,
1717
+ y: yp,
1718
+ z: zp
1719
+ }, {
1720
+ x: xp,
1721
+ y: yp,
1722
+ z: zm
1723
+ }, {
1724
+ x: xpp,
1725
+ y: ypp,
1726
+ z: zmm
1727
+ }],
1728
+ enabled: frame.right.visible && !frame.bottom.visible
1729
+ },
1730
+ { //top
1731
+ fill: H.color(frame.right.color).brighten(0.1).get(),
1732
+ vertexes: [{
1733
+ x: xpp,
1734
+ y: ymm,
1735
+ z: zmm
1736
+ }, {
1737
+ x: xp,
1738
+ y: ym,
1739
+ z: zm
1740
+ }, {
1741
+ x: xp,
1742
+ y: ym,
1743
+ z: zp
1744
+ }, {
1745
+ x: xpp,
1746
+ y: ymm,
1747
+ z: zpp
1748
+ }],
1749
+ enabled: frame.right.visible && !frame.top.visible
1750
+ },
1751
+ { //left
1752
+ fill: H.color(frame.right.color).brighten(-0.1).get(),
1753
+ vertexes: [{
1754
+ x: xp,
1755
+ y: ym,
1756
+ z: zm
1757
+ }, {
1758
+ x: xp,
1759
+ y: yp,
1760
+ z: zm
1761
+ }, {
1762
+ x: xp,
1763
+ y: yp,
1764
+ z: zp
1765
+ }, {
1766
+ x: xp,
1767
+ y: ym,
1768
+ z: zp
1769
+ }],
1770
+ enabled: frame.right.visible
1771
+ },
1772
+ { //right
1773
+ fill: H.color(frame.right.color).brighten(-0.1).get(),
1774
+ vertexes: [{
1775
+ x: xpp,
1776
+ y: ypp,
1777
+ z: zmm
1778
+ }, {
1779
+ x: xpp,
1780
+ y: ymm,
1781
+ z: zmm
1782
+ }, {
1783
+ x: xpp,
1784
+ y: ymm,
1785
+ z: zpp
1786
+ }, {
1787
+ x: xpp,
1788
+ y: ypp,
1789
+ z: zpp
1790
+ }],
1791
+ enabled: frame.right.visible
1792
+ },
1793
+ { //front
1794
+ fill: H.color(frame.right.color).get(),
1795
+ vertexes: [{
1796
+ x: xpp,
1797
+ y: ymm,
1798
+ z: zmm
1799
+ }, {
1800
+ x: xpp,
1801
+ y: ypp,
1802
+ z: zmm
1803
+ }, {
1804
+ x: xp,
1805
+ y: yp,
1806
+ z: zm
1807
+ }, {
1808
+ x: xp,
1809
+ y: ym,
1810
+ z: zm
1811
+ }],
1812
+ enabled: frame.right.visible && !frame.front.visible
1813
+ },
1814
+ { //back
1815
+ fill: H.color(frame.right.color).get(),
1816
+ vertexes: [{
1817
+ x: xpp,
1818
+ y: ypp,
1819
+ z: zpp
1820
+ }, {
1821
+ x: xpp,
1822
+ y: ymm,
1823
+ z: zpp
1824
+ }, {
1825
+ x: xp,
1826
+ y: ym,
1827
+ z: zp
1828
+ }, {
1829
+ x: xp,
1830
+ y: yp,
1831
+ z: zp
1832
+ }],
1833
+ enabled: frame.right.visible && !frame.back.visible
1834
+ }
1835
+ ]
1836
+ });
1837
+ this.frameShapes.back[verb]({
1838
+ 'class': 'highcharts-3d-frame highcharts-3d-frame-back',
1839
+ zIndex: frame.back.frontFacing ? -1000 : 1000,
1840
+ faces: [{ //bottom
1841
+ fill: H.color(frame.back.color).brighten(0.1).get(),
1842
+ vertexes: [{
1843
+ x: xpp,
1844
+ y: ypp,
1845
+ z: zpp
1846
+ }, {
1847
+ x: xmm,
1848
+ y: ypp,
1849
+ z: zpp
1850
+ }, {
1851
+ x: xm,
1852
+ y: yp,
1853
+ z: zp
1854
+ }, {
1855
+ x: xp,
1856
+ y: yp,
1857
+ z: zp
1858
+ }],
1859
+ enabled: frame.back.visible && !frame.bottom.visible
1860
+ },
1861
+ { //top
1862
+ fill: H.color(frame.back.color).brighten(0.1).get(),
1863
+ vertexes: [{
1864
+ x: xmm,
1865
+ y: ymm,
1866
+ z: zpp
1867
+ }, {
1868
+ x: xpp,
1869
+ y: ymm,
1870
+ z: zpp
1871
+ }, {
1872
+ x: xp,
1873
+ y: ym,
1874
+ z: zp
1875
+ }, {
1876
+ x: xm,
1877
+ y: ym,
1878
+ z: zp
1879
+ }],
1880
+ enabled: frame.back.visible && !frame.top.visible
1881
+ },
1882
+ { //left
1883
+ fill: H.color(frame.back.color).brighten(-0.1).get(),
1884
+ vertexes: [{
1885
+ x: xmm,
1886
+ y: ypp,
1887
+ z: zpp
1888
+ }, {
1889
+ x: xmm,
1890
+ y: ymm,
1891
+ z: zpp
1892
+ }, {
1893
+ x: xm,
1894
+ y: ym,
1895
+ z: zp
1896
+ }, {
1897
+ x: xm,
1898
+ y: yp,
1899
+ z: zp
1900
+ }],
1901
+ enabled: frame.back.visible && !frame.left.visible
1902
+ },
1903
+ { //right
1904
+ fill: H.color(frame.back.color).brighten(-0.1).get(),
1905
+ vertexes: [{
1906
+ x: xpp,
1907
+ y: ymm,
1908
+ z: zpp
1909
+ }, {
1910
+ x: xpp,
1911
+ y: ypp,
1912
+ z: zpp
1913
+ }, {
1914
+ x: xp,
1915
+ y: yp,
1916
+ z: zp
1917
+ }, {
1918
+ x: xp,
1919
+ y: ym,
1920
+ z: zp
1921
+ }],
1922
+ enabled: frame.back.visible && !frame.right.visible
1923
+ },
1924
+ { //front
1925
+ fill: H.color(frame.back.color).get(),
1926
+ vertexes: [{
1927
+ x: xm,
1928
+ y: ym,
1929
+ z: zp
1930
+ }, {
1931
+ x: xp,
1932
+ y: ym,
1933
+ z: zp
1934
+ }, {
1935
+ x: xp,
1936
+ y: yp,
1937
+ z: zp
1938
+ }, {
1939
+ x: xm,
1940
+ y: yp,
1941
+ z: zp
1942
+ }],
1943
+ enabled: frame.back.visible
1944
+ },
1945
+ { //back
1946
+ fill: H.color(frame.back.color).get(),
1947
+ vertexes: [{
1948
+ x: xmm,
1949
+ y: ypp,
1950
+ z: zpp
1951
+ }, {
1952
+ x: xpp,
1953
+ y: ypp,
1954
+ z: zpp
1955
+ }, {
1956
+ x: xpp,
1957
+ y: ymm,
1958
+ z: zpp
1959
+ }, {
1960
+ x: xmm,
1961
+ y: ymm,
1962
+ z: zpp
1963
+ }],
1964
+ enabled: frame.back.visible
1965
+ }
1966
+ ]
1967
+ });
1968
+ this.frameShapes.front[verb]({
1969
+ 'class': 'highcharts-3d-frame highcharts-3d-frame-front',
1970
+ zIndex: frame.front.frontFacing ? -1000 : 1000,
1971
+ faces: [{ //bottom
1972
+ fill: H.color(frame.front.color).brighten(0.1).get(),
1973
+ vertexes: [{
1974
+ x: xmm,
1975
+ y: ypp,
1976
+ z: zmm
1977
+ }, {
1978
+ x: xpp,
1979
+ y: ypp,
1980
+ z: zmm
1981
+ }, {
1982
+ x: xp,
1983
+ y: yp,
1984
+ z: zm
1985
+ }, {
1986
+ x: xm,
1987
+ y: yp,
1988
+ z: zm
1989
+ }],
1990
+ enabled: frame.front.visible && !frame.bottom.visible
1991
+ },
1992
+ { //top
1993
+ fill: H.color(frame.front.color).brighten(0.1).get(),
1994
+ vertexes: [{
1995
+ x: xpp,
1996
+ y: ymm,
1997
+ z: zmm
1998
+ }, {
1999
+ x: xmm,
2000
+ y: ymm,
2001
+ z: zmm
2002
+ }, {
2003
+ x: xm,
2004
+ y: ym,
2005
+ z: zm
2006
+ }, {
2007
+ x: xp,
2008
+ y: ym,
2009
+ z: zm
2010
+ }],
2011
+ enabled: frame.front.visible && !frame.top.visible
2012
+ },
2013
+ { //left
2014
+ fill: H.color(frame.front.color).brighten(-0.1).get(),
2015
+ vertexes: [{
2016
+ x: xmm,
2017
+ y: ymm,
2018
+ z: zmm
2019
+ }, {
2020
+ x: xmm,
2021
+ y: ypp,
2022
+ z: zmm
2023
+ }, {
2024
+ x: xm,
2025
+ y: yp,
2026
+ z: zm
2027
+ }, {
2028
+ x: xm,
2029
+ y: ym,
2030
+ z: zm
2031
+ }],
2032
+ enabled: frame.front.visible && !frame.left.visible
2033
+ },
2034
+ { //right
2035
+ fill: H.color(frame.front.color).brighten(-0.1).get(),
2036
+ vertexes: [{
2037
+ x: xpp,
2038
+ y: ypp,
2039
+ z: zmm
2040
+ }, {
2041
+ x: xpp,
2042
+ y: ymm,
2043
+ z: zmm
2044
+ }, {
2045
+ x: xp,
2046
+ y: ym,
2047
+ z: zm
2048
+ }, {
2049
+ x: xp,
2050
+ y: yp,
2051
+ z: zm
2052
+ }],
2053
+ enabled: frame.front.visible && !frame.right.visible
2054
+ },
2055
+ { //front
2056
+ fill: H.color(frame.front.color).get(),
2057
+ vertexes: [{
2058
+ x: xp,
2059
+ y: ym,
2060
+ z: zm
2061
+ }, {
2062
+ x: xm,
2063
+ y: ym,
2064
+ z: zm
2065
+ }, {
2066
+ x: xm,
2067
+ y: yp,
2068
+ z: zm
2069
+ }, {
2070
+ x: xp,
2071
+ y: yp,
2072
+ z: zm
2073
+ }],
2074
+ enabled: frame.front.visible
2075
+ },
2076
+ { //back
2077
+ fill: H.color(frame.front.color).get(),
2078
+ vertexes: [{
2079
+ x: xpp,
2080
+ y: ypp,
2081
+ z: zmm
2082
+ }, {
2083
+ x: xmm,
2084
+ y: ypp,
2085
+ z: zmm
2086
+ }, {
2087
+ x: xmm,
2088
+ y: ymm,
2089
+ z: zmm
2090
+ }, {
2091
+ x: xpp,
2092
+ y: ymm,
2093
+ z: zmm
2094
+ }],
2095
+ enabled: frame.front.visible
2096
+ }
2097
+ ]
2098
+ });
2099
+ }
2100
+
2101
+ return proceed.apply(this, [].slice.call(arguments, 1));
2102
+ });
2103
+
1129
2104
  Chart.prototype.retrieveStacks = function(stacking) {
1130
2105
  var series = this.series,
1131
2106
  stacks = {},
@@ -1149,6 +2124,401 @@
1149
2124
  return stacks;
1150
2125
  };
1151
2126
 
2127
+ Chart.prototype.get3dFrame = function() {
2128
+ var chart = this,
2129
+ options3d = chart.options.chart.options3d,
2130
+ frameOptions = options3d.frame,
2131
+ xm = chart.plotLeft,
2132
+ xp = chart.plotLeft + chart.plotWidth,
2133
+ ym = chart.plotTop,
2134
+ yp = chart.plotTop + chart.plotHeight,
2135
+ zm = 0,
2136
+ zp = options3d.depth,
2137
+ bottomOrientation = H.shapeArea3d([{
2138
+ x: xm,
2139
+ y: yp,
2140
+ z: zp
2141
+ }, {
2142
+ x: xp,
2143
+ y: yp,
2144
+ z: zp
2145
+ }, {
2146
+ x: xp,
2147
+ y: yp,
2148
+ z: zm
2149
+ }, {
2150
+ x: xm,
2151
+ y: yp,
2152
+ z: zm
2153
+ }], chart),
2154
+ topOrientation = H.shapeArea3d([{
2155
+ x: xm,
2156
+ y: ym,
2157
+ z: zm
2158
+ }, {
2159
+ x: xp,
2160
+ y: ym,
2161
+ z: zm
2162
+ }, {
2163
+ x: xp,
2164
+ y: ym,
2165
+ z: zp
2166
+ }, {
2167
+ x: xm,
2168
+ y: ym,
2169
+ z: zp
2170
+ }], chart),
2171
+ leftOrientation = H.shapeArea3d([{
2172
+ x: xm,
2173
+ y: ym,
2174
+ z: zm
2175
+ }, {
2176
+ x: xm,
2177
+ y: ym,
2178
+ z: zp
2179
+ }, {
2180
+ x: xm,
2181
+ y: yp,
2182
+ z: zp
2183
+ }, {
2184
+ x: xm,
2185
+ y: yp,
2186
+ z: zm
2187
+ }], chart),
2188
+ rightOrientation = H.shapeArea3d([{
2189
+ x: xp,
2190
+ y: ym,
2191
+ z: zp
2192
+ }, {
2193
+ x: xp,
2194
+ y: ym,
2195
+ z: zm
2196
+ }, {
2197
+ x: xp,
2198
+ y: yp,
2199
+ z: zm
2200
+ }, {
2201
+ x: xp,
2202
+ y: yp,
2203
+ z: zp
2204
+ }], chart),
2205
+ frontOrientation = H.shapeArea3d([{
2206
+ x: xm,
2207
+ y: yp,
2208
+ z: zm
2209
+ }, {
2210
+ x: xp,
2211
+ y: yp,
2212
+ z: zm
2213
+ }, {
2214
+ x: xp,
2215
+ y: ym,
2216
+ z: zm
2217
+ }, {
2218
+ x: xm,
2219
+ y: ym,
2220
+ z: zm
2221
+ }], chart),
2222
+ backOrientation = H.shapeArea3d([{
2223
+ x: xm,
2224
+ y: ym,
2225
+ z: zp
2226
+ }, {
2227
+ x: xp,
2228
+ y: ym,
2229
+ z: zp
2230
+ }, {
2231
+ x: xp,
2232
+ y: yp,
2233
+ z: zp
2234
+ }, {
2235
+ x: xm,
2236
+ y: yp,
2237
+ z: zp
2238
+ }], chart),
2239
+ defaultShowBottom = false,
2240
+ defaultShowTop = false,
2241
+ defaultShowLeft = false,
2242
+ defaultShowRight = false,
2243
+ defaultShowFront = false,
2244
+ defaultShowBack = true;
2245
+
2246
+ // The 'default' criteria to visible faces of the frame is looking up every
2247
+ // axis to decide whenever the left/right//top/bottom sides of the frame
2248
+ // will be shown
2249
+ each([].concat(chart.xAxis, chart.yAxis, chart.zAxis), function(axis) {
2250
+ if (axis) {
2251
+ if (axis.horiz) {
2252
+ if (axis.opposite) {
2253
+ defaultShowTop = true;
2254
+ } else {
2255
+ defaultShowBottom = true;
2256
+ }
2257
+ } else {
2258
+ if (axis.opposite) {
2259
+ defaultShowRight = true;
2260
+ } else {
2261
+ defaultShowLeft = true;
2262
+ }
2263
+ }
2264
+ }
2265
+ });
2266
+
2267
+ var getFaceOptions = function(sources, faceOrientation, defaultVisible) {
2268
+ var faceAttrs = ['size', 'color', 'visible'];
2269
+ var options = {};
2270
+ for (var i = 0; i < faceAttrs.length; i++) {
2271
+ var attr = faceAttrs[i];
2272
+ for (var j = 0; j < sources.length; j++) {
2273
+ if (typeof sources[j] === 'object') {
2274
+ var val = sources[j][attr];
2275
+ if (val !== undefined && val !== null) {
2276
+ options[attr] = val;
2277
+ break;
2278
+ }
2279
+ }
2280
+ }
2281
+ }
2282
+ var isVisible = defaultVisible;
2283
+ if (options.visible === true || options.visible === false) {
2284
+ isVisible = options.visible;
2285
+ } else if (options.visible === 'auto') {
2286
+ isVisible = faceOrientation >= 0;
2287
+ }
2288
+
2289
+ return {
2290
+ size: pick(options.size, 1),
2291
+ color: pick(options.color, 'none'),
2292
+ frontFacing: faceOrientation > 0,
2293
+ visible: isVisible
2294
+ };
2295
+ };
2296
+
2297
+ // docs @TODO: Add all frame options (left, right, top, bottom, front, back) to
2298
+ // apioptions JSDoc once the new system is up.
2299
+ var ret = {
2300
+ // FIXME: Previously, left/right, top/bottom and front/back pairs shared
2301
+ // size and color.
2302
+ // For compatibility and consistency sake, when one face have
2303
+ // size/color/visibility set, the opposite face will default to the same
2304
+ // values. Also, left/right used to be called 'side', so that's also
2305
+ // added as a fallback
2306
+ bottom: getFaceOptions(
2307
+ [frameOptions.bottom, frameOptions.top, frameOptions],
2308
+ bottomOrientation,
2309
+ defaultShowBottom
2310
+ ),
2311
+ top: getFaceOptions(
2312
+ [frameOptions.top, frameOptions.bottom, frameOptions],
2313
+ topOrientation,
2314
+ defaultShowTop
2315
+ ),
2316
+ left: getFaceOptions(
2317
+ [
2318
+ frameOptions.left,
2319
+ frameOptions.right,
2320
+ frameOptions.side,
2321
+ frameOptions
2322
+ ],
2323
+ leftOrientation,
2324
+ defaultShowLeft
2325
+ ),
2326
+ right: getFaceOptions(
2327
+ [
2328
+ frameOptions.right,
2329
+ frameOptions.left,
2330
+ frameOptions.side,
2331
+ frameOptions
2332
+ ],
2333
+ rightOrientation,
2334
+ defaultShowRight
2335
+ ),
2336
+ back: getFaceOptions(
2337
+ [frameOptions.back, frameOptions.front, frameOptions],
2338
+ backOrientation,
2339
+ defaultShowBack
2340
+ ),
2341
+ front: getFaceOptions(
2342
+ [frameOptions.front, frameOptions.back, frameOptions],
2343
+ frontOrientation,
2344
+ defaultShowFront
2345
+ )
2346
+ };
2347
+
2348
+
2349
+ // Decide the bast place to put axis title/labels based on the visible faces.
2350
+ // Ideally, The labels can only be on the edge between a visible face and an invisble one.
2351
+ // Also, the Y label should be one the left-most edge (right-most if opposite),
2352
+ if (options3d.axisLabelPosition === 'auto') {
2353
+ var isValidEdge = function(face1, face2) {
2354
+ return (face1.visible !== face2.visible) ||
2355
+ (face1.visible && face2.visible && (face1.frontFacing !== face2.frontFacing));
2356
+ };
2357
+
2358
+ var yEdges = [];
2359
+ if (isValidEdge(ret.left, ret.front)) {
2360
+ yEdges.push({
2361
+ y: (ym + yp) / 2,
2362
+ x: xm,
2363
+ z: zm
2364
+ });
2365
+ }
2366
+ if (isValidEdge(ret.left, ret.back)) {
2367
+ yEdges.push({
2368
+ y: (ym + yp) / 2,
2369
+ x: xm,
2370
+ z: zp
2371
+ });
2372
+ }
2373
+ if (isValidEdge(ret.right, ret.front)) {
2374
+ yEdges.push({
2375
+ y: (ym + yp) / 2,
2376
+ x: xp,
2377
+ z: zm
2378
+ });
2379
+ }
2380
+ if (isValidEdge(ret.right, ret.back)) {
2381
+ yEdges.push({
2382
+ y: (ym + yp) / 2,
2383
+ x: xp,
2384
+ z: zp
2385
+ });
2386
+ }
2387
+
2388
+ var xBottomEdges = [];
2389
+ if (isValidEdge(ret.bottom, ret.front)) {
2390
+ xBottomEdges.push({
2391
+ x: (xm + xp) / 2,
2392
+ y: yp,
2393
+ z: zm
2394
+ });
2395
+ }
2396
+ if (isValidEdge(ret.bottom, ret.back)) {
2397
+ xBottomEdges.push({
2398
+ x: (xm + xp) / 2,
2399
+ y: yp,
2400
+ z: zp
2401
+ });
2402
+ }
2403
+
2404
+ var xTopEdges = [];
2405
+ if (isValidEdge(ret.top, ret.front)) {
2406
+ xTopEdges.push({
2407
+ x: (xm + xp) / 2,
2408
+ y: ym,
2409
+ z: zm
2410
+ });
2411
+ }
2412
+ if (isValidEdge(ret.top, ret.back)) {
2413
+ xTopEdges.push({
2414
+ x: (xm + xp) / 2,
2415
+ y: ym,
2416
+ z: zp
2417
+ });
2418
+ }
2419
+
2420
+ var zBottomEdges = [];
2421
+ if (isValidEdge(ret.bottom, ret.left)) {
2422
+ zBottomEdges.push({
2423
+ z: (zm + zp) / 2,
2424
+ y: yp,
2425
+ x: xm
2426
+ });
2427
+ }
2428
+ if (isValidEdge(ret.bottom, ret.right)) {
2429
+ zBottomEdges.push({
2430
+ z: (zm + zp) / 2,
2431
+ y: yp,
2432
+ x: xp
2433
+ });
2434
+ }
2435
+
2436
+ var zTopEdges = [];
2437
+ if (isValidEdge(ret.top, ret.left)) {
2438
+ zTopEdges.push({
2439
+ z: (zm + zp) / 2,
2440
+ y: ym,
2441
+ x: xm
2442
+ });
2443
+ }
2444
+ if (isValidEdge(ret.top, ret.right)) {
2445
+ zTopEdges.push({
2446
+ z: (zm + zp) / 2,
2447
+ y: ym,
2448
+ x: xp
2449
+ });
2450
+ }
2451
+
2452
+ var pickEdge = function(edges, axis, mult) {
2453
+ if (edges.length === 0) {
2454
+ return null;
2455
+ } else if (edges.length === 1) {
2456
+ return edges[0];
2457
+ }
2458
+ var best = 0,
2459
+ projections = perspective(edges, chart, false);
2460
+ for (var i = 1; i < projections.length; i++) {
2461
+ if (mult * projections[i][axis] > mult * projections[best][axis]) {
2462
+ best = i;
2463
+ } else if ((mult * projections[i][axis] === mult * projections[best][axis]) && (projections[i].z < projections[best].z)) {
2464
+ best = i;
2465
+ }
2466
+ }
2467
+ return edges[best];
2468
+ };
2469
+ ret.axes = {
2470
+ y: {
2471
+ 'left': pickEdge(yEdges, 'x', -1),
2472
+ 'right': pickEdge(yEdges, 'x', +1)
2473
+ },
2474
+ x: {
2475
+ 'top': pickEdge(xTopEdges, 'y', -1),
2476
+ 'bottom': pickEdge(xBottomEdges, 'y', +1)
2477
+ },
2478
+ z: {
2479
+ 'top': pickEdge(zTopEdges, 'y', -1),
2480
+ 'bottom': pickEdge(zBottomEdges, 'y', +1)
2481
+ }
2482
+ };
2483
+ } else {
2484
+ ret.axes = {
2485
+ y: {
2486
+ 'left': {
2487
+ x: xm,
2488
+ z: zm
2489
+ },
2490
+ 'right': {
2491
+ x: xp,
2492
+ z: zm
2493
+ }
2494
+ },
2495
+ x: {
2496
+ 'top': {
2497
+ y: ym,
2498
+ z: zm
2499
+ },
2500
+ 'bottom': {
2501
+ y: yp,
2502
+ z: zm
2503
+ }
2504
+ },
2505
+ z: {
2506
+ 'top': {
2507
+ x: defaultShowLeft ? xp : xm,
2508
+ y: ym
2509
+ },
2510
+ 'bottom': {
2511
+ x: defaultShowLeft ? xp : xm,
2512
+ y: yp
2513
+ }
2514
+ }
2515
+ };
2516
+ }
2517
+
2518
+ return ret;
2519
+ };
2520
+
2521
+
1152
2522
  }(Highcharts));
1153
2523
  (function(H) {
1154
2524
  /**
@@ -1181,109 +2551,6 @@
1181
2551
  }
1182
2552
  });
1183
2553
 
1184
- wrap(Axis.prototype, 'render', function(proceed) {
1185
- proceed.apply(this, [].slice.call(arguments, 1));
1186
-
1187
- // Do not do this if the chart is not 3D
1188
- if (!this.chart.is3d() || this.coll === 'colorAxis') {
1189
- return;
1190
- }
1191
-
1192
- var chart = this.chart,
1193
- renderer = chart.renderer,
1194
- options3d = chart.options.chart.options3d,
1195
- frame = options3d.frame,
1196
- fbottom = frame.bottom,
1197
- fback = frame.back,
1198
- fside = frame.side,
1199
- depth = options3d.depth,
1200
- height = this.height,
1201
- width = this.width,
1202
- left = this.left,
1203
- top = this.top;
1204
-
1205
- if (this.isZAxis) {
1206
- return;
1207
- }
1208
- if (this.horiz) {
1209
- var bottomShape = {
1210
- x: left,
1211
- y: top + (chart.xAxis[0].opposite ? -fbottom.size : height),
1212
- z: 0,
1213
- width: width,
1214
- height: fbottom.size,
1215
- depth: depth,
1216
- insidePlotArea: false
1217
- };
1218
- if (!this.bottomFrame) {
1219
- this.bottomFrame = renderer.cuboid(bottomShape).attr({
1220
- 'class': 'highcharts-3d-frame highcharts-3d-frame-bottom',
1221
- 'zIndex': (chart.yAxis[0].reversed && options3d.alpha > 0 ? 4 : -1)
1222
- }).add();
1223
-
1224
-
1225
- this.bottomFrame.attr({
1226
- fill: fbottom.color || 'none',
1227
- stroke: fbottom.color || 'none'
1228
- });
1229
-
1230
- } else {
1231
- this.bottomFrame.animate(bottomShape);
1232
- }
1233
- } else {
1234
- // BACK
1235
- var backShape = {
1236
- x: left + (chart.yAxis[0].opposite ? 0 : -fside.size),
1237
- y: top + (chart.xAxis[0].opposite ? -fbottom.size : 0),
1238
- z: depth,
1239
- width: width + fside.size,
1240
- height: height + fbottom.size,
1241
- depth: fback.size,
1242
- insidePlotArea: false
1243
- };
1244
- if (!this.backFrame) {
1245
- this.backFrame = renderer.cuboid(backShape).attr({
1246
- 'class': 'highcharts-3d-frame highcharts-3d-frame-back',
1247
- zIndex: -3
1248
- }).add();
1249
-
1250
-
1251
- this.backFrame.attr({
1252
- fill: fback.color || 'none',
1253
- stroke: fback.color || 'none'
1254
- });
1255
-
1256
- } else {
1257
- this.backFrame.animate(backShape);
1258
- }
1259
- var sideShape = {
1260
- x: left + (chart.yAxis[0].opposite ? width : -fside.size),
1261
- y: top + (chart.xAxis[0].opposite ? -fbottom.size : 0),
1262
- z: 0,
1263
- width: fside.size,
1264
- height: height + fbottom.size,
1265
- depth: depth,
1266
- insidePlotArea: false
1267
- };
1268
- if (!this.sideFrame) {
1269
- this.sideFrame = renderer.cuboid(sideShape).attr({
1270
- 'class': 'highcharts-3d-frame highcharts-3d-frame-side',
1271
- zIndex: -2
1272
- }).add();
1273
-
1274
-
1275
- this.sideFrame.attr({
1276
- fill: fside.color || 'none',
1277
- stroke: fside.color || 'none'
1278
- });
1279
-
1280
-
1281
- } else {
1282
- this.sideFrame.animate(sideShape);
1283
- }
1284
- }
1285
- });
1286
-
1287
2554
  wrap(Axis.prototype, 'getPlotLinePath', function(proceed) {
1288
2555
  var path = proceed.apply(this, [].slice.call(arguments, 1));
1289
2556
 
@@ -1299,15 +2566,13 @@
1299
2566
  var chart = this.chart,
1300
2567
  options3d = chart.options.chart.options3d,
1301
2568
  d = this.isZAxis ? chart.plotWidth : options3d.depth,
1302
- opposite = this.opposite;
1303
- if (this.horiz) {
1304
- opposite = !opposite;
1305
- }
2569
+ frame = chart.frame3d;
2570
+
1306
2571
  var pArr = [
1307
2572
  this.swapZ({
1308
2573
  x: path[1],
1309
2574
  y: path[2],
1310
- z: (opposite ? d : 0)
2575
+ z: 0
1311
2576
  }),
1312
2577
  this.swapZ({
1313
2578
  x: path[1],
@@ -1317,19 +2582,60 @@
1317
2582
  this.swapZ({
1318
2583
  x: path[4],
1319
2584
  y: path[5],
1320
- z: d
2585
+ z: 0
1321
2586
  }),
1322
2587
  this.swapZ({
1323
2588
  x: path[4],
1324
2589
  y: path[5],
1325
- z: (opposite ? 0 : d)
2590
+ z: d
1326
2591
  })
1327
2592
  ];
1328
2593
 
1329
- pArr = perspective(pArr, this.chart, false);
1330
- path = this.chart.renderer.toLinePath(pArr, false);
2594
+ var pathSegments = [];
2595
+ if (!this.horiz) { // Y-Axis
2596
+ if (frame.front.visible) {
2597
+ pathSegments.push(pArr[0], pArr[2]);
2598
+ }
2599
+ if (frame.back.visible) {
2600
+ pathSegments.push(pArr[1], pArr[3]);
2601
+ }
2602
+ if (frame.left.visible) {
2603
+ pathSegments.push(pArr[0], pArr[1]);
2604
+ }
2605
+ if (frame.right.visible) {
2606
+ pathSegments.push(pArr[2], pArr[3]);
2607
+ }
2608
+ } else if (this.isZAxis) { // Z-Axis
2609
+ if (frame.left.visible) {
2610
+ pathSegments.push(pArr[0], pArr[2]);
2611
+ }
2612
+ if (frame.right.visible) {
2613
+ pathSegments.push(pArr[1], pArr[3]);
2614
+ }
2615
+ if (frame.top.visible) {
2616
+ pathSegments.push(pArr[0], pArr[1]);
2617
+ }
2618
+ if (frame.bottom.visible) {
2619
+ pathSegments.push(pArr[2], pArr[3]);
2620
+ }
2621
+ } else { // X-Axis
2622
+ if (frame.front.visible) {
2623
+ pathSegments.push(pArr[0], pArr[2]);
2624
+ }
2625
+ if (frame.back.visible) {
2626
+ pathSegments.push(pArr[1], pArr[3]);
2627
+ }
2628
+ if (frame.top.visible) {
2629
+ pathSegments.push(pArr[0], pArr[1]);
2630
+ }
2631
+ if (frame.bottom.visible) {
2632
+ pathSegments.push(pArr[2], pArr[3]);
2633
+ }
2634
+ }
2635
+
2636
+ pathSegments = perspective(pathSegments, this.chart, false);
1331
2637
 
1332
- return path;
2638
+ return this.chart.renderer.toLineSegments(pathSegments);
1333
2639
  });
1334
2640
 
1335
2641
  // Do not draw axislines in 3D
@@ -1346,31 +2652,99 @@
1346
2652
  var args = arguments,
1347
2653
  from = args[1],
1348
2654
  to = args[2],
1349
- toPath = this.getPlotLinePath(to),
1350
- path = this.getPlotLinePath(from);
1351
-
1352
- if (path && toPath) {
1353
- path.push(
1354
- 'L',
1355
- toPath[10], // These two do not exist in the regular getPlotLine
1356
- toPath[11], // ---- # 3005
1357
- 'L',
1358
- toPath[7],
1359
- toPath[8],
1360
- 'L',
1361
- toPath[4],
1362
- toPath[5],
1363
- 'L',
1364
- toPath[1],
1365
- toPath[2]
1366
- );
1367
- } else { // outside the axis area
1368
- path = null;
2655
+ path = [],
2656
+ fromPath = this.getPlotLinePath(from),
2657
+ toPath = this.getPlotLinePath(to);
2658
+
2659
+ if (fromPath && toPath) {
2660
+ for (var i = 0; i < fromPath.length; i += 6) {
2661
+ path.push(
2662
+ 'M', fromPath[i + 1], fromPath[i + 2],
2663
+ 'L', fromPath[i + 4], fromPath[i + 5],
2664
+ 'L', toPath[i + 4], toPath[i + 5],
2665
+ 'L', toPath[i + 1], toPath[i + 2],
2666
+ 'Z');
2667
+ }
1369
2668
  }
1370
2669
 
1371
2670
  return path;
1372
2671
  });
1373
2672
 
2673
+
2674
+ function fix3dPosition(axis, pos) {
2675
+ if (axis.chart.is3d() && axis.coll !== 'colorAxis') {
2676
+ var chart = axis.chart,
2677
+ frame = chart.frame3d,
2678
+ plotLeft = chart.plotLeft,
2679
+ plotRight = chart.plotWidth + plotLeft,
2680
+ plotTop = chart.plotTop,
2681
+ plotBottom = chart.plotHeight + plotTop,
2682
+ dx = 0,
2683
+ dy = 0;
2684
+
2685
+ pos = axis.swapZ({
2686
+ x: pos.x,
2687
+ y: pos.y,
2688
+ z: 0
2689
+ });
2690
+
2691
+
2692
+ if (axis.isZAxis) { // Z Axis
2693
+ if (axis.opposite) {
2694
+ if (frame.axes.z.top === null) {
2695
+ return {};
2696
+ }
2697
+ dy = pos.y - plotTop;
2698
+ pos.x = frame.axes.z.top.x;
2699
+ pos.y = frame.axes.z.top.y;
2700
+ } else {
2701
+ if (frame.axes.z.bottom === null) {
2702
+ return {};
2703
+ }
2704
+ dy = pos.y - plotBottom;
2705
+ pos.x = frame.axes.z.bottom.x;
2706
+ pos.y = frame.axes.z.bottom.y;
2707
+ }
2708
+ } else if (axis.horiz) { // X Axis
2709
+ if (axis.opposite) {
2710
+ if (frame.axes.x.top === null) {
2711
+ return {};
2712
+ }
2713
+ dy = pos.y - plotTop;
2714
+ pos.y = frame.axes.x.top.y;
2715
+ pos.z = frame.axes.x.top.z;
2716
+ } else {
2717
+ if (frame.axes.x.bottom === null) {
2718
+ return {};
2719
+ }
2720
+ dy = pos.y - plotBottom;
2721
+ pos.y = frame.axes.x.bottom.y;
2722
+ pos.z = frame.axes.x.bottom.z;
2723
+ }
2724
+ } else { //Y Axis
2725
+ if (axis.opposite) {
2726
+ if (frame.axes.y.right === null) {
2727
+ return {};
2728
+ }
2729
+ dx = pos.x - plotRight;
2730
+ pos.x = frame.axes.y.right.x;
2731
+ pos.z = frame.axes.y.right.z;
2732
+ } else {
2733
+ if (frame.axes.y.left === null) {
2734
+ return {};
2735
+ }
2736
+ dx = pos.x - plotLeft;
2737
+ pos.x = frame.axes.y.left.x;
2738
+ pos.z = frame.axes.y.left.z;
2739
+ }
2740
+ }
2741
+ pos = perspective([pos], axis.chart)[0];
2742
+ pos.x += dx;
2743
+ pos.y += dy;
2744
+ }
2745
+ return pos;
2746
+ }
2747
+
1374
2748
  /***
1375
2749
  EXTENSION TO THE TICKS
1376
2750
  ***/
@@ -1378,73 +2752,30 @@
1378
2752
  wrap(Tick.prototype, 'getMarkPath', function(proceed) {
1379
2753
  var path = proceed.apply(this, [].slice.call(arguments, 1));
1380
2754
 
1381
- // Do not do this if the chart is not 3D
1382
- if (!this.axis.chart.is3d() || this.axis.coll === 'colorAxis') {
1383
- return path;
1384
- }
1385
-
1386
2755
  var pArr = [
1387
- this.axis.swapZ({
2756
+ fix3dPosition(this.axis, {
1388
2757
  x: path[1],
1389
2758
  y: path[2],
1390
2759
  z: 0
1391
2760
  }),
1392
- this.axis.swapZ({
2761
+ fix3dPosition(this.axis, {
1393
2762
  x: path[4],
1394
2763
  y: path[5],
1395
2764
  z: 0
1396
2765
  })
1397
2766
  ];
1398
2767
 
1399
- pArr = perspective(pArr, this.axis.chart, false);
1400
- path = [
1401
- 'M', pArr[0].x, pArr[0].y,
1402
- 'L', pArr[1].x, pArr[1].y
1403
- ];
1404
- return path;
2768
+ return this.axis.chart.renderer.toLineSegments(pArr);
1405
2769
  });
1406
2770
 
1407
2771
  wrap(Tick.prototype, 'getLabelPosition', function(proceed) {
1408
2772
  var pos = proceed.apply(this, [].slice.call(arguments, 1));
1409
-
1410
- // Do not do this if the chart is not 3D
1411
- if (this.axis.chart.is3d() && this.axis.coll !== 'colorAxis') {
1412
- pos = perspective([this.axis.swapZ({
1413
- x: pos.x,
1414
- y: pos.y,
1415
- z: 0
1416
- })], this.axis.chart, false)[0];
1417
- }
1418
- return pos;
2773
+ return fix3dPosition(this.axis, pos);
1419
2774
  });
1420
2775
 
1421
2776
  H.wrap(Axis.prototype, 'getTitlePosition', function(proceed) {
1422
- var is3d = this.chart.is3d() && this.coll !== 'colorAxis',
1423
- pos,
1424
- axisTitleMargin;
1425
-
1426
- // Pull out the axis title margin, that is not subject to the perspective
1427
- if (is3d) {
1428
- axisTitleMargin = this.axisTitleMargin;
1429
- this.axisTitleMargin = 0;
1430
- }
1431
-
1432
- pos = proceed.apply(this, [].slice.call(arguments, 1));
1433
-
1434
- if (is3d) {
1435
- pos = perspective([this.swapZ({
1436
- x: pos.x,
1437
- y: pos.y,
1438
- z: 0
1439
- })], this.chart, false)[0];
1440
-
1441
- // Re-apply the axis title margin outside the perspective
1442
- pos[this.horiz ? 'y' : 'x'] += (this.horiz ? 1 : -1) * // horizontal axis reverses the margin ...
1443
- (this.opposite ? -1 : 1) * // ... so does opposite axes
1444
- axisTitleMargin;
1445
- this.axisTitleMargin = axisTitleMargin;
1446
- }
1447
- return pos;
2777
+ var pos = proceed.apply(this, [].slice.call(arguments, 1));
2778
+ return fix3dPosition(this, pos);
1448
2779
  });
1449
2780
 
1450
2781
  wrap(Axis.prototype, 'drawCrosshair', function(proceed) {
@@ -1476,9 +2807,8 @@
1476
2807
  Axis.prototype.swapZ = function(p, insidePlotArea) {
1477
2808
  if (this.isZAxis) {
1478
2809
  var plotLeft = insidePlotArea ? 0 : this.chart.plotLeft;
1479
- var chart = this.chart;
1480
2810
  return {
1481
- x: plotLeft + (chart.yAxis[0].opposite ? p.z : chart.xAxis[0].width - p.z),
2811
+ x: plotLeft + p.z,
1482
2812
  y: p.y,
1483
2813
  z: p.x - plotLeft
1484
2814
  };
@@ -2203,10 +3533,13 @@
2203
3533
  animate: false
2204
3534
  });
2205
3535
 
3536
+ VMLRenderer.prototype.face3d = SVGRenderer.prototype.face3d;
3537
+ VMLRenderer.prototype.polyhedron = SVGRenderer.prototype.polyhedron;
2206
3538
  VMLRenderer.prototype.cuboid = SVGRenderer.prototype.cuboid;
2207
3539
  VMLRenderer.prototype.cuboidPath = SVGRenderer.prototype.cuboidPath;
2208
3540
 
2209
3541
  VMLRenderer.prototype.toLinePath = SVGRenderer.prototype.toLinePath;
3542
+ VMLRenderer.prototype.toLineSegments = SVGRenderer.prototype.toLineSegments;
2210
3543
 
2211
3544
  VMLRenderer.prototype.createElement3D = SVGRenderer.prototype.createElement3D;
2212
3545