highcharts-rails 4.2.7 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.markdown +34 -0
  3. data/Gemfile +4 -0
  4. data/Rakefile +53 -32
  5. data/app/assets/javascripts/highcharts.js +18775 -17176
  6. data/app/assets/javascripts/highcharts/highcharts-3d.js +1849 -1563
  7. data/app/assets/javascripts/highcharts/highcharts-more.js +2162 -1988
  8. data/app/assets/javascripts/highcharts/modules/accessibility.js +1005 -0
  9. data/app/assets/javascripts/highcharts/modules/annotations.js +408 -401
  10. data/app/assets/javascripts/highcharts/modules/boost.js +561 -546
  11. data/app/assets/javascripts/highcharts/modules/broken-axis.js +330 -324
  12. data/app/assets/javascripts/highcharts/modules/data.js +973 -965
  13. data/app/assets/javascripts/highcharts/modules/drilldown.js +783 -723
  14. data/app/assets/javascripts/highcharts/modules/exporting.js +864 -785
  15. data/app/assets/javascripts/highcharts/modules/funnel.js +290 -306
  16. data/app/assets/javascripts/highcharts/modules/heatmap.js +701 -645
  17. data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +150 -132
  18. data/app/assets/javascripts/highcharts/modules/offline-exporting.js +414 -355
  19. data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +164 -0
  20. data/app/assets/javascripts/highcharts/modules/series-label.js +473 -448
  21. data/app/assets/javascripts/highcharts/modules/solid-gauge.js +279 -271
  22. data/app/assets/javascripts/highcharts/modules/treemap.js +921 -886
  23. data/app/assets/javascripts/highcharts/themes/dark-blue.js +307 -244
  24. data/app/assets/javascripts/highcharts/themes/dark-green.js +303 -244
  25. data/app/assets/javascripts/highcharts/themes/dark-unica.js +231 -201
  26. data/app/assets/javascripts/highcharts/themes/gray.js +314 -245
  27. data/app/assets/javascripts/highcharts/themes/grid-light.js +91 -66
  28. data/app/assets/javascripts/highcharts/themes/grid.js +124 -96
  29. data/app/assets/javascripts/highcharts/themes/sand-signika.js +119 -94
  30. data/app/assets/javascripts/highcharts/themes/skies.js +108 -85
  31. data/lib/highcharts/version.rb +1 -1
  32. metadata +13 -14
  33. data/app/assets/javascripts/highcharts/adapters/standalone-framework.js +0 -1
  34. data/app/assets/javascripts/highcharts/modules/canvas-tools.js +0 -3115
  35. data/app/assets/javascripts/highcharts/modules/map.js +0 -2117
@@ -1,731 +1,791 @@
1
1
  /**
2
+ * @license Highcharts JS v5.0.0 (2016-09-29)
2
3
  * Highcharts Drilldown module
3
4
  *
4
5
  * Author: Torstein Honsi
5
6
  * License: www.highcharts.com/license
6
7
  *
7
8
  */
