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