/* * * * (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} 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} * 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} 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} 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} 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)); };