app/assets/javascripts/highcharts/highcharts-3d.js in highcharts-rails-5.0.10 vs app/assets/javascripts/highcharts/highcharts-3d.js in highcharts-rails-5.0.11
- old
+ new
@@ -1,7 +1,7 @@
/**
- * @license Highcharts JS v5.0.10 (2017-03-31)
+ * @license Highcharts JS v5.0.11 (2017-05-04)
*
* 3D features for Highcharts JS
*
* @license: www.highcharts.com/license
*/
@@ -179,19 +179,10 @@
area += vertexes[i].x * vertexes[j].y - vertexes[j].x * vertexes[i].y;
}
return area / 2;
}
- function averageZ(vertexes) {
- var z = 0,
- i;
- for (i = 0; i < vertexes.length; i++) {
- z += vertexes[i].z;
- }
- return vertexes.length ? z / vertexes.length : 0;
- }
-
/** Method to construct a curved path
* Can 'wrap' around more then 180 degrees
*/
function curveTo(cx, cy, rx, ry, start, end, dx, dy) {
var result = [],
@@ -254,20 +245,17 @@
});
// create the 3 sides
result.front = this.path(paths[0]).attr({
- 'class': 'highcharts-3d-front',
- zIndex: paths[3]
- }).add(result);
+ 'class': 'highcharts-3d-front'
+ }).add(result); // Front, top and side are never overlapping in our case so it is redundant to set zIndex of every element.
result.top = this.path(paths[1]).attr({
- 'class': 'highcharts-3d-top',
- zIndex: paths[4]
+ 'class': 'highcharts-3d-top'
}).add(result);
result.side = this.path(paths[2]).attr({
- 'class': 'highcharts-3d-side',
- zIndex: paths[5]
+ 'class': 'highcharts-3d-side'
}).add(result);
// apply the fill everywhere, the top a bit brighter, the side a bit darker
result.fillSetter = function(fill) {
this.front.attr({
@@ -309,20 +297,17 @@
if (args.shapeArgs || defined(args.x)) {
var shapeArgs = args.shapeArgs || args;
var paths = this.renderer.cuboidPath(shapeArgs);
this.front.attr({
- d: paths[0],
- zIndex: paths[3]
+ d: paths[0]
});
this.top.attr({
- d: paths[1],
- zIndex: paths[4]
+ d: paths[1]
});
this.side.attr({
- d: paths[2],
- zIndex: paths[5]
+ d: paths[2]
});
} else {
return H.SVGElement.prototype.attr.call(this, args); // getter returns value
}
@@ -330,27 +315,21 @@
};
result.animate = function(args, duration, complete) {
if (defined(args.x) && defined(args.y)) {
var paths = this.renderer.cuboidPath(args);
- this.front.attr({
- zIndex: paths[3]
- }).animate({
+ this.front.animate({
d: paths[0]
}, duration, complete);
- this.top.attr({
- zIndex: paths[4]
- }).animate({
+ this.top.animate({
d: paths[1]
}, duration, complete);
- this.side.attr({
- zIndex: paths[5]
- }).animate({
+ this.side.animate({
d: paths[2]
}, duration, complete);
this.attr({
- zIndex: -paths[6] // #4774
+ zIndex: -paths[3] // #4774
});
} else if (args.opacity) {
this.front.animate(args, duration, complete);
this.top.animate(args, duration, complete);
this.side.animate(args, duration, complete);
@@ -369,106 +348,168 @@
return destroy.call(this);
};
// Apply the Z index to the cuboid group
result.attr({
- zIndex: -paths[6]
+ zIndex: -paths[3]
});
return result;
};
/**
* Generates a cuboid
*/
- SVGRenderer.prototype.cuboidPath = function(shapeArgs) {
+ H.SVGRenderer.prototype.cuboidPath = function(shapeArgs) {
var x = shapeArgs.x,
y = shapeArgs.y,
z = shapeArgs.z,
h = shapeArgs.height,
w = shapeArgs.width,
d = shapeArgs.depth,
- chart = charts[this.chartIndex];
+ chart = charts[this.chartIndex],
+ front,
+ back,
+ top,
+ bottom,
+ left,
+ right,
+ shape,
+ path1,
+ path2,
+ path3,
+ isFront,
+ isTop,
+ isRight,
+ options3d = chart.options.chart.options3d,
+ alpha = options3d.alpha,
+ // Priority for x axis is the biggest,
+ // because of x direction has biggest influence on zIndex
+ incrementX = 10000,
+ // y axis has the smallest priority in case of our charts
+ // (needs to be set because of stacking)
+ incrementY = 10,
+ incrementZ = 100,
+ zIndex = 0;
// The 8 corners of the cube
var pArr = [{
- x: x,
- y: y,
- z: z
- },
- {
- x: x + w,
- y: y,
- z: z
- },
- {
- x: x + w,
- y: y + h,
- z: z
- },
- {
- x: x,
- y: y + h,
- z: z
- },
- {
- x: x,
- y: y + h,
- z: z + d
- },
- {
- x: x + w,
- y: y + h,
- z: z + d
- },
- {
- x: x + w,
- y: y,
- z: z + d
- },
- {
- x: x,
- y: y,
- z: z + d
- }
- ];
+ x: x,
+ y: y,
+ z: z
+ }, {
+ x: x + w,
+ y: y,
+ z: z
+ }, {
+ x: x + w,
+ y: y + h,
+ z: z
+ }, {
+ x: x,
+ y: y + h,
+ z: z
+ }, {
+ x: x,
+ y: y + h,
+ z: z + d
+ }, {
+ x: x + w,
+ y: y + h,
+ z: z + d
+ }, {
+ x: x + w,
+ y: y,
+ z: z + d
+ }, {
+ x: x,
+ y: y,
+ z: z + d
+ }];
// apply perspective
pArr = perspective(pArr, chart, shapeArgs.insidePlotArea);
// helper method to decide which side is visible
function mapPath(i) {
return pArr[i];
}
+
+ /*
+ * First value - path with specific side
+ * Second value - added information about side for later calculations.
+ * Possible second values are 0 for path1, 1 for path2 and -1 for no path choosed.
+ */
var pickShape = function(path1, path2) {
- var ret = [];
+ var ret = [
+ [], -1
+ ];
path1 = map(path1, mapPath);
path2 = map(path2, mapPath);
if (shapeArea(path1) < 0) {
- ret = path1;
+ ret = [path1, 0];
} else if (shapeArea(path2) < 0) {
- ret = path2;
+ ret = [path2, 1];
}
return ret;
};
// front or back
- var front = [3, 2, 1, 0];
- var back = [7, 6, 5, 4];
- var path1 = pickShape(front, back);
+ front = [3, 2, 1, 0];
+ back = [7, 6, 5, 4];
+ shape = pickShape(front, back);
+ path1 = shape[0];
+ isFront = shape[1];
+
// top or bottom
- var top = [1, 6, 7, 0];
- var bottom = [4, 5, 2, 3];
- var path2 = pickShape(top, bottom);
+ top = [1, 6, 7, 0];
+ bottom = [4, 5, 2, 3];
+ shape = pickShape(top, bottom);
+ path2 = shape[0];
+ isTop = shape[1];
// side
- var right = [1, 2, 5, 6];
- var left = [0, 7, 4, 3];
- var path3 = pickShape(right, left);
+ right = [1, 2, 5, 6];
+ left = [0, 7, 4, 3];
+ shape = pickShape(right, left);
+ path3 = shape[0];
+ isRight = shape[1];
- return [this.toLinePath(path1, true), this.toLinePath(path2, true), this.toLinePath(path3, true), averageZ(path1), averageZ(path2), averageZ(path3), averageZ(map(bottom, mapPath)) * 9e9]; // #4774
+ /*
+ * New block used for calculating zIndex. It is basing on X, Y and Z position of specific columns.
+ * All zIndexes (for X, Y and Z values) are added to the final zIndex, where every value has different priority.
+ * The biggest priority is in X and Z directions, the lowest index is for stacked columns (Y direction and the same X and Z positions).
+ * Big differents between priorities is made because we need to ensure that even for big changes in Y and Z parameters
+ * all columns will be drawn correctly.
+ */
+
+ if (isRight === 1) {
+ zIndex += incrementX * (1000 - x);
+ } else if (!isRight) {
+ zIndex += incrementX * x;
+ }
+
+ zIndex += incrementY * (!isTop ||
+ (alpha >= 0 && alpha <= 180 || alpha < 360 && alpha > 357.5) ? // Numbers checked empirically
+ chart.plotHeight - y : 10 + y
+ );
+
+ if (isFront === 1) {
+ zIndex += incrementZ * (z);
+ } else if (!isFront) {
+ zIndex += incrementZ * (1000 - z);
+ }
+
+ zIndex = -Math.round(zIndex);
+
+ return [
+ this.toLinePath(path1, true),
+ this.toLinePath(path2, true),
+ this.toLinePath(path3, true),
+ zIndex
+ ]; // #4774
};
////// SECTORS //////
H.SVGRenderer.prototype.arc3d = function(attribs) {
@@ -1336,11 +1377,11 @@
wrap(Tick.prototype, 'getMarkPath', function(proceed) {
var path = proceed.apply(this, [].slice.call(arguments, 1));
// Do not do this if the chart is not 3D
- if (!this.axis.chart.is3d() || this.coll === 'colorAxis') {
+ if (!this.axis.chart.is3d() || this.axis.coll === 'colorAxis') {
return path;
}
var pArr = [
this.axis.swapZ({
@@ -1365,11 +1406,11 @@
wrap(Tick.prototype, 'getLabelPosition', function(proceed) {
var pos = proceed.apply(this, [].slice.call(arguments, 1));
// Do not do this if the chart is not 3D
- if (this.axis.chart.is3d() && this.coll !== 'colorAxis') {
+ if (this.axis.chart.is3d() && this.axis.coll !== 'colorAxis') {
pos = perspective([this.axis.swapZ({
x: pos.x,
y: pos.y,
z: 0
})], this.axis.chart, false)[0];
@@ -1536,12 +1577,14 @@
var each = H.each,
perspective = H.perspective,
pick = H.pick,
Series = H.Series,
seriesTypes = H.seriesTypes,
+ inArray = H.inArray,
svg = H.svg,
wrap = H.wrap;
+
/***
EXTENSION FOR 3D COLUMNS
***/
wrap(seriesTypes.column.prototype, 'translate', function(proceed) {
proceed.apply(this, [].slice.call(arguments, 1));
@@ -1552,26 +1595,60 @@
}
var series = this,
chart = series.chart,
seriesOptions = series.options,
- depth = seriesOptions.depth || 25;
+ depth = seriesOptions.depth || 25,
+ borderCrisp = series.borderWidth % 2 ? 0.5 : 0;
- var stack = seriesOptions.stacking ? (seriesOptions.stack || 0) : series._i;
+ if (
+ (chart.inverted && !series.yAxis.reversed) ||
+ (!chart.inverted && series.yAxis.reversed)
+ ) {
+ borderCrisp *= -1;
+ }
+
+ var stack = seriesOptions.stacking ? (seriesOptions.stack || 0) : series.index; // #4743
var z = stack * (depth + (seriesOptions.groupZPadding || 1));
if (seriesOptions.grouping !== false) {
z = 0;
}
z += (seriesOptions.groupZPadding || 1);
-
each(series.data, function(point) {
if (point.y !== null) {
var shapeArgs = point.shapeArgs,
- tooltipPos = point.tooltipPos;
+ 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 shape arguments are inside plotArea.
+ each(dimensions, function(d) {
+ borderlessBase = shapeArgs[d[0]] - borderCrisp;
+ if (
+ borderlessBase + shapeArgs[d[1]] < 0 || // End column position is smaller than axis start.
+ borderlessBase > series[d[0] + 'Axis'].len // Start column position is bigger than axis end.
+ ) {
+ for (var key in shapeArgs) { // Set args to 0 if column is outside the chart.
+ shapeArgs[key] = 0;
+ }
+ }
+ if (borderlessBase < 0) {
+ shapeArgs[d[1]] += shapeArgs[d[0]];
+ shapeArgs[d[0]] = 0;
+ }
+ if (borderlessBase + shapeArgs[d[1]] > series[d[0] + 'Axis'].len) {
+ shapeArgs[d[1]] = series[d[0] + 'Axis'].len - shapeArgs[d[0]];
+ }
+ });
+
point.shapeType = 'cuboid';
shapeArgs.z = z;
shapeArgs.depth = depth;
shapeArgs.insidePlotArea = true;
@@ -1635,10 +1712,48 @@
}
}
}
});
+ /*
+ * 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]) {
+ this[prop] = parent;
+ parent.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()) {
+ each(series.data, function(point) {
+ point.visible = point.options.visible = vis = vis === undefined ? !point.visible : vis;
+ pointVis = vis ? 'visible' : 'hidden';
+ series.options.data[inArray(point, series.data)] = point.options;
+ if (point.graphic) {
+ point.graphic.attr({
+ visibility: pointVis
+ });
+ }
+ });
+ }
+ proceed.apply(this, Array.prototype.slice.call(arguments, 1));
+ });
+
wrap(seriesTypes.column.prototype, 'init', function(proceed) {
proceed.apply(this, [].slice.call(arguments, 1));
if (this.chart.is3d()) {
var seriesOptions = this.options,
@@ -1682,28 +1797,15 @@
}
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;
}
- function draw3DPoints(proceed) {
- // Do not do this if the chart is not 3D
- if (this.chart.is3d()) {
- var grouping = this.chart.options.plotOptions.column.grouping;
- if (grouping !== undefined && !grouping && this.group.zIndex !== undefined && !this.zIndexSet) {
- this.group.attr({
- zIndex: this.group.zIndex * 10
- });
- this.zIndexSet = true; // #4062 set zindex only once
- }
- }
-
- proceed.apply(this, [].slice.call(arguments, 1));
- }
-
wrap(Series.prototype, 'alignDataLabel', function(proceed) {
// Only do this for 3D columns and columnranges
if (this.chart.is3d() && (this.type === 'column' || this.type === 'columnrange')) {
var series = this,
@@ -1722,15 +1824,9 @@
alignTo.y = pos.y;
}
proceed.apply(this, [].slice.call(arguments, 1));
});
-
- if (seriesTypes.columnrange) {
- wrap(seriesTypes.columnrange.prototype, 'drawPoints', draw3DPoints);
- }
-
- wrap(seriesTypes.column.prototype, 'drawPoints', draw3DPoints);
/***
EXTENSION FOR 3D CYLINDRICAL COLUMNS
Not supported
***/