app/assets/javascripts/highcharts/modules/drilldown.js in highcharts-rails-3.0.9 vs app/assets/javascripts/highcharts/modules/drilldown.js in highcharts-rails-3.0.10

- old
+ new

@@ -14,10 +14,11 @@ var noop = function () {}, defaultOptions = H.getOptions(), each = H.each, extend = H.extend, + format = H.format, wrap = H.wrap, Chart = H.Chart, seriesTypes = H.seriesTypes, PieSeries = seriesTypes.pie, ColumnSeries = seriesTypes.column, @@ -71,55 +72,79 @@ */ H.SVGRenderer.prototype.Element.prototype.fadeIn = function (animation) { this .attr({ opacity: 0.1, - visibility: 'visible' + visibility: 'inherit' }) .animate({ opacity: 1 }, animation || { duration: 250 }); }; - // Extend the Chart prototype - Chart.prototype.drilldownLevels = []; - Chart.prototype.addSeriesAsDrilldown = function (point, ddOptions) { + this.addSingleSeriesAsDrilldown(point, ddOptions); + this.applyDrilldown(); + }; + Chart.prototype.addSingleSeriesAsDrilldown = function (point, ddOptions) { var oldSeries = point.series, xAxis = oldSeries.xAxis, yAxis = oldSeries.yAxis, newSeries, color = point.color || oldSeries.color, pointIndex, - level; + levelSeries = [], + levelSeriesOptions = [], + level, + levelNumber; + + levelNumber = oldSeries.levelNumber || 0; ddOptions = extend({ color: color }, ddOptions); pointIndex = inArray(point, oldSeries.points); + + // Record options for all current series + each(oldSeries.chart.series, function (series) { + if (series.xAxis === xAxis && series.yAxis === yAxis) { + levelSeries.push(series); + levelSeriesOptions.push(series.userOptions); + series.levelNumber = series.levelNumber || 0; + } + }); + // Add a record of properties for each drilldown level level = { + levelNumber: levelNumber, seriesOptions: oldSeries.userOptions, + levelSeriesOptions: levelSeriesOptions, + levelSeries: levelSeries, shapeArgs: point.shapeArgs, bBox: point.graphic.getBBox(), color: color, - newSeries: ddOptions, + lowerSeriesOptions: ddOptions, pointOptions: oldSeries.options.data[pointIndex], pointIndex: pointIndex, oldExtremes: { xMin: xAxis && xAxis.userMin, xMax: xAxis && xAxis.userMax, yMin: yAxis && yAxis.userMin, yMax: yAxis && yAxis.userMax } }; + // Generate and push it to a lookup array + if (!this.drilldownLevels) { + this.drilldownLevels = []; + } this.drilldownLevels.push(level); - newSeries = this.addSeries(ddOptions, false); + newSeries = level.lowerSeries = this.addSeries(ddOptions, false); + newSeries.levelNumber = levelNumber + 1; if (xAxis) { xAxis.oldPos = xAxis.pos; xAxis.userMin = xAxis.userMax = null; yAxis.userMin = yAxis.userMax = null; } @@ -127,22 +152,35 @@ // Run fancy cross-animation on supported and equal types if (oldSeries.type === newSeries.type) { newSeries.animate = newSeries.animateDrilldown || noop; newSeries.options.animation = true; } + }; + + Chart.prototype.applyDrilldown = function () { + var drilldownLevels = this.drilldownLevels, + levelToRemove = drilldownLevels[drilldownLevels.length - 1].levelNumber; - oldSeries.remove(false); + 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 + series.remove(false); + } + }); + } + }); this.redraw(); this.showDrillUpButton(); }; Chart.prototype.getDrilldownBackText = function () { var lastLevel = this.drilldownLevels[this.drilldownLevels.length - 1]; + lastLevel.series = lastLevel.seriesOptions; + return format(this.options.lang.drillUpText, lastLevel); - return this.options.lang.drillUpText.replace('{series.name}', lastLevel.seriesOptions.name); - }; Chart.prototype.showDrillUpButton = function () { var chart = this, backText = this.getDrilldownBackText(), @@ -180,36 +218,66 @@ } }; Chart.prototype.drillUp = function () { var chart = this, - level = chart.drilldownLevels.pop(), - oldSeries = chart.series[0], - oldExtremes = level.oldExtremes, - newSeries = chart.addSeries(level.seriesOptions, false); + drilldownLevels = chart.drilldownLevels, + levelNumber = drilldownLevels[drilldownLevels.length - 1].levelNumber, + i = drilldownLevels.length, + level, + oldSeries, + newSeries, + oldExtremes, + addSeries = function (seriesOptions) { + var addedSeries; + each(chart.series, function (series) { + if (series.userOptions === seriesOptions) { + addedSeries = series; + } + }); + + addedSeries = addedSeries || chart.addSeries(seriesOptions, false); + if (addedSeries.type === oldSeries.type && addedSeries.animateDrillupTo) { + addedSeries.animate = addedSeries.animateDrillupTo; + } + if (seriesOptions === level.seriesOptions) { + newSeries = addedSeries; + } + }; - fireEvent(chart, 'drillup', { seriesOptions: level.seriesOptions }); + while (i--) { - if (newSeries.type === oldSeries.type) { - newSeries.drilldownLevel = level; - newSeries.animate = newSeries.animateDrillupTo || noop; - newSeries.options.animation = true; + level = drilldownLevels[i]; + if (level.levelNumber === levelNumber) { + drilldownLevels.pop(); + + oldSeries = level.lowerSeries; - if (oldSeries.animateDrillupFrom) { - oldSeries.animateDrillupFrom(level); - } - } + each(level.levelSeriesOptions, addSeries); + + fireEvent(chart, 'drillup', { seriesOptions: level.seriesOptions }); - oldSeries.remove(false); + if (newSeries.type === oldSeries.type) { + newSeries.drilldownLevel = level; + newSeries.options.animation = true; - // Reset the zoom level of the upper series - if (newSeries.xAxis) { - newSeries.xAxis.setExtremes(oldExtremes.xMin, oldExtremes.xMax, false); - newSeries.yAxis.setExtremes(oldExtremes.yMin, oldExtremes.yMax, false); + if (oldSeries.animateDrillupFrom) { + oldSeries.animateDrillupFrom(level); + } + } + + oldSeries.remove(false); + + // Reset the zoom level of the upper series + if (newSeries.xAxis) { + oldExtremes = level.oldExtremes; + newSeries.xAxis.setExtremes(oldExtremes.xMin, oldExtremes.xMax, false); + newSeries.yAxis.setExtremes(oldExtremes.yMin, oldExtremes.yMax, false); + } + } } - this.redraw(); if (this.drilldownLevels.length === 0) { this.drillUpButton = this.drillUpButton.destroy(); } else { @@ -218,50 +286,18 @@ }) .align(); } }; - PieSeries.prototype.animateDrilldown = function (init) { - 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; - 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 - })) - .animate(point.shapeArgs, H.merge(animationOptions, { - step: function (val, fx) { - if (fx.prop === 'start') { - this.attr({ - fill: tweenColors(startColor, endColor, fx.pos) - }); - } - } - })); - /*jslint unparam: false*/ - }); - } - }; - - + ColumnSeries.prototype.supportsDrilldown = true; + /** * When drilling up, keep the upper series invisible until the lower series has * moved into place */ - PieSeries.prototype.animateDrillupTo = - ColumnSeries.prototype.animateDrillupTo = function (init) { + ColumnSeries.prototype.animateDrillupTo = function (init) { if (!init) { var newSeries = this, level = newSeries.drilldownLevel; each(this.points, function (point) { @@ -277,17 +313,18 @@ // 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.pointIndex ? 'show' : 'fadeIn'; - point.graphic[verb](); + var verb = i === (level && level.pointIndex) ? 'show' : 'fadeIn', + inherit = verb === 'show' ? true : undefined; + point.graphic[verb](inherit); if (point.dataLabel) { - point.dataLabel[verb](); + point.dataLabel[verb](inherit); } if (point.connector) { - point.connector[verb](); + point.connector[verb](inherit); } }); }, Math.max(this.chart.options.drilldown.animation.duration - 50, 0)); // Reset @@ -295,68 +332,121 @@ } }; ColumnSeries.prototype.animateDrilldown = function (init) { - var animateFrom = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1].shapeArgs, + var series = this, + drilldownLevels = this.chart.drilldownLevels, + animateFrom = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1].shapeArgs, animationOptions = this.chart.options.drilldown.animation; if (!init) { + each(drilldownLevels, function (level) { + if (series.userOptions === level.lowerSeriesOptions) { + animateFrom = level.shapeArgs; + } + }); animateFrom.x += (this.xAxis.oldPos - this.xAxis.pos); each(this.points, function (point) { - point.graphic - .attr(animateFrom) - .animate(point.shapeArgs, animationOptions); + if (point.graphic) { + point.graphic + .attr(animateFrom) + .animate(point.shapeArgs, animationOptions); + } if (point.dataLabel) { point.dataLabel.fadeIn(animationOptions); } }); + this.animate = null; } }; /** * When drilling up, pull out the individual point graphics from the lower series * and animate them into the origin point in the upper series. */ - ColumnSeries.prototype.animateDrillupFrom = - PieSeries.prototype.animateDrillupFrom = - function (level) { + ColumnSeries.prototype.animateDrillupFrom = function (level) { var animationOptions = this.chart.options.drilldown.animation, group = this.group; delete this.group; each(this.points, function (point) { var graphic = point.graphic, startColor = H.Color(point.color).rgba; - delete point.graphic; + if (graphic) { + + delete point.graphic; - /*jslint unparam: true*/ - graphic.animate(level.shapeArgs, H.merge(animationOptions, { + /*jslint unparam: true*/ + graphic.animate(level.shapeArgs, H.merge(animationOptions, { - step: function (val, fx) { - if (fx.prop === 'start') { - this.attr({ - fill: tweenColors(startColor, H.Color(level.color).rgba, fx.pos) - }); + step: function (val, fx) { + if (fx.prop === 'start') { + this.attr({ + fill: tweenColors(startColor, H.Color(level.color).rgba, fx.pos) + }); + } + }, + complete: function () { + graphic.destroy(); + if (group) { + group = group.destroy(); + } } - }, - complete: function () { - graphic.destroy(); - if (group) { - group = group.destroy(); - } - } - })); - /*jslint unparam: false*/ + })); + /*jslint unparam: false*/ + } }); }; + + if (PieSeries) { + extend(PieSeries.prototype, { + supportsDrilldown: true, + animateDrillupTo: ColumnSeries.prototype.animateDrillupTo, + animateDrillupFrom: ColumnSeries.prototype.animateDrillupFrom, + + animateDrilldown: function (init) { + 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; + + 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 + })) + .animate(point.shapeArgs, H.merge(animationOptions, { + step: function (val, fx) { + if (fx.prop === 'start') { + this.attr({ + fill: tweenColors(startColor, endColor, fx.pos) + }); + } + } + })); + /*jslint unparam: false*/ + }); + this.animate = null; + } + } + }); + } - H.Point.prototype.doDrilldown = function () { + H.Point.prototype.doDrilldown = function (_holdRedraw) { var series = this.series, chart = series.chart, drilldown = chart.options.drilldown, i = (drilldown.series || []).length, seriesOptions; @@ -373,11 +463,15 @@ point: this, seriesOptions: seriesOptions }); if (seriesOptions) { - chart.addSeriesAsDrilldown(this, seriesOptions); + if (_holdRedraw) { + chart.addSingleSeriesAsDrilldown(this, seriesOptions); + } else { + chart.addSeriesAsDrilldown(this, seriesOptions); + } } }; wrap(H.Point.prototype, 'init', function (proceed, series, options, x) { @@ -400,14 +494,21 @@ } tickLabel .addClass('highcharts-drilldown-axis-label') .css(chart.options.drilldown.activeAxisLabelStyle) .on('click', function () { - if (point.doDrilldown) { - point.doDrilldown(); - } + each(tickLabel.ddPoints, function (point) { + if (point.doDrilldown) { + point.doDrilldown(true); + } + }); + chart.applyDrilldown(); }); + if (!tickLabel.ddPoints) { + tickLabel.ddPoints = []; + } + tickLabel.ddPoints.push(point); } } else if (tickLabel && tickLabel._basicStyle) { tickLabel.element.setAttribute('style', tickLabel._basicStyle); } @@ -433,11 +534,9 @@ } }); }); // Mark the trackers with a pointer - ColumnSeries.prototype.supportsDrilldown = true; - PieSeries.prototype.supportsDrilldown = true; var type, drawTrackerWrapper = function (proceed) { proceed.call(this); each(this.points, function (point) { if (point.drilldown && point.graphic) {