initial commit

This commit is contained in:
2021-07-10 16:25:16 +02:00
parent bff57cbf45
commit 20fb7267a8
2426 changed files with 792090 additions and 0 deletions
@@ -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));
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,437 @@
/* *
* (c) 2010-2019 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
import '../parts/Series.js';
var addEvent = H.addEvent,
perspective = H.perspective,
pick = H.pick,
Series = H.Series,
seriesTypes = H.seriesTypes,
svg = H.svg,
wrap = H.wrap;
/**
* Depth of the columns in a 3D column chart. Requires `highcharts-3d.js`.
*
* @type {number}
* @default 25
* @since 4.0
* @product highcharts
* @apioption plotOptions.column.depth
*/
/**
* 3D columns only. The color of the edges. Similar to `borderColor`,
* except it defaults to the same color as the column.
*
* @type {Highcharts.ColorString}
* @product highcharts
* @apioption plotOptions.column.edgeColor
*/
/**
* 3D columns only. The width of the colored edges.
*
* @type {number}
* @default 1
* @product highcharts
* @apioption plotOptions.column.edgeWidth
*/
/**
* The spacing between columns on the Z Axis in a 3D chart. Requires
* `highcharts-3d.js`.
*
* @type {number}
* @default 1
* @since 4.0
* @product highcharts
* @apioption plotOptions.column.groupZPadding
*/
wrap(seriesTypes.column.prototype, 'translate', function (proceed) {
proceed.apply(this, [].slice.call(arguments, 1));
// Do not do this if the chart is not 3D
if (this.chart.is3d()) {
this.translate3dShapes();
}
});
// In 3D we need to pass point.outsidePlot option to the justifyDataLabel
// method for disabling justifying dataLabels in columns outside plot
wrap(H.Series.prototype, 'alignDataLabel', function (proceed) {
arguments[3].outside3dPlot = arguments[1].outside3dPlot;
proceed.apply(this, [].slice.call(arguments, 1));
});
// Don't use justifyDataLabel when point is outsidePlot
wrap(H.Series.prototype, 'justifyDataLabel', function (proceed) {
return !(arguments[2].outside3dPlot) ?
proceed.apply(this, [].slice.call(arguments, 1)) :
false;
});
seriesTypes.column.prototype.translate3dPoints = function () {};
seriesTypes.column.prototype.translate3dShapes = function () {
var series = this,
chart = series.chart,
seriesOptions = series.options,
depth = seriesOptions.depth || 25,
stack = seriesOptions.stacking ?
(seriesOptions.stack || 0) :
series.index, // #4743
z = stack * (depth + (seriesOptions.groupZPadding || 1)),
borderCrisp = series.borderWidth % 2 ? 0.5 : 0;
if (chart.inverted && !series.yAxis.reversed) {
borderCrisp *= -1;
}
if (seriesOptions.grouping !== false) {
z = 0;
}
z += (seriesOptions.groupZPadding || 1);
series.data.forEach(function (point) {
// #7103 Reset outside3dPlot flag
point.outside3dPlot = null;
if (point.y !== null) {
var shapeArgs = point.shapeArgs,
tooltipPos = point.tooltipPos,
// Array for final shapeArgs calculation.
// We are checking two dimensions (x and y).
dimensions = [['x', 'width'], ['y', 'height']],
borderlessBase; // Crisped rects can have +/- 0.5 pixels offset.
// #3131 We need to check if column is inside plotArea.
dimensions.forEach(function (d) {
borderlessBase = shapeArgs[d[0]] - borderCrisp;
if (borderlessBase < 0) {
// If borderLessBase is smaller than 0, it is needed to set
// its value to 0 or 0.5 depending on borderWidth
// borderWidth may be even or odd.
shapeArgs[d[1]] += shapeArgs[d[0]] + borderCrisp;
shapeArgs[d[0]] = -borderCrisp;
borderlessBase = 0;
}
if (
(
borderlessBase + shapeArgs[d[1]] >
series[d[0] + 'Axis'].len
) &&
// Do not change height/width of column if 0 (#6708)
shapeArgs[d[1]] !== 0
) {
shapeArgs[d[1]] =
series[d[0] + 'Axis'].len - shapeArgs[d[0]];
}
if (
// Do not remove columns with zero height/width.
(shapeArgs[d[1]] !== 0) &&
(
shapeArgs[d[0]] >= series[d[0] + 'Axis'].len ||
shapeArgs[d[0]] + shapeArgs[d[1]] <= borderCrisp
)
) {
// Set args to 0 if column is outside the chart.
for (var key in shapeArgs) {
shapeArgs[key] = 0;
}
// #7103 outside3dPlot flag is set on Points which are
// currently outside of plot.
point.outside3dPlot = true;
}
});
// Change from 2d to 3d
if (point.shapeType === 'rect') {
point.shapeType = 'cuboid';
}
shapeArgs.z = z;
shapeArgs.depth = depth;
shapeArgs.insidePlotArea = true;
// Translate the tooltip position in 3d space
tooltipPos = perspective(
[{ x: tooltipPos[0], y: tooltipPos[1], z: z }],
chart,
true
)[0];
point.tooltipPos = [tooltipPos.x, tooltipPos.y];
}
});
// store for later use #4067
series.z = z;
};
wrap(seriesTypes.column.prototype, 'animate', function (proceed) {
if (!this.chart.is3d()) {
proceed.apply(this, [].slice.call(arguments, 1));
} else {
var args = arguments,
init = args[1],
yAxis = this.yAxis,
series = this,
reversed = this.yAxis.reversed;
if (svg) { // VML is too slow anyway
if (init) {
series.data.forEach(function (point) {
if (point.y !== null) {
point.height = point.shapeArgs.height;
point.shapey = point.shapeArgs.y; // #2968
point.shapeArgs.height = 1;
if (!reversed) {
if (point.stackY) {
point.shapeArgs.y =
point.plotY + yAxis.translate(point.stackY);
} else {
point.shapeArgs.y =
point.plotY +
(
point.negative ?
-point.height :
point.height
);
}
}
}
});
} else { // run the animation
series.data.forEach(function (point) {
if (point.y !== null) {
point.shapeArgs.height = point.height;
point.shapeArgs.y = point.shapey; // #2968
// null value do not have a graphic
if (point.graphic) {
point.graphic.animate(
point.shapeArgs,
series.options.animation
);
}
}
});
// redraw datalabels to the correct position
this.drawDataLabels();
// delete this function to allow it only once
series.animate = null;
}
}
}
});
// In case of 3d columns there is no sense to add this columns to a specific
// series group - if series is added to a group all columns will have the same
// zIndex in comparison with different series.
wrap(
seriesTypes.column.prototype,
'plotGroup',
function (proceed, prop, name, visibility, zIndex, parent) {
if (this.chart.is3d() && parent && !this[prop]) {
if (!this.chart.columnGroup) {
this.chart.columnGroup =
this.chart.renderer.g('columnGroup').add(parent);
}
this[prop] = this.chart.columnGroup;
this.chart.columnGroup.attr(this.getPlotBox());
this[prop].survive = true;
}
return proceed.apply(this, Array.prototype.slice.call(arguments, 1));
}
);
// When series is not added to group it is needed to change setVisible method to
// allow correct Legend funcionality. This wrap is basing on pie chart series.
wrap(
seriesTypes.column.prototype,
'setVisible',
function (proceed, vis) {
var series = this,
pointVis;
if (series.chart.is3d()) {
series.data.forEach(function (point) {
point.visible = point.options.visible = vis =
vis === undefined ? !point.visible : vis;
pointVis = vis ? 'visible' : 'hidden';
series.options.data[series.data.indexOf(point)] =
point.options;
if (point.graphic) {
point.graphic.attr({
visibility: pointVis
});
}
});
}
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
}
);
seriesTypes.column.prototype.handle3dGrouping = true;
addEvent(Series, 'afterInit', function () {
if (this.chart.is3d() && this.handle3dGrouping) {
var seriesOptions = this.options,
grouping = seriesOptions.grouping,
stacking = seriesOptions.stacking,
reversedStacks = pick(this.yAxis.options.reversedStacks, true),
z = 0;
if (!(grouping !== undefined && !grouping)) {
var stacks = this.chart.retrieveStacks(stacking),
stack = seriesOptions.stack || 0,
i; // position within the stack
for (i = 0; i < stacks[stack].series.length; i++) {
if (stacks[stack].series[i] === this) {
break;
}
}
z = (10 * (stacks.totalStacks - stacks[stack].position)) +
(reversedStacks ? i : -i); // #4369
// In case when axis is reversed, columns are also reversed inside
// the group (#3737)
if (!this.xAxis.reversed) {
z = (stacks.totalStacks * 10) - z;
}
}
seriesOptions.zIndex = z;
}
});
function pointAttribs(proceed) {
var attr = proceed.apply(this, [].slice.call(arguments, 1));
if (this.chart.is3d && this.chart.is3d()) {
// Set the fill color to the fill color to provide a smooth edge
attr.stroke = this.options.edgeColor || attr.fill;
attr['stroke-width'] = pick(this.options.edgeWidth, 1); // #4055
}
return attr;
}
wrap(seriesTypes.column.prototype, 'pointAttribs', pointAttribs);
if (seriesTypes.columnrange) {
wrap(seriesTypes.columnrange.prototype, 'pointAttribs', pointAttribs);
seriesTypes.columnrange.prototype.plotGroup =
seriesTypes.column.prototype.plotGroup;
seriesTypes.columnrange.prototype.setVisible =
seriesTypes.column.prototype.setVisible;
}
wrap(Series.prototype, 'alignDataLabel', function (proceed) {
// Only do this for 3D columns and it's derived series
if (
this.chart.is3d() &&
this instanceof seriesTypes.column
) {
var series = this,
chart = series.chart;
var args = arguments,
alignTo = args[4],
point = args[1];
var pos = ({ x: alignTo.x, y: alignTo.y, z: series.z });
pos = perspective([pos], chart, true)[0];
alignTo.x = pos.x;
// #7103 If point is outside of plotArea, hide data label.
alignTo.y = point.outside3dPlot ? -9e9 : pos.y;
}
proceed.apply(this, [].slice.call(arguments, 1));
});
// Added stackLabels position calculation for 3D charts.
wrap(H.StackItem.prototype, 'getStackBox', function (proceed, chart) { // #3946
var stackBox = proceed.apply(this, [].slice.call(arguments, 1));
// Only do this for 3D chart.
if (chart.is3d()) {
var pos = ({
x: stackBox.x,
y: stackBox.y,
z: 0
});
pos = H.perspective([pos], chart, true)[0];
stackBox.x = pos.x;
stackBox.y = pos.y;
}
return stackBox;
});
/*
@merge v6.2
@todo
EXTENSION FOR 3D CYLINDRICAL COLUMNS
Not supported
*/
/*
var defaultOptions = H.getOptions();
defaultOptions.plotOptions.cylinder =
H.merge(defaultOptions.plotOptions.column);
var CylinderSeries = H.extendClass(seriesTypes.column, {
type: 'cylinder'
});
seriesTypes.cylinder = CylinderSeries;
wrap(seriesTypes.cylinder.prototype, 'translate', function (proceed) {
proceed.apply(this, [].slice.call(arguments, 1));
// Do not do this if the chart is not 3D
if (!this.chart.is3d()) {
return;
}
var series = this,
chart = series.chart,
options = chart.options,
cylOptions = options.plotOptions.cylinder,
options3d = options.chart.options3d,
depth = cylOptions.depth || 0,
alpha = chart.alpha3d;
var z = cylOptions.stacking ?
(this.options.stack || 0) * depth :
series._i * depth;
z += depth / 2;
if (cylOptions.grouping !== false) { z = 0; }
each(series.data, function (point) {
var shapeArgs = point.shapeArgs,
deg2rad = H.deg2rad;
point.shapeType = 'arc3d';
shapeArgs.x += depth / 2;
shapeArgs.z = z;
shapeArgs.start = 0;
shapeArgs.end = 2 * PI;
shapeArgs.r = depth * 0.95;
shapeArgs.innerR = 0;
shapeArgs.depth =
shapeArgs.height * (1 / sin((90 - alpha) * deg2rad)) - z;
shapeArgs.alpha = 90 - alpha;
shapeArgs.beta = 0;
});
});
*/
@@ -0,0 +1,206 @@
/* *
* (c) 2010-2019 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
// Mathematical Functionility
var deg2rad = H.deg2rad,
pick = H.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 */
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).
H.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.Point>} 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.Point>}
* An array of transformed points
*/
H.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 = H.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 {object} coordinates
* The coordinates of the specific point
*
* @param {Highcharts.Chart} chart
* The chart
*
* @return {number}
* A distance from camera to point
*/
H.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<object>} vertexes
*
* @return {number}
*/
H.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<object>} vertexes
*
* @param {Highcharts.Chart} chart
*
* @param {boolean} [insidePlotArea]
*
* @return {number}
*/
H.shapeArea3d = function (vertexes, chart, insidePlotArea) {
return H.shapeArea(H.perspective(vertexes, chart, insidePlotArea));
};
@@ -0,0 +1,207 @@
/* *
* (c) 2010-2019 Torstein Honsi
*
* 3D pie series
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
var deg2rad = H.deg2rad,
pick = H.pick,
seriesTypes = H.seriesTypes,
svg = H.svg,
wrap = H.wrap;
/**
* The thickness of a 3D pie. Requires `highcharts-3d.js`
*
* @type {number}
* @default 0
* @since 4.0
* @product highcharts
* @apioption plotOptions.pie.depth
*/
wrap(seriesTypes.pie.prototype, 'translate', function (proceed) {
proceed.apply(this, [].slice.call(arguments, 1));
// Do not do this if the chart is not 3D
if (!this.chart.is3d()) {
return;
}
var series = this,
seriesOptions = series.options,
depth = seriesOptions.depth || 0,
options3d = series.chart.options.chart.options3d,
alpha = options3d.alpha,
beta = options3d.beta,
z = seriesOptions.stacking ?
(seriesOptions.stack || 0) * depth :
series._i * depth;
z += depth / 2;
if (seriesOptions.grouping !== false) {
z = 0;
}
series.data.forEach(function (point) {
var shapeArgs = point.shapeArgs,
angle;
point.shapeType = 'arc3d';
shapeArgs.z = z;
shapeArgs.depth = depth * 0.75;
shapeArgs.alpha = alpha;
shapeArgs.beta = beta;
shapeArgs.center = series.center;
angle = (shapeArgs.end + shapeArgs.start) / 2;
point.slicedTranslation = {
translateX: Math.round(
Math.cos(angle) *
seriesOptions.slicedOffset *
Math.cos(alpha * deg2rad)
),
translateY: Math.round(
Math.sin(angle) *
seriesOptions.slicedOffset *
Math.cos(alpha * deg2rad)
)
};
});
});
wrap(
seriesTypes.pie.prototype.pointClass.prototype,
'haloPath',
function (proceed) {
var args = arguments;
return this.series.chart.is3d() ? [] : proceed.call(this, args[1]);
}
);
wrap(
seriesTypes.pie.prototype,
'pointAttribs',
function (proceed, point, state) {
var attr = proceed.call(this, point, state),
options = this.options;
if (this.chart.is3d() && !this.chart.styledMode) {
attr.stroke = options.edgeColor || point.color || this.color;
attr['stroke-width'] = pick(options.edgeWidth, 1);
}
return attr;
}
);
wrap(seriesTypes.pie.prototype, 'drawDataLabels', function (proceed) {
if (this.chart.is3d()) {
var series = this,
chart = series.chart,
options3d = chart.options.chart.options3d;
series.data.forEach(function (point) {
var shapeArgs = point.shapeArgs,
r = shapeArgs.r,
// #3240 issue with datalabels for 0 and null values
a1 = (shapeArgs.alpha || options3d.alpha) * deg2rad,
b1 = (shapeArgs.beta || options3d.beta) * deg2rad,
a2 = (shapeArgs.start + shapeArgs.end) / 2,
labelPosition = point.labelPosition,
connectorPosition = labelPosition.connectorPosition,
yOffset = (-r * (1 - Math.cos(a1)) * Math.sin(a2)),
xOffset = r * (Math.cos(b1) - 1) * Math.cos(a2);
// Apply perspective on label positions
[
labelPosition.natural,
connectorPosition.breakAt,
connectorPosition.touchingSliceAt
].forEach(function (coordinates) {
coordinates.x += xOffset;
coordinates.y += yOffset;
});
});
}
proceed.apply(this, [].slice.call(arguments, 1));
});
wrap(seriesTypes.pie.prototype, 'addPoint', function (proceed) {
proceed.apply(this, [].slice.call(arguments, 1));
if (this.chart.is3d()) {
// destroy (and rebuild) everything!!!
this.update(this.userOptions, true); // #3845 pass the old options
}
});
wrap(seriesTypes.pie.prototype, 'animate', function (proceed) {
if (!this.chart.is3d()) {
proceed.apply(this, [].slice.call(arguments, 1));
} else {
var args = arguments,
init = args[1],
animation = this.options.animation,
attribs,
center = this.center,
group = this.group,
markerGroup = this.markerGroup;
if (svg) { // VML is too slow anyway
if (animation === true) {
animation = {};
}
// Initialize the animation
if (init) {
// Scale down the group and place it in the center
group.oldtranslateX = group.translateX;
group.oldtranslateY = group.translateY;
attribs = {
translateX: center[0],
translateY: center[1],
scaleX: 0.001, // #1499
scaleY: 0.001
};
group.attr(attribs);
if (markerGroup) {
markerGroup.attrSetters = group.attrSetters;
markerGroup.attr(attribs);
}
// Run the animation
} else {
attribs = {
translateX: group.oldtranslateX,
translateY: group.oldtranslateY,
scaleX: 1,
scaleY: 1
};
group.animate(attribs, animation);
if (markerGroup) {
markerGroup.animate(attribs, animation);
}
// Delete this function to allow it only once
this.animate = null;
}
}
}
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,154 @@
/* *
* (c) 2010-2019 Torstein Honsi
*
* Scatter 3D series.
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
var Point = H.Point,
seriesType = H.seriesType,
seriesTypes = H.seriesTypes;
/**
* @private
* @class
* @name Highcharts.seriesTypes.scatter3d
*
* @augments Highcharts.Series
*/
seriesType(
'scatter3d',
'scatter',
/**
* A 3D scatter plot uses x, y and z coordinates to display values for three
* variables for a set of data.
*
* @sample {highcharts} highcharts/3d/scatter/
* Simple 3D scatter
* @sample {highcharts} highcharts/demo/3d-scatter-draggable
* Draggable 3d scatter
*
* @extends plotOptions.scatter
* @product highcharts
* @optionparent plotOptions.scatter3d
*/
{
tooltip: {
pointFormat: 'x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>z: <b>{point.z}</b><br/>'
}
// Series class
}, {
pointAttribs: function (point) {
var attribs = seriesTypes.scatter.prototype.pointAttribs
.apply(this, arguments);
if (this.chart.is3d() && point) {
attribs.zIndex = H.pointCameraDistance(point, this.chart);
}
return attribs;
},
axisTypes: ['xAxis', 'yAxis', 'zAxis'],
pointArrayMap: ['x', 'y', 'z'],
parallelArrays: ['x', 'y', 'z'],
// Require direct touch rather than using the k-d-tree, because the
// k-d-tree currently doesn't take the xyz coordinate system into
// account (#4552)
directTouch: true
// Point class
}, {
applyOptions: function () {
Point.prototype.applyOptions.apply(this, arguments);
if (this.z === undefined) {
this.z = 0;
}
return this;
}
}
);
/**
* A `scatter3d` series. If the [type](#series.scatter3d.type) option is
* not specified, it is inherited from [chart.type](#chart.type).
*
* scatter3d](#plotOptions.scatter3d).
*
* @extends series,plotOptions.scatter3d
* @product highcharts
* @apioption series.scatter3d
*/
/**
* An array of data points for the series. For the `scatter3d` series
* type, points can be given in the following ways:
*
* 1. An array of arrays with 3 values. In this case, the values correspond
* to `x,y,z`. If the first value is a string, it is applied as the name
* of the point, and the `x` value is inferred.
*
* ```js
* data: [
* [0, 0, 1],
* [1, 8, 7],
* [2, 9, 2]
* ]
* ```
*
* 3. An array of objects with named values. The following snippet shows only a
* few settings, see the complete options set below. If the total number of data
* points exceeds the series'
* [turboThreshold](#series.scatter3d.turboThreshold), this option is not
* available.
*
* ```js
* data: [{
* x: 1,
* y: 2,
* z: 24,
* name: "Point2",
* color: "#00FF00"
* }, {
* x: 1,
* y: 4,
* z: 12,
* name: "Point1",
* color: "#FF00FF"
* }]
* ```
*
* @sample {highcharts} highcharts/chart/reflow-true/
* Numerical values
* @sample {highcharts} highcharts/series/data-array-of-arrays/
* Arrays of numeric x and y
* @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
* Arrays of datetime x and y
* @sample {highcharts} highcharts/series/data-array-of-name-value/
* Arrays of point.name and y
* @sample {highcharts} highcharts/series/data-array-of-objects/
* Config objects
*
* @type {Array<Array<number>|*>}
* @extends series.scatter.data
* @product highcharts
* @apioption series.scatter3d.data
*/
/**
* The z value for each data point.
*
* @type {number}
* @product highcharts
* @apioption series.scatter3d.data.z
*/
@@ -0,0 +1,73 @@
/* *
* (c) 2010-2019 Torstein Honsi
*
* Extension to the Series object in 3D charts.
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
var addEvent = H.addEvent,
perspective = H.perspective,
pick = H.pick;
// Wrap the translate method to post-translate points into 3D perspective
addEvent(H.Series, 'afterTranslate', function () {
if (this.chart.is3d()) {
this.translate3dPoints();
}
});
// Translate the plotX, plotY properties and add plotZ.
H.Series.prototype.translate3dPoints = function () {
var series = this,
chart = series.chart,
zAxis = pick(series.zAxis, chart.options.zAxis[0]),
rawPoints = [],
rawPoint,
projectedPoints,
projectedPoint,
zValue,
i;
for (i = 0; i < series.data.length; i++) {
rawPoint = series.data[i];
if (zAxis && zAxis.translate) {
zValue = zAxis.isLog && zAxis.val2lin ?
zAxis.val2lin(rawPoint.z) :
rawPoint.z; // #4562
rawPoint.plotZ = zAxis.translate(zValue);
rawPoint.isInside = rawPoint.isInside ?
(zValue >= zAxis.min && zValue <= zAxis.max) :
false;
} else {
rawPoint.plotZ = 0;
}
rawPoint.axisXpos = rawPoint.plotX;
rawPoint.axisYpos = rawPoint.plotY;
rawPoint.axisZpos = rawPoint.plotZ;
rawPoints.push({
x: rawPoint.plotX,
y: rawPoint.plotY,
z: rawPoint.plotZ
});
}
projectedPoints = perspective(rawPoints, chart, true);
for (i = 0; i < series.data.length; i++) {
rawPoint = series.data[i];
projectedPoint = projectedPoints[i];
rawPoint.plotX = projectedPoint.x;
rawPoint.plotY = projectedPoint.y;
rawPoint.plotZ = projectedPoint.z;
}
};
@@ -0,0 +1,62 @@
/* *
* (c) 2010-2019 Torstein Honsi
*
* Extension to the VML Renderer
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
import '../parts/Axis.js';
import '../parts/SvgRenderer.js';
var addEvent = H.addEvent,
Axis = H.Axis,
SVGRenderer = H.SVGRenderer,
VMLRenderer = H.VMLRenderer;
if (VMLRenderer) {
H.setOptions({ animate: false });
VMLRenderer.prototype.face3d = SVGRenderer.prototype.face3d;
VMLRenderer.prototype.polyhedron = SVGRenderer.prototype.polyhedron;
VMLRenderer.prototype.elements3d = SVGRenderer.prototype.elements3d;
VMLRenderer.prototype.element3d = SVGRenderer.prototype.element3d;
VMLRenderer.prototype.cuboid = SVGRenderer.prototype.cuboid;
VMLRenderer.prototype.cuboidPath = SVGRenderer.prototype.cuboidPath;
VMLRenderer.prototype.toLinePath = SVGRenderer.prototype.toLinePath;
VMLRenderer.prototype.toLineSegments = SVGRenderer.prototype.toLineSegments;
VMLRenderer.prototype.arc3d = function (shapeArgs) {
var result = SVGRenderer.prototype.arc3d.call(this, shapeArgs);
result.css({ zIndex: result.zIndex });
return result;
};
H.VMLRenderer.prototype.arc3dPath = H.SVGRenderer.prototype.arc3dPath;
addEvent(Axis, 'render', function () {
// VML doesn't support a negative z-index
if (this.sideFrame) {
this.sideFrame.css({ zIndex: 0 });
this.sideFrame.front.attr({ fill: this.sideFrame.color });
}
if (this.bottomFrame) {
this.bottomFrame.css({ zIndex: 1 });
this.bottomFrame.front.attr({ fill: this.bottomFrame.color });
}
if (this.backFrame) {
this.backFrame.css({ zIndex: 0 });
this.backFrame.front.attr({ fill: this.backFrame.color });
}
});
}