highcharts-rails 4.2.5 → 4.2.6

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