highcharts-rails 3.0.9 → 3.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v3.0.9 (2014-01-15)
2
+ * @license Highcharts JS v3.0.10 (2014-03-10)
3
3
  * MooTools adapter
4
4
  *
5
5
  * (c) 2010-2014 Torstein Honsi
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v3.0.9 (2014-01-15)
2
+ * @license Highcharts JS v3.0.10 (2014-03-10)
3
3
  * Prototype adapter
4
4
  *
5
5
  * @author Michael Nelson, Torstein Honsi.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v3.0.9 (2014-01-15)
2
+ * @license Highcharts JS v3.0.10 (2014-03-10)
3
3
  *
4
4
  * Standalone Highcharts Framework
5
5
  *
@@ -304,7 +304,7 @@ return {
304
304
  // HTML styles
305
305
  } else {
306
306
  styles = {};
307
- styles[elem] = this.now + this.unit;
307
+ styles[this.prop] = this.now + this.unit;
308
308
  Highcharts.css(elem, styles);
309
309
  }
310
310
 
@@ -350,9 +350,10 @@ return {
350
350
  ret,
351
351
  done,
352
352
  options = this.options,
353
+ elem = this.elem,
353
354
  i;
354
-
355
- if (this.elem.stopAnimation) {
355
+
356
+ if (elem.stopAnimation || (elem.attr && !elem.element)) { // #2616, element including flag is destroyed
356
357
  ret = false;
357
358
 
358
359
  } else if (gotoEnd || t >= options.duration + this.startTime) {
@@ -371,7 +372,7 @@ return {
371
372
 
372
373
  if (done) {
373
374
  if (options.complete) {
374
- options.complete.call(this.elem);
375
+ options.complete.call(elem);
375
376
  }
376
377
  }
377
378
  ret = false;
@@ -504,19 +505,16 @@ return {
504
505
  return results;
505
506
  },
506
507
 
508
+ /**
509
+ * Get the element's offset position, corrected by overflow:auto. Loosely based on jQuery's offset method.
510
+ */
507
511
  offset: function (el) {
508
- var left = 0,
509
- top = 0;
510
-
511
- while (el) {
512
- left += el.offsetLeft;
513
- top += el.offsetTop;
514
- el = el.offsetParent;
515
- }
512
+ var docElem = document.documentElement,
513
+ box = el.getBoundingClientRect();
516
514
 
517
515
  return {
518
- left: left,
519
- top: top
516
+ top: box.top + (window.pageYOffset || docElem.scrollTop) - (docElem.clientTop || 0),
517
+ left: box.left + (window.pageXOffset || docElem.scrollLeft) - (docElem.clientLeft || 0)
520
518
  };
521
519
  },
522
520
 
@@ -2,7 +2,7 @@
2
2
  // @compilation_level SIMPLE_OPTIMIZATIONS
3
3
 
4
4
  /**
5
- * @license Highcharts JS v3.0.9 (2014-01-15)
5
+ * @license Highcharts JS v3.0.10 (2014-03-10)
6
6
  *
7
7
  * (c) 2009-2014 Torstein Honsi
8
8
  *
@@ -155,7 +155,6 @@ var radialAxisMixin = {
155
155
  minorTickLength: 10,
156
156
  minorTickPosition: 'inside',
157
157
  minorTickWidth: 1,
158
- plotBands: [],
159
158
  tickLength: 10,
160
159
  tickPosition: 'inside',
161
160
  tickWidth: 2,
@@ -176,7 +175,6 @@ var radialAxisMixin = {
176
175
  },
177
176
  maxPadding: 0,
178
177
  minPadding: 0,
179
- plotBands: [],
180
178
  showLastLabel: false,
181
179
  tickLength: 0
182
180
  },
@@ -189,7 +187,6 @@ var radialAxisMixin = {
189
187
  x: -3,
190
188
  y: -2
191
189
  },
192
- plotBands: [],
193
190
  showLastLabel: false,
194
191
  title: {
195
192
  x: 4,
@@ -203,11 +200,16 @@ var radialAxisMixin = {
203
200
  */
204
201
  setOptions: function (userOptions) {
205
202
 
206
- this.options = merge(
203
+ var options = this.options = merge(
207
204
  this.defaultOptions,
208
205
  this.defaultRadialOptions,
209
206
  userOptions
210
207
  );
208
+
209
+ // Make sure the plotBands array is instanciated for each Axis (#2649)
210
+ if (!options.plotBands) {
211
+ options.plotBands = [];
212
+ }
211
213
 
212
214
  },
213
215
 
@@ -272,8 +274,7 @@ var radialAxisMixin = {
272
274
  }
273
275
 
274
276
  if (this.isXAxis) {
275
- this.minPixelPadding = this.transA * this.minPointOffset +
276
- (this.reversed ? (this.endAngleRad - this.startAngleRad) / 4 : 0); // ???
277
+ this.minPixelPadding = this.transA * this.minPointOffset;
277
278
  } else {
278
279
  // This is a workaround for regression #2593, but categories still don't position correctly.
279
280
  // TODO: Implement true handling of Y axis categories on gauges.
@@ -304,10 +305,16 @@ var radialAxisMixin = {
304
305
 
305
306
  // Set the center array
306
307
  this.center = this.pane.center = Highcharts.CenteredSeriesMixin.getCenter.call(this.pane);
308
+
309
+ // The sector is used in Axis.translate to compute the translation of reversed axis points (#2570)
310
+ if (this.isCircular) {
311
+ this.sector = this.endAngleRad - this.startAngleRad;
312
+ }
307
313
 
308
- this.len = this.width = this.height = this.isCircular ?
309
- this.center[2] * (this.endAngleRad - this.startAngleRad) / 2 :
310
- this.center[2] / 2;
314
+ // Axis len is used to lay out the ticks
315
+ this.len = this.width = this.height = this.center[2] * pick(this.sector, 1) / 2;
316
+
317
+
311
318
  }
312
319
  },
313
320
 
@@ -795,6 +802,7 @@ seriesTypes.arearange = extendClass(seriesTypes.area, {
795
802
 
796
803
  // Set preliminary values
797
804
  point.y = point.high;
805
+ point._plotY = point.plotY;
798
806
  point.plotY = point.plotHigh;
799
807
 
800
808
  // Store original data labels and set preliminary label objects to be picked up
@@ -827,7 +835,7 @@ seriesTypes.arearange = extendClass(seriesTypes.area, {
827
835
 
828
836
  // Reset values
829
837
  point.y = point.low;
830
- point.plotY = point.plotLow;
838
+ point.plotY = point._plotY;
831
839
 
832
840
  // Set the default offset
833
841
  point.below = true;
@@ -1020,12 +1028,18 @@ var GaugeSeries = {
1020
1028
  rearLength = (pInt(pick(dialOptions.rearLength, 10)) * radius) / 100,
1021
1029
  baseWidth = dialOptions.baseWidth || 3,
1022
1030
  topWidth = dialOptions.topWidth || 1,
1031
+ overshoot = options.overshoot,
1023
1032
  rotation = yAxis.startAngleRad + yAxis.translate(point.y, null, null, null, true);
1024
1033
 
1025
- // Handle the wrap option
1026
- if (options.wrap === false) {
1034
+ // Handle the wrap and overshoot options
1035
+ if (overshoot && typeof overshoot === 'number') {
1036
+ overshoot = overshoot / 180 * Math.PI;
1037
+ rotation = Math.max(yAxis.startAngleRad - overshoot, Math.min(yAxis.endAngleRad + overshoot, rotation));
1038
+
1039
+ } else if (options.wrap === false) {
1027
1040
  rotation = Math.max(yAxis.startAngleRad, Math.min(yAxis.endAngleRad, rotation));
1028
1041
  }
1042
+
1029
1043
  rotation = rotation * 180 / Math.PI;
1030
1044
 
1031
1045
  point.shapeType = 'path';
@@ -1457,6 +1471,7 @@ seriesTypes.errorbar = extendClass(seriesTypes.boxplot, {
1457
1471
  },
1458
1472
  pointValKey: 'high', // defines the top of the tracker
1459
1473
  doQuartiles: false,
1474
+ drawDataLabels: seriesTypes.arearange ? seriesTypes.arearange.prototype.drawDataLabels : noop,
1460
1475
 
1461
1476
  /**
1462
1477
  * Get the width and X offset, either on top of the linked series column
@@ -1947,7 +1962,7 @@ Axis.prototype.beforePadding = function () {
1947
1962
  var seriesOptions = series.options,
1948
1963
  zData;
1949
1964
 
1950
- if (series.bubblePadding && series.visible) {
1965
+ if (series.bubblePadding && (series.visible || !chart.options.chart.ignoreHiddenSeries)) {
1951
1966
 
1952
1967
  // Correction for #1673
1953
1968
  axis.allowZoomOutside = true;
@@ -2040,14 +2055,20 @@ Axis.prototype.beforePadding = function () {
2040
2055
  var xy,
2041
2056
  chart = this.chart,
2042
2057
  plotX = point.plotX,
2043
- plotY = point.plotY;
2058
+ plotY = point.plotY,
2059
+ clientX;
2044
2060
 
2045
2061
  // Save rectangular plotX, plotY for later computation
2046
2062
  point.rectPlotX = plotX;
2047
2063
  point.rectPlotY = plotY;
2048
2064
 
2049
2065
  // Record the angle in degrees for use in tooltip
2050
- point.clientX = ((plotX / Math.PI * 180) + this.xAxis.pane.options.startAngle) % 360;
2066
+ clientX = ((plotX / Math.PI * 180) + this.xAxis.pane.options.startAngle) % 360;
2067
+ if (clientX < 0) { // #2665
2068
+ clientX += 360;
2069
+ }
2070
+ point.clientX = clientX;
2071
+
2051
2072
 
2052
2073
  // Find the polar plotX and plotY
2053
2074
  xy = this.xAxis.postTranslate(point.plotX, this.yAxis.len - plotY);
@@ -2330,7 +2351,6 @@ Axis.prototype.beforePadding = function () {
2330
2351
  tooltipLen: 360 // degrees are the resolution unit of the tooltipPoints array
2331
2352
  });
2332
2353
  }
2333
-
2334
2354
  // Run uber method
2335
2355
  return proceed.call(this, renew);
2336
2356
  });
@@ -2908,7 +2908,7 @@ if (CanvasRenderingContext2D) {
2908
2908
  });
2909
2909
  }
2910
2910
  }/**
2911
- * @license Highcharts JS v3.0.9 (2014-01-15)
2911
+ * @license Highcharts JS v3.0.10 (2014-03-10)
2912
2912
  * CanVGRenderer Extension module
2913
2913
  *
2914
2914
  * (c) 2011-2012 Torstein Honsi, Erik Olsson
@@ -232,9 +232,8 @@
232
232
  startRow = options.startRow || 0,
233
233
  endRow = options.endRow || Number.MAX_VALUE,
234
234
  startColumn = options.startColumn || 0,
235
- endColumn = options.endColumn || Number.MAX_VALUE,
236
- colNo;
237
-
235
+ endColumn = options.endColumn || Number.MAX_VALUE;
236
+
238
237
  if (table) {
239
238
 
240
239
  if (typeof table === 'string') {
@@ -242,16 +241,14 @@
242
241
  }
243
242
 
244
243
  each(table.getElementsByTagName('tr'), function (tr, rowNo) {
245
- colNo = 0;
246
244
  if (rowNo >= startRow && rowNo <= endRow) {
247
- each(tr.childNodes, function (item) {
245
+ each(tr.children, function (item, colNo) {
248
246
  if ((item.tagName === 'TD' || item.tagName === 'TH') && colNo >= startColumn && colNo <= endColumn) {
249
- if (!columns[colNo]) {
250
- columns[colNo] = [];
247
+ if (!columns[colNo - startColumn]) {
248
+ columns[colNo - startColumn] = [];
251
249
  }
252
- columns[colNo][rowNo - startRow] = item.innerHTML;
253
250
 
254
- colNo += 1;
251
+ columns[colNo - startColumn][rowNo - startRow] = item.innerHTML;
255
252
  }
256
253
  });
257
254
  }
@@ -276,53 +273,56 @@
276
273
  gc; // google column
277
274
 
278
275
  if (googleSpreadsheetKey) {
279
- jQuery.getJSON('https://spreadsheets.google.com/feeds/cells/' +
276
+ jQuery.ajax({
277
+ dataType: 'json',
278
+ url: 'https://spreadsheets.google.com/feeds/cells/' +
280
279
  googleSpreadsheetKey + '/' + (options.googleSpreadsheetWorksheet || 'od6') +
281
280
  '/public/values?alt=json-in-script&callback=?',
282
- function (json) {
283
-
284
- // Prepare the data from the spreadsheat
285
- var cells = json.feed.entry,
286
- cell,
287
- cellCount = cells.length,
288
- colCount = 0,
289
- rowCount = 0,
290
- i;
291
-
292
- // First, find the total number of columns and rows that
293
- // are actually filled with data
294
- for (i = 0; i < cellCount; i++) {
295
- cell = cells[i];
296
- colCount = Math.max(colCount, cell.gs$cell.col);
297
- rowCount = Math.max(rowCount, cell.gs$cell.row);
298
- }
299
-
300
- // Set up arrays containing the column data
301
- for (i = 0; i < colCount; i++) {
302
- if (i >= startColumn && i <= endColumn) {
303
- // Create new columns with the length of either end-start or rowCount
304
- columns[i - startColumn] = [];
305
-
306
- // Setting the length to avoid jslint warning
307
- columns[i - startColumn].length = Math.min(rowCount, endRow - startRow);
281
+ error: options.error,
282
+ success: function (json) {
283
+ // Prepare the data from the spreadsheat
284
+ var cells = json.feed.entry,
285
+ cell,
286
+ cellCount = cells.length,
287
+ colCount = 0,
288
+ rowCount = 0,
289
+ i;
290
+
291
+ // First, find the total number of columns and rows that
292
+ // are actually filled with data
293
+ for (i = 0; i < cellCount; i++) {
294
+ cell = cells[i];
295
+ colCount = Math.max(colCount, cell.gs$cell.col);
296
+ rowCount = Math.max(rowCount, cell.gs$cell.row);
308
297
  }
309
- }
310
298
 
311
- // Loop over the cells and assign the value to the right
312
- // place in the column arrays
313
- for (i = 0; i < cellCount; i++) {
314
- cell = cells[i];
315
- gr = cell.gs$cell.row - 1; // rows start at 1
316
- gc = cell.gs$cell.col - 1; // columns start at 1
317
-
318
- // If both row and col falls inside start and end
319
- // set the transposed cell value in the newly created columns
320
- if (gc >= startColumn && gc <= endColumn &&
321
- gr >= startRow && gr <= endRow) {
322
- columns[gc - startColumn][gr - startRow] = cell.content.$t;
299
+ // Set up arrays containing the column data
300
+ for (i = 0; i < colCount; i++) {
301
+ if (i >= startColumn && i <= endColumn) {
302
+ // Create new columns with the length of either end-start or rowCount
303
+ columns[i - startColumn] = [];
304
+
305
+ // Setting the length to avoid jslint warning
306
+ columns[i - startColumn].length = Math.min(rowCount, endRow - startRow);
307
+ }
323
308
  }
309
+
310
+ // Loop over the cells and assign the value to the right
311
+ // place in the column arrays
312
+ for (i = 0; i < cellCount; i++) {
313
+ cell = cells[i];
314
+ gr = cell.gs$cell.row - 1; // rows start at 1
315
+ gc = cell.gs$cell.col - 1; // columns start at 1
316
+
317
+ // If both row and col falls inside start and end
318
+ // set the transposed cell value in the newly created columns
319
+ if (gc >= startColumn && gc <= endColumn &&
320
+ gr >= startRow && gr <= endRow) {
321
+ columns[gc - startColumn][gr - startRow] = cell.content.$t;
322
+ }
323
+ }
324
+ self.dataFound();
324
325
  }
325
- self.dataFound();
326
326
  });
327
327
  }
328
328
  },
@@ -523,22 +523,27 @@
523
523
 
524
524
  // Iterate down the cells of each column and add data to the series
525
525
  data = [];
526
- for (j = 0; j < columns[i].length; j++) {
527
- data[j] = [
528
- firstCol[j],
529
- columns[i][j] !== undefined ? columns[i][j] : null
530
- ];
531
- if (valueCount > 1) {
532
- data[j].push(columns[i + 1][j] !== undefined ? columns[i + 1][j] : null);
533
- }
534
- if (valueCount > 2) {
535
- data[j].push(columns[i + 2][j] !== undefined ? columns[i + 2][j] : null);
536
- }
537
- if (valueCount > 3) {
538
- data[j].push(columns[i + 3][j] !== undefined ? columns[i + 3][j] : null);
539
- }
540
- if (valueCount > 4) {
541
- data[j].push(columns[i + 4][j] !== undefined ? columns[i + 4][j] : null);
526
+
527
+ // Only loop and fill the data series if there are columns available.
528
+ // We need this check to avoid reading outside the array bounds.
529
+ if (i + valueCount <= columns.length) {
530
+ for (j = 0; j < columns[i].length; j++) {
531
+ data[j] = [
532
+ firstCol[j],
533
+ columns[i][j] !== undefined ? columns[i][j] : null
534
+ ];
535
+ if (valueCount > 1) {
536
+ data[j].push(columns[i + 1][j] !== undefined ? columns[i + 1][j] : null);
537
+ }
538
+ if (valueCount > 2) {
539
+ data[j].push(columns[i + 2][j] !== undefined ? columns[i + 2][j] : null);
540
+ }
541
+ if (valueCount > 3) {
542
+ data[j].push(columns[i + 3][j] !== undefined ? columns[i + 3][j] : null);
543
+ }
544
+ if (valueCount > 4) {
545
+ data[j].push(columns[i + 4][j] !== undefined ? columns[i + 4][j] : null);
546
+ }
542
547
  }
543
548
  }
544
549
 
@@ -16,6 +16,7 @@
16
16
  defaultOptions = H.getOptions(),
17
17
  each = H.each,
18
18
  extend = H.extend,
19
+ format = H.format,
19
20
  wrap = H.wrap,
20
21
  Chart = H.Chart,
21
22
  seriesTypes = H.seriesTypes,
@@ -73,7 +74,7 @@
73
74
  this
74
75
  .attr({
75
76
  opacity: 0.1,
76
- visibility: 'visible'
77
+ visibility: 'inherit'
77
78
  })
78
79
  .animate({
79
80
  opacity: 1
@@ -82,29 +83,48 @@
82
83
  });
83
84
  };
84
85
 
85
- // Extend the Chart prototype
86
- Chart.prototype.drilldownLevels = [];
87
-
88
86
  Chart.prototype.addSeriesAsDrilldown = function (point, ddOptions) {
87
+ this.addSingleSeriesAsDrilldown(point, ddOptions);
88
+ this.applyDrilldown();
89
+ };
90
+ Chart.prototype.addSingleSeriesAsDrilldown = function (point, ddOptions) {
89
91
  var oldSeries = point.series,
90
92
  xAxis = oldSeries.xAxis,
91
93
  yAxis = oldSeries.yAxis,
92
94
  newSeries,
93
95
  color = point.color || oldSeries.color,
94
96
  pointIndex,
95
- level;
97
+ levelSeries = [],
98
+ levelSeriesOptions = [],
99
+ level,
100
+ levelNumber;
101
+
102
+ levelNumber = oldSeries.levelNumber || 0;
96
103
 
97
104
  ddOptions = extend({
98
105
  color: color
99
106
  }, ddOptions);
100
107
  pointIndex = inArray(point, oldSeries.points);
108
+
109
+ // Record options for all current series
110
+ each(oldSeries.chart.series, function (series) {
111
+ if (series.xAxis === xAxis && series.yAxis === yAxis) {
112
+ levelSeries.push(series);
113
+ levelSeriesOptions.push(series.userOptions);
114
+ series.levelNumber = series.levelNumber || 0;
115
+ }
116
+ });
101
117
 
118
+ // Add a record of properties for each drilldown level
102
119
  level = {
120
+ levelNumber: levelNumber,
103
121
  seriesOptions: oldSeries.userOptions,
122
+ levelSeriesOptions: levelSeriesOptions,
123
+ levelSeries: levelSeries,
104
124
  shapeArgs: point.shapeArgs,
105
125
  bBox: point.graphic.getBBox(),
106
126
  color: color,
107
- newSeries: ddOptions,
127
+ lowerSeriesOptions: ddOptions,
108
128
  pointOptions: oldSeries.options.data[pointIndex],
109
129
  pointIndex: pointIndex,
110
130
  oldExtremes: {
@@ -115,9 +135,14 @@
115
135
  }
116
136
  };
117
137
 
138
+ // Generate and push it to a lookup array
139
+ if (!this.drilldownLevels) {
140
+ this.drilldownLevels = [];
141
+ }
118
142
  this.drilldownLevels.push(level);
119
143
 
120
- newSeries = this.addSeries(ddOptions, false);
144
+ newSeries = level.lowerSeries = this.addSeries(ddOptions, false);
145
+ newSeries.levelNumber = levelNumber + 1;
121
146
  if (xAxis) {
122
147
  xAxis.oldPos = xAxis.pos;
123
148
  xAxis.userMin = xAxis.userMax = null;
@@ -129,8 +154,21 @@
129
154
  newSeries.animate = newSeries.animateDrilldown || noop;
130
155
  newSeries.options.animation = true;
131
156
  }
157
+ };
158
+
159
+ Chart.prototype.applyDrilldown = function () {
160
+ var drilldownLevels = this.drilldownLevels,
161
+ levelToRemove = drilldownLevels[drilldownLevels.length - 1].levelNumber;
132
162
 
133
- oldSeries.remove(false);
163
+ each(this.drilldownLevels, function (level) {
164
+ if (level.levelNumber === levelToRemove) {
165
+ each(level.levelSeries, function (series) {
166
+ if (series.levelNumber === levelToRemove) { // Not removed, not added as part of a multi-series drilldown
167
+ series.remove(false);
168
+ }
169
+ });
170
+ }
171
+ });
134
172
 
135
173
  this.redraw();
136
174
  this.showDrillUpButton();
@@ -138,8 +176,8 @@
138
176
 
139
177
  Chart.prototype.getDrilldownBackText = function () {
140
178
  var lastLevel = this.drilldownLevels[this.drilldownLevels.length - 1];
141
-
142
- return this.options.lang.drillUpText.replace('{series.name}', lastLevel.seriesOptions.name);
179
+ lastLevel.series = lastLevel.seriesOptions;
180
+ return format(this.options.lang.drillUpText, lastLevel);
143
181
 
144
182
  };
145
183
 
@@ -182,32 +220,62 @@
182
220
 
183
221
  Chart.prototype.drillUp = function () {
184
222
  var chart = this,
185
- level = chart.drilldownLevels.pop(),
186
- oldSeries = chart.series[0],
187
- oldExtremes = level.oldExtremes,
188
- newSeries = chart.addSeries(level.seriesOptions, false);
223
+ drilldownLevels = chart.drilldownLevels,
224
+ levelNumber = drilldownLevels[drilldownLevels.length - 1].levelNumber,
225
+ i = drilldownLevels.length,
226
+ level,
227
+ oldSeries,
228
+ newSeries,
229
+ oldExtremes,
230
+ addSeries = function (seriesOptions) {
231
+ var addedSeries;
232
+ each(chart.series, function (series) {
233
+ if (series.userOptions === seriesOptions) {
234
+ addedSeries = series;
235
+ }
236
+ });
237
+
238
+ addedSeries = addedSeries || chart.addSeries(seriesOptions, false);
239
+ if (addedSeries.type === oldSeries.type && addedSeries.animateDrillupTo) {
240
+ addedSeries.animate = addedSeries.animateDrillupTo;
241
+ }
242
+ if (seriesOptions === level.seriesOptions) {
243
+ newSeries = addedSeries;
244
+ }
245
+ };
189
246
 
190
- fireEvent(chart, 'drillup', { seriesOptions: level.seriesOptions });
247
+ while (i--) {
191
248
 
192
- if (newSeries.type === oldSeries.type) {
193
- newSeries.drilldownLevel = level;
194
- newSeries.animate = newSeries.animateDrillupTo || noop;
195
- newSeries.options.animation = true;
249
+ level = drilldownLevels[i];
250
+ if (level.levelNumber === levelNumber) {
251
+ drilldownLevels.pop();
252
+
253
+ oldSeries = level.lowerSeries;
196
254
 
197
- if (oldSeries.animateDrillupFrom) {
198
- oldSeries.animateDrillupFrom(level);
199
- }
200
- }
255
+ each(level.levelSeriesOptions, addSeries);
256
+
257
+ fireEvent(chart, 'drillup', { seriesOptions: level.seriesOptions });
201
258
 
202
- oldSeries.remove(false);
259
+ if (newSeries.type === oldSeries.type) {
260
+ newSeries.drilldownLevel = level;
261
+ newSeries.options.animation = true;
203
262
 
204
- // Reset the zoom level of the upper series
205
- if (newSeries.xAxis) {
206
- newSeries.xAxis.setExtremes(oldExtremes.xMin, oldExtremes.xMax, false);
207
- newSeries.yAxis.setExtremes(oldExtremes.yMin, oldExtremes.yMax, false);
263
+ if (oldSeries.animateDrillupFrom) {
264
+ oldSeries.animateDrillupFrom(level);
265
+ }
266
+ }
267
+
268
+ oldSeries.remove(false);
269
+
270
+ // Reset the zoom level of the upper series
271
+ if (newSeries.xAxis) {
272
+ oldExtremes = level.oldExtremes;
273
+ newSeries.xAxis.setExtremes(oldExtremes.xMin, oldExtremes.xMax, false);
274
+ newSeries.yAxis.setExtremes(oldExtremes.yMin, oldExtremes.yMax, false);
275
+ }
276
+ }
208
277
  }
209
278
 
210
-
211
279
  this.redraw();
212
280
 
213
281
  if (this.drilldownLevels.length === 0) {
@@ -220,46 +288,14 @@
220
288
  }
221
289
  };
222
290
 
223
- PieSeries.prototype.animateDrilldown = function (init) {
224
- var level = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1],
225
- animationOptions = this.chart.options.drilldown.animation,
226
- animateFrom = level.shapeArgs,
227
- start = animateFrom.start,
228
- angle = animateFrom.end - start,
229
- startAngle = angle / this.points.length,
230
- startColor = H.Color(level.color).rgba;
231
-
232
- if (!init) {
233
- each(this.points, function (point, i) {
234
- var endColor = H.Color(point.color).rgba;
235
-
236
- /*jslint unparam: true*/
237
- point.graphic
238
- .attr(H.merge(animateFrom, {
239
- start: start + i * startAngle,
240
- end: start + (i + 1) * startAngle
241
- }))
242
- .animate(point.shapeArgs, H.merge(animationOptions, {
243
- step: function (val, fx) {
244
- if (fx.prop === 'start') {
245
- this.attr({
246
- fill: tweenColors(startColor, endColor, fx.pos)
247
- });
248
- }
249
- }
250
- }));
251
- /*jslint unparam: false*/
252
- });
253
- }
254
- };
255
-
256
291
 
292
+ ColumnSeries.prototype.supportsDrilldown = true;
293
+
257
294
  /**
258
295
  * When drilling up, keep the upper series invisible until the lower series has
259
296
  * moved into place
260
297
  */
261
- PieSeries.prototype.animateDrillupTo =
262
- ColumnSeries.prototype.animateDrillupTo = function (init) {
298
+ ColumnSeries.prototype.animateDrillupTo = function (init) {
263
299
  if (!init) {
264
300
  var newSeries = this,
265
301
  level = newSeries.drilldownLevel;
@@ -279,13 +315,14 @@
279
315
  setTimeout(function () {
280
316
  each(newSeries.points, function (point, i) {
281
317
  // Fade in other points
282
- var verb = i === level.pointIndex ? 'show' : 'fadeIn';
283
- point.graphic[verb]();
318
+ var verb = i === (level && level.pointIndex) ? 'show' : 'fadeIn',
319
+ inherit = verb === 'show' ? true : undefined;
320
+ point.graphic[verb](inherit);
284
321
  if (point.dataLabel) {
285
- point.dataLabel[verb]();
322
+ point.dataLabel[verb](inherit);
286
323
  }
287
324
  if (point.connector) {
288
- point.connector[verb]();
325
+ point.connector[verb](inherit);
289
326
  }
290
327
  });
291
328
  }, Math.max(this.chart.options.drilldown.animation.duration - 50, 0));
@@ -297,21 +334,31 @@
297
334
  };
298
335
 
299
336
  ColumnSeries.prototype.animateDrilldown = function (init) {
300
- var animateFrom = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1].shapeArgs,
337
+ var series = this,
338
+ drilldownLevels = this.chart.drilldownLevels,
339
+ animateFrom = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1].shapeArgs,
301
340
  animationOptions = this.chart.options.drilldown.animation;
302
341
 
303
342
  if (!init) {
343
+ each(drilldownLevels, function (level) {
344
+ if (series.userOptions === level.lowerSeriesOptions) {
345
+ animateFrom = level.shapeArgs;
346
+ }
347
+ });
304
348
 
305
349
  animateFrom.x += (this.xAxis.oldPos - this.xAxis.pos);
306
350
 
307
351
  each(this.points, function (point) {
308
- point.graphic
309
- .attr(animateFrom)
310
- .animate(point.shapeArgs, animationOptions);
352
+ if (point.graphic) {
353
+ point.graphic
354
+ .attr(animateFrom)
355
+ .animate(point.shapeArgs, animationOptions);
356
+ }
311
357
  if (point.dataLabel) {
312
358
  point.dataLabel.fadeIn(animationOptions);
313
359
  }
314
360
  });
361
+ this.animate = null;
315
362
  }
316
363
 
317
364
  };
@@ -320,9 +367,7 @@
320
367
  * When drilling up, pull out the individual point graphics from the lower series
321
368
  * and animate them into the origin point in the upper series.
322
369
  */
323
- ColumnSeries.prototype.animateDrillupFrom =
324
- PieSeries.prototype.animateDrillupFrom =
325
- function (level) {
370
+ ColumnSeries.prototype.animateDrillupFrom = function (level) {
326
371
  var animationOptions = this.chart.options.drilldown.animation,
327
372
  group = this.group;
328
373
 
@@ -331,30 +376,75 @@
331
376
  var graphic = point.graphic,
332
377
  startColor = H.Color(point.color).rgba;
333
378
 
334
- delete point.graphic;
379
+ if (graphic) {
380
+
381
+ delete point.graphic;
335
382
 
336
- /*jslint unparam: true*/
337
- graphic.animate(level.shapeArgs, H.merge(animationOptions, {
383
+ /*jslint unparam: true*/
384
+ graphic.animate(level.shapeArgs, H.merge(animationOptions, {
338
385
 
339
- step: function (val, fx) {
340
- if (fx.prop === 'start') {
341
- this.attr({
342
- fill: tweenColors(startColor, H.Color(level.color).rgba, fx.pos)
343
- });
344
- }
345
- },
346
- complete: function () {
347
- graphic.destroy();
348
- if (group) {
349
- group = group.destroy();
386
+ step: function (val, fx) {
387
+ if (fx.prop === 'start') {
388
+ this.attr({
389
+ fill: tweenColors(startColor, H.Color(level.color).rgba, fx.pos)
390
+ });
391
+ }
392
+ },
393
+ complete: function () {
394
+ graphic.destroy();
395
+ if (group) {
396
+ group = group.destroy();
397
+ }
350
398
  }
351
- }
352
- }));
353
- /*jslint unparam: false*/
399
+ }));
400
+ /*jslint unparam: false*/
401
+ }
354
402
  });
355
403
  };
404
+
405
+ if (PieSeries) {
406
+ extend(PieSeries.prototype, {
407
+ supportsDrilldown: true,
408
+ animateDrillupTo: ColumnSeries.prototype.animateDrillupTo,
409
+ animateDrillupFrom: ColumnSeries.prototype.animateDrillupFrom,
410
+
411
+ animateDrilldown: function (init) {
412
+ var level = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1],
413
+ animationOptions = this.chart.options.drilldown.animation,
414
+ animateFrom = level.shapeArgs,
415
+ start = animateFrom.start,
416
+ angle = animateFrom.end - start,
417
+ startAngle = angle / this.points.length,
418
+ startColor = H.Color(level.color).rgba;
419
+
420
+ if (!init) {
421
+ each(this.points, function (point, i) {
422
+ var endColor = H.Color(point.color).rgba;
423
+
424
+ /*jslint unparam: true*/
425
+ point.graphic
426
+ .attr(H.merge(animateFrom, {
427
+ start: start + i * startAngle,
428
+ end: start + (i + 1) * startAngle
429
+ }))
430
+ .animate(point.shapeArgs, H.merge(animationOptions, {
431
+ step: function (val, fx) {
432
+ if (fx.prop === 'start') {
433
+ this.attr({
434
+ fill: tweenColors(startColor, endColor, fx.pos)
435
+ });
436
+ }
437
+ }
438
+ }));
439
+ /*jslint unparam: false*/
440
+ });
441
+ this.animate = null;
442
+ }
443
+ }
444
+ });
445
+ }
356
446
 
357
- H.Point.prototype.doDrilldown = function () {
447
+ H.Point.prototype.doDrilldown = function (_holdRedraw) {
358
448
  var series = this.series,
359
449
  chart = series.chart,
360
450
  drilldown = chart.options.drilldown,
@@ -375,7 +465,11 @@
375
465
  });
376
466
 
377
467
  if (seriesOptions) {
378
- chart.addSeriesAsDrilldown(this, seriesOptions);
468
+ if (_holdRedraw) {
469
+ chart.addSingleSeriesAsDrilldown(this, seriesOptions);
470
+ } else {
471
+ chart.addSeriesAsDrilldown(this, seriesOptions);
472
+ }
379
473
  }
380
474
 
381
475
  };
@@ -402,10 +496,17 @@
402
496
  .addClass('highcharts-drilldown-axis-label')
403
497
  .css(chart.options.drilldown.activeAxisLabelStyle)
404
498
  .on('click', function () {
405
- if (point.doDrilldown) {
406
- point.doDrilldown();
407
- }
499
+ each(tickLabel.ddPoints, function (point) {
500
+ if (point.doDrilldown) {
501
+ point.doDrilldown(true);
502
+ }
503
+ });
504
+ chart.applyDrilldown();
408
505
  });
506
+ if (!tickLabel.ddPoints) {
507
+ tickLabel.ddPoints = [];
508
+ }
509
+ tickLabel.ddPoints.push(point);
409
510
 
410
511
  }
411
512
  } else if (tickLabel && tickLabel._basicStyle) {
@@ -435,8 +536,6 @@
435
536
  });
436
537
 
437
538
  // Mark the trackers with a pointer
438
- ColumnSeries.prototype.supportsDrilldown = true;
439
- PieSeries.prototype.supportsDrilldown = true;
440
539
  var type,
441
540
  drawTrackerWrapper = function (proceed) {
442
541
  proceed.call(this);