highcharts_rails 0.1.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 (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +106 -0
  9. data/Rakefile +6 -0
  10. data/highcharts_rails.gemspec +27 -0
  11. data/lib/highcharts_rails/version.rb +3 -0
  12. data/lib/highcharts_rails.rb +8 -0
  13. data/vendor/assets/javascripts/highcharts-3d.src.js +2139 -0
  14. data/vendor/assets/javascripts/highcharts-more.src.js +2982 -0
  15. data/vendor/assets/javascripts/highcharts.src.js +22947 -0
  16. data/vendor/assets/javascripts/js/highcharts-3d.src.js +2085 -0
  17. data/vendor/assets/javascripts/js/highcharts-more.src.js +2820 -0
  18. data/vendor/assets/javascripts/js/highcharts.src.js +20917 -0
  19. data/vendor/assets/javascripts/js/modules/accessibility.src.js +1072 -0
  20. data/vendor/assets/javascripts/js/modules/annotations.src.js +408 -0
  21. data/vendor/assets/javascripts/js/modules/boost.src.js +652 -0
  22. data/vendor/assets/javascripts/js/modules/broken-axis.src.js +338 -0
  23. data/vendor/assets/javascripts/js/modules/data.src.js +981 -0
  24. data/vendor/assets/javascripts/js/modules/drilldown.src.js +756 -0
  25. data/vendor/assets/javascripts/js/modules/exporting.src.js +953 -0
  26. data/vendor/assets/javascripts/js/modules/funnel.src.js +290 -0
  27. data/vendor/assets/javascripts/js/modules/gantt.src.js +791 -0
  28. data/vendor/assets/javascripts/js/modules/grid-axis.src.js +545 -0
  29. data/vendor/assets/javascripts/js/modules/heatmap.src.js +798 -0
  30. data/vendor/assets/javascripts/js/modules/no-data-to-display.src.js +150 -0
  31. data/vendor/assets/javascripts/js/modules/offline-exporting.src.js +492 -0
  32. data/vendor/assets/javascripts/js/modules/overlapping-datalabels.src.js +164 -0
  33. data/vendor/assets/javascripts/js/modules/series-label.src.js +606 -0
  34. data/vendor/assets/javascripts/js/modules/solid-gauge.src.js +305 -0
  35. data/vendor/assets/javascripts/js/modules/treemap.src.js +881 -0
  36. data/vendor/assets/javascripts/js/modules/xrange-series.src.js +254 -0
  37. data/vendor/assets/javascripts/js/themes/dark-blue.js +317 -0
  38. data/vendor/assets/javascripts/js/themes/dark-green.js +314 -0
  39. data/vendor/assets/javascripts/js/themes/dark-unica.js +243 -0
  40. data/vendor/assets/javascripts/js/themes/gray.js +326 -0
  41. data/vendor/assets/javascripts/js/themes/grid-light.js +99 -0
  42. data/vendor/assets/javascripts/js/themes/grid.js +131 -0
  43. data/vendor/assets/javascripts/js/themes/sand-signika.js +129 -0
  44. data/vendor/assets/javascripts/js/themes/skies.js +112 -0
  45. data/vendor/assets/javascripts/lib/canvg.src.js +3073 -0
  46. data/vendor/assets/javascripts/lib/jspdf.src.js +3031 -0
  47. data/vendor/assets/javascripts/lib/rgbcolor.src.js +299 -0
  48. data/vendor/assets/javascripts/lib/svg2pdf.src.js +1451 -0
  49. data/vendor/assets/javascripts/modules/accessibility.src.js +1072 -0
  50. data/vendor/assets/javascripts/modules/annotations.src.js +408 -0
  51. data/vendor/assets/javascripts/modules/boost.src.js +652 -0
  52. data/vendor/assets/javascripts/modules/broken-axis.src.js +338 -0
  53. data/vendor/assets/javascripts/modules/data.src.js +981 -0
  54. data/vendor/assets/javascripts/modules/drilldown.src.js +797 -0
  55. data/vendor/assets/javascripts/modules/exporting.src.js +882 -0
  56. data/vendor/assets/javascripts/modules/funnel.src.js +304 -0
  57. data/vendor/assets/javascripts/modules/gantt.src.js +815 -0
  58. data/vendor/assets/javascripts/modules/grid-axis.src.js +547 -0
  59. data/vendor/assets/javascripts/modules/heatmap.src.js +810 -0
  60. data/vendor/assets/javascripts/modules/no-data-to-display.src.js +161 -0
  61. data/vendor/assets/javascripts/modules/offline-exporting.src.js +492 -0
  62. data/vendor/assets/javascripts/modules/overlapping-datalabels.src.js +164 -0
  63. data/vendor/assets/javascripts/modules/series-label.src.js +606 -0
  64. data/vendor/assets/javascripts/modules/solid-gauge.src.js +316 -0
  65. data/vendor/assets/javascripts/modules/treemap.src.js +935 -0
  66. data/vendor/assets/javascripts/modules/xrange-series.src.js +276 -0
  67. data/vendor/assets/javascripts/themes/dark-blue.js +317 -0
  68. data/vendor/assets/javascripts/themes/dark-green.js +314 -0
  69. data/vendor/assets/javascripts/themes/dark-unica.js +243 -0
  70. data/vendor/assets/javascripts/themes/gray.js +326 -0
  71. data/vendor/assets/javascripts/themes/grid-light.js +99 -0
  72. data/vendor/assets/javascripts/themes/grid.js +131 -0
  73. data/vendor/assets/javascripts/themes/sand-signika.js +129 -0
  74. data/vendor/assets/javascripts/themes/skies.js +112 -0
  75. data/vendor/assets/stylesheets/highcharts.scss +610 -0
  76. metadata +161 -0
@@ -0,0 +1,606 @@
1
+ /**
2
+ * @license Highcharts JS v5.0.6 (2016-12-07)
3
+ *
4
+ * (c) 2009-2016 Torstein Honsi
5
+ *
6
+ * License: www.highcharts.com/license
7
+ */
8
+ (function(factory) {
9
+ if (typeof module === 'object' && module.exports) {
10
+ module.exports = factory;
11
+ } else {
12
+ factory(Highcharts);
13
+ }
14
+ }(function(Highcharts) {
15
+ (function(H) {
16
+ /**
17
+ * (c) 2009-2016 Torstein Honsi
18
+ *
19
+ * License: www.highcharts.com/license
20
+ */
21
+ /**
22
+ * EXPERIMENTAL Highcharts module to place labels next to a series in a natural position.
23
+ *
24
+ * TODO:
25
+ * - add column support (box collision detection, boxesToAvoid logic)
26
+ * - other series types, area etc.
27
+ * - avoid data labels, when data labels above, show series label below.
28
+ * - add more options (connector, format, formatter)
29
+ *
30
+ * http://jsfiddle.net/highcharts/L2u9rpwr/
31
+ * http://jsfiddle.net/highcharts/y5A37/
32
+ * http://jsfiddle.net/highcharts/264Nm/
33
+ * http://jsfiddle.net/highcharts/y5A37/
34
+ */
35
+
36
+ 'use strict';
37
+
38
+ var labelDistance = 3,
39
+ wrap = H.wrap,
40
+ each = H.each,
41
+ extend = H.extend,
42
+ isNumber = H.isNumber,
43
+ Series = H.Series,
44
+ SVGRenderer = H.SVGRenderer,
45
+ Chart = H.Chart;
46
+
47
+ H.setOptions({
48
+ plotOptions: {
49
+ series: {
50
+ label: {
51
+ enabled: true,
52
+ // Allow labels to be placed distant to the graph if necessary, and
53
+ // draw a connector line to the graph
54
+ connectorAllowed: true,
55
+ connectorNeighbourDistance: 24, // If the label is closer than this to a neighbour graph, draw a connector
56
+ styles: {
57
+ fontWeight: 'bold'
58
+ }
59
+ // boxesToAvoid: []
60
+ }
61
+ }
62
+ }
63
+ });
64
+
65
+ /**
66
+ * Counter-clockwise, part of the fast line intersection logic
67
+ */
68
+ function ccw(x1, y1, x2, y2, x3, y3) {
69
+ var cw = ((y3 - y1) * (x2 - x1)) - ((y2 - y1) * (x3 - x1));
70
+ return cw > 0 ? true : cw < 0 ? false : true;
71
+ }
72
+
73
+ /**
74
+ * Detect if two lines intersect
75
+ */
76
+ function intersectLine(x1, y1, x2, y2, x3, y3, x4, y4) {
77
+ return ccw(x1, y1, x3, y3, x4, y4) !== ccw(x2, y2, x3, y3, x4, y4) &&
78
+ ccw(x1, y1, x2, y2, x3, y3) !== ccw(x1, y1, x2, y2, x4, y4);
79
+ }
80
+
81
+ /**
82
+ * Detect if a box intersects with a line
83
+ */
84
+ function boxIntersectLine(x, y, w, h, x1, y1, x2, y2) {
85
+ return (
86
+ intersectLine(x, y, x + w, y, x1, y1, x2, y2) || // top of label
87
+ intersectLine(x + w, y, x + w, y + h, x1, y1, x2, y2) || // right of label
88
+ intersectLine(x, y + h, x + w, y + h, x1, y1, x2, y2) || // bottom of label
89
+ intersectLine(x, y, x, y + h, x1, y1, x2, y2) // left of label
90
+ );
91
+ }
92
+
93
+ /**
94
+ * General symbol definition for labels with connector
95
+ */
96
+ SVGRenderer.prototype.symbols.connector = function(x, y, w, h, options) {
97
+ var anchorX = options && options.anchorX,
98
+ anchorY = options && options.anchorY,
99
+ path,
100
+ yOffset,
101
+ lateral = w / 2;
102
+
103
+ if (isNumber(anchorX) && isNumber(anchorY)) {
104
+
105
+ path = ['M', anchorX, anchorY];
106
+
107
+ // Prefer 45 deg connectors
108
+ yOffset = y - anchorY;
109
+ if (yOffset < 0) {
110
+ yOffset = -h - yOffset;
111
+ }
112
+ if (yOffset < w) {
113
+ lateral = anchorX < x + (w / 2) ? yOffset : w - yOffset;
114
+ }
115
+
116
+ // Anchor below label
117
+ if (anchorY > y + h) {
118
+ path.push('L', x + lateral, y + h);
119
+
120
+ // Anchor above label
121
+ } else if (anchorY < y) {
122
+ path.push('L', x + lateral, y);
123
+
124
+ // Anchor left of label
125
+ } else if (anchorX < x) {
126
+ path.push('L', x, y + h / 2);
127
+
128
+ // Anchor right of label
129
+ } else if (anchorX > x + w) {
130
+ path.push('L', x + w, y + h / 2);
131
+ }
132
+ }
133
+ return path || [];
134
+ };
135
+
136
+ /**
137
+ * Points to avoid. In addition to actual data points, the label should avoid
138
+ * interpolated positions.
139
+ */
140
+ Series.prototype.getPointsOnGraph = function() {
141
+ var distance = 16,
142
+ points = this.points,
143
+ point,
144
+ last,
145
+ interpolated = [],
146
+ i,
147
+ deltaX,
148
+ deltaY,
149
+ delta,
150
+ len,
151
+ n,
152
+ j,
153
+ d,
154
+ graph = this.graph || this.area,
155
+ node = graph.element,
156
+ inverted = this.chart.inverted,
157
+ paneLeft = inverted ? this.yAxis.pos : this.xAxis.pos,
158
+ paneTop = inverted ? this.xAxis.pos : this.yAxis.pos;
159
+
160
+ // For splines, get the point at length (possible caveat: peaks are not correctly detected)
161
+ if (this.getPointSpline && node.getPointAtLength) {
162
+ // If it is animating towards a path definition, use that briefly, and reset
163
+ if (graph.toD) {
164
+ d = graph.attr('d');
165
+ graph.attr({
166
+ d: graph.toD
167
+ });
168
+ }
169
+ len = node.getTotalLength();
170
+ for (i = 0; i < len; i += distance) {
171
+ point = node.getPointAtLength(i);
172
+ interpolated.push({
173
+ chartX: paneLeft + point.x,
174
+ chartY: paneTop + point.y,
175
+ plotX: point.x,
176
+ plotY: point.y
177
+ });
178
+ }
179
+ if (d) {
180
+ graph.attr({
181
+ d: d
182
+ });
183
+ }
184
+ // Last point
185
+ point = points[points.length - 1];
186
+ point.chartX = paneLeft + point.plotX;
187
+ point.chartY = paneTop + point.plotY;
188
+ interpolated.push(point);
189
+
190
+ // Interpolate
191
+ } else {
192
+ len = points.length;
193
+ for (i = 0; i < len; i += 1) {
194
+
195
+ point = points[i];
196
+ last = points[i - 1];
197
+
198
+ // Absolute coordinates so we can compare different panes
199
+ point.chartX = paneLeft + point.plotX;
200
+ point.chartY = paneTop + point.plotY;
201
+
202
+ // Add interpolated points
203
+ if (i > 0) {
204
+ deltaX = Math.abs(point.chartX - last.chartX);
205
+ deltaY = Math.abs(point.chartY - last.chartY);
206
+ delta = Math.max(deltaX, deltaY);
207
+ if (delta > distance) {
208
+
209
+ n = Math.ceil(delta / distance);
210
+
211
+ for (j = 1; j < n; j += 1) {
212
+ interpolated.push({
213
+ chartX: last.chartX + (point.chartX - last.chartX) * (j / n),
214
+ chartY: last.chartY + (point.chartY - last.chartY) * (j / n),
215
+ plotX: last.plotX + (point.plotX - last.plotX) * (j / n),
216
+ plotY: last.plotY + (point.plotY - last.plotY) * (j / n)
217
+ });
218
+ }
219
+ }
220
+ }
221
+
222
+ // Add the real point in order to find positive and negative peaks
223
+ if (isNumber(point.plotY)) {
224
+ interpolated.push(point);
225
+ }
226
+ }
227
+ }
228
+ return interpolated;
229
+ };
230
+
231
+ /**
232
+ * Check whether a proposed label position is clear of other elements
233
+ */
234
+ Series.prototype.checkClearPoint = function(x, y, bBox, checkDistance) {
235
+ var distToOthersSquared = Number.MAX_VALUE, // distance to other graphs
236
+ distToPointSquared = Number.MAX_VALUE,
237
+ dist,
238
+ connectorPoint,
239
+ connectorEnabled = this.options.label.connectorAllowed,
240
+
241
+ chart = this.chart,
242
+ series,
243
+ points,
244
+ leastDistance = 16,
245
+ withinRange,
246
+ i,
247
+ j;
248
+
249
+ function intersectRect(r1, r2) {
250
+ return !(r2.left > r1.right ||
251
+ r2.right < r1.left ||
252
+ r2.top > r1.bottom ||
253
+ r2.bottom < r1.top);
254
+ }
255
+
256
+ /**
257
+ * Get the weight in order to determine the ideal position. Larger distance to
258
+ * other series gives more weight. Smaller distance to the actual point (connector points only)
259
+ * gives more weight.
260
+ */
261
+ function getWeight(distToOthersSquared, distToPointSquared) {
262
+ return distToOthersSquared - distToPointSquared;
263
+ }
264
+
265
+ // First check for collision with existing labels
266
+ for (i = 0; i < chart.boxesToAvoid.length; i += 1) {
267
+ if (intersectRect(chart.boxesToAvoid[i], {
268
+ left: x,
269
+ right: x + bBox.width,
270
+ top: y,
271
+ bottom: y + bBox.height
272
+ })) {
273
+ return false;
274
+ }
275
+ }
276
+
277
+ // For each position, check if the lines around the label intersect with any of the
278
+ // graphs
279
+ for (i = 0; i < chart.series.length; i += 1) {
280
+ series = chart.series[i];
281
+ points = series.interpolatedPoints;
282
+ if (series.visible && points) {
283
+ for (j = 1; j < points.length; j += 1) {
284
+ // If any of the box sides intersect with the line, return
285
+ if (boxIntersectLine(
286
+ x,
287
+ y,
288
+ bBox.width,
289
+ bBox.height,
290
+ points[j - 1].chartX,
291
+ points[j - 1].chartY,
292
+ points[j].chartX,
293
+ points[j].chartY
294
+ )) {
295
+ return false;
296
+ }
297
+
298
+ // But if it is too far away (a padded box doesn't intersect), also return
299
+ if (this === series && !withinRange && checkDistance) {
300
+ withinRange = boxIntersectLine(
301
+ x - leastDistance,
302
+ y - leastDistance,
303
+ bBox.width + 2 * leastDistance,
304
+ bBox.height + 2 * leastDistance,
305
+ points[j - 1].chartX,
306
+ points[j - 1].chartY,
307
+ points[j].chartX,
308
+ points[j].chartY
309
+ );
310
+ }
311
+
312
+ // Find the squared distance from the center of the label
313
+ if (this !== series) {
314
+ distToOthersSquared = Math.min(
315
+ distToOthersSquared,
316
+ Math.pow(x + bBox.width / 2 - points[j].chartX, 2) + Math.pow(y + bBox.height / 2 - points[j].chartY, 2),
317
+ Math.pow(x - points[j].chartX, 2) + Math.pow(y - points[j].chartY, 2),
318
+ Math.pow(x + bBox.width - points[j].chartX, 2) + Math.pow(y - points[j].chartY, 2),
319
+ Math.pow(x + bBox.width - points[j].chartX, 2) + Math.pow(y + bBox.height - points[j].chartY, 2),
320
+ Math.pow(x - points[j].chartX, 2) + Math.pow(y + bBox.height - points[j].chartY, 2)
321
+ );
322
+ }
323
+ }
324
+
325
+ // Do we need a connector?
326
+ if (connectorEnabled && this === series && ((checkDistance && !withinRange) ||
327
+ distToOthersSquared < Math.pow(this.options.label.connectorNeighbourDistance, 2))) {
328
+ for (j = 1; j < points.length; j += 1) {
329
+ dist = Math.min(
330
+ Math.pow(x + bBox.width / 2 - points[j].chartX, 2) + Math.pow(y + bBox.height / 2 - points[j].chartY, 2),
331
+ Math.pow(x - points[j].chartX, 2) + Math.pow(y - points[j].chartY, 2),
332
+ Math.pow(x + bBox.width - points[j].chartX, 2) + Math.pow(y - points[j].chartY, 2),
333
+ Math.pow(x + bBox.width - points[j].chartX, 2) + Math.pow(y + bBox.height - points[j].chartY, 2),
334
+ Math.pow(x - points[j].chartX, 2) + Math.pow(y + bBox.height - points[j].chartY, 2)
335
+ );
336
+ if (dist < distToPointSquared) {
337
+ distToPointSquared = dist;
338
+ connectorPoint = points[j];
339
+ }
340
+ }
341
+ withinRange = true;
342
+ }
343
+ }
344
+ }
345
+
346
+ return !checkDistance || withinRange ? {
347
+ x: x,
348
+ y: y,
349
+ weight: getWeight(distToOthersSquared, connectorPoint ? distToPointSquared : 0),
350
+ connectorPoint: connectorPoint
351
+ } : false;
352
+
353
+ };
354
+
355
+ /**
356
+ * The main initiator method that runs on chart level after initiation and redraw. It runs in
357
+ * a timeout to prevent locking, and loops over all series, taking all series and labels into
358
+ * account when placing the labels.
359
+ */
360
+ Chart.prototype.drawSeriesLabels = function() {
361
+ var chart = this,
362
+ labelSeries = this.labelSeries;
363
+
364
+ chart.boxesToAvoid = [];
365
+
366
+ // Build the interpolated points
367
+ each(labelSeries, function(series) {
368
+ series.interpolatedPoints = series.getPointsOnGraph();
369
+
370
+ each(series.options.label.boxesToAvoid || [], function(box) {
371
+ chart.boxesToAvoid.push(box);
372
+ });
373
+ });
374
+
375
+ each(chart.series, function(series) {
376
+ var bBox,
377
+ x,
378
+ y,
379
+ results = [],
380
+ clearPoint,
381
+ i,
382
+ best,
383
+ inverted = chart.inverted,
384
+ paneLeft = inverted ? series.yAxis.pos : series.xAxis.pos,
385
+ paneTop = inverted ? series.xAxis.pos : series.yAxis.pos,
386
+ paneWidth = chart.inverted ? series.yAxis.len : series.xAxis.len,
387
+ paneHeight = chart.inverted ? series.xAxis.len : series.yAxis.len,
388
+ points = series.interpolatedPoints,
389
+ label = series.labelBySeries;
390
+
391
+ function insidePane(x, y, bBox) {
392
+ return x > paneLeft && x <= paneLeft + paneWidth - bBox.width &&
393
+ y >= paneTop && y <= paneTop + paneHeight - bBox.height;
394
+ }
395
+
396
+ if (series.visible && points) {
397
+ if (!label) {
398
+ series.labelBySeries = label = chart.renderer
399
+ .label(series.name, 0, -9999, 'connector')
400
+ .css(extend({
401
+ color: series.color
402
+ }, series.options.label.styles))
403
+ .attr({
404
+ padding: 0,
405
+ opacity: 0,
406
+ stroke: series.color,
407
+ 'stroke-width': 1
408
+ })
409
+ .add(series.group)
410
+ .animate({
411
+ opacity: 1
412
+ }, {
413
+ duration: 200
414
+ });
415
+ }
416
+
417
+ bBox = label.getBBox();
418
+ bBox.width = Math.round(bBox.width);
419
+
420
+ // Ideal positions are centered above or below a point on right side
421
+ // of chart
422
+ for (i = points.length - 1; i > 0; i -= 1) {
423
+
424
+ // Right - up
425
+ x = points[i].chartX + labelDistance;
426
+ y = points[i].chartY - bBox.height - labelDistance;
427
+ if (insidePane(x, y, bBox)) {
428
+ best = series.checkClearPoint(
429
+ x,
430
+ y,
431
+ bBox
432
+ );
433
+ }
434
+ if (best) {
435
+ results.push(best);
436
+ }
437
+
438
+ // Right - down
439
+ x = points[i].chartX + labelDistance;
440
+ y = points[i].chartY + labelDistance;
441
+ if (insidePane(x, y, bBox)) {
442
+ best = series.checkClearPoint(
443
+ x,
444
+ y,
445
+ bBox
446
+ );
447
+ }
448
+ if (best) {
449
+ results.push(best);
450
+ }
451
+
452
+ // Left - down
453
+ x = points[i].chartX - bBox.width - labelDistance;
454
+ y = points[i].chartY + labelDistance;
455
+ if (insidePane(x, y, bBox)) {
456
+ best = series.checkClearPoint(
457
+ x,
458
+ y,
459
+ bBox
460
+ );
461
+ }
462
+ if (best) {
463
+ results.push(best);
464
+ }
465
+
466
+ // Left - up
467
+ x = points[i].chartX - bBox.width - labelDistance;
468
+ y = points[i].chartY - bBox.height - labelDistance;
469
+ if (insidePane(x, y, bBox)) {
470
+ best = series.checkClearPoint(
471
+ x,
472
+ y,
473
+ bBox
474
+ );
475
+ }
476
+ if (best) {
477
+ results.push(best);
478
+ }
479
+
480
+ }
481
+
482
+ // Brute force, try all positions on the chart in a 16x16 grid
483
+ if (!results.length) {
484
+ for (x = paneLeft + paneWidth - bBox.width; x >= paneLeft; x -= 16) {
485
+ for (y = paneTop; y < paneTop + paneHeight - bBox.height; y += 16) {
486
+ clearPoint = series.checkClearPoint(x, y, bBox, true);
487
+ if (clearPoint) {
488
+ results.push(clearPoint);
489
+ }
490
+ }
491
+ }
492
+ }
493
+
494
+ if (results.length) {
495
+
496
+ results.sort(function(a, b) {
497
+ return b.weight - a.weight;
498
+ });
499
+
500
+ best = results[0];
501
+
502
+ chart.boxesToAvoid.push({
503
+ left: best.x,
504
+ right: best.x + bBox.width,
505
+ top: best.y,
506
+ bottom: best.y + bBox.height
507
+ });
508
+
509
+ // Move it if needed
510
+ if (Math.round(best.x) !== Math.round(label.x) ||
511
+ Math.round(best.y) !== Math.round(label.y)) {
512
+ series.labelBySeries
513
+ .attr({
514
+ opacity: 0,
515
+ x: best.x - paneLeft,
516
+ y: best.y - paneTop,
517
+ anchorX: best.connectorPoint && best.connectorPoint.plotX,
518
+ anchorY: best.connectorPoint && best.connectorPoint.plotY
519
+ })
520
+ .animate({
521
+ opacity: 1
522
+ });
523
+
524
+ // Record closest point to stick to for sync redraw
525
+ series.options.kdNow = true;
526
+ series.buildKDTree();
527
+ var closest = series.searchPoint({
528
+ chartX: best.x,
529
+ chartY: best.y
530
+ }, true);
531
+ label.closest = [
532
+ closest,
533
+ best.x - paneLeft - closest.plotX,
534
+ best.y - paneTop - closest.plotY
535
+ ];
536
+
537
+ }
538
+
539
+ } else if (label) {
540
+ series.labelBySeries = label.destroy();
541
+ }
542
+ }
543
+ });
544
+ };
545
+
546
+ /**
547
+ * Prepare drawing series labels
548
+ */
549
+ function drawLabels(proceed) {
550
+
551
+ var chart = this,
552
+ delay = Math.max(
553
+ H.animObject(chart.renderer.globalAnimation).duration,
554
+ 250
555
+ ),
556
+ initial = !chart.hasRendered;
557
+
558
+ proceed.apply(chart, [].slice.call(arguments, 1));
559
+
560
+ chart.labelSeries = [];
561
+
562
+ clearTimeout(chart.seriesLabelTimer);
563
+
564
+ // Which series should have labels
565
+ each(chart.series, function(series) {
566
+ var options = series.options.label,
567
+ label = series.labelBySeries,
568
+ closest = label && label.closest;
569
+
570
+ if (options.enabled && series.visible && (series.graph || series.area)) {
571
+ chart.labelSeries.push(series);
572
+
573
+ // The labels are processing heavy, wait until the animation is done
574
+ if (initial) {
575
+ delay = Math.max(
576
+ delay,
577
+ H.animObject(series.options.animation).duration
578
+ );
579
+ }
580
+
581
+ // Keep the position updated to the axis while redrawing
582
+ if (closest) {
583
+ if (closest[0].plotX !== undefined) {
584
+ label.animate({
585
+ x: closest[0].plotX + closest[1],
586
+ y: closest[0].plotY + closest[2]
587
+ });
588
+ } else {
589
+ label.attr({
590
+ opacity: 0
591
+ });
592
+ }
593
+ }
594
+ }
595
+ });
596
+
597
+ chart.seriesLabelTimer = setTimeout(function() {
598
+ chart.drawSeriesLabels();
599
+ }, delay);
600
+
601
+ }
602
+ wrap(Chart.prototype, 'render', drawLabels);
603
+ wrap(Chart.prototype, 'redraw', drawLabels);
604
+
605
+ }(Highcharts));
606
+ }));