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,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
+ }));