8
-
9
- (function (factory) {
10
- if (typeof module === 'object' && module.exports) {
11
- module.exports = factory;
12
- } else {
13
- factory(Highcharts);
14
- }
15
- }(function (H) {
16
-
17
- 'use strict';
18
-
19
- var noop = function () {},
20
- defaultOptions = H.getOptions(),
21
- each = H.each,
22
- extend = H.extend,
23
- format = H.format,
24
- merge = H.merge,
25
- pick = H.pick,
26
- wrap = H.wrap,
27
- Chart = H.Chart,
28
- seriesTypes = H.seriesTypes,
29
- PieSeries = seriesTypes.pie,
30
- ColumnSeries = seriesTypes.column,
31
- Tick = H.Tick,
32
- fireEvent = H.fireEvent,
33
- inArray = H.inArray,
34
- ddSeriesId = 1;
35
-
36
- // Utilities
37
- /*
38
- * Return an intermediate color between two colors, according to pos where 0
39
- * is the from color and 1 is the to color. This method is copied from ColorAxis.js
40
- * and should always be kept updated, until we get AMD support.
41
- */
42
- function tweenColors(from, to, pos) {
43
- // Check for has alpha, because rgba colors perform worse due to lack of
44
- // support in WebKit.
45
- var hasAlpha,
46
- ret;
47
-
48
- // Unsupported color, return to-color (#3920)
49
- if (!to.rgba.length || !from.rgba.length) {
50
- ret = to.input || 'none';
51
-
52
- // Interpolate
53
- } else {
54
- from = from.rgba;
55
- to = to.rgba;
56
- hasAlpha = (to[3] !== 1 || from[3] !== 1);
57
- ret = (hasAlpha ? 'rgba(' : 'rgb(') +
58
- Math.round(to[0] + (from[0] - to[0]) * (1 - pos)) + ',' +
59
- Math.round(to[1] + (from[1] - to[1]) * (1 - pos)) + ',' +
60
- Math.round(to[2] + (from[2] - to[2]) * (1 - pos)) +
61
- (hasAlpha ? (',' + (to[3] + (from[3] - to[3]) * (1 - pos))) : '') + ')';
62
- }
63
- return ret;
64
- }
65
- /**
66
- * Handle animation of the color attributes directly
67
- */
68
- each(['fill', 'stroke'], function (prop) {
69
- H.Fx.prototype[prop + 'Setter'] = function () {
70
- this.elem.attr(prop, tweenColors(H.Color(this.start), H.Color(this.end), this.pos));
71
- };
72
- });
73
-
74
- // Add language
75
- extend(defaultOptions.lang, {
76
- drillUpText: ' Back to {series.name}'
77
- });
78
- defaultOptions.drilldown = {
79
- activeAxisLabelStyle: {
80
- cursor: 'pointer',
81
- color: '#0d233a',
82
- fontWeight: 'bold',
83
- textDecoration: 'underline'
84
- },
85
- activeDataLabelStyle: {
86
- cursor: 'pointer',
87
- fontWeight: 'bold',
88
- textDecoration: 'underline'
89
- },
90
- animation: {
91
- duration: 500
92
- },
93
- drillUpButton: {
94
- position: {
95
- align: 'right',
96
- x: -10,
97
- y: 10
98
- }
99
- // relativeTo: 'plotBox'
100
- // theme
101
- }
102
- };
103
-
104
- /**
105
- * A general fadeIn method
106
- */
107
- H.SVGRenderer.prototype.Element.prototype.fadeIn = function (animation) {
108
- this
109
- .attr({
110
- opacity: 0.1,
111
- visibility: 'inherit'
112
- })
113
- .animate({
114
- opacity: pick(this.newOpacity, 1) // newOpacity used in maps
115
- }, animation || {
116
- duration: 250
117
- });
118
- };
119
-
120
- Chart.prototype.addSeriesAsDrilldown = function (point, ddOptions) {
121
- this.addSingleSeriesAsDrilldown(point, ddOptions);
122
- this.applyDrilldown();
123
- };
124
- Chart.prototype.addSingleSeriesAsDrilldown = function (point, ddOptions) {
125
- var oldSeries = point.series,
126
- xAxis = oldSeries.xAxis,
127
- yAxis = oldSeries.yAxis,
128
- newSeries,
129
- color = point.color || oldSeries.color,
130
- pointIndex,
131
- levelSeries = [],
132
- levelSeriesOptions = [],
133
- level,
134
- levelNumber,
135
- last;
136
-
137
- if (!this.drilldownLevels) {
138
- this.drilldownLevels = [];
139
- }
140
-
141
- levelNumber = oldSeries.options._levelNumber || 0;
142
-
143
- // See if we can reuse the registered series from last run
144
- last = this.drilldownLevels[this.drilldownLevels.length - 1];
145
- if (last && last.levelNumber !== levelNumber) {
146
- last = undefined;
147
- }
148
-
149
- if (!ddOptions.color) {
150
- ddOptions.color = color;
151
- }
152
- ddOptions._ddSeriesId = ddSeriesId++;
153
-
154
- pointIndex = inArray(point, oldSeries.points);
155
-
156
- // Record options for all current series
157
- each(oldSeries.chart.series, function (series) {
158
- if (series.xAxis === xAxis && !series.isDrilling) {
159
- series.options._ddSeriesId = series.options._ddSeriesId || ddSeriesId++;
160
- series.options._colorIndex = series.userOptions._colorIndex;
161
- series.options._levelNumber = series.options._levelNumber || levelNumber; // #3182
162
-
163
- if (last) {
164
- levelSeries = last.levelSeries;
165
- levelSeriesOptions = last.levelSeriesOptions;
166
- } else {
167
- levelSeries.push(series);
168
- levelSeriesOptions.push(series.options);
169
- }
170
- }
171
- });
172
-
173
- // Add a record of properties for each drilldown level
174
- level = {
175
- levelNumber: levelNumber,
176
- seriesOptions: oldSeries.options,
177
- levelSeriesOptions: levelSeriesOptions,
178
- levelSeries: levelSeries,
179
- shapeArgs: point.shapeArgs,
180
- bBox: point.graphic ? point.graphic.getBBox() : {}, // no graphic in line series with markers disabled
181
- color: point.isNull ? new Highcharts.Color(color).setOpacity(0).get() : color,
182
- lowerSeriesOptions: ddOptions,
183
- pointOptions: oldSeries.options.data[pointIndex],
184
- pointIndex: pointIndex,
185
- oldExtremes: {
186
- xMin: xAxis && xAxis.userMin,
187
- xMax: xAxis && xAxis.userMax,
188
- yMin: yAxis && yAxis.userMin,
189
- yMax: yAxis && yAxis.userMax
190
- }
191
- };
192
-
193
- // Push it to the lookup array
194
- this.drilldownLevels.push(level);
195
-
196
- newSeries = level.lowerSeries = this.addSeries(ddOptions, false);
197
- newSeries.options._levelNumber = levelNumber + 1;
198
- if (xAxis) {
199
- xAxis.oldPos = xAxis.pos;
200
- xAxis.userMin = xAxis.userMax = null;
201
- yAxis.userMin = yAxis.userMax = null;
202
- }
203
-
204
- // Run fancy cross-animation on supported and equal types
205
- if (oldSeries.type === newSeries.type) {
206
- newSeries.animate = newSeries.animateDrilldown || noop;
207
- newSeries.options.animation = true;
208
- }
209
- };
210
-
211
- Chart.prototype.applyDrilldown = function () {
212
- var drilldownLevels = this.drilldownLevels,
213
- levelToRemove;
214
-
215
- if (drilldownLevels && drilldownLevels.length > 0) { // #3352, async loading
216
- levelToRemove = drilldownLevels[drilldownLevels.length - 1].levelNumber;
217
- each(this.drilldownLevels, function (level) {
218
- if (level.levelNumber === levelToRemove) {
219
- each(level.levelSeries, function (series) {
220
- if (series.options && series.options._levelNumber === levelToRemove) { // Not removed, not added as part of a multi-series drilldown
221
- series.remove(false);
222
- }
223
- });
224
- }
225
- });
226
- }
227
-
228
- this.redraw();
229
- this.showDrillUpButton();
230
- };
231
-
232
- Chart.prototype.getDrilldownBackText = function () {
233
- var drilldownLevels = this.drilldownLevels,
234
- lastLevel;
235
- if (drilldownLevels && drilldownLevels.length > 0) { // #3352, async loading
236
- lastLevel = drilldownLevels[drilldownLevels.length - 1];
237
- lastLevel.series = lastLevel.seriesOptions;
238
- return format(this.options.lang.drillUpText, lastLevel);
239
- }
240
-
241
- };
242
-
243
- Chart.prototype.showDrillUpButton = function () {
244
- var chart = this,
245
- backText = this.getDrilldownBackText(),
246
- buttonOptions = chart.options.drilldown.drillUpButton,
247
- attr,
248
- states;
249
-
250
-
251
- if (!this.drillUpButton) {
252
- attr = buttonOptions.theme;
253
- states = attr && attr.states;
254
-
255
- this.drillUpButton = this.renderer.button(
256
- backText,
257
- null,
258
- null,
259
- function () {
260
- chart.drillUp();
261
- },
262
- attr,
263
- states && states.hover,
264
- states && states.select
265
- )
266
- .attr({
267
- align: buttonOptions.position.align,
268
- zIndex: 9
269
- })
270
- .add()
271
- .align(buttonOptions.position, false, buttonOptions.relativeTo || 'plotBox');
272
- } else {
273
- this.drillUpButton.attr({
274
- text: backText
275
- })
276
- .align();
277
- }
278
- };
279
-
280
- Chart.prototype.drillUp = function () {
281
- var chart = this,
282
- drilldownLevels = chart.drilldownLevels,
283
- levelNumber = drilldownLevels[drilldownLevels.length - 1].levelNumber,
284
- i = drilldownLevels.length,
285
- chartSeries = chart.series,
286
- seriesI,
287
- level,
288
- oldSeries,
289
- newSeries,
290
- oldExtremes,
291
- addSeries = function (seriesOptions) {
292
- var addedSeries;
293
- each(chartSeries, function (series) {
294
- if (series.options._ddSeriesId === seriesOptions._ddSeriesId) {
295
- addedSeries = series;
296
- }
297
- });
298
-
299
- addedSeries = addedSeries || chart.addSeries(seriesOptions, false);
300
- if (addedSeries.type === oldSeries.type && addedSeries.animateDrillupTo) {
301
- addedSeries.animate = addedSeries.animateDrillupTo;
302
- }
303
- if (seriesOptions === level.seriesOptions) {
304
- newSeries = addedSeries;
305
- }
306
- };
307
-
308
- while (i--) {
309
-
310
- level = drilldownLevels[i];
311
- if (level.levelNumber === levelNumber) {
312
- drilldownLevels.pop();
313
-
314
- // Get the lower series by reference or id
315
- oldSeries = level.lowerSeries;
316
- if (!oldSeries.chart) { // #2786
317
- seriesI = chartSeries.length; // #2919
318
- while (seriesI--) {
319
- if (chartSeries[seriesI].options.id === level.lowerSeriesOptions.id &&
320
- chartSeries[seriesI].options._levelNumber === levelNumber + 1) { // #3867
321
- oldSeries = chartSeries[seriesI];
322
- break;
323
- }
324
- }
325
- }
326
- oldSeries.xData = []; // Overcome problems with minRange (#2898)
327
-
328
- each(level.levelSeriesOptions, addSeries);
329
-
330
- fireEvent(chart, 'drillup', { seriesOptions: level.seriesOptions });
331
-
332
- if (newSeries.type === oldSeries.type) {
333
- newSeries.drilldownLevel = level;
334
- newSeries.options.animation = chart.options.drilldown.animation;
335
-
336
- if (oldSeries.animateDrillupFrom && oldSeries.chart) { // #2919
337
- oldSeries.animateDrillupFrom(level);
338
- }
339
- }
340
- newSeries.options._levelNumber = levelNumber;
341
-
342
- oldSeries.remove(false);
343
-
344
- // Reset the zoom level of the upper series
345
- if (newSeries.xAxis) {
346
- oldExtremes = level.oldExtremes;
347
- newSeries.xAxis.setExtremes(oldExtremes.xMin, oldExtremes.xMax, false);
348
- newSeries.yAxis.setExtremes(oldExtremes.yMin, oldExtremes.yMax, false);
349
- }
350
- }
351
- }
352
-
353
- // Fire a once-off event after all series have been drilled up (#5158)
354
- fireEvent(chart, 'drillupall');
355
-
356
- this.redraw();
357
-
358
- if (this.drilldownLevels.length === 0) {
359
- this.drillUpButton = this.drillUpButton.destroy();
360
- } else {
361
- this.drillUpButton.attr({
362
- text: this.getDrilldownBackText()
363
- })
364
- .align();
365
- }
366
-
367
- this.ddDupes.length = []; // #3315
368
- };
369
-
370
-
371
- ColumnSeries.prototype.supportsDrilldown = true;
372
-
373
- /**
374
- * When drilling up, keep the upper series invisible until the lower series has
375
- * moved into place
376
- */
377
- ColumnSeries.prototype.animateDrillupTo = function (init) {
378
- if (!init) {
379
- var newSeries = this,
380
- level = newSeries.drilldownLevel;
381
-
382
- each(this.points, function (point) {
383
- if (point.graphic) { // #3407
384
- point.graphic.hide();
385
- }
386
- if (point.dataLabel) {
387
- point.dataLabel.hide();
388
- }
389
- if (point.connector) {
390
- point.connector.hide();
391
- }
392
- });
393
-
394
-
395
- // Do dummy animation on first point to get to complete
396
- setTimeout(function () {
397
- if (newSeries.points) { // May be destroyed in the meantime, #3389
398
- each(newSeries.points, function (point, i) {
399
- // Fade in other points
400
- var verb = i === (level && level.pointIndex) ? 'show' : 'fadeIn',
401
- inherit = verb === 'show' ? true : undefined;
402
- if (point.graphic) { // #3407
403
- point.graphic[verb](inherit);
404
- }
405
- if (point.dataLabel) {
406
- point.dataLabel[verb](inherit);
407
- }
408
- if (point.connector) {
409
- point.connector[verb](inherit);
410
- }
411
- });
412
- }
413
- }, Math.max(this.chart.options.drilldown.animation.duration - 50, 0));
414
-
415
- // Reset
416
- this.animate = noop;
417
- }
418
-
419
- };
420
-
421
- ColumnSeries.prototype.animateDrilldown = function (init) {
422
- var series = this,
423
- drilldownLevels = this.chart.drilldownLevels,
424
- animateFrom,
425
- animationOptions = this.chart.options.drilldown.animation,
426
- xAxis = this.xAxis;
427
-
428
- if (!init) {
429
- each(drilldownLevels, function (level) {
430
- if (series.options._ddSeriesId === level.lowerSeriesOptions._ddSeriesId) {
431
- animateFrom = level.shapeArgs;
432
- animateFrom.fill = level.color;
433
- }
434
- });
435
-
436
- animateFrom.x += (pick(xAxis.oldPos, xAxis.pos) - xAxis.pos);
437
-
438
- each(this.points, function (point) {
439
- if (point.graphic) {
440
- point.graphic
441
- .attr(animateFrom)
442
- .animate(
443
- extend(point.shapeArgs, { fill: point.color || series.color }),
444
- animationOptions
445
- );
446
- }
447
- if (point.dataLabel) {
448
- point.dataLabel.fadeIn(animationOptions);
449
- }
450
- });
451
- this.animate = null;
452
- }
453
-
454
- };
455
-
456
- /**
457
- * When drilling up, pull out the individual point graphics from the lower series
458
- * and animate them into the origin point in the upper series.
459
- */
460
- ColumnSeries.prototype.animateDrillupFrom = function (level) {
461
- var animationOptions = this.chart.options.drilldown.animation,
462
- group = this.group,
463
- series = this;
464
-
465
- // Cancel mouse events on the series group (#2787)
466
- each(series.trackerGroups, function (key) {
467
- if (series[key]) { // we don't always have dataLabelsGroup
468
- series[key].on('mouseover');
469
- }
470
- });
471
-
472
-
473
- delete this.group;
474
- each(this.points, function (point) {
475
- var graphic = point.graphic,
476
- complete = function () {
477
- graphic.destroy();
478
- if (group) {
479
- group = group.destroy();
480
- }
481
- };
482
-
483
- if (graphic) {
484
-
485
- delete point.graphic;
486
-
487
- if (animationOptions) {
488
- graphic.animate(
489
- extend(level.shapeArgs, { fill: level.color }),
490
- H.merge(animationOptions, { complete: complete })
491
- );
492
- } else {
493
- graphic.attr(level.shapeArgs);
494
- complete();
495
- }
496
- }
497
- });
498
- };
499
-
500
- if (PieSeries) {
501
- extend(PieSeries.prototype, {
502
- supportsDrilldown: true,
503
- animateDrillupTo: ColumnSeries.prototype.animateDrillupTo,
504
- animateDrillupFrom: ColumnSeries.prototype.animateDrillupFrom,
505
-
506
- animateDrilldown: function (init) {
507
- var level = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1],
508
- animationOptions = this.chart.options.drilldown.animation,
509
- animateFrom = level.shapeArgs,
510
- start = animateFrom.start,
511
- angle = animateFrom.end - start,
512
- startAngle = angle / this.points.length;
513
-
514
- if (!init) {
515
- each(this.points, function (point, i) {
516
- if (point.graphic) {
517
- point.graphic
518
- .attr(H.merge(animateFrom, {
519
- start: start + i * startAngle,
520
- end: start + (i + 1) * startAngle,
521
- fill: level.color
522
- }))[animationOptions ? 'animate' : 'attr'](
523
- extend(point.shapeArgs, { fill: point.color }),
524
- animationOptions
525
- );
526
- }
527
- });
528
- this.animate = null;
529
- }
530
- }
531
- });
532
- }
533
-
534
- H.Point.prototype.doDrilldown = function (_holdRedraw, category, originalEvent) {
535
- var series = this.series,
536
- chart = series.chart,
537
- drilldown = chart.options.drilldown,
538
- i = (drilldown.series || []).length,
539
- seriesOptions;
540
-
541
- if (!chart.ddDupes) {
542
- chart.ddDupes = [];
543
- }
544
-
545
- while (i-- && !seriesOptions) {
546
- if (drilldown.series[i].id === this.drilldown && inArray(this.drilldown, chart.ddDupes) === -1) {
547
- seriesOptions = drilldown.series[i];
548
- chart.ddDupes.push(this.drilldown);
549
- }
550
- }
551
-
552
- // Fire the event. If seriesOptions is undefined, the implementer can check for
553
- // seriesOptions, and call addSeriesAsDrilldown async if necessary.
554
- fireEvent(chart, 'drilldown', {
555
- point: this,
556
- seriesOptions: seriesOptions,
557
- category: category,
558
- originalEvent: originalEvent,
559
- points: category !== undefined && this.series.xAxis.getDDPoints(category).slice(0)
560
- }, function (e) {
561
- var chart = e.point.series && e.point.series.chart,
562
- seriesOptions = e.seriesOptions;
563
- if (chart && seriesOptions) {
564
- if (_holdRedraw) {
565
- chart.addSingleSeriesAsDrilldown(e.point, seriesOptions);
566
- } else {
567
- chart.addSeriesAsDrilldown(e.point, seriesOptions);
568
- }
569
- }
570
- });
571
-
572
-
573
- };
574
-
575
- /**
576
- * Drill down to a given category. This is the same as clicking on an axis label.
577
- */
578
- H.Axis.prototype.drilldownCategory = function (x, e) {
579
- var key,
580
- point,
581
- ddPointsX = this.getDDPoints(x);
582
- for (key in ddPointsX) {
583
- point = ddPointsX[key];
584
- if (point && point.series && point.series.visible && point.doDrilldown) { // #3197
585
- point.doDrilldown(true, x, e);
586
- }
587
- }
588
- this.chart.applyDrilldown();
589
- };
590
-
591
- /**
592
- * Return drillable points for this specific X value
593
- */
594
- H.Axis.prototype.getDDPoints = function (x) {
595
- var ret = [];
596
- each(this.series, function (series) {
597
- var i,
598
- xData = series.xData,
599
- points = series.points;
600
-
601
- for (i = 0; i < xData.length; i++) {
602
- if (xData[i] === x && series.options.data[i].drilldown) {
603
- ret.push(points ? points[i] : true);
604
- break;
605
- }
606
- }
607
- });
608
- return ret;
609
- };
610
-
611
-
612
- /**
613
- * Make a tick label drillable, or remove drilling on update
614
- */
615
- Tick.prototype.drillable = function () {
616
- var pos = this.pos,
617
- label = this.label,
618
- axis = this.axis,
619
- isDrillable = axis.coll === 'xAxis' && axis.getDDPoints,
620
- ddPointsX = isDrillable && axis.getDDPoints(pos);
621
-
622
- if (isDrillable) {
623
- if (label && ddPointsX.length) {
624
- if (!label.basicStyles) {
625
- label.basicStyles = H.merge(label.styles);
626
- }
627
- label
628
- .addClass('highcharts-drilldown-axis-label')
629
- .css(axis.chart.options.drilldown.activeAxisLabelStyle)
630
- .on('click', function (e) {
631
- axis.drilldownCategory(pos, e);
632
- });
633
-
634
- } else if (label && label.basicStyles) {
635
- label.styles = {}; // reset for full overwrite of styles
636
- label.css(label.basicStyles);
637
- label.on('click', null); // #3806
638
- }
639
- }
640
- };
641
-
642
- /**
643
- * Always keep the drillability updated (#3951)
644
- */
645
- wrap(Tick.prototype, 'addLabel', function (proceed) {
646
- proceed.call(this);
647
- this.drillable();
648
- });
649
-
650
-
651
- /**
652
- * On initialization of each point, identify its label and make it clickable. Also, provide a
653
- * list of points associated to that label.
654
- */
655
- wrap(H.Point.prototype, 'init', function (proceed, series, options, x) {
656
- var point = proceed.call(this, series, options, x),
657
- xAxis = series.xAxis,
658
- tick = xAxis && xAxis.ticks[x];
659
-
660
- if (point.drilldown) {
661
-
662
- // Add the click event to the point
663
- H.addEvent(point, 'click', function (e) {
664
- if (series.xAxis && series.chart.options.drilldown.allowPointDrilldown === false) {
665
- series.xAxis.drilldownCategory(x, e);
666
- } else {
667
- point.doDrilldown(undefined, undefined, e);
668
- }
669
- });
670
- /*wrap(point, 'importEvents', function (proceed) { // wrapping importEvents makes point.click event work
671
- if (!this.hasImportedEvents) {
672
- proceed.call(this);
673
- H.addEvent(this, 'click', function () {
674
- this.doDrilldown();
675
- });
676
- }
677
- });*/
678
-
679
- }
680
-
681
- // Add or remove click handler and style on the tick label
682
- if (tick) {
683
- tick.drillable();
684
- }
685
-
686
- return point;
687
- });
688
-
689
- wrap(H.Series.prototype, 'drawDataLabels', function (proceed) {
690
- var series = this,
691
- css = series.chart.options.drilldown.activeDataLabelStyle,
692
- renderer = series.chart.renderer;
693
-
694
- proceed.call(series);
695
-
696
- each(series.points, function (point) {
697
- var pointCss = {};
698
- if (point.drilldown && point.dataLabel) {
699
- if (css.color === 'contrast') {
700
- pointCss.color = renderer.getContrast(point.color || series.color);
701
- }
702
- point.dataLabel
703
- .attr({
704
- 'class': 'highcharts-drilldown-data-label'
705
- })
706
- .css(merge(css, pointCss));
707
- }
708
- });
709
- });
710
-
711
- // Mark the trackers with a pointer
712
- var type,
713
- drawTrackerWrapper = function (proceed) {
714
- proceed.call(this);
715
- each(this.points, function (point) {
716
- if (point.drilldown && point.graphic) {
717
- point.graphic
718
- .attr({
719
- 'class': 'highcharts-drilldown-point'
720
- })
721
- .css({ cursor: 'pointer' });
722
- }
723
- });
724
- };
725
- for (type in seriesTypes) {
726
- if (seriesTypes[type].prototype.supportsDrilldown) {
727
- wrap(seriesTypes[type].prototype, 'drawTracker', drawTrackerWrapper);
728
- }
729
- }
730
-
9
+ (function(factory) {
10
+ if (typeof module === 'object' && module.exports) {
11
+ module.exports = factory;
12
+ } else {
13
+ factory(Highcharts);
14
+ }
15
+ }(function(Highcharts) {
16
+ (function(H) {
17
+ /**
18
+ * Highcharts Drilldown module
19
+ *
20
+ * Author: Torstein Honsi
21
+ * License: www.highcharts.com/license
22
+ *
23
+ */
24
+
25
+ 'use strict';
26
+
27
+ var noop = H.noop,
28
+ color = H.color,
29
+ defaultOptions = H.defaultOptions,
30
+ each = H.each,
31
+ extend = H.extend,
32
+ format = H.format,
33
+ pick = H.pick,
34
+ wrap = H.wrap,
35
+ Chart = H.Chart,
36
+ seriesTypes = H.seriesTypes,
37
+ PieSeries = seriesTypes.pie,
38
+ ColumnSeries = seriesTypes.column,
39
+ Tick = H.Tick,
40
+ fireEvent = H.fireEvent,
41
+ inArray = H.inArray,
42
+ ddSeriesId = 1;
43
+
44
+ // Utilities
45
+ /*
46
+ * Return an intermediate color between two colors, according to pos where 0
47
+ * is the from color and 1 is the to color. This method is copied from ColorAxis.js
48
+ * and should always be kept updated, until we get AMD support.
49
+ */
50
+ function tweenColors(from, to, pos) {
51
+ // Check for has alpha, because rgba colors perform worse due to lack of
52
+ // support in WebKit.
53
+ var hasAlpha,
54
+ ret;
55
+
56
+ // Unsupported color, return to-color (#3920)
57
+ if (!to.rgba.length || !from.rgba.length) {
58
+ ret = to.input || 'none';
59
+
60
+ // Interpolate
61
+ } else {
62
+ from = from.rgba;
63
+ to = to.rgba;
64
+ hasAlpha = (to[3] !== 1 || from[3] !== 1);
65
+ ret = (hasAlpha ? 'rgba(' : 'rgb(') +
66
+ Math.round(to[0] + (from[0] - to[0]) * (1 - pos)) + ',' +
67
+ Math.round(to[1] + (from[1] - to[1]) * (1 - pos)) + ',' +
68
+ Math.round(to[2] + (from[2] - to[2]) * (1 - pos)) +
69
+ (hasAlpha ? (',' + (to[3] + (from[3] - to[3]) * (1 - pos))) : '') + ')';
70
+ }
71
+ return ret;
72
+ }
73
+ /**
74
+ * Handle animation of the color attributes directly
75
+ */
76
+ each(['fill', 'stroke'], function(prop) {
77
+ H.Fx.prototype[prop + 'Setter'] = function() {
78
+ this.elem.attr(prop, tweenColors(color(this.start), color(this.end), this.pos));
79
+ };
80
+ });
81
+
82
+ // Add language
83
+ extend(defaultOptions.lang, {
84
+ drillUpText: '◁ Back to {series.name}'
85
+ });
86
+ defaultOptions.drilldown = {
87
+
88
+ activeAxisLabelStyle: {
89
+ cursor: 'pointer',
90
+ color: '#003399',
91
+ fontWeight: 'bold',
92
+ textDecoration: 'underline'
93
+ },
94
+ activeDataLabelStyle: {
95
+ cursor: 'pointer',
96
+ color: '#003399',
97
+ fontWeight: 'bold',
98
+ textDecoration: 'underline'
99
+ },
100
+
101
+ animation: {
102
+ duration: 500
103
+ },
104
+ drillUpButton: {
105
+ position: {
106
+ align: 'right',
107
+ x: -10,
108
+ y: 10
109
+ }
110
+ // relativeTo: 'plotBox'
111
+ // theme
112
+ }
113
+ };
114
+
115
+ /**
116
+ * A general fadeIn method
117
+ */
118
+ H.SVGRenderer.prototype.Element.prototype.fadeIn = function(animation) {
119
+ this
120
+ .attr({
121
+ opacity: 0.1,
122
+ visibility: 'inherit'
123
+ })
124
+ .animate({
125
+ opacity: pick(this.newOpacity, 1) // newOpacity used in maps
126
+ }, animation || {
127
+ duration: 250
128
+ });
129
+ };
130
+
131
+ Chart.prototype.addSeriesAsDrilldown = function(point, ddOptions) {
132
+ this.addSingleSeriesAsDrilldown(point, ddOptions);
133
+ this.applyDrilldown();
134
+ };
135
+ Chart.prototype.addSingleSeriesAsDrilldown = function(point, ddOptions) {
136
+ var oldSeries = point.series,
137
+ xAxis = oldSeries.xAxis,
138
+ yAxis = oldSeries.yAxis,
139
+ newSeries,
140
+ pointIndex,
141
+ levelSeries = [],
142
+ levelSeriesOptions = [],
143
+ level,
144
+ levelNumber,
145
+ last,
146
+ colorProp;
147
+
148
+
149
+
150
+ colorProp = {
151
+ color: point.color || oldSeries.color
152
+ };
153
+
154
+
155
+ if (!this.drilldownLevels) {
156
+ this.drilldownLevels = [];
157
+ }
158
+
159
+ levelNumber = oldSeries.options._levelNumber || 0;
160
+
161
+ // See if we can reuse the registered series from last run
162
+ last = this.drilldownLevels[this.drilldownLevels.length - 1];
163
+ if (last && last.levelNumber !== levelNumber) {
164
+ last = undefined;
165
+ }
166
+
167
+ ddOptions = extend(extend({
168
+ _ddSeriesId: ddSeriesId++
169
+ }, colorProp), ddOptions);
170
+ pointIndex = inArray(point, oldSeries.points);
171
+
172
+ // Record options for all current series
173
+ each(oldSeries.chart.series, function(series) {
174
+ if (series.xAxis === xAxis && !series.isDrilling) {
175
+ series.options._ddSeriesId = series.options._ddSeriesId || ddSeriesId++;
176
+ series.options._colorIndex = series.userOptions._colorIndex;
177
+ series.options._levelNumber = series.options._levelNumber || levelNumber; // #3182
178
+
179
+ if (last) {
180
+ levelSeries = last.levelSeries;
181
+ levelSeriesOptions = last.levelSeriesOptions;
182
+ } else {
183
+ levelSeries.push(series);
184
+ levelSeriesOptions.push(series.options);
185
+ }
186
+ }
187
+ });
188
+
189
+ // Add a record of properties for each drilldown level
190
+ level = extend({
191
+ levelNumber: levelNumber,
192
+ seriesOptions: oldSeries.options,
193
+ levelSeriesOptions: levelSeriesOptions,
194
+ levelSeries: levelSeries,
195
+ shapeArgs: point.shapeArgs,
196
+ bBox: point.graphic ? point.graphic.getBBox() : {}, // no graphic in line series with markers disabled
197
+ lowerSeriesOptions: ddOptions,
198
+ pointOptions: oldSeries.options.data[pointIndex],
199
+ pointIndex: pointIndex,
200
+ oldExtremes: {
201
+ xMin: xAxis && xAxis.userMin,
202
+ xMax: xAxis && xAxis.userMax,
203
+ yMin: yAxis && yAxis.userMin,
204
+ yMax: yAxis && yAxis.userMax
205
+ }
206
+ }, colorProp);
207
+
208
+ // Push it to the lookup array
209
+ this.drilldownLevels.push(level);
210
+
211
+ newSeries = level.lowerSeries = this.addSeries(ddOptions, false);
212
+ newSeries.options._levelNumber = levelNumber + 1;
213
+ if (xAxis) {
214
+ xAxis.oldPos = xAxis.pos;
215
+ xAxis.userMin = xAxis.userMax = null;
216
+ yAxis.userMin = yAxis.userMax = null;
217
+ }
218
+
219
+ // Run fancy cross-animation on supported and equal types
220
+ if (oldSeries.type === newSeries.type) {
221
+ newSeries.animate = newSeries.animateDrilldown || noop;
222
+ newSeries.options.animation = true;
223
+ }
224
+ };
225
+
226
+ Chart.prototype.applyDrilldown = function() {
227
+ var drilldownLevels = this.drilldownLevels,
228
+ levelToRemove;
229
+
230
+ if (drilldownLevels && drilldownLevels.length > 0) { // #3352, async loading
231
+ levelToRemove = drilldownLevels[drilldownLevels.length - 1].levelNumber;
232
+ each(this.drilldownLevels, function(level) {
233
+ if (level.levelNumber === levelToRemove) {
234
+ each(level.levelSeries, function(series) {
235
+ if (series.options && series.options._levelNumber === levelToRemove) { // Not removed, not added as part of a multi-series drilldown
236
+ series.remove(false);
237
+ }
238
+ });
239
+ }
240
+ });
241
+ }
242
+
243
+ this.redraw();
244
+ this.showDrillUpButton();
245
+ };
246
+
247
+ Chart.prototype.getDrilldownBackText = function() {
248
+ var drilldownLevels = this.drilldownLevels,
249
+ lastLevel;
250
+ if (drilldownLevels && drilldownLevels.length > 0) { // #3352, async loading
251
+ lastLevel = drilldownLevels[drilldownLevels.length - 1];
252
+ lastLevel.series = lastLevel.seriesOptions;
253
+ return format(this.options.lang.drillUpText, lastLevel);
254
+ }
255
+
256
+ };
257
+
258
+ Chart.prototype.showDrillUpButton = function() {
259
+ var chart = this,
260
+ backText = this.getDrilldownBackText(),
261
+ buttonOptions = chart.options.drilldown.drillUpButton,
262
+ attr,
263
+ states;
264
+
265
+
266
+ if (!this.drillUpButton) {
267
+ attr = buttonOptions.theme;
268
+ states = attr && attr.states;
269
+
270
+ this.drillUpButton = this.renderer.button(
271
+ backText,
272
+ null,
273
+ null,
274
+ function() {
275
+ chart.drillUp();
276
+ },
277
+ attr,
278
+ states && states.hover,
279
+ states && states.select
280
+ )
281
+ .addClass('highcharts-drillup-button')
282
+ .attr({
283
+ align: buttonOptions.position.align,
284
+ zIndex: 7
285
+ })
286
+ .add()
287
+ .align(buttonOptions.position, false, buttonOptions.relativeTo || 'plotBox');
288
+ } else {
289
+ this.drillUpButton.attr({
290
+ text: backText
291
+ })
292
+ .align();
293
+ }
294
+ };
295
+
296
+ Chart.prototype.drillUp = function() {
297
+ var chart = this,
298
+ drilldownLevels = chart.drilldownLevels,
299
+ levelNumber = drilldownLevels[drilldownLevels.length - 1].levelNumber,
300
+ i = drilldownLevels.length,
301
+ chartSeries = chart.series,
302
+ seriesI,
303
+ level,
304
+ oldSeries,
305
+ newSeries,
306
+ oldExtremes,
307
+ addSeries = function(seriesOptions) {
308
+ var addedSeries;
309
+ each(chartSeries, function(series) {
310
+ if (series.options._ddSeriesId === seriesOptions._ddSeriesId) {
311
+ addedSeries = series;
312
+ }
313
+ });
314
+
315
+ addedSeries = addedSeries || chart.addSeries(seriesOptions, false);
316
+ if (addedSeries.type === oldSeries.type && addedSeries.animateDrillupTo) {
317
+ addedSeries.animate = addedSeries.animateDrillupTo;
318
+ }
319
+ if (seriesOptions === level.seriesOptions) {
320
+ newSeries = addedSeries;
321
+ }
322
+ };
323
+
324
+ while (i--) {
325
+
326
+ level = drilldownLevels[i];
327
+ if (level.levelNumber === levelNumber) {
328
+ drilldownLevels.pop();
329
+
330
+ // Get the lower series by reference or id
331
+ oldSeries = level.lowerSeries;
332
+ if (!oldSeries.chart) { // #2786
333
+ seriesI = chartSeries.length; // #2919
334
+ while (seriesI--) {
335
+ if (chartSeries[seriesI].options.id === level.lowerSeriesOptions.id &&
336
+ chartSeries[seriesI].options._levelNumber === levelNumber + 1) { // #3867
337
+ oldSeries = chartSeries[seriesI];
338
+ break;
339
+ }
340
+ }
341
+ }
342
+ oldSeries.xData = []; // Overcome problems with minRange (#2898)
343
+
344
+ each(level.levelSeriesOptions, addSeries);
345
+
346
+ fireEvent(chart, 'drillup', {
347
+ seriesOptions: level.seriesOptions
348
+ });
349
+
350
+ if (newSeries.type === oldSeries.type) {
351
+ newSeries.drilldownLevel = level;
352
+ newSeries.options.animation = chart.options.drilldown.animation;
353
+
354
+ if (oldSeries.animateDrillupFrom && oldSeries.chart) { // #2919
355
+ oldSeries.animateDrillupFrom(level);
356
+ }
357
+ }
358
+ newSeries.options._levelNumber = levelNumber;
359
+
360
+ oldSeries.remove(false);
361
+
362
+ // Reset the zoom level of the upper series
363
+ if (newSeries.xAxis) {
364
+ oldExtremes = level.oldExtremes;
365
+ newSeries.xAxis.setExtremes(oldExtremes.xMin, oldExtremes.xMax, false);
366
+ newSeries.yAxis.setExtremes(oldExtremes.yMin, oldExtremes.yMax, false);
367
+ }
368
+ }
369
+ }
370
+
371
+ // Fire a once-off event after all series have been drilled up (#5158)
372
+ fireEvent(chart, 'drillupall');
373
+
374
+ this.redraw();
375
+
376
+ if (this.drilldownLevels.length === 0) {
377
+ this.drillUpButton = this.drillUpButton.destroy();
378
+ } else {
379
+ this.drillUpButton.attr({
380
+ text: this.getDrilldownBackText()
381
+ })
382
+ .align();
383
+ }
384
+
385
+ this.ddDupes.length = []; // #3315
386
+ };
387
+
388
+
389
+ ColumnSeries.prototype.supportsDrilldown = true;
390
+
391
+ /**
392
+ * When drilling up, keep the upper series invisible until the lower series has
393
+ * moved into place
394
+ */
395
+ ColumnSeries.prototype.animateDrillupTo = function(init) {
396
+ if (!init) {
397
+ var newSeries = this,
398
+ level = newSeries.drilldownLevel;
399
+
400
+ each(this.points, function(point) {
401
+ if (point.graphic) { // #3407
402
+ point.graphic.hide();
403
+ }
404
+ if (point.dataLabel) {
405
+ point.dataLabel.hide();
406
+ }
407
+ if (point.connector) {
408
+ point.connector.hide();
409
+ }
410
+ });
411
+
412
+
413
+ // Do dummy animation on first point to get to complete
414
+ setTimeout(function() {
415
+ if (newSeries.points) { // May be destroyed in the meantime, #3389
416
+ each(newSeries.points, function(point, i) {
417
+ // Fade in other points
418
+ var verb = i === (level && level.pointIndex) ? 'show' : 'fadeIn',
419
+ inherit = verb === 'show' ? true : undefined;
420
+ if (point.graphic) { // #3407
421
+ point.graphic[verb](inherit);
422
+ }
423
+ if (point.dataLabel) {
424
+ point.dataLabel[verb](inherit);
425
+ }
426
+ if (point.connector) {
427
+ point.connector[verb](inherit);
428
+ }
429
+ });
430
+ }
431
+ }, Math.max(this.chart.options.drilldown.animation.duration - 50, 0));
432
+
433
+ // Reset
434
+ this.animate = noop;
435
+ }
436
+
437
+ };
438
+
439
+ ColumnSeries.prototype.animateDrilldown = function(init) {
440
+ var series = this,
441
+ drilldownLevels = this.chart.drilldownLevels,
442
+ animateFrom,
443
+ animationOptions = this.chart.options.drilldown.animation,
444
+ xAxis = this.xAxis;
445
+
446
+ if (!init) {
447
+ each(drilldownLevels, function(level) {
448
+ if (series.options._ddSeriesId === level.lowerSeriesOptions._ddSeriesId) {
449
+ animateFrom = level.shapeArgs;
450
+
451
+ // Add the point colors to animate from
452
+ animateFrom.fill = level.color;
453
+
454
+ }
455
+ });
456
+
457
+ animateFrom.x += (pick(xAxis.oldPos, xAxis.pos) - xAxis.pos);
458
+
459
+ each(this.points, function(point) {
460
+ var animateTo = point.shapeArgs;
461
+
462
+
463
+ // Add the point colors to animate to
464
+ animateTo.fill = point.color;
465
+
466
+
467
+ if (point.graphic) {
468
+ point.graphic
469
+ .attr(animateFrom)
470
+ .animate(
471
+ extend(point.shapeArgs, {
472
+ fill: point.color || series.color
473
+ }),
474
+ animationOptions
475
+ );
476
+ }
477
+ if (point.dataLabel) {
478
+ point.dataLabel.fadeIn(animationOptions);
479
+ }
480
+ });
481
+ this.animate = null;
482
+ }
483
+
484
+ };
485
+
486
+ /**
487
+ * When drilling up, pull out the individual point graphics from the lower series
488
+ * and animate them into the origin point in the upper series.
489
+ */
490
+ ColumnSeries.prototype.animateDrillupFrom = function(level) {
491
+ var animationOptions = this.chart.options.drilldown.animation,
492
+ group = this.group,
493
+ series = this;
494
+
495
+ // Cancel mouse events on the series group (#2787)
496
+ each(series.trackerGroups, function(key) {
497
+ if (series[key]) { // we don't always have dataLabelsGroup
498
+ series[key].on('mouseover');
499
+ }
500
+ });
501
+
502
+
503
+ delete this.group;
504
+ each(this.points, function(point) {
505
+ var graphic = point.graphic,
506
+ animateTo = level.shapeArgs,
507
+ complete = function() {
508
+ graphic.destroy();
509
+ if (group) {
510
+ group = group.destroy();
511
+ }
512
+ };
513
+
514
+ if (graphic) {
515
+
516
+ delete point.graphic;
517
+
518
+
519
+ animateTo.fill = level.color;
520
+
521
+
522
+ if (animationOptions) {
523
+ graphic.animate(
524
+ animateTo,
525
+ H.merge(animationOptions, {
526
+ complete: complete
527
+ })
528
+ );
529
+ } else {
530
+ graphic.attr(animateTo);
531
+ complete();
532
+ }
533
+ }
534
+ });
535
+ };
536
+
537
+ if (PieSeries) {
538
+ extend(PieSeries.prototype, {
539
+ supportsDrilldown: true,
540
+ animateDrillupTo: ColumnSeries.prototype.animateDrillupTo,
541
+ animateDrillupFrom: ColumnSeries.prototype.animateDrillupFrom,
542
+
543
+ animateDrilldown: function(init) {
544
+ var level = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1],
545
+ animationOptions = this.chart.options.drilldown.animation,
546
+ animateFrom = level.shapeArgs,
547
+ start = animateFrom.start,
548
+ angle = animateFrom.end - start,
549
+ startAngle = angle / this.points.length;
550
+
551
+ if (!init) {
552
+ each(this.points, function(point, i) {
553
+ var animateTo = point.shapeArgs;
554
+
555
+
556
+ animateFrom.fill = level.color;
557
+ animateTo.fill = point.color;
558
+
559
+
560
+ if (point.graphic) {
561
+ point.graphic
562
+ .attr(H.merge(animateFrom, {
563
+ start: start + i * startAngle,
564
+ end: start + (i + 1) * startAngle
565
+ }))[animationOptions ? 'animate' : 'attr'](
566
+ animateTo,
567
+ animationOptions
568
+ );
569
+ }
570
+ });
571
+ this.animate = null;
572
+ }
573
+ }
574
+ });
575
+ }
576
+
577
+ H.Point.prototype.doDrilldown = function(_holdRedraw, category, originalEvent) {
578
+ var series = this.series,
579
+ chart = series.chart,
580
+ drilldown = chart.options.drilldown,
581
+ i = (drilldown.series || []).length,
582
+ seriesOptions;
583
+
584
+ if (!chart.ddDupes) {
585
+ chart.ddDupes = [];
586
+ }
587
+
588
+ while (i-- && !seriesOptions) {
589
+ if (drilldown.series[i].id === this.drilldown && inArray(this.drilldown, chart.ddDupes) === -1) {
590
+ seriesOptions = drilldown.series[i];
591
+ chart.ddDupes.push(this.drilldown);
592
+ }
593
+ }
594
+
595
+ // Fire the event. If seriesOptions is undefined, the implementer can check for
596
+ // seriesOptions, and call addSeriesAsDrilldown async if necessary.
597
+ fireEvent(chart, 'drilldown', {
598
+ point: this,
599
+ seriesOptions: seriesOptions,
600
+ category: category,
601
+ originalEvent: originalEvent,
602
+ points: category !== undefined && this.series.xAxis.getDDPoints(category).slice(0)
603
+ }, function(e) {
604
+ var chart = e.point.series && e.point.series.chart,
605
+ seriesOptions = e.seriesOptions;
606
+ if (chart && seriesOptions) {
607
+ if (_holdRedraw) {
608
+ chart.addSingleSeriesAsDrilldown(e.point, seriesOptions);
609
+ } else {
610
+ chart.addSeriesAsDrilldown(e.point, seriesOptions);
611
+ }
612
+ }
613
+ });
614
+
615
+
616
+ };
617
+
618
+ /**
619
+ * Drill down to a given category. This is the same as clicking on an axis label.
620
+ */
621
+ H.Axis.prototype.drilldownCategory = function(x, e) {
622
+ var key,
623
+ point,
624
+ ddPointsX = this.getDDPoints(x);
625
+ for (key in ddPointsX) {
626
+ point = ddPointsX[key];
627
+ if (point && point.series && point.series.visible && point.doDrilldown) { // #3197
628
+ point.doDrilldown(true, x, e);
629
+ }
630
+ }
631
+ this.chart.applyDrilldown();
632
+ };
633
+
634
+ /**
635
+ * Return drillable points for this specific X value
636
+ */
637
+ H.Axis.prototype.getDDPoints = function(x) {
638
+ var ret = [];
639
+ each(this.series, function(series) {
640
+ var i,
641
+ xData = series.xData,
642
+ points = series.points;
643
+
644
+ for (i = 0; i < xData.length; i++) {
645
+ if (xData[i] === x && series.options.data[i].drilldown) {
646
+ ret.push(points ? points[i] : true);
647
+ break;
648
+ }
649
+ }
650
+ });
651
+ return ret;
652
+ };
653
+
654
+
655
+ /**
656
+ * Make a tick label drillable, or remove drilling on update
657
+ */
658
+ Tick.prototype.drillable = function() {
659
+ var pos = this.pos,
660
+ label = this.label,
661
+ axis = this.axis,
662
+ isDrillable = axis.coll === 'xAxis' && axis.getDDPoints,
663
+ ddPointsX = isDrillable && axis.getDDPoints(pos);
664
+
665
+ if (isDrillable) {
666
+ if (label && ddPointsX.length) {
667
+ label.drillable = true;
668
+
669
+
670
+ if (!label.basicStyles) {
671
+ label.basicStyles = H.merge(label.styles);
672
+ }
673
+
674
+
675
+ label
676
+ .addClass('highcharts-drilldown-axis-label')
677
+
678
+ .css(axis.chart.options.drilldown.activeAxisLabelStyle)
679
+
680
+ .on('click', function(e) {
681
+ axis.drilldownCategory(pos, e);
682
+ });
683
+
684
+ } else if (label && label.drillable) {
685
+
686
+
687
+ label.styles = {}; // reset for full overwrite of styles
688
+ label.css(label.basicStyles);
689
+
690
+
691
+ label.on('click', null); // #3806
692
+ label.removeClass('highcharts-drilldown-axis-label');
693
+ }
694
+ }
695
+ };
696
+
697
+ /**
698
+ * Always keep the drillability updated (#3951)
699
+ */
700
+ wrap(Tick.prototype, 'addLabel', function(proceed) {
701
+ proceed.call(this);
702
+ this.drillable();
703
+ });
704
+
705
+
706
+ /**
707
+ * On initialization of each point, identify its label and make it clickable. Also, provide a
708
+ * list of points associated to that label.
709
+ */
710
+ wrap(H.Point.prototype, 'init', function(proceed, series, options, x) {
711
+ var point = proceed.call(this, series, options, x),
712
+ xAxis = series.xAxis,
713
+ tick = xAxis && xAxis.ticks[x];
714
+
715
+ if (point.drilldown) {
716
+
717
+ // Add the click event to the point
718
+ H.addEvent(point, 'click', function(e) {
719
+ if (series.xAxis && series.chart.options.drilldown.allowPointDrilldown === false) {
720
+ series.xAxis.drilldownCategory(x, e);
721
+ } else {
722
+ point.doDrilldown(undefined, undefined, e);
723
+ }
724
+ });
725
+ /*wrap(point, 'importEvents', function (proceed) { // wrapping importEvents makes point.click event work
726
+ if (!this.hasImportedEvents) {
727
+ proceed.call(this);
728
+ H.addEvent(this, 'click', function () {
729
+ this.doDrilldown();
730
+ });
731
+ }
732
+ });*/
733
+
734
+ }
735
+
736
+ // Add or remove click handler and style on the tick label
737
+ if (tick) {
738
+ tick.drillable();
739
+ }
740
+
741
+ return point;
742
+ });
743
+
744
+ wrap(H.Series.prototype, 'drawDataLabels', function(proceed) {
745
+ var css = this.chart.options.drilldown.activeDataLabelStyle,
746
+ renderer = this.chart.renderer;
747
+
748
+ proceed.call(this);
749
+
750
+ each(this.points, function(point) {
751
+ var pointCSS = {};
752
+ if (point.drilldown && point.dataLabel) {
753
+ if (css.color === 'contrast') {
754
+ pointCSS.color = renderer.getContrast(point.color || this.color);
755
+ }
756
+ point.dataLabel
757
+ .addClass('highcharts-drilldown-data-label');
758
+
759
+
760
+ point.dataLabel
761
+ .css(css)
762
+ .css(pointCSS);
763
+
764
+ }
765
+ }, this);
766
+ });
767
+
768
+ // Mark the trackers with a pointer
769
+ var type,
770
+ drawTrackerWrapper = function(proceed) {
771
+ proceed.call(this);
772
+ each(this.points, function(point) {
773
+ if (point.drilldown && point.graphic) {
774
+ point.graphic.addClass('highcharts-drilldown-point');
775
+
776
+
777
+ point.graphic.css({
778
+ cursor: 'pointer'
779
+ });
780
+
781
+ }
782
+ });
783
+ };
784
+ for (type in seriesTypes) {
785
+ if (seriesTypes[type].prototype.supportsDrilldown) {
786
+ wrap(seriesTypes[type].prototype, 'drawTracker', drawTrackerWrapper);
787
+ }
788
+ }
789
+
790
+ }(Highcharts));
731
791
  }));