highcharts-rails 4.1.8 → 4.1.9

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.
@@ -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
  },