highcharts-rails 4.1.8 → 4.1.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v4.1.8 (2015-08-20)
2
+ * @license Highcharts JS v4.1.9 (2015-10-07)
3
3
  * Data module
4
4
  *
5
5
  * (c) 2012-2014 Torstein Honsi
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v4.1.8 (2015-08-20)
2
+ * @license Highcharts JS v4.1.9 (2015-10-07)
3
3
  * Exporting module
4
4
  *
5
5
  * (c) 2010-2014 Torstein Honsi
@@ -293,7 +293,8 @@ extend(Chart.prototype, {
293
293
  extend(options.chart, {
294
294
  animation: false,
295
295
  renderTo: sandbox,
296
- forExport: !allowHTML,
296
+ forExport: true,
297
+ renderer: 'SVGRenderer',
297
298
  width: sourceWidth,
298
299
  height: sourceHeight
299
300
  });
@@ -353,7 +354,7 @@ extend(Chart.prototype, {
353
354
  if (allowHTML) {
354
355
  html = svg.match(/<\/svg>(.*?$)/);
355
356
  if (html) {
356
- html = '<foreignObject x="0" y="0 width="200" height="200">' +
357
+ html = '<foreignObject x="0" y="0" width="200" height="200">' +
357
358
  '<body xmlns="http://www.w3.org/1999/xhtml">' +
358
359
  html[1] +
359
360
  '</body>' +
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v4.1.8 (2015-08-20)
2
+ * @license Highcharts JS v4.1.9 (2015-10-07)
3
3
  *
4
4
  * (c) 2011-2014 Torstein Honsi
5
5
  *
@@ -256,20 +256,23 @@ extend(ColorAxis.prototype, {
256
256
  return color;
257
257
  },
258
258
 
259
+ /**
260
+ * Override the getOffset method to add the whole axis groups inside the legend.
261
+ */
259
262
  getOffset: function () {
260
263
  var group = this.legendGroup,
261
264
  sideOffset = this.chart.axisOffset[this.side];
262
265
 
263
266
  if (group) {
264
267
 
268
+ // Hook for the getOffset method to add groups to this parent group
269
+ this.axisParent = group;
270
+
271
+ // Call the base
265
272
  Axis.prototype.getOffset.call(this);
266
-
267
- if (!this.axisGroup.parentGroup) {
268
273
 
269
- // Move the axis elements inside the legend group
270
- this.axisGroup.add(group);
271
- this.gridGroup.add(group);
272
- this.labelGroup.add(group);
274
+ // First time only
275
+ if (!this.added) {
273
276
 
274
277
  this.added = true;
275
278
 
@@ -644,17 +647,20 @@ seriesTypes.heatmap = extendClass(seriesTypes.scatter, merge(colorSeriesMixin, {
644
647
  var series = this,
645
648
  options = series.options,
646
649
  xAxis = series.xAxis,
647
- yAxis = series.yAxis;
650
+ yAxis = series.yAxis,
651
+ between = function (x, a, b) {
652
+ return Math.min(Math.max(a, x), b);
653
+ };
648
654
 
649
655
  series.generatePoints();
650
656
 
651
657
  each(series.points, function (point) {
652
658
  var xPad = (options.colsize || 1) / 2,
653
659
  yPad = (options.rowsize || 1) / 2,
654
- x1 = Math.round(xAxis.len - xAxis.translate(point.x - xPad, 0, 1, 0, 1)),
655
- x2 = Math.round(xAxis.len - xAxis.translate(point.x + xPad, 0, 1, 0, 1)),
656
- y1 = Math.round(yAxis.translate(point.y - yPad, 0, 1, 0, 1)),
657
- y2 = Math.round(yAxis.translate(point.y + yPad, 0, 1, 0, 1));
660
+ x1 = between(Math.round(xAxis.len - xAxis.translate(point.x - xPad, 0, 1, 0, 1)), 0, xAxis.len),
661
+ x2 = between(Math.round(xAxis.len - xAxis.translate(point.x + xPad, 0, 1, 0, 1)), 0, xAxis.len),
662
+ y1 = between(Math.round(yAxis.translate(point.y - yPad, 0, 1, 0, 1)), 0, yAxis.len),
663
+ y2 = between(Math.round(yAxis.translate(point.y + yPad, 0, 1, 0, 1)), 0, yAxis.len);
658
664
 
659
665
  // Set plotX and plotY for use in K-D-Tree and more
660
666
  point.plotX = point.clientX = (x1 + x2) / 2;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v4.1.8 (2015-08-20)
2
+ * @license Highcharts JS v4.1.9 (2015-10-07)
3
3
  * Plugin for displaying a message when there is no data visible in chart.
4
4
  *
5
5
  * (c) 2010-2014 Highsoft AS
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v4.1.8 (2015-08-20)
2
+ * @license Highcharts JS v4.1.9 (2015-10-07)
3
3
  * Client side exporting module
4
4
  *
5
5
  * (c) 2015 Torstein Honsi / Oystein Moseng
@@ -85,7 +85,8 @@ Highcharts.Chart.prototype.exportChartLocal = function (exportingOptions, chartO
85
85
  svgToDataUrl = function (svg) {
86
86
  try {
87
87
  // Safari requires data URI since it doesn't allow navigation to blob URLs
88
- if (!webKit) {
88
+ // Firefox has an issue with Blobs and internal references, leading to gradients not working using Blobs (#4550)
89
+ if (!webKit && navigator.userAgent.toLowerCase().indexOf('firefox') < 0) {
89
90
  return domurl.createObjectURL(new Blob([svg], { type: 'image/svg+xml;charset-utf-16'}));
90
91
  }
91
92
  } catch (e) {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v4.1.8 (2015-08-20)
2
+ * @license Highcharts JS v4.1.9 (2015-10-07)
3
3
  * Solid angular gauge module
4
4
  *
5
5
  * (c) 2010-2014 Torstein Honsi
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v4.1.8 (2015-08-20)
2
+ * @license Highcharts JS v4.1.9 (2015-10-07)
3
3
  *
4
4
  * (c) 2014 Highsoft AS
5
5
  * Authors: Jon Arild Nygard / Oystein Moseng
@@ -10,6 +10,7 @@
10
10
  /*global HighchartsAdapter */
11
11
  (function (H) {
12
12
  var seriesTypes = H.seriesTypes,
13
+ map = H.map,
13
14
  merge = H.merge,
14
15
  extend = H.extend,
15
16
  extendClass = H.extendClass,
@@ -20,7 +21,33 @@
20
21
  grep = HighchartsAdapter.grep,
21
22
  pick = H.pick,
22
23
  Series = H.Series,
23
- Color = H.Color;
24
+ Color = H.Color,
25
+ eachObject = function (list, func, context) {
26
+ var key;
27
+ context = context || this;
28
+ for (key in list) {
29
+ if (list.hasOwnProperty(key)) {
30
+ func.call(context, list[key], key, list);
31
+ }
32
+ }
33
+ },
34
+ reduce = function (arr, func, previous, context) {
35
+ context = context || this;
36
+ arr = arr || []; // @note should each be able to handle empty values automatically?
37
+ each(arr, function (current, i) {
38
+ previous = func.call(context, previous, current, i, arr);
39
+ });
40
+ return previous;
41
+ },
42
+ // @todo find correct name for this function.
43
+ recursive = function (item, func, context) {
44
+ var next;
45
+ context = context || this;
46
+ next = func.call(context, item);
47
+ if (next !== false) {
48
+ recursive(next, func, context);
49
+ }
50
+ };
24
51
 
25
52
  // Define default options
26
53
  plotOptions.treemap = merge(plotOptions.scatter, {
@@ -64,12 +91,7 @@
64
91
  // Stolen from heatmap
65
92
  var colorSeriesMixin = {
66
93
  // mapping between SVG attributes and the corresponding options
67
- pointAttrToOptions: {
68
- stroke: 'borderColor',
69
- 'stroke-width': 'borderWidth',
70
- fill: 'color',
71
- dashstyle: 'borderDashStyle'
72
- },
94
+ pointAttrToOptions: {},
73
95
  pointArrayMap: ['value'],
74
96
  axisTypes: seriesTypes.heatmap ? ['xAxis', 'yAxis', 'colorAxis'] : ['xAxis', 'yAxis'],
75
97
  optionalAxis: 'colorAxis',
@@ -84,33 +106,35 @@
84
106
  type: 'treemap',
85
107
  trackerGroups: ['group', 'dataLabelsGroup'],
86
108
  pointClass: extendClass(H.Point, {
87
- setState: function (state, move) {
88
- H.Point.prototype.setState.call(this, state, move);
89
- if (state === 'hover') {
90
- if (this.dataLabel) {
91
- this.dataLabel.attr({ zIndex: 1002 });
92
- }
93
- } else {
94
- if (this.dataLabel) {
95
- this.dataLabel.attr({ zIndex: (this.pointAttr[''].zIndex + 1) });
96
- }
97
- }
98
- },
99
109
  setVisible: seriesTypes.pie.prototype.pointClass.prototype.setVisible
100
110
  }),
101
- // @todo Move to translate
102
- handleLayout: function () {
103
- var tree = this.tree,
104
- seriesArea;
105
- if (this.points.length) {
106
- // Assign variables
107
- this.rootNode = pick(this.rootNode, "");
108
- tree = this.tree = this.getTree();
109
- this.levelMap = this.getLevels();
110
- seriesArea = this.getSeriesArea(tree.val);
111
- this.calculateChildrenAreas(tree, seriesArea);
112
- this.setPointValues();
113
- }
111
+ /**
112
+ * Creates an object map from parent id to childrens index.
113
+ * @param {Array} data List of points set in options.
114
+ * @param {string} data[].parent Parent id of point.
115
+ * @param {Array} ids List of all point ids.
116
+ * @return {Object} Map from parent id to children index in data.
117
+ */
118
+ getListOfParents: function (data, ids) {
119
+ var listOfParents = reduce(data, function (prev, curr, i) {
120
+ var parent = pick(curr.parent, "");
121
+ if (prev[parent] === undefined) {
122
+ prev[parent] = [];
123
+ }
124
+ prev[parent].push(i);
125
+ return prev;
126
+ }, {});
127
+
128
+ // If parent does not exist, hoist parent to root of tree.
129
+ eachObject(listOfParents, function (children, parent, list) {
130
+ if ((parent !== "") && (HighchartsAdapter.inArray(parent, ids) === -1)) {
131
+ each(children, function (child) {
132
+ list[""].push(child);
133
+ });
134
+ delete list[parent];
135
+ }
136
+ });
137
+ return listOfParents;
114
138
  },
115
139
  /**
116
140
  * Creates a tree structured object from the series points
@@ -118,51 +142,42 @@
118
142
  getTree: function () {
119
143
  var tree,
120
144
  series = this,
121
- parentList = [],
122
- allIds = [],
123
- key,
124
- insertItem = function (key) {
125
- each(parentList[key], function (item) {
126
- parentList[""].push(item);
127
- });
128
- };
129
- // Actions
130
- this.nodeMap = [];
131
-
132
- // Map children to index
133
- // @todo Use data instead of points
134
- each(this.points, function (point, index) {
135
- var parent = "";
136
- allIds.push(point.id);
137
- if (point.parent !== undefined) {
138
- parent = point.parent;
139
- }
140
- if (parentList[parent] === undefined) {
141
- parentList[parent] = [];
142
- }
143
- parentList[parent].push(index);
144
- });
145
- /*
146
- * Quality check:
147
- * - If parent does not exist, then set parent to tree root
148
- * - Add node id to parents children list
149
- */
150
- for (key in parentList) {
151
- if ((parentList.hasOwnProperty(key)) && (key !== "") && (HighchartsAdapter.inArray(key, allIds) === -1)) {
152
- insertItem(key);
153
- delete parentList[key];
154
- }
155
- }
145
+ allIds = map(this.data, function (d) {
146
+ return d.id;
147
+ }),
148
+ parentList = series.getListOfParents(this.data, allIds);
149
+
150
+ series.nodeMap = [];
156
151
  tree = series.buildNode("", -1, 0, parentList, null);
157
- this.eachParents(this.nodeMap[this.rootNode], function (node) {
152
+ recursive(this.nodeMap[this.rootNode], function (node) {
153
+ var next = false,
154
+ p = node.parent;
158
155
  node.visible = true;
156
+ if (p || p === "") {
157
+ next = series.nodeMap[p];
158
+ }
159
+ return next;
159
160
  });
160
- this.eachChildren(this.nodeMap[this.rootNode], function (node) {
161
- node.visible = true;
161
+ recursive(this.nodeMap[this.rootNode].children, function (children) {
162
+ var next = false;
163
+ each(children, function (child) {
164
+ child.visible = true;
165
+ if (child.children.length) {
166
+ next = (next || []).concat(child.children);
167
+ }
168
+ });
169
+ return next;
162
170
  });
163
171
  this.setTreeValues(tree);
164
172
  return tree;
165
173
  },
174
+ init: function (chart, options) {
175
+ var series = this;
176
+ Series.prototype.init.call(series, chart, options);
177
+ if (series.options.allowDrillToNode) {
178
+ series.drillTo();
179
+ }
180
+ },
166
181
  buildNode: function (id, i, level, list, parent) {
167
182
  var series = this,
168
183
  children = [],
@@ -191,6 +206,7 @@
191
206
  },
192
207
  setTreeValues: function (tree) {
193
208
  var series = this,
209
+ options = series.options,
194
210
  childrenTotal = 0,
195
211
  sorted = [],
196
212
  val,
@@ -207,12 +223,19 @@
207
223
  childrenTotal += child.val;
208
224
  } else {
209
225
  // @todo Add predicate to avoid looping already ignored children
210
- series.eachChildren(child, function (node) {
211
- extend(node, {
212
- ignore: true,
213
- isLeaf: false,
214
- visible: false
226
+ recursive(child.children, function (children) {
227
+ var next = false;
228
+ each(children, function (node) {
229
+ extend(node, {
230
+ ignore: true,
231
+ isLeaf: false,
232
+ visible: false
233
+ });
234
+ if (node.children.length) {
235
+ next = (next || []).concat(node.children);
236
+ }
215
237
  });
238
+ return next;
216
239
  });
217
240
  }
218
241
  });
@@ -225,28 +248,12 @@
225
248
  // Ignore this node if point is not visible
226
249
  ignore: !(pick(point && point.visible, true) && (val > 0)),
227
250
  isLeaf: tree.visible && !childrenTotal,
251
+ levelDynamic: (options.levelIsConstant ? tree.level : (tree.level - series.nodeMap[series.rootNode].level)),
228
252
  name: pick(point && point.name, ""),
229
253
  val: val
230
254
  });
231
255
  return tree;
232
256
  },
233
- eachChildren: function (node, callback) {
234
- var series = this,
235
- children = node.children;
236
- callback(node);
237
- if (children.length) {
238
- each(children, function (child) {
239
- series.eachChildren(child, callback);
240
- });
241
- }
242
- },
243
- eachParents: function (node, callback) {
244
- var parent = this.nodeMap[node.parent];
245
- callback(node);
246
- if (parent) {
247
- this.eachParents(parent, callback);
248
- }
249
- },
250
257
  /**
251
258
  * Recursive function which calculates the area for all children of a node.
252
259
  * @param {Object} node The node which is parent to the children.
@@ -255,13 +262,11 @@
255
262
  calculateChildrenAreas: function (parent, area) {
256
263
  var series = this,
257
264
  options = series.options,
258
- levelNumber = (options.levelIsConstant ? parent.level : (parent.level - this.nodeMap[this.rootNode].level)),
259
- level = this.levelMap[levelNumber + 1],
265
+ level = this.levelMap[parent.levelDynamic + 1],
260
266
  algorithm = pick((series[level && level.layoutAlgorithm] && level.layoutAlgorithm), options.layoutAlgorithm),
261
267
  alternate = options.alternateStartingDirection,
262
268
  childrenValues = [],
263
- children,
264
- point;
269
+ children;
265
270
 
266
271
  // Collect all children which should be included
267
272
  children = grep(parent.children, function (n) {
@@ -273,12 +278,15 @@
273
278
  }
274
279
  childrenValues = series[algorithm](area, children);
275
280
  each(children, function (child, index) {
276
- point = series.points[child.i];
277
- point.level = levelNumber + 1;
278
- child.values = merge(childrenValues[index], {
281
+ var values = childrenValues[index];
282
+ child.values = merge(values, {
279
283
  val: child.childrenTotal,
280
284
  direction: (alternate ? 1 - area.direction : area.direction)
281
285
  });
286
+ child.pointValues = merge(values, {
287
+ x: (values.x / series.axisRatio),
288
+ width: (values.width / series.axisRatio)
289
+ });
282
290
  // If node has children, then call method recursively
283
291
  if (child.children.length) {
284
292
  series.calculateChildrenAreas(child, child.values);
@@ -289,23 +297,15 @@
289
297
  var series = this,
290
298
  xAxis = series.xAxis,
291
299
  yAxis = series.yAxis;
292
- series.nodeMap[""].values = {
293
- x: 0,
294
- y: 0,
295
- width: 100,
296
- height: 100
297
- };
298
300
  each(series.points, function (point) {
299
301
  var node = point.node,
300
- values = node.values,
302
+ values = node.pointValues,
301
303
  x1,
302
304
  x2,
303
305
  y1,
304
306
  y2;
305
307
  // Points which is ignored, have no values.
306
308
  if (values) {
307
- values.x = values.x / series.axisRatio;
308
- values.width = values.width / series.axisRatio;
309
309
  x1 = Math.round(xAxis.translate(values.x, 0, 0, 0, 1));
310
310
  x2 = Math.round(xAxis.translate(values.x + values.width, 0, 0, 0, 1));
311
311
  y1 = Math.round(yAxis.translate(values.y, 0, 0, 0, 1));
@@ -327,43 +327,13 @@
327
327
  }
328
328
  });
329
329
  },
330
- getSeriesArea: function (val) {
331
- var x = 0,
332
- y = 0,
333
- h = 100,
334
- r = this.axisRatio = (this.xAxis.len / this.yAxis.len),
335
- w = 100 * r,
336
- d = this.options.layoutStartingDirection === 'vertical' ? 0 : 1,
337
- seriesArea = {
338
- x: x,
339
- y: y,
340
- width: w,
341
- height: h,
342
- direction: d,
343
- val: val
344
- };
345
- this.nodeMap[""].values = seriesArea;
346
- return seriesArea;
347
- },
348
- getLevels: function () {
349
- var map = [],
350
- levels = this.options.levels;
351
- if (levels) {
352
- each(levels, function (level) {
353
- if (level.level !== undefined) {
354
- map[level.level] = level;
355
- }
356
- });
357
- }
358
- return map;
359
- },
360
330
  setColorRecursive: function (node, color) {
361
331
  var series = this,
362
332
  point,
363
333
  level;
364
334
  if (node) {
365
335
  point = series.points[node.i];
366
- level = series.levelMap[node.level];
336
+ level = series.levelMap[node.levelDynamic];
367
337
  // Select either point color, level color or inherited color.
368
338
  color = pick(point && point.options.color, level && level.color, color);
369
339
  if (point) {
@@ -573,16 +543,51 @@
573
543
  return this.alg_func_fill(false, parent, children);
574
544
  },
575
545
  translate: function () {
546
+ var pointValues,
547
+ seriesArea,
548
+ tree,
549
+ val;
550
+
576
551
  // Call prototype function
577
552
  Series.prototype.translate.call(this);
578
- this.handleLayout();
579
553
 
580
- // If a colorAxis is defined
554
+ if (this.points.length) {
555
+ // Assign variables
556
+ this.rootNode = pick(this.options.rootId, "");
557
+ // Create a object map from level to options
558
+ this.levelMap = reduce(this.options.levels, function (arr, item) {
559
+ arr[item.level] = item;
560
+ return arr;
561
+ }, {});
562
+ tree = this.tree = this.getTree(); // @todo Only if series.isDirtyData is true
563
+
564
+ // Calculate plotting values.
565
+ this.axisRatio = (this.xAxis.len / this.yAxis.len);
566
+ this.nodeMap[""].pointValues = pointValues = {x: 0, y: 0, width: 100, height: 100 };
567
+ this.nodeMap[""].values = seriesArea = merge(pointValues, {
568
+ width: (pointValues.width * this.axisRatio),
569
+ direction: (this.options.layoutStartingDirection === 'vertical' ? 0 : 1),
570
+ val: tree.val
571
+ });
572
+ this.calculateChildrenAreas(tree, seriesArea);
573
+ }
574
+
575
+ // Logic for point colors
581
576
  if (this.colorAxis) {
582
577
  this.translateColors();
583
578
  } else if (!this.options.colorByPoint) {
584
579
  this.setColorRecursive(this.tree, undefined);
585
580
  }
581
+
582
+ // Update axis extremes according to the root node.
583
+ val = this.nodeMap[this.rootNode].pointValues;
584
+ this.xAxis.setExtremes(val.x, val.x + val.width, false);
585
+ this.yAxis.setExtremes(val.y, val.y + val.height, false);
586
+ this.xAxis.setScale();
587
+ this.yAxis.setScale();
588
+
589
+ // Assign values to points.
590
+ this.setPointValues();
586
591
  },
587
592
  /**
588
593
  * Extend drawDataLabels with logic to handle custom options related to the treemap series:
@@ -592,12 +597,13 @@
592
597
  */
593
598
  drawDataLabels: function () {
594
599
  var series = this,
595
- dataLabelsGroup = series.dataLabelsGroup,
596
- points = series.points,
600
+ points = grep(series.points, function (n) {
601
+ return n.node.visible;
602
+ }),
597
603
  options,
598
604
  level;
599
605
  each(points, function (point) {
600
- level = series.levelMap[point.level];
606
+ level = series.levelMap[point.node.levelDynamic];
601
607
  // Set options to new object to avoid problems with scope
602
608
  options = {style: {}};
603
609
 
@@ -620,82 +626,88 @@
620
626
  // Merge custom options with point options
621
627
  point.dlOptions = merge(options, point.options.dataLabels);
622
628
  });
623
-
624
- this.dataLabelsGroup = this.group; // Draw dataLabels in same group as points, because of z-index on hover
625
629
  Series.prototype.drawDataLabels.call(this);
626
- this.dataLabelsGroup = dataLabelsGroup;
627
630
  },
628
631
  alignDataLabel: seriesTypes.column.prototype.alignDataLabel,
632
+
633
+ /**
634
+ * Get presentational attributes
635
+ */
636
+ pointAttribs: function (point, state) {
637
+ var level = this.levelMap[point.node.levelDynamic] || {},
638
+ options = this.options,
639
+ attr,
640
+ stateOptions = (state && options.states[state]) || {};
641
+
642
+ // Set attributes by precedence. Point trumps level trumps series. Stroke width uses pick
643
+ // because it can be 0.
644
+ attr = {
645
+ 'stroke': point.borderColor || level.borderColor || stateOptions.borderColor || options.borderColor,
646
+ 'stroke-width': pick(point.borderWidth, level.borderWidth, stateOptions.borderWidth, options.borderWidth),
647
+ 'dashstyle': point.borderDashStyle || level.borderDashStyle || stateOptions.borderDashStyle || options.borderDashStyle,
648
+ 'fill': point.color || this.color
649
+ };
650
+
651
+ if (state === 'hover') {
652
+ attr.zIndex = 1;
653
+ }
654
+
655
+ if (point.node.level <= this.nodeMap[this.rootNode].level) {
656
+ // Hide levels above the current view
657
+ attr.fill = 'none';
658
+ attr["stroke-width"] = 0;
659
+ } else if (!point.node.isLeaf) {
660
+ // If not a leaf, then remove fill
661
+ // @todo let users set the opacity
662
+ attr.fill = pick(options.interactByLeaf, !options.allowDrillToNode) ? 'none' : Color(attr.fill).setOpacity(state === 'hover' ? 0.75 : 0.15).get();
663
+ } else if (state) {
664
+ // Brighten and hoist the hover nodes
665
+ attr.fill = Color(attr.fill).brighten(stateOptions.brightness).get();
666
+ }
667
+
668
+ return attr;
669
+ },
670
+
629
671
  /**
630
672
  * Extending ColumnSeries drawPoints
631
673
  */
632
674
  drawPoints: function () {
633
675
  var series = this,
634
- points = series.points,
635
- seriesOptions = series.options,
636
- attr,
637
- hover,
638
- level;
676
+ points = grep(series.points, function (n) {
677
+ return n.node.visible;
678
+ });
679
+
639
680
  each(points, function (point) {
640
- level = series.levelMap[point.level];
641
- attr = {
642
- stroke: seriesOptions.borderColor,
643
- 'stroke-width': seriesOptions.borderWidth,
644
- dashstyle: seriesOptions.borderDashStyle,
645
- r: 0, // borderRadius gives wrong size relations and should always be disabled
646
- fill: pick(point.color, series.color)
647
- };
648
- // Overwrite standard series options with level options
649
- if (level) {
650
- attr.stroke = level.borderColor || attr.stroke;
651
- attr['stroke-width'] = level.borderWidth || attr['stroke-width'];
652
- attr.dashstyle = level.borderDashStyle || attr.dashstyle;
653
- }
654
- // Merge with point attributes
655
- attr.stroke = point.borderColor || attr.stroke;
656
- attr['stroke-width'] = point.borderWidth || attr['stroke-width'];
657
- attr.dashstyle = point.borderDashStyle || attr.dashstyle;
658
- attr.zIndex = (1000 - (point.level * 2));
659
-
660
- // Make a copy to prevent overwriting individual props
661
- point.pointAttr = merge(point.pointAttr);
662
- hover = point.pointAttr.hover;
663
- hover.zIndex = 1001;
664
- hover.fill = Color(attr.fill).brighten(seriesOptions.states.hover.brightness).get();
665
- // If not a leaf, then remove fill
666
- if (!point.node.isLeaf) {
667
- if (pick(seriesOptions.interactByLeaf, !seriesOptions.allowDrillToNode)) {
668
- attr.fill = 'none';
669
- delete hover.fill;
670
- } else {
671
- // TODO: let users set the opacity
672
- attr.fill = Color(attr.fill).setOpacity(0.15).get();
673
- hover.fill = Color(hover.fill).setOpacity(0.75).get();
674
- }
675
- }
676
- if (point.node.level <= series.nodeMap[series.rootNode].level) {
677
- attr.fill = 'none';
678
- attr.zIndex = 0;
679
- delete hover.fill;
680
- }
681
- point.pointAttr[''] = H.extend(point.pointAttr[''], attr);
682
- // @todo Move this to drawDataLabels
683
- if (point.dataLabel) {
684
- point.dataLabel.attr({ zIndex: (point.pointAttr[''].zIndex + 1) });
681
+ var groupKey = "levelGroup-" + point.node.levelDynamic;
682
+ if (!series[groupKey]) {
683
+ series[groupKey] = series.chart.renderer.g(groupKey)
684
+ .attr({
685
+ zIndex: 1000 - point.node.levelDynamic // @todo Set the zIndex based upon the number of levels, instead of using 1000
686
+ })
687
+ .add(series.group);
685
688
  }
689
+ point.group = series[groupKey];
690
+ // Preliminary code in prepraration for HC5 that uses pointAttribs for all series
691
+ point.pointAttr = {
692
+ '': series.pointAttribs(point),
693
+ 'hover': series.pointAttribs(point, 'hover'),
694
+ 'select': {}
695
+ };
686
696
  });
687
697
  // Call standard drawPoints
688
698
  seriesTypes.column.prototype.drawPoints.call(this);
689
699
 
690
- each(points, function (point) {
691
- if (point.graphic) {
692
- point.graphic.attr(point.pointAttr['']);
693
- }
694
- });
695
-
696
- // Set click events on points
697
- if (seriesOptions.allowDrillToNode) {
698
- series.drillTo();
700
+ // If drillToNode is allowed, set a point cursor on clickables & add drillId to point
701
+ if (series.options.allowDrillToNode) {
702
+ each(points, function (point) {
703
+ var cursor,
704
+ drillId;
705
+ if (point.graphic) {
706
+ drillId = point.drillId = series.options.interactByLeaf ? series.drillToByLeaf(point) : series.drillToByGroup(point);
707
+ cursor = drillId ? "pointer" : "default";
708
+ point.graphic.css({ cursor: cursor });
709
+ }
710
+ });
699
711
  }
700
712
  },
701
713
  /**
@@ -725,34 +737,17 @@
725
737
  * Add drilling on the suitable points
726
738
  */
727
739
  drillTo: function () {
728
- var series = this,
729
- points = series.points;
730
- each(points, function (point) {
731
- var drillId,
740
+ var series = this;
741
+ H.addEvent(series, 'click', function (event) {
742
+ var point = event.point,
743
+ drillId = point.drillId,
732
744
  drillName;
733
- H.removeEvent(point, 'click.drillTo');
734
- if (point.graphic) {
735
- point.graphic.css({ cursor: 'default' });
736
- }
737
-
738
- // Get the drill to id
739
- if (series.options.interactByLeaf) {
740
- drillId = series.drillToByLeaf(point);
741
- } else {
742
- drillId = series.drillToByGroup(point);
743
- }
744
-
745
745
  // If a drill id is returned, add click event and cursor.
746
746
  if (drillId) {
747
747
  drillName = series.nodeMap[series.rootNode].name || series.rootNode;
748
- if (point.graphic) {
749
- point.graphic.css({ cursor: 'pointer' });
750
- }
751
- H.addEvent(point, 'click.drillTo', function () {
752
- point.setState(''); // Remove hover
753
- series.drillToNode(drillId);
754
- series.showDrillUpButton(drillName);
755
- });
748
+ point.setState(''); // Remove hover
749
+ series.drillToNode(drillId);
750
+ series.showDrillUpButton(drillName);
756
751
  }
757
752
  });
758
753
  },
@@ -815,11 +810,7 @@
815
810
  }
816
811
  },
817
812
  drillToNode: function (id) {
818
- var node = this.nodeMap[id],
819
- val = node.values;
820
- this.rootNode = id;
821
- this.xAxis.setExtremes(val.x, val.x + val.width, false);
822
- this.yAxis.setExtremes(val.y, val.y + val.height, false);
813
+ this.options.rootId = id;
823
814
  this.isDirty = true; // Force redraw
824
815
  this.chart.redraw();
825
816
  },