highcharts-rails 4.2.5 → 4.2.6

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.
@@ -2,7 +2,7 @@
2
2
  // @compilation_level SIMPLE_OPTIMIZATIONS
3
3
 
4
4
  /**
5
- * @license Highcharts JS v4.2.5 (2016-05-06)
5
+ * @license Highcharts JS v4.2.6 (2016-08-02)
6
6
  *
7
7
  * 3D features for Highcharts JS
8
8
  *
@@ -35,6 +35,41 @@
35
35
  cos = Math.cos,
36
36
  round = Math.round;
37
37
 
38
+ /**
39
+ * Apply 3-D rotation
40
+ * Euler Angles (XYZ): cosA = cos(Alfa|Roll), cosB = cos(Beta|Pitch), cosG = cos(Gamma|Yaw)
41
+ *
42
+ * Composite rotation:
43
+ * | cosB * cosG | cosB * sinG | -sinB |
44
+ * | sinA * sinB * cosG - cosA * sinG | sinA * sinB * sinG + cosA * cosG | sinA * cosB |
45
+ * | cosA * sinB * cosG + sinA * sinG | cosA * sinB * sinG - sinA * cosG | cosA * cosB |
46
+ *
47
+ * Now, Gamma/Yaw is not used (angle=0), so we assume cosG = 1 and sinG = 0, so we get:
48
+ * | cosB | 0 | - sinB |
49
+ * | sinA * sinB | cosA | sinA * cosB |
50
+ * | cosA * sinB | - sinA | cosA * cosB |
51
+ *
52
+ * But in browsers, y is reversed, so we get sinA => -sinA. The general result is:
53
+ * | cosB | 0 | - sinB | | x | | px |
54
+ * | - sinA * sinB | cosA | - sinA * cosB | x | y | = | py |
55
+ * | cosA * sinB | sinA | cosA * cosB | | z | | pz |
56
+ */
57
+ function rotate3D(x, y, z, angles) {
58
+ return {
59
+ x: angles.cosB * x - angles.sinB * z,
60
+ y: -angles.sinA * angles.sinB * x + angles.cosA * y - angles.cosB * angles.sinA * z,
61
+ z: angles.cosA * angles.sinB * x + angles.sinA * y + angles.cosA * angles.cosB * z
62
+ };
63
+ }
64
+
65
+ function perspective3D(coordinate, origin, distance) {
66
+ var projection = ((distance > 0) && (distance < Number.POSITIVE_INFINITY)) ? distance / (coordinate.z + origin.z + distance) : 1;
67
+ return {
68
+ x: coordinate.x * projection,
69
+ y: coordinate.y * projection
70
+ };
71
+ }
72
+
38
73
  /**
39
74
  * Transforms a given array of points according to the angles in chart.options.
40
75
  * Parameters:
@@ -44,97 +79,52 @@
44
79
  * Returns:
45
80
  * - an array of transformed points
46
81
  */
