app/assets/javascripts/highcharts/modules/drilldown.js in highcharts-rails-4.0.4.1 vs app/assets/javascripts/highcharts/modules/drilldown.js in highcharts-rails-4.1.0
- old
+ new
@@ -5,11 +5,11 @@
* License: MIT License
*
* Demo: http://jsfiddle.net/highcharts/Vf3yT/
*/
-/*global HighchartsAdapter*/
+/*global Highcharts,HighchartsAdapter*/
(function (H) {
"use strict";
var noop = function () {},
@@ -23,22 +23,43 @@
seriesTypes = H.seriesTypes,
PieSeries = seriesTypes.pie,
ColumnSeries = seriesTypes.column,
fireEvent = HighchartsAdapter.fireEvent,
inArray = HighchartsAdapter.inArray,
- dupes = [];
+ dupes = [],
+ ddSeriesId = 1;
// Utilities
- function tweenColors(startColor, endColor, pos) {
- var rgba = [
- Math.round(startColor[0] + (endColor[0] - startColor[0]) * pos),
- Math.round(startColor[1] + (endColor[1] - startColor[1]) * pos),
- Math.round(startColor[2] + (endColor[2] - startColor[2]) * pos),
- startColor[3] + (endColor[3] - startColor[3]) * pos
- ];
- return 'rgba(' + rgba.join(',') + ')';
+ /*
+ * Return an intermediate color between two colors, according to pos where 0
+ * is the from color and 1 is the to color
+ */
+ function tweenColors(from, to, pos) {
+ // Check for has alpha, because rgba colors perform worse due to lack of
+ // support in WebKit.
+ var hasAlpha;
+
+ from = from.rgba;
+ to = to.rgba;
+ hasAlpha = (to[3] !== 1 || from[3] !== 1);
+ if (!to.length || !from.length) {
+ Highcharts.error(23);
+ }
+ return (hasAlpha ? 'rgba(' : 'rgb(') +
+ Math.round(to[0] + (from[0] - to[0]) * (1 - pos)) + ',' +
+ Math.round(to[1] + (from[1] - to[1]) * (1 - pos)) + ',' +
+ Math.round(to[2] + (from[2] - to[2]) * (1 - pos)) +
+ (hasAlpha ? (',' + (to[3] + (from[3] - to[3]) * (1 - pos))) : '') + ')';
}
+ /**
+ * Handle animation of the color attributes directly
+ */
+ each(['fill', 'stroke'], function (prop) {
+ HighchartsAdapter.addAnimSetter(prop, function (fx) {
+ fx.elem.attr(prop, tweenColors(H.Color(fx.start), H.Color(fx.end), fx.pos));
+ });
+ });
// Add language
extend(defaultOptions.lang, {
drillUpText: '◁ Back to {series.name}'
});
@@ -99,34 +120,37 @@
levelSeries = [],
levelSeriesOptions = [],
level,
levelNumber;
- levelNumber = oldSeries.levelNumber || 0;
+ levelNumber = oldSeries.options._levelNumber || 0;
ddOptions = extend({
- color: color
+ color: color,
+ _ddSeriesId: ddSeriesId++
}, ddOptions);
pointIndex = inArray(point, oldSeries.points);
// Record options for all current series
each(oldSeries.chart.series, function (series) {
if (series.xAxis === xAxis) {
levelSeries.push(series);
- levelSeriesOptions.push(series.userOptions);
- series.levelNumber = series.levelNumber || levelNumber; // #3182
+ series.options._ddSeriesId = series.options._ddSeriesId || ddSeriesId++;
+ series.options._colorIndex = series.userOptions._colorIndex;
+ levelSeriesOptions.push(series.options);
+ series.options._levelNumber = series.options._levelNumber || levelNumber; // #3182
}
});
// Add a record of properties for each drilldown level
level = {
levelNumber: levelNumber,
- seriesOptions: oldSeries.userOptions,
+ seriesOptions: oldSeries.options,
levelSeriesOptions: levelSeriesOptions,
levelSeries: levelSeries,
shapeArgs: point.shapeArgs,
- bBox: point.graphic.getBBox(),
+ bBox: point.graphic ? point.graphic.getBBox() : {}, // no graphic in line series with markers disabled
color: color,
lowerSeriesOptions: ddOptions,
pointOptions: oldSeries.options.data[pointIndex],
pointIndex: pointIndex,
oldExtremes: {
@@ -142,11 +166,11 @@
this.drilldownLevels = [];
}
this.drilldownLevels.push(level);
newSeries = level.lowerSeries = this.addSeries(ddOptions, false);
- newSeries.levelNumber = levelNumber + 1;
+ newSeries.options._levelNumber = levelNumber + 1;
if (xAxis) {
xAxis.oldPos = xAxis.pos;
xAxis.userMin = xAxis.userMax = null;
yAxis.userMin = yAxis.userMax = null;
}
@@ -165,11 +189,11 @@
if (drilldownLevels && drilldownLevels.length > 0) { // #3352, async loading
levelToRemove = drilldownLevels[drilldownLevels.length - 1].levelNumber;
each(this.drilldownLevels, function (level) {
if (level.levelNumber === levelToRemove) {
each(level.levelSeries, function (series) {
- if (series.levelNumber === levelToRemove) { // Not removed, not added as part of a multi-series drilldown
+ if (series.options && series.options._levelNumber === levelToRemove) { // Not removed, not added as part of a multi-series drilldown
series.remove(false);
}
});
}
});
@@ -231,19 +255,19 @@
var chart = this,
drilldownLevels = chart.drilldownLevels,
levelNumber = drilldownLevels[drilldownLevels.length - 1].levelNumber,
i = drilldownLevels.length,
chartSeries = chart.series,
- seriesI = chartSeries.length,
+ seriesI,
level,
oldSeries,
newSeries,
oldExtremes,
addSeries = function (seriesOptions) {
var addedSeries;
each(chartSeries, function (series) {
- if (series.userOptions === seriesOptions) {
+ if (series.options._ddSeriesId === seriesOptions._ddSeriesId) {
addedSeries = series;
}
});
addedSeries = addedSeries || chart.addSeries(seriesOptions, false);
@@ -252,20 +276,21 @@
}
if (seriesOptions === level.seriesOptions) {
newSeries = addedSeries;
}
};
-
+
while (i--) {
level = drilldownLevels[i];
if (level.levelNumber === levelNumber) {
drilldownLevels.pop();
// Get the lower series by reference or id
oldSeries = level.lowerSeries;
if (!oldSeries.chart) { // #2786
+ seriesI = chartSeries.length; // #2919
while (seriesI--) {
if (chartSeries[seriesI].options.id === level.lowerSeriesOptions.id) {
oldSeries = chartSeries[seriesI];
break;
}
@@ -279,15 +304,15 @@
if (newSeries.type === oldSeries.type) {
newSeries.drilldownLevel = level;
newSeries.options.animation = chart.options.drilldown.animation;
- if (oldSeries.animateDrillupFrom) {
+ if (oldSeries.animateDrillupFrom && oldSeries.chart) { // #2919
oldSeries.animateDrillupFrom(level);
}
}
- newSeries.levelNumber = levelNumber;
+ newSeries.options._levelNumber = levelNumber;
oldSeries.remove(false);
// Reset the zoom level of the upper series
if (newSeries.xAxis) {
@@ -323,11 +348,13 @@
if (!init) {
var newSeries = this,
level = newSeries.drilldownLevel;
each(this.points, function (point) {
- point.graphic.hide();
+ if (point.graphic) { // #3407
+ point.graphic.hide();
+ }
if (point.dataLabel) {
point.dataLabel.hide();
}
if (point.connector) {
point.connector.hide();
@@ -335,22 +362,26 @@
});
// Do dummy animation on first point to get to complete
setTimeout(function () {
- each(newSeries.points, function (point, i) {
- // Fade in other points
- var verb = i === (level && level.pointIndex) ? 'show' : 'fadeIn',
- inherit = verb === 'show' ? true : undefined;
- point.graphic[verb](inherit);
- if (point.dataLabel) {
- point.dataLabel[verb](inherit);
- }
- if (point.connector) {
- point.connector[verb](inherit);
- }
- });
+ if (newSeries.points) { // May be destroyed in the meantime, #3389
+ each(newSeries.points, function (point, i) {
+ // Fade in other points
+ var verb = i === (level && level.pointIndex) ? 'show' : 'fadeIn',
+ inherit = verb === 'show' ? true : undefined;
+ if (point.graphic) { // #3407
+ point.graphic[verb](inherit);
+ }
+ if (point.dataLabel) {
+ point.dataLabel[verb](inherit);
+ }
+ if (point.connector) {
+ point.connector[verb](inherit);
+ }
+ });
+ }
}, Math.max(this.chart.options.drilldown.animation.duration - 50, 0));
// Reset
this.animate = noop;
}
@@ -358,27 +389,32 @@
};
ColumnSeries.prototype.animateDrilldown = function (init) {
var series = this,
drilldownLevels = this.chart.drilldownLevels,
- animateFrom = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1].shapeArgs,
- animationOptions = this.chart.options.drilldown.animation;
+ animateFrom,
+ animationOptions = this.chart.options.drilldown.animation,
+ xAxis = this.xAxis;
if (!init) {
each(drilldownLevels, function (level) {
- if (series.userOptions === level.lowerSeriesOptions) {
+ if (series.options._ddSeriesId === level.lowerSeriesOptions._ddSeriesId) {
animateFrom = level.shapeArgs;
+ animateFrom.fill = level.color;
}
});
- animateFrom.x += (this.xAxis.oldPos - this.xAxis.pos);
-
+ animateFrom.x += (pick(xAxis.oldPos, xAxis.pos) - xAxis.pos);
+
each(this.points, function (point) {
if (point.graphic) {
point.graphic
.attr(animateFrom)
- .animate(point.shapeArgs, animationOptions);
+ .animate(
+ extend(point.shapeArgs, { fill: point.color }),
+ animationOptions
+ );
}
if (point.dataLabel) {
point.dataLabel.fadeIn(animationOptions);
}
});
@@ -405,12 +441,10 @@
delete this.group;
each(this.points, function (point) {
var graphic = point.graphic,
- startColor = H.Color(point.color).rgba,
- endColor = H.Color(level.color).rgba,
complete = function () {
graphic.destroy();
if (group) {
group = group.destroy();
}
@@ -419,22 +453,14 @@
if (graphic) {
delete point.graphic;
if (animationOptions) {
- /*jslint unparam: true*/
- graphic.animate(level.shapeArgs, H.merge(animationOptions, {
- step: function (val, fx) {
- if (fx.prop === 'start' && startColor.length === 4 && endColor.length === 4) {
- this.attr({
- fill: tweenColors(startColor, endColor, fx.pos)
- });
- }
- },
- complete: complete
- }));
- /*jslint unparam: false*/
+ graphic.animate(
+ extend(level.shapeArgs, { fill: level.color }),
+ H.merge(animationOptions, { complete: complete })
+ );
} else {
graphic.attr(level.shapeArgs);
complete();
}
}
@@ -451,40 +477,31 @@
var level = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1],
animationOptions = this.chart.options.drilldown.animation,
animateFrom = level.shapeArgs,
start = animateFrom.start,
angle = animateFrom.end - start,
- startAngle = angle / this.points.length,
- startColor = H.Color(level.color).rgba;
+ startAngle = angle / this.points.length;
if (!init) {
each(this.points, function (point, i) {
- var endColor = H.Color(point.color).rgba;
-
- /*jslint unparam: true*/
point.graphic
.attr(H.merge(animateFrom, {
start: start + i * startAngle,
- end: start + (i + 1) * startAngle
- }))[animationOptions ? 'animate' : 'attr'](point.shapeArgs, H.merge(animationOptions, {
- step: function (val, fx) {
- if (fx.prop === 'start' && startColor.length === 4 && endColor.length === 4) {
- this.attr({
- fill: tweenColors(startColor, endColor, fx.pos)
- });
- }
- }
- }));
- /*jslint unparam: false*/
+ end: start + (i + 1) * startAngle,
+ fill: level.color
+ }))[animationOptions ? 'animate' : 'attr'](
+ extend(point.shapeArgs, { fill: point.color }),
+ animationOptions
+ );
});
this.animate = null;
}
}
});
}
- H.Point.prototype.doDrilldown = function (_holdRedraw) {
+ H.Point.prototype.doDrilldown = function (_holdRedraw, category) {
var series = this.series,
chart = series.chart,
drilldown = chart.options.drilldown,
i = (drilldown.series || []).length,
seriesOptions;
@@ -498,21 +515,33 @@
// Fire the event. If seriesOptions is undefined, the implementer can check for
// seriesOptions, and call addSeriesAsDrilldown async if necessary.
fireEvent(chart, 'drilldown', {
point: this,
- seriesOptions: seriesOptions
+ seriesOptions: seriesOptions,
+ category: category
});
if (seriesOptions) {
if (_holdRedraw) {
chart.addSingleSeriesAsDrilldown(this, seriesOptions);
} else {
chart.addSeriesAsDrilldown(this, seriesOptions);
}
}
+ };
+ /**
+ * Drill down to a given category. This is the same as clicking on an axis label.
+ */
+ H.Axis.prototype.drilldownCategory = function (x) {
+ each(this.ticks[x].label.ddPoints, function (point) {
+ if (point.series && point.series.visible && point.doDrilldown) { // #3197
+ point.doDrilldown(true, x);
+ }
+ });
+ this.chart.applyDrilldown();
};
wrap(H.Point.prototype, 'init', function (proceed, series, options, x) {
var point = proceed.call(this, series, options, x),
chart = series.chart,
@@ -541,15 +570,10 @@
}
tickLabel
.addClass('highcharts-drilldown-axis-label')
.css(chart.options.drilldown.activeAxisLabelStyle)
.on('click', function () {
- each(tickLabel.ddPoints, function (point) {
- if (point.doDrilldown) {
- point.doDrilldown(true);
- }
- });
- chart.applyDrilldown();
+ series.xAxis.drilldownCategory(x);
});
if (!tickLabel.ddPoints) {
tickLabel.ddPoints = [];
}
tickLabel.ddPoints.push(point);