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,881 @@
1
+ /**
2
+ * @license Highcharts JS v5.0.6 (2016-12-07)
3
+ *
4
+ * (c) 2014 Highsoft AS
5
+ * Authors: Jon Arild Nygard / Oystein Moseng
6
+ *
7
+ * License: www.highcharts.com/license
8
+ */
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
+ * (c) 2014 Highsoft AS
19
+ * Authors: Jon Arild Nygard / Oystein Moseng
20
+ *
21
+ * License: www.highcharts.com/license
22
+ */
23
+ 'use strict';
24
+
25
+ var seriesType = H.seriesType,
26
+ seriesTypes = H.seriesTypes,
27
+ map = H.map,
28
+ merge = H.merge,
29
+ extend = H.extend,
30
+ noop = H.noop,
31
+ each = H.each,
32
+ grep = H.grep,
33
+ isNumber = H.isNumber,
34
+ pick = H.pick,
35
+ Series = H.Series,
36
+ stableSort = H.stableSort,
37
+ color = H.Color,
38
+ eachObject = function(list, func, context) {
39
+ var key;
40
+ context = context || this;
41
+ for (key in list) {
42
+ if (list.hasOwnProperty(key)) {
43
+ func.call(context, list[key], key, list);
44
+ }
45
+ }
46
+ },
47
+ reduce = function(arr, func, previous, context) {
48
+ context = context || this;
49
+ arr = arr || []; // @note should each be able to handle empty values automatically?
50
+ each(arr, function(current, i) {
51
+ previous = func.call(context, previous, current, i, arr);
52
+ });
53
+ return previous;
54
+ },
55
+ // @todo find correct name for this function.
56
+ // @todo Similar to reduce, this function is likely redundant
57
+ recursive = function(item, func, context) {
58
+ var next;
59
+ context = context || this;
60
+ next = func.call(context, item);
61
+ if (next !== false) {
62
+ recursive(next, func, context);
63
+ }
64
+ };
65
+
66
+ // The Treemap series type
67
+ seriesType('treemap', 'scatter', {
68
+ showInLegend: false,
69
+ marker: false,
70
+ dataLabels: {
71
+ enabled: true,
72
+ defer: false,
73
+ verticalAlign: 'middle',
74
+ formatter: function() { // #2945
75
+ return this.point.name || this.point.id;
76
+ },
77
+ inside: true
78
+ },
79
+ tooltip: {
80
+ headerFormat: '',
81
+ pointFormat: '<b>{point.name}</b>: {point.value}</b><br/>'
82
+ },
83
+ layoutAlgorithm: 'sliceAndDice',
84
+ layoutStartingDirection: 'vertical',
85
+ alternateStartingDirection: false,
86
+ levelIsConstant: true,
87
+ drillUpButton: {
88
+ position: {
89
+ align: 'right',
90
+ x: -10,
91
+ y: 10
92
+ }
93
+ },
94
+
95
+
96
+ // Prototype members
97
+ }, {
98
+ pointArrayMap: ['value'],
99
+ axisTypes: seriesTypes.heatmap ? ['xAxis', 'yAxis', 'colorAxis'] : ['xAxis', 'yAxis'],
100
+ optionalAxis: 'colorAxis',
101
+ getSymbol: noop,
102
+ parallelArrays: ['x', 'y', 'value', 'colorValue'],
103
+ colorKey: 'colorValue', // Point color option key
104
+ translateColors: seriesTypes.heatmap && seriesTypes.heatmap.prototype.translateColors,
105
+ trackerGroups: ['group', 'dataLabelsGroup'],
106
+ /**
107
+ * Creates an object map from parent id to childrens index.
108
+ * @param {Array} data List of points set in options.
109
+ * @param {string} data[].parent Parent id of point.
110
+ * @param {Array} ids List of all point ids.
111
+ * @return {Object} Map from parent id to children index in data.
112
+ */
113
+ getListOfParents: function(data, ids) {
114
+ var listOfParents = reduce(data, function(prev, curr, i) {
115
+ var parent = pick(curr.parent, '');
116
+ if (prev[parent] === undefined) {
117
+ prev[parent] = [];
118
+ }
119
+ prev[parent].push(i);
120
+ return prev;
121
+ }, {});
122
+
123
+ // If parent does not exist, hoist parent to root of tree.
124
+ eachObject(listOfParents, function(children, parent, list) {
125
+ if ((parent !== '') && (H.inArray(parent, ids) === -1)) {
126
+ each(children, function(child) {
127
+ list[''].push(child);
128
+ });
129
+ delete list[parent];
130
+ }
131
+ });
132
+ return listOfParents;
133
+ },
134
+ /**
135
+ * Creates a tree structured object from the series points
136
+ */
137
+ getTree: function() {
138
+ var tree,
139
+ series = this,
140
+ allIds = map(this.data, function(d) {
141
+ return d.id;
142
+ }),
143
+ parentList = series.getListOfParents(this.data, allIds);
144
+
145
+ series.nodeMap = [];
146
+ tree = series.buildNode('', -1, 0, parentList, null);
147
+ // Parents of the root node is by default visible
148
+ recursive(this.nodeMap[this.rootNode], function(node) {
149
+ var next = false,
150
+ p = node.parent;
151
+ node.visible = true;
152
+ if (p || p === '') {
153
+ next = series.nodeMap[p];
154
+ }
155
+ return next;
156
+ });
157
+ // Children of the root node is by default visible
158
+ recursive(this.nodeMap[this.rootNode].children, function(children) {
159
+ var next = false;
160
+ each(children, function(child) {
161
+ child.visible = true;
162
+ if (child.children.length) {
163
+ next = (next || []).concat(child.children);
164
+ }
165
+ });
166
+ return next;
167
+ });
168
+ this.setTreeValues(tree);
169
+ return tree;
170
+ },
171
+ init: function(chart, options) {
172
+ var series = this;
173
+ Series.prototype.init.call(series, chart, options);
174
+ if (series.options.allowDrillToNode) {
175
+ series.drillTo();
176
+ }
177
+ },
178
+ buildNode: function(id, i, level, list, parent) {
179
+ var series = this,
180
+ children = [],
181
+ point = series.points[i],
182
+ node,
183
+ child;
184
+
185
+ // Actions
186
+ each((list[id] || []), function(i) {
187
+ child = series.buildNode(series.points[i].id, i, (level + 1), list, id);
188
+ children.push(child);
189
+ });
190
+ node = {
191
+ id: id,
192
+ i: i,
193
+ children: children,
194
+ level: level,
195
+ parent: parent,
196
+ visible: false // @todo move this to better location
197
+ };
198
+ series.nodeMap[node.id] = node;
199
+ if (point) {
200
+ point.node = node;
201
+ }
202
+ return node;
203
+ },
204
+ setTreeValues: function(tree) {
205
+ var series = this,
206
+ options = series.options,
207
+ childrenTotal = 0,
208
+ children = [],
209
+ val,
210
+ point = series.points[tree.i];
211
+
212
+ // First give the children some values
213
+ each(tree.children, function(child) {
214
+ child = series.setTreeValues(child);
215
+ children.push(child);
216
+
217
+ if (!child.ignore) {
218
+ childrenTotal += child.val;
219
+ } else {
220
+ // @todo Add predicate to avoid looping already ignored children
221
+ recursive(child.children, function(children) {
222
+ var next = false;
223
+ each(children, function(node) {
224
+ extend(node, {
225
+ ignore: true,
226
+ isLeaf: false,
227
+ visible: false
228
+ });
229
+ if (node.children.length) {
230
+ next = (next || []).concat(node.children);
231
+ }
232
+ });
233
+ return next;
234
+ });
235
+ }
236
+ });
237
+ // Sort the children
238
+ stableSort(children, function(a, b) {
239
+ return a.sortIndex - b.sortIndex;
240
+ });
241
+ // Set the values
242
+ val = pick(point && point.options.value, childrenTotal);
243
+ if (point) {
244
+ point.value = val;
245
+ }
246
+ extend(tree, {
247
+ children: children,
248
+ childrenTotal: childrenTotal,
249
+ // Ignore this node if point is not visible
250
+ ignore: !(pick(point && point.visible, true) && (val > 0)),
251
+ isLeaf: tree.visible && !childrenTotal,
252
+ levelDynamic: (options.levelIsConstant ? tree.level : (tree.level - series.nodeMap[series.rootNode].level)),
253
+ name: pick(point && point.name, ''),
254
+ sortIndex: pick(point && point.sortIndex, -val),
255
+ val: val
256
+ });
257
+ return tree;
258
+ },
259
+ /**
260
+ * Recursive function which calculates the area for all children of a node.
261
+ * @param {Object} node The node which is parent to the children.
262
+ * @param {Object} area The rectangular area of the parent.
263
+ */
264
+ calculateChildrenAreas: function(parent, area) {
265
+ var series = this,
266
+ options = series.options,
267
+ level = this.levelMap[parent.levelDynamic + 1],
268
+ algorithm = pick((series[level && level.layoutAlgorithm] && level.layoutAlgorithm), options.layoutAlgorithm),
269
+ alternate = options.alternateStartingDirection,
270
+ childrenValues = [],
271
+ children;
272
+
273
+ // Collect all children which should be included
274
+ children = grep(parent.children, function(n) {
275
+ return !n.ignore;
276
+ });
277
+
278
+ if (level && level.layoutStartingDirection) {
279
+ area.direction = level.layoutStartingDirection === 'vertical' ? 0 : 1;
280
+ }
281
+ childrenValues = series[algorithm](area, children);
282
+ each(children, function(child, index) {
283
+ var values = childrenValues[index];
284
+ child.values = merge(values, {
285
+ val: child.childrenTotal,
286
+ direction: (alternate ? 1 - area.direction : area.direction)
287
+ });
288
+ child.pointValues = merge(values, {
289
+ x: (values.x / series.axisRatio),
290
+ width: (values.width / series.axisRatio)
291
+ });
292
+ // If node has children, then call method recursively
293
+ if (child.children.length) {
294
+ series.calculateChildrenAreas(child, child.values);
295
+ }
296
+ });
297
+ },
298
+ setPointValues: function() {
299
+ var series = this,
300
+ xAxis = series.xAxis,
301
+ yAxis = series.yAxis;
302
+ each(series.points, function(point) {
303
+ var node = point.node,
304
+ values = node.pointValues,
305
+ x1,
306
+ x2,
307
+ y1,
308
+ y2,
309
+ crispCorr = 0.5; // Assume 1px borderWidth for simplicity
310
+
311
+ // Points which is ignored, have no values.
312
+ if (values && node.visible) {
313
+ x1 = Math.round(xAxis.translate(values.x, 0, 0, 0, 1)) - crispCorr;
314
+ x2 = Math.round(xAxis.translate(values.x + values.width, 0, 0, 0, 1)) - crispCorr;
315
+ y1 = Math.round(yAxis.translate(values.y, 0, 0, 0, 1)) - crispCorr;
316
+ y2 = Math.round(yAxis.translate(values.y + values.height, 0, 0, 0, 1)) - crispCorr;
317
+ // Set point values
318
+ point.shapeType = 'rect';
319
+ point.shapeArgs = {
320
+ x: Math.min(x1, x2),
321
+ y: Math.min(y1, y2),
322
+ width: Math.abs(x2 - x1),
323
+ height: Math.abs(y2 - y1)
324
+ };
325
+ point.plotX = point.shapeArgs.x + (point.shapeArgs.width / 2);
326
+ point.plotY = point.shapeArgs.y + (point.shapeArgs.height / 2);
327
+ } else {
328
+ // Reset visibility
329
+ delete point.plotX;
330
+ delete point.plotY;
331
+ }
332
+ });
333
+ },
334
+ setColorRecursive: function(node, color, colorIndex) {
335
+ var series = this,
336
+ point,
337
+ level;
338
+ if (node) {
339
+ point = series.points[node.i];
340
+ level = series.levelMap[node.levelDynamic];
341
+ // Select either point color, level color or inherited color.
342
+ color = pick(point && point.options.color, level && level.color, color);
343
+ colorIndex = pick(point && point.options.colorIndex, level && level.colorIndex, colorIndex);
344
+ if (point) {
345
+ point.color = color;
346
+ point.colorIndex = colorIndex;
347
+ }
348
+
349
+ // Do it all again with the children
350
+ if (node.children.length) {
351
+ each(node.children, function(child) {
352
+ series.setColorRecursive(child, color, colorIndex);
353
+ });
354
+ }
355
+ }
356
+ },
357
+ algorithmGroup: function(h, w, d, p) {
358
+ this.height = h;
359
+ this.width = w;
360
+ this.plot = p;
361
+ this.direction = d;
362
+ this.startDirection = d;
363
+ this.total = 0;
364
+ this.nW = 0;
365
+ this.lW = 0;
366
+ this.nH = 0;
367
+ this.lH = 0;
368
+ this.elArr = [];
369
+ this.lP = {
370
+ total: 0,
371
+ lH: 0,
372
+ nH: 0,
373
+ lW: 0,
374
+ nW: 0,
375
+ nR: 0,
376
+ lR: 0,
377
+ aspectRatio: function(w, h) {
378
+ return Math.max((w / h), (h / w));
379
+ }
380
+ };
381
+ this.addElement = function(el) {
382
+ this.lP.total = this.elArr[this.elArr.length - 1];
383
+ this.total = this.total + el;
384
+ if (this.direction === 0) {
385
+ // Calculate last point old aspect ratio
386
+ this.lW = this.nW;
387
+ this.lP.lH = this.lP.total / this.lW;
388
+ this.lP.lR = this.lP.aspectRatio(this.lW, this.lP.lH);
389
+ // Calculate last point new aspect ratio
390
+ this.nW = this.total / this.height;
391
+ this.lP.nH = this.lP.total / this.nW;
392
+ this.lP.nR = this.lP.aspectRatio(this.nW, this.lP.nH);
393
+ } else {
394
+ // Calculate last point old aspect ratio
395
+ this.lH = this.nH;
396
+ this.lP.lW = this.lP.total / this.lH;
397
+ this.lP.lR = this.lP.aspectRatio(this.lP.lW, this.lH);
398
+ // Calculate last point new aspect ratio
399
+ this.nH = this.total / this.width;
400
+ this.lP.nW = this.lP.total / this.nH;
401
+ this.lP.nR = this.lP.aspectRatio(this.lP.nW, this.nH);
402
+ }
403
+ this.elArr.push(el);
404
+ };
405
+ this.reset = function() {
406
+ this.nW = 0;
407
+ this.lW = 0;
408
+ this.elArr = [];
409
+ this.total = 0;
410
+ };
411
+ },
412
+ algorithmCalcPoints: function(directionChange, last, group, childrenArea) {
413
+ var pX,
414
+ pY,
415
+ pW,
416
+ pH,
417
+ gW = group.lW,
418
+ gH = group.lH,
419
+ plot = group.plot,
420
+ keep,
421
+ i = 0,
422
+ end = group.elArr.length - 1;
423
+ if (last) {
424
+ gW = group.nW;
425
+ gH = group.nH;
426
+ } else {
427
+ keep = group.elArr[group.elArr.length - 1];
428
+ }
429
+ each(group.elArr, function(p) {
430
+ if (last || (i < end)) {
431
+ if (group.direction === 0) {
432
+ pX = plot.x;
433
+ pY = plot.y;
434
+ pW = gW;
435
+ pH = p / pW;
436
+ } else {
437
+ pX = plot.x;
438
+ pY = plot.y;
439
+ pH = gH;
440
+ pW = p / pH;
441
+ }
442
+ childrenArea.push({
443
+ x: pX,
444
+ y: pY,
445
+ width: pW,
446
+ height: pH
447
+ });
448
+ if (group.direction === 0) {
449
+ plot.y = plot.y + pH;
450
+ } else {
451
+ plot.x = plot.x + pW;
452
+ }
453
+ }
454
+ i = i + 1;
455
+ });
456
+ // Reset variables
457
+ group.reset();
458
+ if (group.direction === 0) {
459
+ group.width = group.width - gW;
460
+ } else {
461
+ group.height = group.height - gH;
462
+ }
463
+ plot.y = plot.parent.y + (plot.parent.height - group.height);
464
+ plot.x = plot.parent.x + (plot.parent.width - group.width);
465
+ if (directionChange) {
466
+ group.direction = 1 - group.direction;
467
+ }
468
+ // If not last, then add uncalculated element
469
+ if (!last) {
470
+ group.addElement(keep);
471
+ }
472
+ },
473
+ algorithmLowAspectRatio: function(directionChange, parent, children) {
474
+ var childrenArea = [],
475
+ series = this,
476
+ pTot,
477
+ plot = {
478
+ x: parent.x,
479
+ y: parent.y,
480
+ parent: parent
481
+ },
482
+ direction = parent.direction,
483
+ i = 0,
484
+ end = children.length - 1,
485
+ group = new this.algorithmGroup(parent.height, parent.width, direction, plot); // eslint-disable-line new-cap
486
+ // Loop through and calculate all areas
487
+ each(children, function(child) {
488
+ pTot = (parent.width * parent.height) * (child.val / parent.val);
489
+ group.addElement(pTot);
490
+ if (group.lP.nR > group.lP.lR) {
491
+ series.algorithmCalcPoints(directionChange, false, group, childrenArea, plot);
492
+ }
493
+ // If last child, then calculate all remaining areas
494
+ if (i === end) {
495
+ series.algorithmCalcPoints(directionChange, true, group, childrenArea, plot);
496
+ }
497
+ i = i + 1;
498
+ });
499
+ return childrenArea;
500
+ },
501
+ algorithmFill: function(directionChange, parent, children) {
502
+ var childrenArea = [],
503
+ pTot,
504
+ direction = parent.direction,
505
+ x = parent.x,
506
+ y = parent.y,
507
+ width = parent.width,
508
+ height = parent.height,
509
+ pX,
510
+ pY,
511
+ pW,
512
+ pH;
513
+ each(children, function(child) {
514
+ pTot = (parent.width * parent.height) * (child.val / parent.val);
515
+ pX = x;
516
+ pY = y;
517
+ if (direction === 0) {
518
+ pH = height;
519
+ pW = pTot / pH;
520
+ width = width - pW;
521
+ x = x + pW;
522
+ } else {
523
+ pW = width;
524
+ pH = pTot / pW;
525
+ height = height - pH;
526
+ y = y + pH;
527
+ }
528
+ childrenArea.push({
529
+ x: pX,
530
+ y: pY,
531
+ width: pW,
532
+ height: pH
533
+ });
534
+ if (directionChange) {
535
+ direction = 1 - direction;
536
+ }
537
+ });
538
+ return childrenArea;
539
+ },
540
+ strip: function(parent, children) {
541
+ return this.algorithmLowAspectRatio(false, parent, children);
542
+ },
543
+ squarified: function(parent, children) {
544
+ return this.algorithmLowAspectRatio(true, parent, children);
545
+ },
546
+ sliceAndDice: function(parent, children) {
547
+ return this.algorithmFill(true, parent, children);
548
+ },
549
+ stripes: function(parent, children) {
550
+ return this.algorithmFill(false, parent, children);
551
+ },
552
+ translate: function() {
553
+ var pointValues,
554
+ seriesArea,
555
+ tree,
556
+ val;
557
+
558
+ // Call prototype function
559
+ Series.prototype.translate.call(this);
560
+
561
+ // Assign variables
562
+ this.rootNode = pick(this.options.rootId, '');
563
+ // Create a object map from level to options
564
+ this.levelMap = reduce(this.options.levels, function(arr, item) {
565
+ arr[item.level] = item;
566
+ return arr;
567
+ }, {});
568
+ tree = this.tree = this.getTree(); // @todo Only if series.isDirtyData is true
569
+
570
+ // Calculate plotting values.
571
+ this.axisRatio = (this.xAxis.len / this.yAxis.len);
572
+ this.nodeMap[''].pointValues = pointValues = {
573
+ x: 0,
574
+ y: 0,
575
+ width: 100,
576
+ height: 100
577
+ };
578
+ this.nodeMap[''].values = seriesArea = merge(pointValues, {
579
+ width: (pointValues.width * this.axisRatio),
580
+ direction: (this.options.layoutStartingDirection === 'vertical' ? 0 : 1),
581
+ val: tree.val
582
+ });
583
+ this.calculateChildrenAreas(tree, seriesArea);
584
+
585
+ // Logic for point colors
586
+ if (this.colorAxis) {
587
+ this.translateColors();
588
+ } else if (!this.options.colorByPoint) {
589
+ this.setColorRecursive(this.tree);
590
+ }
591
+
592
+ // Update axis extremes according to the root node.
593
+ if (this.options.allowDrillToNode) {
594
+ val = this.nodeMap[this.rootNode].pointValues;
595
+ this.xAxis.setExtremes(val.x, val.x + val.width, false);
596
+ this.yAxis.setExtremes(val.y, val.y + val.height, false);
597
+ this.xAxis.setScale();
598
+ this.yAxis.setScale();
599
+ }
600
+
601
+ // Assign values to points.
602
+ this.setPointValues();
603
+ },
604
+ /**
605
+ * Extend drawDataLabels with logic to handle custom options related to the treemap series:
606
+ * - Points which is not a leaf node, has dataLabels disabled by default.
607
+ * - Options set on series.levels is merged in.
608
+ * - Width of the dataLabel is set to match the width of the point shape.
609
+ */
610
+ drawDataLabels: function() {
611
+ var series = this,
612
+ points = grep(series.points, function(n) {
613
+ return n.node.visible;
614
+ }),
615
+ options,
616
+ level;
617
+ each(points, function(point) {
618
+ level = series.levelMap[point.node.levelDynamic];
619
+ // Set options to new object to avoid problems with scope
620
+ options = {
621
+ style: {}
622
+ };
623
+
624
+ // If not a leaf, then label should be disabled as default
625
+ if (!point.node.isLeaf) {
626
+ options.enabled = false;
627
+ }
628
+
629
+ // If options for level exists, include them as well
630
+ if (level && level.dataLabels) {
631
+ options = merge(options, level.dataLabels);
632
+ series._hasPointLabels = true;
633
+ }
634
+
635
+ // Set dataLabel width to the width of the point shape.
636
+ if (point.shapeArgs) {
637
+ options.style.width = point.shapeArgs.width;
638
+ if (point.dataLabel) {
639
+ point.dataLabel.css({
640
+ width: point.shapeArgs.width + 'px'
641
+ });
642
+ }
643
+ }
644
+
645
+ // Merge custom options with point options
646
+ point.dlOptions = merge(options, point.options.dataLabels);
647
+ });
648
+ Series.prototype.drawDataLabels.call(this);
649
+ },
650
+
651
+ /**
652
+ * Over the alignment method by setting z index
653
+ */
654
+ alignDataLabel: function(point) {
655
+ seriesTypes.column.prototype.alignDataLabel.apply(this, arguments);
656
+ if (point.dataLabel) {
657
+ point.dataLabel.attr({
658
+ zIndex: point.node.zIndex + 1
659
+ });
660
+ }
661
+ },
662
+
663
+
664
+
665
+ /**
666
+ * Extending ColumnSeries drawPoints
667
+ */
668
+ drawPoints: function() {
669
+ var series = this,
670
+ points = grep(series.points, function(n) {
671
+ return n.node.visible;
672
+ });
673
+
674
+ each(points, function(point) {
675
+ var groupKey = 'levelGroup-' + point.node.levelDynamic;
676
+ if (!series[groupKey]) {
677
+ series[groupKey] = series.chart.renderer.g(groupKey)
678
+ .attr({
679
+ zIndex: 1000 - point.node.levelDynamic // @todo Set the zIndex based upon the number of levels, instead of using 1000
680
+ })
681
+ .add(series.group);
682
+ }
683
+ point.group = series[groupKey];
684
+
685
+ });
686
+ // Call standard drawPoints
687
+ seriesTypes.column.prototype.drawPoints.call(this);
688
+
689
+ // If drillToNode is allowed, set a point cursor on clickables & add drillId to point
690
+ if (series.options.allowDrillToNode) {
691
+ each(points, function(point) {
692
+ if (point.graphic) {
693
+ point.drillId = series.options.interactByLeaf ? series.drillToByLeaf(point) : series.drillToByGroup(point);
694
+ }
695
+ });
696
+ }
697
+ },
698
+ /**
699
+ * Add drilling on the suitable points
700
+ */
701
+ drillTo: function() {
702
+ var series = this;
703
+ H.addEvent(series, 'click', function(event) {
704
+ var point = event.point,
705
+ drillId = point.drillId,
706
+ drillName;
707
+ // If a drill id is returned, add click event and cursor.
708
+ if (drillId) {
709
+ drillName = series.nodeMap[series.rootNode].name || series.rootNode;
710
+ point.setState(''); // Remove hover
711
+ series.drillToNode(drillId);
712
+ series.showDrillUpButton(drillName);
713
+ }
714
+ });
715
+ },
716
+ /**
717
+ * Finds the drill id for a parent node.
718
+ * Returns false if point should not have a click event
719
+ * @param {Object} point
720
+ * @return {string || boolean} Drill to id or false when point should not have a click event
721
+ */
722
+ drillToByGroup: function(point) {
723
+ var series = this,
724
+ drillId = false;
725
+ if ((point.node.level - series.nodeMap[series.rootNode].level) === 1 && !point.node.isLeaf) {
726
+ drillId = point.id;
727
+ }
728
+ return drillId;
729
+ },
730
+ /**
731
+ * Finds the drill id for a leaf node.
732
+ * Returns false if point should not have a click event
733
+ * @param {Object} point
734
+ * @return {string || boolean} Drill to id or false when point should not have a click event
735
+ */
736
+ drillToByLeaf: function(point) {
737
+ var series = this,
738
+ drillId = false,
739
+ nodeParent;
740
+ if ((point.node.parent !== series.rootNode) && (point.node.isLeaf)) {
741
+ nodeParent = point.node;
742
+ while (!drillId) {
743
+ nodeParent = series.nodeMap[nodeParent.parent];
744
+ if (nodeParent.parent === series.rootNode) {
745
+ drillId = nodeParent.id;
746
+ }
747
+ }
748
+ }
749
+ return drillId;
750
+ },
751
+ drillUp: function() {
752
+ var drillPoint = null,
753
+ node,
754
+ parent;
755
+ if (this.rootNode) {
756
+ node = this.nodeMap[this.rootNode];
757
+ if (node.parent !== null) {
758
+ drillPoint = this.nodeMap[node.parent];
759
+ } else {
760
+ drillPoint = this.nodeMap[''];
761
+ }
762
+ }
763
+
764
+ if (drillPoint !== null) {
765
+ this.drillToNode(drillPoint.id);
766
+ if (drillPoint.id === '') {
767
+ this.drillUpButton = this.drillUpButton.destroy();
768
+ } else {
769
+ parent = this.nodeMap[drillPoint.parent];
770
+ this.showDrillUpButton((parent.name || parent.id));
771
+ }
772
+ }
773
+ },
774
+ drillToNode: function(id) {
775
+ this.options.rootId = id;
776
+ this.isDirty = true; // Force redraw
777
+ this.chart.redraw();
778
+ },
779
+ showDrillUpButton: function(name) {
780
+ var series = this,
781
+ backText = (name || '< Back'),
782
+ buttonOptions = series.options.drillUpButton,
783
+ attr,
784
+ states;
785
+
786
+ if (buttonOptions.text) {
787
+ backText = buttonOptions.text;
788
+ }
789
+ if (!this.drillUpButton) {
790
+ attr = buttonOptions.theme;
791
+ states = attr && attr.states;
792
+
793
+ this.drillUpButton = this.chart.renderer.button(
794
+ backText,
795
+ null,
796
+ null,
797
+ function() {
798
+ series.drillUp();
799
+ },
800
+ attr,
801
+ states && states.hover,
802
+ states && states.select
803
+ )
804
+ .attr({
805
+ align: buttonOptions.position.align,
806
+ zIndex: 7
807
+ })
808
+ .add()
809
+ .align(buttonOptions.position, false, buttonOptions.relativeTo || 'plotBox');
810
+ } else {
811
+ this.drillUpButton.attr({
812
+ text: backText
813
+ })
814
+ .align();
815
+ }
816
+ },
817
+ buildKDTree: noop,
818
+ drawLegendSymbol: H.LegendSymbolMixin.drawRectangle,
819
+ getExtremes: function() {
820
+ // Get the extremes from the value data
821
+ Series.prototype.getExtremes.call(this, this.colorValueData);
822
+ this.valueMin = this.dataMin;
823
+ this.valueMax = this.dataMax;
824
+
825
+ // Get the extremes from the y data
826
+ Series.prototype.getExtremes.call(this);
827
+ },
828
+ getExtremesFromAll: true,
829
+ bindAxes: function() {
830
+ var treeAxis = {
831
+ endOnTick: false,
832
+ gridLineWidth: 0,
833
+ lineWidth: 0,
834
+ min: 0,
835
+ dataMin: 0,
836
+ minPadding: 0,
837
+ max: 100,
838
+ dataMax: 100,
839
+ maxPadding: 0,
840
+ startOnTick: false,
841
+ title: null,
842
+ tickPositions: []
843
+ };
844
+ Series.prototype.bindAxes.call(this);
845
+ H.extend(this.yAxis.options, treeAxis);
846
+ H.extend(this.xAxis.options, treeAxis);
847
+ }
848
+
849
+ // Point class
850
+ }, {
851
+ getClassName: function() {
852
+ var className = H.Point.prototype.getClassName.call(this),
853
+ series = this.series,
854
+ options = series.options;
855
+
856
+ // Above the current level
857
+ if (this.node.level <= series.nodeMap[series.rootNode].level) {
858
+ className += ' highcharts-above-level';
859
+
860
+ } else if (!this.node.isLeaf && !pick(options.interactByLeaf, !options.allowDrillToNode)) {
861
+ className += ' highcharts-internal-node-interactive';
862
+
863
+ } else if (!this.node.isLeaf) {
864
+ className += ' highcharts-internal-node';
865
+ }
866
+ return className;
867
+ },
868
+ isValid: function() {
869
+ return isNumber(this.value);
870
+ },
871
+ setState: function(state) {
872
+ H.Point.prototype.setState.call(this, state);
873
+ this.graphic.attr({
874
+ zIndex: state === 'hover' ? 1 : 0
875
+ });
876
+ },
877
+ setVisible: seriesTypes.pie.prototype.pointClass.prototype.setVisible
878
+ });
879
+
880
+ }(Highcharts));
881
+ }));