47
- function perspective(points, chart, insidePlotArea) {
82
+ var perspective = Highcharts.perspective = function (points, chart, insidePlotArea) {
48
83
  var options3d = chart.options.chart.options3d,
49
- inverted = false,
50
- origin,
51
- scale = chart.scale3d || 1;
52
-
53
- if (insidePlotArea) {
54
- inverted = chart.inverted;
84
+ inverted = insidePlotArea ? chart.inverted : false,
55
85
  origin = {
56
86
  x: chart.plotWidth / 2,
57
87
  y: chart.plotHeight / 2,
58
88
  z: options3d.depth / 2,
59
89
  vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
90
+ },
91
+ scale = chart.scale3d || 1,
92
+ beta = deg2rad * options3d.beta * (inverted ? -1 : 1),
93
+ alpha = deg2rad * options3d.alpha * (inverted ? -1 : 1),
94
+ angles = {
95
+ cosA: cos(alpha),
96
+ cosB: cos(-beta),
97
+ sinA: sin(alpha),
98
+ sinB: sin(-beta)
60
99
  };
61
- } else {
62
- origin = {
63
- x: chart.plotLeft + (chart.plotWidth / 2),
64
- y: chart.plotTop + (chart.plotHeight / 2),
65
- z: options3d.depth / 2,
66
- vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
67
- };
68
- }
69
-
70
- var result = [],
71
- xe = origin.x,
72
- ye = origin.y,
73
- ze = origin.z,
74
- vd = origin.vd,
75
- angle1 = deg2rad * (inverted ? options3d.beta : -options3d.beta),
76
- angle2 = deg2rad * (inverted ? -options3d.alpha : options3d.alpha),
77
- s1 = sin(angle1),
78
- c1 = cos(angle1),
79
- s2 = sin(angle2),
80
- c2 = cos(angle2);
81
100
 
82
- var x, y, z, px, py, pz;
101
+ if (!insidePlotArea) {
102
+ origin.x += chart.plotLeft;
103
+ origin.y += chart.plotTop;
104
+ }
83
105
 
84
106
  // Transform each point
85
- each(points, function (point) {
86
- x = (inverted ? point.y : point.x) - xe;
87
- y = (inverted ? point.x : point.y) - ye;
88
- z = (point.z || 0) - ze;
89
-
90
- // Apply 3-D rotation
91
- // Euler Angles (XYZ): cosA = cos(Alfa|Roll), cosB = cos(Beta|Pitch), cosG = cos(Gamma|Yaw)
92
- //
93
- // Composite rotation:
94
- // | cosB * cosG | cosB * sinG | -sinB |
95
- // | sinA * sinB * cosG - cosA * sinG | sinA * sinB * sinG + cosA * cosG | sinA * cosB |
96
- // | cosA * sinB * cosG + sinA * sinG | cosA * sinB * sinG - sinA * cosG | cosA * cosB |
97
- //
98
- // Now, Gamma/Yaw is not used (angle=0), so we assume cosG = 1 and sinG = 0, so we get:
99
- // | cosB | 0 | - sinB |
100
- // | sinA * sinB | cosA | sinA * cosB |
101
- // | cosA * sinB | - sinA | cosA * cosB |
102
- //
103
- // But in browsers, y is reversed, so we get sinA => -sinA. The general result is:
104
- // | cosB | 0 | - sinB | | x | | px |
105
- // | - sinA * sinB | cosA | - sinA * cosB | x | y | = | py |
106
- // | cosA * sinB | sinA | cosA * cosB | | z | | pz |
107
- //
108
- // Result:
109
- px = c1 * x - s1 * z;
110
- py = -s1 * s2 * x + c2 * y - c1 * s2 * z;
111
- pz = s1 * c2 * x + s2 * y + c1 * c2 * z;
112
-
113
-
114
- // Apply perspective
115
- if ((vd > 0) && (vd < Number.POSITIVE_INFINITY)) {
116
- px = px * (vd / (pz + ze + vd));
117
- py = py * (vd / (pz + ze + vd));
118
- }
119
-
107
+ return Highcharts.map(points, function (point) {
108
+ var rotated = rotate3D(
109
+ (inverted ? point.y : point.x) - origin.x,
110
+ (inverted ? point.x : point.y) - origin.y,
111
+ (point.z || 0) - origin.z,
112
+ angles
113
+ ),
114
+ coordinate = perspective3D(rotated, origin, origin.vd); // Apply perspective
115
+
116
+ // Apply translation
117
+ coordinate.x = coordinate.x * scale + origin.x;
118
+ coordinate.y = coordinate.y * scale + origin.y;
119
+ coordinate.z = rotated.z * scale + origin.z;
120
120
 
121
- //Apply translation
122
- px = px * scale + xe;
123
- py = py * scale + ye;
124
- pz = pz * scale + ze;
125
-
126
-
127
- result.push({
128
- x: (inverted ? py : px),
129
- y: (inverted ? px : py),
130
- z: pz
131
- });
121
+ return {
122
+ x: (inverted ? coordinate.y : coordinate.x),
123
+ y: (inverted ? coordinate.x : coordinate.y),
124
+ z: coordinate.z
125
+ };
132
126
  });
133
- return result;
134
- }
135
- // Make function acessible to plugins
136
- Highcharts.perspective = perspective;
137
- /***
127
+ };/***
138
128
  EXTENSION TO THE SVG-RENDERER TO ENABLE 3D SHAPES
139
129
  ***/
140
130
  ////// HELPER METHODS //////
@@ -480,7 +470,8 @@
480
470
  wrap(wrapper, 'animate', function (proceed, params, animation, complete) {
481
471
  var ca,
482
472
  from = this.attribs,
483
- to;
473
+ to,
474
+ anim;
484
475
 
485
476
  // Attribute-line properties connected to 3D. These shouldn't have been in the
486
477
  // attribs collection in the first place.
@@ -490,15 +481,15 @@
490
481
  delete params.alpha;
491
482
  delete params.beta;
492
483
 
493
- animation = animObject(pick(animation, this.renderer.globalAnimation));
484
+ anim = animObject(pick(animation, this.renderer.globalAnimation));
494
485
 
495
- if (animation.duration) {
486
+ if (anim.duration) {
496
487
  params = merge(params); // Don't mutate the original object
497
488
  ca = suckOutCustom(params);
498
489
 
499
490
  if (ca) {
500
491
  to = ca;
501
- animation.step = function (a, fx) {
492
+ anim.step = function (a, fx) {
502
493
  function interpolate(key) {
503
494
  return from[key] + (pick(to[key], from[key]) - from[key]) * fx.pos;
504
495
  }
@@ -726,104 +717,103 @@
726
717
  };
727
718
 
728
719
  /**
729
- * Extend the getMargins method to calculate scale of the 3D view. That is required to
720
+ * Calculate scale of the 3D view. That is required to
730
721
  * fit chart's 3D projection into the actual plotting area. Reported as #4933.
722
+ * @notice This function should ideally take the plot values instead of a chart object,
723
+ * but since the chart object is needed for perspective it is not practical.
724
+ * Possible to make both getScale and perspective more logical and also immutable.
725
+ * @param {Object} chart Chart object
726
+ * @param {Number} chart.plotLeft
727
+ * @param {Number} chart.plotWidth
728
+ * @param {Number} chart.plotTop
729
+ * @param {Number} chart.plotHeight
730
+ * @param {Number} depth The depth of the chart
731
+ * @return {Number} The scale to fit the 3D chart into the plotting area.
731
732
  */
732
- Highcharts.wrap(Highcharts.Chart.prototype, 'getMargins', function (proceed) {
733
- var chart = this,
734
- options3d = chart.options.chart.options3d,
733
+ function getScale(chart, depth) {
734
+ var plotLeft = chart.plotLeft,
735
+ plotRight = chart.plotWidth + plotLeft,
736
+ plotTop = chart.plotTop,
737
+ plotBottom = chart.plotHeight + plotTop,
738
+ originX = plotLeft + chart.plotWidth / 2,
739
+ originY = plotTop + chart.plotHeight / 2,
735
740
  bbox3d = {
736
741
  minX: Number.MAX_VALUE,
737
742
  maxX: -Number.MAX_VALUE,
738
743
  minY: Number.MAX_VALUE,
739
744
  maxY: -Number.MAX_VALUE
740
745
  },
741
- plotLeft = chart.plotLeft,
742
- plotRight = chart.plotWidth + plotLeft,
743
- plotTop = chart.plotTop,
744
- plotBottom = chart.plotHeight + plotTop,
745
- originX = plotLeft + chart.plotWidth / 2,
746
- originY = plotTop + chart.plotHeight / 2,
747
- scale = 1,
748
- corners = [],
749
- i;
746
+ corners,
747
+ scale = 1;
748
+
749
+ // Top left corners:
750
+ corners = [{
751
+ x: plotLeft,
752
+ y: plotTop,
753
+ z: 0
754
+ }, {
755
+ x: plotLeft,
756
+ y: plotTop,
757
+ z: depth
758
+ }];
759
+
760
+ // Top right corners:
761
+ each([0, 1], function (i) {
762
+ corners.push({
763
+ x: plotRight,
764
+ y: corners[i].y,
765
+ z: corners[i].z
766
+ });
767
+ });
750
768
 
751
- proceed.apply(this, [].slice.call(arguments, 1));
769
+ // All bottom corners:
770
+ each([0, 1, 2, 3], function (i) {
771
+ corners.push({
772
+ x: corners[i].x,
773
+ y: plotBottom,
774
+ z: corners[i].z
775
+ });
776
+ });
752
777
 
753
- if (this.is3d()) {
754
- if (options3d.fitToPlot === true) {
755
- // Clear previous scale in case of updates:
756
- chart.scale3d = 1;
757
-
758
- // Top left corners:
759
- corners = [{
760
- x: plotLeft,
761
- y: plotTop,
762
- z: 0
763
- }, {
764
- x: plotLeft,
765
- y: plotTop,
766
- z: options3d.depth
767
- }];
768
-
769
- // Top right corners:
770
- for (i = 0; i < 2; i++) {
771
- corners.push({
772
- x: plotRight,
773
- y: corners[i].y,
774
- z: corners[i].z
775
- });
776
- }
778
+ // Calculate 3D corners:
779
+ corners = perspective(corners, chart, false);
777
780
 
778
- // All bottom corners:
779
- for (i = 0; i < 4; i++) {
780
- corners.push({
781
- x: corners[i].x,
782
- y: plotBottom,
783
- z: corners[i].z
784
- });
785
- }
781
+ // Get bounding box of 3D element:
782
+ each(corners, function (corner) {
783
+ bbox3d.minX = Math.min(bbox3d.minX, corner.x);
784
+ bbox3d.maxX = Math.max(bbox3d.maxX, corner.x);
785
+ bbox3d.minY = Math.min(bbox3d.minY, corner.y);
786
+ bbox3d.maxY = Math.max(bbox3d.maxY, corner.y);
787
+ });
786
788
 
787
- // Calculate 3D corners:
788
- corners = perspective(corners, chart, false);
789
+ // Left edge:
790
+ if (plotLeft > bbox3d.minX) {
791
+ scale = Math.min(scale, 1 - Math.abs((plotLeft + originX) / (bbox3d.minX + originX)) % 1);
792
+ }
789
793
 
790
- // Get bounding box of 3D element:
791
- each(corners, function (corner) {
792
- bbox3d.minX = Math.min(bbox3d.minX, corner.x);
793
- bbox3d.maxX = Math.max(bbox3d.maxX, corner.x);
794
- bbox3d.minY = Math.min(bbox3d.minY, corner.y);
795
- bbox3d.maxY = Math.max(bbox3d.maxY, corner.y);
796
- });
794
+ // Right edge:
795
+ if (plotRight < bbox3d.maxX) {
796
+ scale = Math.min(scale, (plotRight - originX) / (bbox3d.maxX - originX));
797
+ }
797
798
 
798
- // Left edge:
799
- if (plotLeft > bbox3d.minX) {
800
- scale = Math.min(scale, 1 - Math.abs((plotLeft + originX) / (bbox3d.minX + originX)) % 1);
801
- }
799
+ // Top edge:
800
+ if (plotTop > bbox3d.minY) {
801
+ if (bbox3d.minY < 0) {
802
+ scale = Math.min(scale, (plotTop + originY) / (-bbox3d.minY + plotTop + originY));
803
+ } else {
804
+ scale = Math.min(scale, 1 - (plotTop + originY) / (bbox3d.minY + originY) % 1);
805
+ }
806
+ }
802
807
 
803
- // Right edge:
804
- if (plotRight < bbox3d.maxX) {
805
- scale = Math.min(scale, (plotRight - originX) / (bbox3d.maxX - originX));
806
- }
808
+ // Bottom edge:
809
+ if (plotBottom < bbox3d.maxY) {
810
+ scale = Math.min(scale, Math.abs((plotBottom - originY) / (bbox3d.maxY - originY)));
811
+ }
807
812
 
808
- // Top edge:
809
- if (plotTop > bbox3d.minY) {
810
- if (bbox3d.minY < 0) {
811
- scale = Math.min(scale, (plotTop + originY) / (-bbox3d.minY + plotTop + originY));
812
- } else {
813
- scale = Math.min(scale, 1 - (plotTop + originY) / (bbox3d.minY + originY) % 1);
814
- }
815
- }
813
+ return scale;
814
+ }
816
815
 
817
- // Bottom edge:
818
- if (plotBottom < bbox3d.maxY) {
819
- scale = Math.min(scale, Math.abs((plotBottom - originY) / (bbox3d.maxY - originY)));
820
- }
821
816
 
822
- // Set scale, used later in perspective method():
823
- chart.scale3d = scale;
824
- }
825
- }
826
- });
827
817
 
828
818
  Highcharts.wrap(Highcharts.Chart.prototype, 'isInsidePlot', function (proceed) {
829
819
  return this.is3d() || proceed.apply(this, [].slice.call(arguments, 1));
@@ -863,12 +853,15 @@
863
853
  });
864
854
 
865
855
  Highcharts.wrap(Highcharts.Chart.prototype, 'setChartSize', function (proceed) {
866
- proceed.apply(this, [].slice.call(arguments, 1));
856
+ var chart = this,
857
+ options3d = chart.options.chart.options3d;
867
858
 
868
- if (this.is3d()) {
869
- var inverted = this.inverted,
870
- clipBox = this.clipBox,
871
- margin = this.margin,
859
+ proceed.apply(chart, [].slice.call(arguments, 1));
860
+
861
+ if (chart.is3d()) {
862
+ var inverted = chart.inverted,
863
+ clipBox = chart.clipBox,
864
+ margin = chart.margin,
872
865
  x = inverted ? 'y' : 'x',
873
866
  y = inverted ? 'x' : 'y',
874
867
  w = inverted ? 'height' : 'width',
@@ -876,8 +869,14 @@
876
869
 
877
870
  clipBox[x] = -(margin[3] || 0);
878
871
  clipBox[y] = -(margin[0] || 0);
879
- clipBox[w] = this.chartWidth + (margin[3] || 0) + (margin[1] || 0);
880
- clipBox[h] = this.chartHeight + (margin[0] || 0) + (margin[2] || 0);
872
+ clipBox[w] = chart.chartWidth + (margin[3] || 0) + (margin[1] || 0);
873
+ clipBox[h] = chart.chartHeight + (margin[0] || 0) + (margin[2] || 0);
874
+
875
+ // Set scale, used later in perspective method():
876
+ chart.scale3d = 1; // @notice getScale uses perspective, so scale3d has to be reset.
877
+ if (options3d.fitToPlot === true) {
878
+ chart.scale3d = getScale(chart, options3d.depth);
879
+ }
881
880
  }
882
881
  });
883
882
 
@@ -1126,21 +1125,10 @@
1126
1125
  var pos = proceed.apply(this, [].slice.call(arguments, 1));
1127
1126
 
1128
1127
  // Do not do this if the chart is not 3D
1129
- if (!this.axis.chart.is3d()) {
1130
- return pos;
1131
- }
1132
-
1133
- var newPos = perspective([this.axis.swapZ({ x: pos.x, y: pos.y, z: 0 })], this.axis.chart, false)[0];
1134
- newPos.x = newPos.x - (!this.axis.horiz && this.axis.opposite ? this.axis.transA : 0); //#3788
1135
- newPos.old = pos;
1136
- return newPos;
1137
- });
1138
-
1139
- Highcharts.wrap(Highcharts.Tick.prototype, 'handleOverflow', function (proceed, xy) {
1140
1128
  if (this.axis.chart.is3d()) {
1141
- xy = xy.old;
1129
+ pos = perspective([this.axis.swapZ({ x: pos.x, y: pos.y, z: 0 })], this.axis.chart, false)[0];
1142
1130
  }
1143
- return proceed.call(this, xy);
1131
+ return pos;
1144
1132
  });
1145
1133
 
1146
1134
  Highcharts.wrap(Highcharts.Axis.prototype, 'getTitlePosition', function (proceed) {
@@ -1738,6 +1726,7 @@
1738
1726
 
1739
1727
  rawPoint.plotXold = rawPoint.plotX;
1740
1728
  rawPoint.plotYold = rawPoint.plotY;
1729
+ rawPoint.plotZold = rawPoint.plotZ;
1741
1730
 
1742
1731
  rawPoint.plotX = projectedPoint.x;
1743
1732
  rawPoint.plotY = projectedPoint.y;