/* *
|
*
|
* (c) 2010-2019 Torstein Honsi
|
*
|
* License: www.highcharts.com/license
|
*
|
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
|
*
|
* */
|
'use strict';
|
|
var _Globals = require('../parts/Globals.js');
|
|
var _Globals2 = _interopRequireDefault(_Globals);
|
|
require('../parts/Utilities.js');
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
// Mathematical Functionility
|
var deg2rad = _Globals2.default.deg2rad,
|
pick = _Globals2.default.pick;
|
/* eslint-disable max-len */
|
/**
|
* Apply 3-D rotation
|
* Euler Angles (XYZ):
|
* cosA = cos(Alfa|Roll)
|
* cosB = cos(Beta|Pitch)
|
* cosG = cos(Gamma|Yaw)
|
*
|
* Composite rotation:
|
* | cosB * cosG | cosB * sinG | -sinB |
|
* | sinA * sinB * cosG - cosA * sinG | sinA * sinB * sinG + cosA * cosG | sinA * cosB |
|
* | cosA * sinB * cosG + sinA * sinG | cosA * sinB * sinG - sinA * cosG | cosA * cosB |
|
*
|
* Now, Gamma/Yaw is not used (angle=0), so we assume cosG = 1 and sinG = 0, so
|
* we get:
|
* | cosB | 0 | - sinB |
|
* | sinA * sinB | cosA | sinA * cosB |
|
* | cosA * sinB | - sinA | cosA * cosB |
|
*
|
* But in browsers, y is reversed, so we get sinA => -sinA. The general result
|
* is:
|
* | cosB | 0 | - sinB | | x | | px |
|
* | - sinA * sinB | cosA | - sinA * cosB | x | y | = | py |
|
* | cosA * sinB | sinA | cosA * cosB | | z | | pz |
|
*
|
* @private
|
* @function rotate3D
|
*/
|
/* eslint-enable max-len */
|
/**
|
* @private
|
* @param {number} x
|
* X coordinate
|
* @param {number} y
|
* Y coordinate
|
* @param {number} z
|
* Z coordinate
|
* @param {Highcharts.Rotation3dObject} angles
|
* Rotation angles
|
* @return {Highcharts.Rotation3dObject}
|
* Rotated position
|
*/
|
function rotate3D(x, y, z, angles) {
|
return {
|
x: angles.cosB * x - angles.sinB * z,
|
y: -angles.sinA * angles.sinB * x + angles.cosA * y - angles.cosB * angles.sinA * z,
|
z: angles.cosA * angles.sinB * x + angles.sinA * y + angles.cosA * angles.cosB * z
|
};
|
}
|
/**
|
* Perspective3D function is available in global Highcharts scope because is
|
* needed also outside of perspective() function (#8042).
|
* @private
|
* @function Highcharts.perspective3D
|
* @param {Highcharts.Position3dObject} coordinate
|
* 3D position
|
* @param {Highcharts.Position3dObject} origin
|
* 3D root position
|
* @param {number} distance
|
* Perspective distance
|
* @return {Highcharts.PositionObject}
|
* Perspective 3D Position
|
*/
|
_Globals2.default.perspective3D = function (coordinate, origin, distance) {
|
var projection = distance > 0 && distance < Number.POSITIVE_INFINITY ? distance / (coordinate.z + origin.z + distance) : 1;
|
return {
|
x: coordinate.x * projection,
|
y: coordinate.y * projection
|
};
|
};
|
/**
|
* Transforms a given array of points according to the angles in chart.options.
|
*
|
* @private
|
* @function Highcharts.perspective
|
* @param {Array<Highcharts.Position3dObject>} points
|
* The array of points
|
* @param {Highcharts.Chart} chart
|
* The chart
|
* @param {boolean} [insidePlotArea]
|
* Wether to verifiy the points are inside the plotArea
|
* @return {Array<Highcharts.Position3dObject>}
|
* An array of transformed points
|
*/
|
_Globals2.default.perspective = function (points, chart, insidePlotArea) {
|
var options3d = chart.options.chart.options3d,
|
inverted = insidePlotArea ? chart.inverted : false,
|
origin = {
|
x: chart.plotWidth / 2,
|
y: chart.plotHeight / 2,
|
z: options3d.depth / 2,
|
vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
|
},
|
scale = chart.scale3d || 1,
|
beta = deg2rad * options3d.beta * (inverted ? -1 : 1),
|
alpha = deg2rad * options3d.alpha * (inverted ? -1 : 1),
|
angles = {
|
cosA: Math.cos(alpha),
|
cosB: Math.cos(-beta),
|
sinA: Math.sin(alpha),
|
sinB: Math.sin(-beta)
|
};
|
if (!insidePlotArea) {
|
origin.x += chart.plotLeft;
|
origin.y += chart.plotTop;
|
}
|
// Transform each point
|
return points.map(function (point) {
|
var rotated = rotate3D((inverted ? point.y : point.x) - origin.x, (inverted ? point.x : point.y) - origin.y, (point.z || 0) - origin.z, angles),
|
|
// Apply perspective
|
coordinate = _Globals2.default.perspective3D(rotated, origin, origin.vd);
|
// Apply translation
|
coordinate.x = coordinate.x * scale + origin.x;
|
coordinate.y = coordinate.y * scale + origin.y;
|
coordinate.z = rotated.z * scale + origin.z;
|
return {
|
x: inverted ? coordinate.y : coordinate.x,
|
y: inverted ? coordinate.x : coordinate.y,
|
z: coordinate.z
|
};
|
});
|
};
|
/**
|
* Calculate a distance from camera to points - made for calculating zIndex of
|
* scatter points.
|
*
|
* @private
|
* @function Highcharts.pointCameraDistance
|
* @param {Highcharts.Dictionary<number>} coordinates
|
* Coordinates of the specific point
|
* @param {Highcharts.Chart} chart
|
* Related chart
|
* @return {number}
|
* Distance from camera to point
|
*/
|
_Globals2.default.pointCameraDistance = function (coordinates, chart) {
|
var options3d = chart.options.chart.options3d,
|
cameraPosition = {
|
x: chart.plotWidth / 2,
|
y: chart.plotHeight / 2,
|
z: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0) + options3d.depth
|
},
|
distance = Math.sqrt(Math.pow(cameraPosition.x - coordinates.plotX, 2) + Math.pow(cameraPosition.y - coordinates.plotY, 2) + Math.pow(cameraPosition.z - coordinates.plotZ, 2));
|
return distance;
|
};
|
/**
|
* Calculate area of a 2D polygon using Shoelace algorithm
|
* http://en.wikipedia.org/wiki/Shoelace_formula
|
*
|
* @private
|
* @function Highcharts.shapeArea
|
* @param {Array<Highcharts.PositionObject>} vertexes
|
* 2D Polygon
|
* @return {number}
|
* Calculated area
|
*/
|
_Globals2.default.shapeArea = function (vertexes) {
|
var area = 0,
|
i,
|
j;
|
for (i = 0; i < vertexes.length; i++) {
|
j = (i + 1) % vertexes.length;
|
area += vertexes[i].x * vertexes[j].y - vertexes[j].x * vertexes[i].y;
|
}
|
return area / 2;
|
};
|
/**
|
* Calculate area of a 3D polygon after perspective projection
|
*
|
* @private
|
* @function Highcharts.shapeArea3d
|
* @param {Array<Highcharts.Position3dObject>} vertexes
|
* 3D Polygon
|
* @param {Highcharts.Chart} chart
|
* Related chart
|
* @param {boolean} [insidePlotArea]
|
* Wether to verifiy the points are inside the plotArea
|
* @return {number}
|
* Calculated area
|
*/
|
_Globals2.default.shapeArea3d = function (vertexes, chart, insidePlotArea) {
|
return _Globals2.default.shapeArea(_Globals2.default.perspective(vertexes, chart, insidePlotArea));
|
};
|