initial commit
This commit is contained in:
@@ -0,0 +1,669 @@
|
||||
/* *
|
||||
* (c) 2010-2019 Torstein Honsi
|
||||
*
|
||||
* Extenstion for 3d axes
|
||||
*
|
||||
* License: www.highcharts.com/license
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import H from '../parts/Globals.js';
|
||||
import '../parts/Utilities.js';
|
||||
import '../parts/Axis.js';
|
||||
import '../parts/Chart.js';
|
||||
import '../parts/Tick.js';
|
||||
|
||||
var ZAxis,
|
||||
addEvent = H.addEvent,
|
||||
Axis = H.Axis,
|
||||
Chart = H.Chart,
|
||||
deg2rad = H.deg2rad,
|
||||
extend = H.extend,
|
||||
merge = H.merge,
|
||||
perspective = H.perspective,
|
||||
perspective3D = H.perspective3D,
|
||||
pick = H.pick,
|
||||
shapeArea = H.shapeArea,
|
||||
splat = H.splat,
|
||||
Tick = H.Tick,
|
||||
wrap = H.wrap;
|
||||
|
||||
/**
|
||||
* @optionparent xAxis
|
||||
*/
|
||||
var extendedOptions = {
|
||||
labels: {
|
||||
/**
|
||||
* Defines how the labels are be repositioned according to the 3D chart
|
||||
* orientation.
|
||||
*
|
||||
* - `'offset'`: Maintain a fixed horizontal/vertical distance from the
|
||||
* tick marks, despite the chart orientation. This is the backwards
|
||||
* compatible behavior, and causes skewing of X and Z axes.
|
||||
*
|
||||
* - `'chart'`: Preserve 3D position relative to the chart.
|
||||
* This looks nice, but hard to read if the text isn't
|
||||
* forward-facing.
|
||||
*
|
||||
* - `'flap'`: Rotated text along the axis to compensate for the chart
|
||||
* orientation. This tries to maintain text as legible as possible
|
||||
* on all orientations.
|
||||
*
|
||||
* - `'ortho'`: Rotated text along the axis direction so that the labels
|
||||
* are orthogonal to the axis. This is very similar to `'flap'`,
|
||||
* but prevents skewing the labels (X and Y scaling are still
|
||||
* present).
|
||||
*
|
||||
* @sample highcharts/3d/skewed-labels/
|
||||
* Skewed labels
|
||||
*
|
||||
* @since 5.0.15
|
||||
* @validvalue ['offset', 'chart', 'flap', 'ortho']
|
||||
* @product highcharts
|
||||
*/
|
||||
position3d: 'offset',
|
||||
|
||||
/**
|
||||
* If enabled, the axis labels will skewed to follow the perspective.
|
||||
*
|
||||
* This will fix overlapping labels and titles, but texts become less
|
||||
* legible due to the distortion.
|
||||
*
|
||||
* The final appearance depends heavily on `labels.position3d`.
|
||||
*
|
||||
* @sample highcharts/3d/skewed-labels/
|
||||
* Skewed labels
|
||||
*
|
||||
* @since 5.0.15
|
||||
* @product highcharts
|
||||
*/
|
||||
skew3d: false
|
||||
},
|
||||
title: {
|
||||
/**
|
||||
* Defines how the title is repositioned according to the 3D chart
|
||||
* orientation.
|
||||
*
|
||||
* - `'offset'`: Maintain a fixed horizontal/vertical distance from the
|
||||
* tick marks, despite the chart orientation. This is the backwards
|
||||
* compatible behavior, and causes skewing of X and Z axes.
|
||||
*
|
||||
* - `'chart'`: Preserve 3D position relative to the chart.
|
||||
* This looks nice, but hard to read if the text isn't
|
||||
* forward-facing.
|
||||
*
|
||||
* - `'flap'`: Rotated text along the axis to compensate for the chart
|
||||
* orientation. This tries to maintain text as legible as possible on
|
||||
* all orientations.
|
||||
*
|
||||
* - `'ortho'`: Rotated text along the axis direction so that the labels
|
||||
* are orthogonal to the axis. This is very similar to `'flap'`, but
|
||||
* prevents skewing the labels (X and Y scaling are still present).
|
||||
*
|
||||
* - `undefined`: Will use the config from `labels.position3d`
|
||||
*
|
||||
* @sample highcharts/3d/skewed-labels/
|
||||
* Skewed labels
|
||||
*
|
||||
* @type {"offset"|"chart"|"flap"|"ortho"|null}
|
||||
* @since 5.0.15
|
||||
* @product highcharts
|
||||
*/
|
||||
position3d: null,
|
||||
|
||||
/**
|
||||
* If enabled, the axis title will skewed to follow the perspective.
|
||||
*
|
||||
* This will fix overlapping labels and titles, but texts become less
|
||||
* legible due to the distortion.
|
||||
*
|
||||
* The final appearance depends heavily on `title.position3d`.
|
||||
*
|
||||
* A `null` value will use the config from `labels.skew3d`.
|
||||
*
|
||||
* @sample highcharts/3d/skewed-labels/
|
||||
* Skewed labels
|
||||
*
|
||||
* @type {boolean|null}
|
||||
* @since 5.0.15
|
||||
* @product highcharts
|
||||
*/
|
||||
skew3d: null
|
||||
}
|
||||
};
|
||||
|
||||
merge(true, Axis.prototype.defaultOptions, extendedOptions);
|
||||
|
||||
|
||||
addEvent(Axis, 'afterSetOptions', function () {
|
||||
var options;
|
||||
|
||||
if (this.chart.is3d && this.chart.is3d() && this.coll !== 'colorAxis') {
|
||||
options = this.options;
|
||||
options.tickWidth = pick(options.tickWidth, 0);
|
||||
options.gridLineWidth = pick(options.gridLineWidth, 1);
|
||||
}
|
||||
});
|
||||
|
||||
wrap(Axis.prototype, 'getPlotLinePath', function (proceed) {
|
||||
var path = proceed.apply(this, [].slice.call(arguments, 1));
|
||||
|
||||
// Do not do this if the chart is not 3D
|
||||
if (!this.chart.is3d() || this.coll === 'colorAxis') {
|
||||
return path;
|
||||
}
|
||||
|
||||
if (path === null) {
|
||||
return path;
|
||||
}
|
||||
|
||||
var chart = this.chart,
|
||||
options3d = chart.options.chart.options3d,
|
||||
d = this.isZAxis ? chart.plotWidth : options3d.depth,
|
||||
frame = chart.frame3d;
|
||||
|
||||
var pArr = [
|
||||
this.swapZ({ x: path[1], y: path[2], z: 0 }),
|
||||
this.swapZ({ x: path[1], y: path[2], z: d }),
|
||||
this.swapZ({ x: path[4], y: path[5], z: 0 }),
|
||||
this.swapZ({ x: path[4], y: path[5], z: d })
|
||||
];
|
||||
|
||||
var pathSegments = [];
|
||||
|
||||
if (!this.horiz) { // Y-Axis
|
||||
if (frame.front.visible) {
|
||||
pathSegments.push(pArr[0], pArr[2]);
|
||||
}
|
||||
if (frame.back.visible) {
|
||||
pathSegments.push(pArr[1], pArr[3]);
|
||||
}
|
||||
if (frame.left.visible) {
|
||||
pathSegments.push(pArr[0], pArr[1]);
|
||||
}
|
||||
if (frame.right.visible) {
|
||||
pathSegments.push(pArr[2], pArr[3]);
|
||||
}
|
||||
} else if (this.isZAxis) { // Z-Axis
|
||||
if (frame.left.visible) {
|
||||
pathSegments.push(pArr[0], pArr[2]);
|
||||
}
|
||||
if (frame.right.visible) {
|
||||
pathSegments.push(pArr[1], pArr[3]);
|
||||
}
|
||||
if (frame.top.visible) {
|
||||
pathSegments.push(pArr[0], pArr[1]);
|
||||
}
|
||||
if (frame.bottom.visible) {
|
||||
pathSegments.push(pArr[2], pArr[3]);
|
||||
}
|
||||
} else { // X-Axis
|
||||
if (frame.front.visible) {
|
||||
pathSegments.push(pArr[0], pArr[2]);
|
||||
}
|
||||
if (frame.back.visible) {
|
||||
pathSegments.push(pArr[1], pArr[3]);
|
||||
}
|
||||
if (frame.top.visible) {
|
||||
pathSegments.push(pArr[0], pArr[1]);
|
||||
}
|
||||
if (frame.bottom.visible) {
|
||||
pathSegments.push(pArr[2], pArr[3]);
|
||||
}
|
||||
}
|
||||
|
||||
pathSegments = perspective(pathSegments, this.chart, false);
|
||||
|
||||
return this.chart.renderer.toLineSegments(pathSegments);
|
||||
});
|
||||
|
||||
// Do not draw axislines in 3D
|
||||
wrap(Axis.prototype, 'getLinePath', function (proceed) {
|
||||
// Do not do this if the chart is not 3D
|
||||
if (!this.chart.is3d() || this.coll === 'colorAxis') {
|
||||
return proceed.apply(this, [].slice.call(arguments, 1));
|
||||
}
|
||||
|
||||
return [];
|
||||
});
|
||||
|
||||
wrap(Axis.prototype, 'getPlotBandPath', function (proceed) {
|
||||
// Do not do this if the chart is not 3D
|
||||
if (!this.chart.is3d() || this.coll === 'colorAxis') {
|
||||
return proceed.apply(this, [].slice.call(arguments, 1));
|
||||
}
|
||||
|
||||
var args = arguments,
|
||||
from = args[1],
|
||||
to = args[2],
|
||||
path = [],
|
||||
fromPath = this.getPlotLinePath(from),
|
||||
toPath = this.getPlotLinePath(to);
|
||||
|
||||
if (fromPath && toPath) {
|
||||
for (var i = 0; i < fromPath.length; i += 6) {
|
||||
path.push(
|
||||
'M', fromPath[i + 1], fromPath[i + 2],
|
||||
'L', fromPath[i + 4], fromPath[i + 5],
|
||||
'L', toPath[i + 4], toPath[i + 5],
|
||||
'L', toPath[i + 1], toPath[i + 2],
|
||||
'Z'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
});
|
||||
|
||||
|
||||
function fix3dPosition(axis, pos, isTitle) {
|
||||
// Do not do this if the chart is not 3D
|
||||
if (!axis.chart.is3d() || axis.coll === 'colorAxis') {
|
||||
return pos;
|
||||
}
|
||||
|
||||
var chart = axis.chart,
|
||||
alpha = deg2rad * chart.options.chart.options3d.alpha,
|
||||
beta = deg2rad * chart.options.chart.options3d.beta,
|
||||
positionMode = pick(
|
||||
isTitle && axis.options.title.position3d,
|
||||
axis.options.labels.position3d
|
||||
),
|
||||
skew = pick(
|
||||
isTitle && axis.options.title.skew3d,
|
||||
axis.options.labels.skew3d
|
||||
),
|
||||
frame = chart.frame3d,
|
||||
plotLeft = chart.plotLeft,
|
||||
plotRight = chart.plotWidth + plotLeft,
|
||||
plotTop = chart.plotTop,
|
||||
plotBottom = chart.plotHeight + plotTop,
|
||||
// Indicates we are labelling an X or Z axis on the "back" of the chart
|
||||
reverseFlap = false,
|
||||
offsetX = 0,
|
||||
offsetY = 0,
|
||||
vecX,
|
||||
vecY = { x: 0, y: 1, z: 0 };
|
||||
|
||||
pos = axis.swapZ({ x: pos.x, y: pos.y, z: 0 });
|
||||
|
||||
|
||||
if (axis.isZAxis) { // Z Axis
|
||||
if (axis.opposite) {
|
||||
if (frame.axes.z.top === null) {
|
||||
return {};
|
||||
}
|
||||
offsetY = pos.y - plotTop;
|
||||
pos.x = frame.axes.z.top.x;
|
||||
pos.y = frame.axes.z.top.y;
|
||||
vecX = frame.axes.z.top.xDir;
|
||||
reverseFlap = !frame.top.frontFacing;
|
||||
} else {
|
||||
if (frame.axes.z.bottom === null) {
|
||||
return {};
|
||||
}
|
||||
offsetY = pos.y - plotBottom;
|
||||
pos.x = frame.axes.z.bottom.x;
|
||||
pos.y = frame.axes.z.bottom.y;
|
||||
vecX = frame.axes.z.bottom.xDir;
|
||||
reverseFlap = !frame.bottom.frontFacing;
|
||||
}
|
||||
} else if (axis.horiz) { // X Axis
|
||||
if (axis.opposite) {
|
||||
if (frame.axes.x.top === null) {
|
||||
return {};
|
||||
}
|
||||
offsetY = pos.y - plotTop;
|
||||
pos.y = frame.axes.x.top.y;
|
||||
pos.z = frame.axes.x.top.z;
|
||||
vecX = frame.axes.x.top.xDir;
|
||||
reverseFlap = !frame.top.frontFacing;
|
||||
} else {
|
||||
if (frame.axes.x.bottom === null) {
|
||||
return {};
|
||||
}
|
||||
offsetY = pos.y - plotBottom;
|
||||
pos.y = frame.axes.x.bottom.y;
|
||||
pos.z = frame.axes.x.bottom.z;
|
||||
vecX = frame.axes.x.bottom.xDir;
|
||||
reverseFlap = !frame.bottom.frontFacing;
|
||||
}
|
||||
} else { // Y Axis
|
||||
if (axis.opposite) {
|
||||
if (frame.axes.y.right === null) {
|
||||
return {};
|
||||
}
|
||||
offsetX = pos.x - plotRight;
|
||||
pos.x = frame.axes.y.right.x;
|
||||
pos.z = frame.axes.y.right.z;
|
||||
vecX = frame.axes.y.right.xDir;
|
||||
// Rotate 90º on opposite edge
|
||||
vecX = { x: vecX.z, y: vecX.y, z: -vecX.x };
|
||||
} else {
|
||||
if (frame.axes.y.left === null) {
|
||||
return {};
|
||||
}
|
||||
offsetX = pos.x - plotLeft;
|
||||
pos.x = frame.axes.y.left.x;
|
||||
pos.z = frame.axes.y.left.z;
|
||||
vecX = frame.axes.y.left.xDir;
|
||||
}
|
||||
}
|
||||
|
||||
if (positionMode === 'chart') {
|
||||
// Labels preserve their direction relative to the chart
|
||||
// nothing to do
|
||||
|
||||
} else if (positionMode === 'flap') {
|
||||
// Labels are be rotated around the axis direction to face the screen
|
||||
if (!axis.horiz) { // Y Axis
|
||||
vecX = { x: Math.cos(beta), y: 0, z: Math.sin(beta) };
|
||||
} else { // X and Z Axis
|
||||
var sin = Math.sin(alpha);
|
||||
var cos = Math.cos(alpha);
|
||||
|
||||
if (axis.opposite) {
|
||||
sin = -sin;
|
||||
}
|
||||
if (reverseFlap) {
|
||||
sin = -sin;
|
||||
}
|
||||
vecY = { x: vecX.z * sin, y: cos, z: -vecX.x * sin };
|
||||
}
|
||||
} else if (positionMode === 'ortho') {
|
||||
// Labels will be rotated to be ortogonal to the axis
|
||||
if (!axis.horiz) { // Y Axis
|
||||
vecX = { x: Math.cos(beta), y: 0, z: Math.sin(beta) };
|
||||
} else { // X and Z Axis
|
||||
var sina = Math.sin(alpha);
|
||||
var cosa = Math.cos(alpha);
|
||||
var sinb = Math.sin(beta);
|
||||
var cosb = Math.cos(beta);
|
||||
var vecZ = { x: sinb * cosa, y: -sina, z: -cosa * cosb };
|
||||
|
||||
vecY = {
|
||||
x: vecX.y * vecZ.z - vecX.z * vecZ.y,
|
||||
y: vecX.z * vecZ.x - vecX.x * vecZ.z,
|
||||
z: vecX.x * vecZ.y - vecX.y * vecZ.x
|
||||
};
|
||||
var scale = 1 / Math.sqrt(
|
||||
vecY.x * vecY.x + vecY.y * vecY.y + vecY.z * vecY.z
|
||||
);
|
||||
|
||||
if (reverseFlap) {
|
||||
scale = -scale;
|
||||
}
|
||||
vecY = { x: scale * vecY.x, y: scale * vecY.y, z: scale * vecY.z };
|
||||
}
|
||||
} else { // positionMode == 'offset'
|
||||
// Labels will be skewd to maintain vertical / horizontal offsets from
|
||||
// axis
|
||||
if (!axis.horiz) { // Y Axis
|
||||
vecX = { x: Math.cos(beta), y: 0, z: Math.sin(beta) };
|
||||
} else { // X and Z Axis
|
||||
vecY = {
|
||||
x: Math.sin(beta) * Math.sin(alpha),
|
||||
y: Math.cos(alpha),
|
||||
z: -Math.cos(beta) * Math.sin(alpha)
|
||||
};
|
||||
}
|
||||
}
|
||||
pos.x += offsetX * vecX.x + offsetY * vecY.x;
|
||||
pos.y += offsetX * vecX.y + offsetY * vecY.y;
|
||||
pos.z += offsetX * vecX.z + offsetY * vecY.z;
|
||||
|
||||
var projected = perspective([pos], axis.chart)[0];
|
||||
|
||||
if (skew) {
|
||||
// Check if the label text would be mirrored
|
||||
var isMirrored = shapeArea(perspective([
|
||||
pos,
|
||||
{ x: pos.x + vecX.x, y: pos.y + vecX.y, z: pos.z + vecX.z },
|
||||
{ x: pos.x + vecY.x, y: pos.y + vecY.y, z: pos.z + vecY.z }
|
||||
], axis.chart)) < 0;
|
||||
|
||||
if (isMirrored) {
|
||||
vecX = { x: -vecX.x, y: -vecX.y, z: -vecX.z };
|
||||
}
|
||||
|
||||
var pointsProjected = perspective([
|
||||
{ x: pos.x, y: pos.y, z: pos.z },
|
||||
{ x: pos.x + vecX.x, y: pos.y + vecX.y, z: pos.z + vecX.z },
|
||||
{ x: pos.x + vecY.x, y: pos.y + vecY.y, z: pos.z + vecY.z }
|
||||
], axis.chart);
|
||||
|
||||
projected.matrix = [
|
||||
pointsProjected[1].x - pointsProjected[0].x,
|
||||
pointsProjected[1].y - pointsProjected[0].y,
|
||||
pointsProjected[2].x - pointsProjected[0].x,
|
||||
pointsProjected[2].y - pointsProjected[0].y,
|
||||
projected.x,
|
||||
projected.y
|
||||
];
|
||||
projected.matrix[4] -= projected.x * projected.matrix[0] +
|
||||
projected.y * projected.matrix[2];
|
||||
projected.matrix[5] -= projected.x * projected.matrix[1] +
|
||||
projected.y * projected.matrix[3];
|
||||
}
|
||||
|
||||
return projected;
|
||||
}
|
||||
|
||||
/*
|
||||
Tick extensions
|
||||
*/
|
||||
|
||||
wrap(Tick.prototype, 'getMarkPath', function (proceed) {
|
||||
var path = proceed.apply(this, [].slice.call(arguments, 1));
|
||||
|
||||
var pArr = [
|
||||
fix3dPosition(this.axis, { x: path[1], y: path[2], z: 0 }),
|
||||
fix3dPosition(this.axis, { x: path[4], y: path[5], z: 0 })
|
||||
];
|
||||
|
||||
return this.axis.chart.renderer.toLineSegments(pArr);
|
||||
});
|
||||
|
||||
addEvent(Tick, 'afterGetLabelPosition', function (e) {
|
||||
extend(e.pos, fix3dPosition(this.axis, e.pos));
|
||||
});
|
||||
|
||||
wrap(Axis.prototype, 'getTitlePosition', function (proceed) {
|
||||
var pos = proceed.apply(this, [].slice.call(arguments, 1));
|
||||
|
||||
return fix3dPosition(this, pos, true);
|
||||
});
|
||||
|
||||
addEvent(Axis, 'drawCrosshair', function (e) {
|
||||
if (this.chart.is3d() && this.coll !== 'colorAxis') {
|
||||
if (e.point) {
|
||||
e.point.crosshairPos = this.isXAxis ?
|
||||
e.point.axisXpos :
|
||||
this.len - (e.point.axisYpos);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
addEvent(Axis, 'destroy', function () {
|
||||
['backFrame', 'bottomFrame', 'sideFrame'].forEach(function (prop) {
|
||||
if (this[prop]) {
|
||||
this[prop] = this[prop].destroy();
|
||||
}
|
||||
}, this);
|
||||
});
|
||||
|
||||
/*
|
||||
Z-AXIS
|
||||
*/
|
||||
|
||||
Axis.prototype.swapZ = function (p, insidePlotArea) {
|
||||
if (this.isZAxis) {
|
||||
var plotLeft = insidePlotArea ? 0 : this.chart.plotLeft;
|
||||
|
||||
return {
|
||||
x: plotLeft + p.z,
|
||||
y: p.y,
|
||||
z: p.x - plotLeft
|
||||
};
|
||||
}
|
||||
return p;
|
||||
};
|
||||
|
||||
ZAxis = H.ZAxis = function () {
|
||||
this.init.apply(this, arguments);
|
||||
};
|
||||
extend(ZAxis.prototype, Axis.prototype);
|
||||
extend(ZAxis.prototype, {
|
||||
isZAxis: true,
|
||||
setOptions: function (userOptions) {
|
||||
userOptions = merge({
|
||||
offset: 0,
|
||||
lineWidth: 0
|
||||
}, userOptions);
|
||||
Axis.prototype.setOptions.call(this, userOptions);
|
||||
this.coll = 'zAxis';
|
||||
},
|
||||
setAxisSize: function () {
|
||||
Axis.prototype.setAxisSize.call(this);
|
||||
this.width = this.len = this.chart.options.chart.options3d.depth;
|
||||
this.right = this.chart.chartWidth - this.width - this.left;
|
||||
},
|
||||
getSeriesExtremes: function () {
|
||||
var axis = this,
|
||||
chart = axis.chart;
|
||||
|
||||
axis.hasVisibleSeries = false;
|
||||
|
||||
// Reset properties in case we're redrawing (#3353)
|
||||
axis.dataMin =
|
||||
axis.dataMax =
|
||||
axis.ignoreMinPadding =
|
||||
axis.ignoreMaxPadding = null;
|
||||
|
||||
if (axis.buildStacks) {
|
||||
axis.buildStacks();
|
||||
}
|
||||
|
||||
// loop through this axis' series
|
||||
axis.series.forEach(function (series) {
|
||||
|
||||
if (series.visible || !chart.options.chart.ignoreHiddenSeries) {
|
||||
|
||||
var seriesOptions = series.options,
|
||||
zData,
|
||||
threshold = seriesOptions.threshold;
|
||||
|
||||
axis.hasVisibleSeries = true;
|
||||
|
||||
// Validate threshold in logarithmic axes
|
||||
if (axis.positiveValuesOnly && threshold <= 0) {
|
||||
threshold = null;
|
||||
}
|
||||
|
||||
zData = series.zData;
|
||||
if (zData.length) {
|
||||
axis.dataMin = Math.min(
|
||||
pick(axis.dataMin, zData[0]),
|
||||
Math.min.apply(null, zData)
|
||||
);
|
||||
axis.dataMax = Math.max(
|
||||
pick(axis.dataMax, zData[0]),
|
||||
Math.max.apply(null, zData)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Get the Z axis in addition to the default X and Y.
|
||||
addEvent(Chart, 'afterGetAxes', function () {
|
||||
var chart = this,
|
||||
options = this.options,
|
||||
zAxisOptions = options.zAxis = splat(options.zAxis || {});
|
||||
|
||||
if (!chart.is3d()) {
|
||||
return;
|
||||
}
|
||||
this.zAxis = [];
|
||||
zAxisOptions.forEach(function (axisOptions, i) {
|
||||
axisOptions.index = i;
|
||||
// Z-Axis is shown horizontally, so it's kind of a X-Axis
|
||||
axisOptions.isX = true;
|
||||
var zAxis = new ZAxis(chart, axisOptions);
|
||||
|
||||
zAxis.setScale();
|
||||
});
|
||||
});
|
||||
|
||||
// Wrap getSlotWidth function to calculate individual width value for each slot
|
||||
// (#8042).
|
||||
wrap(Axis.prototype, 'getSlotWidth', function (proceed, tick) {
|
||||
if (this.chart.is3d() &&
|
||||
tick &&
|
||||
tick.label &&
|
||||
this.categories &&
|
||||
this.chart.frameShapes
|
||||
) {
|
||||
var chart = this.chart,
|
||||
ticks = this.ticks,
|
||||
gridGroup = this.gridGroup.element.childNodes,
|
||||
firstGridLine = gridGroup[0].getBBox(),
|
||||
frame3DLeft = chart.frameShapes.left.getBBox(),
|
||||
options3d = chart.options.chart.options3d,
|
||||
origin = {
|
||||
x: chart.plotWidth / 2,
|
||||
y: chart.plotHeight / 2,
|
||||
z: options3d.depth / 2,
|
||||
vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
|
||||
},
|
||||
labelPos,
|
||||
prevLabelPos,
|
||||
nextLabelPos,
|
||||
slotWidth,
|
||||
tickId = tick.pos,
|
||||
prevTick = ticks[tickId - 1],
|
||||
nextTick = ticks[tickId + 1];
|
||||
|
||||
// Check whether the tick is not the first one and previous tick exists,
|
||||
// then calculate position of previous label.
|
||||
if (tickId !== 0 && prevTick && prevTick.label.xy) { // #8621
|
||||
prevLabelPos = perspective3D({
|
||||
x: prevTick.label.xy.x,
|
||||
y: prevTick.label.xy.y,
|
||||
z: null
|
||||
}, origin, origin.vd);
|
||||
}
|
||||
// If next label position is defined, then recalculate its position
|
||||
// basing on the perspective.
|
||||
if (nextTick && nextTick.label.xy) {
|
||||
nextLabelPos = perspective3D({
|
||||
x: nextTick.label.xy.x,
|
||||
y: nextTick.label.xy.y,
|
||||
z: null
|
||||
}, origin, origin.vd);
|
||||
}
|
||||
labelPos = {
|
||||
x: tick.label.xy.x,
|
||||
y: tick.label.xy.y,
|
||||
z: null
|
||||
};
|
||||
|
||||
labelPos = perspective3D(labelPos, origin, origin.vd);
|
||||
|
||||
// If tick is first one, check whether next label position is already
|
||||
// calculated, then return difference between the first and the second
|
||||
// label. If there is no next label position calculated, return the
|
||||
// difference between the first grid line and left 3d frame.
|
||||
slotWidth = Math.abs(
|
||||
prevLabelPos ?
|
||||
labelPos.x - prevLabelPos.x : nextLabelPos ?
|
||||
nextLabelPos.x - labelPos.x :
|
||||
firstGridLine.x - frame3DLeft.x
|
||||
);
|
||||
return slotWidth;
|
||||
}
|
||||
return proceed.apply(this, [].slice.call(arguments, 1));
|
||||
});
|
||||
Reference in New Issue
Block a user