highcharts_rails 0.1.0

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