highcharts-rails 3.0.10 → 4.0.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.
@@ -2,7 +2,7 @@
2
2
  // @compilation_level SIMPLE_OPTIMIZATIONS
3
3
 
4
4
  /**
5
- * @license Highcharts JS v3.0.10 (2014-03-10)
5
+ * @license Highcharts JS v4.0.0 (2014-04-22)
6
6
  *
7
7
  * (c) 2009-2014 Torstein Honsi
8
8
  *
@@ -30,7 +30,6 @@ var arrayMin = Highcharts.arrayMin,
30
30
  Tick = Highcharts.Tick,
31
31
  Point = Highcharts.Point,
32
32
  Pointer = Highcharts.Pointer,
33
- TrackerMixin = Highcharts.TrackerMixin,
34
33
  CenteredSeriesMixin = Highcharts.CenteredSeriesMixin,
35
34
  Series = Highcharts.Series,
36
35
  math = Math,
@@ -323,14 +322,9 @@ var radialAxisMixin = {
323
322
  * from center
324
323
  */
325
324
  getPosition: function (value, length) {
326
- if (!this.isCircular) {
327
- length = this.translate(value);
328
- value = this.min;
329
- }
330
-
331
325
  return this.postTranslate(
332
- this.translate(value),
333
- pick(length, this.center[2] / 2) - this.offset
326
+ this.isCircular ? this.translate(value) : 0, // #2848
327
+ pick(this.isCircular ? length : this.translate(value), this.center[2] / 2) - this.offset
334
328
  );
335
329
  },
336
330
 
@@ -343,7 +337,7 @@ var radialAxisMixin = {
343
337
  center = this.center;
344
338
 
345
339
  angle = this.startAngleRad + angle;
346
-
340
+
347
341
  return {
348
342
  x: chart.plotLeft + center[0] + Math.cos(angle) * radius,
349
343
  y: chart.plotTop + center[1] + Math.sin(angle) * radius
@@ -444,7 +438,12 @@ var radialAxisMixin = {
444
438
  }
445
439
  // Concentric polygons
446
440
  } else {
447
- xAxis = chart.xAxis[0];
441
+ // Find the X axis in the same pane
442
+ each(chart.xAxis, function (a) {
443
+ if (a.pane === axis.pane) {
444
+ xAxis = a;
445
+ }
446
+ });
448
447
  ret = [];
449
448
  value = axis.translate(value);
450
449
  tickPositions = xAxis.tickPositions;
@@ -577,7 +576,7 @@ wrap(tickProto, 'getLabelPosition', function (proceed, x, y, label, horiz, label
577
576
  ret,
578
577
  align = labelOptions.align,
579
578
  angle = ((axis.translate(this.pos) + axis.startAngleRad + Math.PI / 2) / Math.PI * 180) % 360;
580
-
579
+
581
580
  if (axis.isRadial) {
582
581
  ret = axis.getPosition(this.pos, (axis.center[2] / 2) + pick(labelOptions.distance, -25));
583
582
 
@@ -654,7 +653,7 @@ defaultPlotOptions.arearange = merge(defaultPlotOptions.area, {
654
653
  marker: null,
655
654
  threshold: null,
656
655
  tooltip: {
657
- pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.low}</b> - <b>{point.high}</b><br/>'
656
+ pointFormat: '<span style="color:{series.color}">\u25CF</span> {series.name}: <b>{point.low}</b> - <b>{point.high}</b><br/>' // docs
658
657
  },
659
658
  trackByArea: true,
660
659
  dataLabels: {
@@ -663,6 +662,11 @@ defaultPlotOptions.arearange = merge(defaultPlotOptions.area, {
663
662
  xHigh: 0,
664
663
  yLow: 0,
665
664
  yHigh: 0
665
+ },
666
+ states: {
667
+ hover: {
668
+ halo: false
669
+ }
666
670
  }
667
671
  });
668
672
 
@@ -909,6 +913,7 @@ seriesTypes.areasplinerange = extendClass(seriesTypes.arearange, {
909
913
  height,
910
914
  y;
911
915
 
916
+ point.tooltipPos = null; // don't inherit from column
912
917
  point.plotHigh = plotHigh = yAxis.translate(point.high, 0, 1, 0, 1);
913
918
  point.plotLow = point.plotY;
914
919
 
@@ -947,6 +952,7 @@ seriesTypes.areasplinerange = extendClass(seriesTypes.arearange, {
947
952
  defaultPlotOptions.gauge = merge(defaultPlotOptions.line, {
948
953
  dataLabels: {
949
954
  enabled: true,
955
+ defer: false,
950
956
  y: 15,
951
957
  borderWidth: 1,
952
958
  borderColor: 'silver',
@@ -1169,8 +1175,7 @@ var GaugeSeries = {
1169
1175
  if (pick(redraw, true)) {
1170
1176
  this.chart.redraw();
1171
1177
  }
1172
- },
1173
- drawTracker: TrackerMixin.drawTrackerPoint
1178
+ }
1174
1179
  };
1175
1180
  seriesTypes.gauge = extendClass(seriesTypes.line, GaugeSeries);
1176
1181
 
@@ -1194,7 +1199,7 @@ defaultPlotOptions.boxplot = merge(defaultPlotOptions.column, {
1194
1199
  //stemWidth: null,
1195
1200
  threshold: null,
1196
1201
  tooltip: {
1197
- pointFormat: '<span style="color:{series.color};font-weight:bold">{series.name}</span><br/>' +
1202
+ pointFormat: '<span style="color:{series.color}">\u25CF</span> <b> {series.name}</b><br/>' + // docs
1198
1203
  'Maximum: {point.high}<br/>' +
1199
1204
  'Upper quartile: {point.q3}<br/>' +
1200
1205
  'Median: {point.median}<br/>' +
@@ -1338,8 +1343,7 @@ seriesTypes.boxplot = extendClass(seriesTypes.column, {
1338
1343
  'M',
1339
1344
  crispX, q1Plot,
1340
1345
  'L',
1341
- crispX, lowPlot,
1342
- 'z'
1346
+ crispX, lowPlot
1343
1347
  ];
1344
1348
 
1345
1349
  // The box
@@ -1398,8 +1402,7 @@ seriesTypes.boxplot = extendClass(seriesTypes.column, {
1398
1402
  medianPlot,
1399
1403
  'L',
1400
1404
  right,
1401
- medianPlot,
1402
- 'z'
1405
+ medianPlot
1403
1406
  ];
1404
1407
 
1405
1408
  // Create or update the graphics
@@ -1457,7 +1460,7 @@ defaultPlotOptions.errorbar = merge(defaultPlotOptions.boxplot, {
1457
1460
  grouping: false,
1458
1461
  linkedTo: ':previous',
1459
1462
  tooltip: {
1460
- pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.low}</b> - <b>{point.high}</b><br/>'
1463
+ pointFormat: '<span style="color:{series.color}">\u25CF</span> {series.name}: <b>{point.low}</b> - <b>{point.high}</b><br/>'
1461
1464
  },
1462
1465
  whiskerWidth: null
1463
1466
  });
@@ -1536,8 +1539,7 @@ seriesTypes.waterfall = extendClass(seriesTypes.column, {
1536
1539
  y,
1537
1540
  previousY,
1538
1541
  stackPoint,
1539
- threshold = options.threshold,
1540
- crispCorr = (options.borderWidth % 2) / 2;
1542
+ threshold = options.threshold;
1541
1543
 
1542
1544
  // run column series translate
1543
1545
  seriesTypes.column.prototype.translate.apply(this);
@@ -1552,7 +1554,7 @@ seriesTypes.waterfall = extendClass(seriesTypes.column, {
1552
1554
 
1553
1555
  // get current stack
1554
1556
  stack = series.getStack(i);
1555
- stackPoint = stack.points[series.index];
1557
+ stackPoint = stack.points[series.index + ',' + i];
1556
1558
 
1557
1559
  // override point value for sums
1558
1560
  if (isNaN(point.y)) {
@@ -1580,7 +1582,7 @@ seriesTypes.waterfall = extendClass(seriesTypes.column, {
1580
1582
  shapeArgs.height *= -1;
1581
1583
  }
1582
1584
 
1583
- point.plotY = shapeArgs.y = mathRound(shapeArgs.y) - crispCorr;
1585
+ point.plotY = shapeArgs.y = mathRound(shapeArgs.y) - (series.borderWidth % 2) / 2;
1584
1586
  shapeArgs.height = mathRound(shapeArgs.height);
1585
1587
  point.yBottom = shapeArgs.y + shapeArgs.height;
1586
1588
  }
@@ -1676,7 +1678,7 @@ seriesTypes.waterfall = extendClass(seriesTypes.column, {
1676
1678
 
1677
1679
  var data = this.data,
1678
1680
  length = data.length,
1679
- lineWidth = this.options.lineWidth + this.options.borderWidth,
1681
+ lineWidth = this.options.lineWidth + this.borderWidth,
1680
1682
  normalizer = mathRound(lineWidth) % 2 / 2,
1681
1683
  path = [],
1682
1684
  M = 'M',
@@ -1741,6 +1743,7 @@ seriesTypes.waterfall = extendClass(seriesTypes.column, {
1741
1743
  // 1 - set default options
1742
1744
  defaultPlotOptions.bubble = merge(defaultPlotOptions.scatter, {
1743
1745
  dataLabels: {
1746
+ format: '{point.z}', // docs?
1744
1747
  inside: true,
1745
1748
  style: {
1746
1749
  color: 'white',
@@ -1758,6 +1761,13 @@ defaultPlotOptions.bubble = merge(defaultPlotOptions.scatter, {
1758
1761
  maxSize: '20%',
1759
1762
  // negativeColor: null,
1760
1763
  // sizeBy: 'area'
1764
+ states: {
1765
+ hover: {
1766
+ halo: {
1767
+ size: 5 // docs
1768
+ }
1769
+ }
1770
+ },
1761
1771
  tooltip: {
1762
1772
  pointFormat: '({point.x}, {point.y}), Size: {point.z}'
1763
1773
  },
@@ -1765,9 +1775,16 @@ defaultPlotOptions.bubble = merge(defaultPlotOptions.scatter, {
1765
1775
  zThreshold: 0
1766
1776
  });
1767
1777
 
1778
+ var BubblePoint = extendClass(Point, {
1779
+ haloPath: function () {
1780
+ return Point.prototype.haloPath.call(this, this.shapeArgs.r + this.series.options.states.hover.halo.size);
1781
+ }
1782
+ });
1783
+
1768
1784
  // 2 - Create the series object
1769
1785
  seriesTypes.bubble = extendClass(seriesTypes.scatter, {
1770
1786
  type: 'bubble',
1787
+ pointClass: BubblePoint,
1771
1788
  pointArrayMap: ['y', 'z'],
1772
1789
  parallelArrays: ['x', 'y', 'z'],
1773
1790
  trackerGroups: ['group', 'dataLabelsGroup'],
@@ -2309,7 +2326,7 @@ Axis.prototype.beforePadding = function () {
2309
2326
 
2310
2327
  group.attr(attribs);
2311
2328
  if (markerGroup) {
2312
- markerGroup.attrSetters = group.attrSetters;
2329
+ //markerGroup.attrSetters = group.attrSetters;
2313
2330
  markerGroup.attr(attribs);
2314
2331
  }
2315
2332
 
@@ -2406,7 +2423,10 @@ Axis.prototype.beforePadding = function () {
2406
2423
  }
2407
2424
  )
2408
2425
  };
2409
- this.toXY(point); // provide correct plotX, plotY for tooltip
2426
+ // Provide correct plotX, plotY for tooltip
2427
+ this.toXY(point);
2428
+ point.tooltipPos = [point.plotX, point.plotY];
2429
+ point.ttBelow = point.plotY > center[1];
2410
2430
  }
2411
2431
  }
2412
2432
  });
@@ -2908,7 +2908,7 @@ if (CanvasRenderingContext2D) {
2908
2908
  });
2909
2909
  }
2910
2910
  }/**
2911
- * @license Highcharts JS v3.0.10 (2014-03-10)
2911
+ * @license Highcharts JS v4.0.0 (2014-04-22)
2912
2912
  * CanVGRenderer Extension module
2913
2913
  *
2914
2914
  * (c) 2011-2012 Torstein Honsi, Erik Olsson
@@ -583,10 +583,14 @@
583
583
  complete: function (dataOptions) {
584
584
 
585
585
  // Merge series configs
586
- if (userOptions.series) {
587
- each(userOptions.series, function (series, i) {
588
- userOptions.series[i] = Highcharts.merge(series, dataOptions.series[i]);
589
- });
586
+ if (userOptions.hasOwnProperty('series')) {
587
+ if (typeof userOptions.series === 'object') {
588
+ each(userOptions.series, function (series, i) {
589
+ userOptions.series[i] = Highcharts.merge(series, dataOptions.series[i]);
590
+ });
591
+ } else { // Allow merging in dataOptions.series (#2856)
592
+ delete userOptions.series;
593
+ }
590
594
  }
591
595
 
592
596
  // Do the merge
@@ -108,7 +108,7 @@
108
108
 
109
109
  // Record options for all current series
110
110
  each(oldSeries.chart.series, function (series) {
111
- if (series.xAxis === xAxis && series.yAxis === yAxis) {
111
+ if (series.xAxis === xAxis) {
112
112
  levelSeries.push(series);
113
113
  levelSeriesOptions.push(series.userOptions);
114
114
  series.levelNumber = series.levelNumber || 0;
@@ -223,13 +223,15 @@
223
223
  drilldownLevels = chart.drilldownLevels,
224
224
  levelNumber = drilldownLevels[drilldownLevels.length - 1].levelNumber,
225
225
  i = drilldownLevels.length,
226
+ chartSeries = chart.series,
227
+ seriesI = chartSeries.length,
226
228
  level,
227
229
  oldSeries,
228
230
  newSeries,
229
231
  oldExtremes,
230
232
  addSeries = function (seriesOptions) {
231
233
  var addedSeries;
232
- each(chart.series, function (series) {
234
+ each(chartSeries, function (series) {
233
235
  if (series.userOptions === seriesOptions) {
234
236
  addedSeries = series;
235
237
  }
@@ -250,7 +252,16 @@
250
252
  if (level.levelNumber === levelNumber) {
251
253
  drilldownLevels.pop();
252
254
 
255
+ // Get the lower series by reference or id
253
256
  oldSeries = level.lowerSeries;
257
+ if (!oldSeries.chart) { // #2786
258
+ while (seriesI--) {
259
+ if (chartSeries[seriesI].options.id === level.lowerSeriesOptions.id) {
260
+ oldSeries = chartSeries[seriesI];
261
+ break;
262
+ }
263
+ }
264
+ }
254
265
 
255
266
  each(level.levelSeriesOptions, addSeries);
256
267
 
@@ -258,12 +269,13 @@
258
269
 
259
270
  if (newSeries.type === oldSeries.type) {
260
271
  newSeries.drilldownLevel = level;
261
- newSeries.options.animation = true;
272
+ newSeries.options.animation = chart.options.drilldown.animation;
262
273
 
263
274
  if (oldSeries.animateDrillupFrom) {
264
275
  oldSeries.animateDrillupFrom(level);
265
276
  }
266
277
  }
278
+ newSeries.levelNumber = levelNumber;
267
279
 
268
280
  oldSeries.remove(false);
269
281
 
@@ -369,35 +381,50 @@
369
381
  */
370
382
  ColumnSeries.prototype.animateDrillupFrom = function (level) {
371
383
  var animationOptions = this.chart.options.drilldown.animation,
372
- group = this.group;
384
+ group = this.group,
385
+ series = this;
386
+
387
+ // Cancel mouse events on the series group (#2787)
388
+ each(series.trackerGroups, function (key) {
389
+ if (series[key]) { // we don't always have dataLabelsGroup
390
+ series[key].on('mouseover');
391
+ }
392
+ });
393
+
373
394
 
374
395
  delete this.group;
375
396
  each(this.points, function (point) {
376
397
  var graphic = point.graphic,
377
- startColor = H.Color(point.color).rgba;
398
+ startColor = H.Color(point.color).rgba,
399
+ endColor = H.Color(level.color).rgba,
400
+ complete = function () {
401
+ graphic.destroy();
402
+ if (group) {
403
+ group = group.destroy();
404
+ }
405
+ };
378
406
 
379
407
  if (graphic) {
380
408
 
381
409
  delete point.graphic;
382
410
 
383
- /*jslint unparam: true*/
384
- graphic.animate(level.shapeArgs, H.merge(animationOptions, {
385
-
386
- step: function (val, fx) {
387
- if (fx.prop === 'start') {
388
- this.attr({
389
- fill: tweenColors(startColor, H.Color(level.color).rgba, fx.pos)
390
- });
391
- }
392
- },
393
- complete: function () {
394
- graphic.destroy();
395
- if (group) {
396
- group = group.destroy();
397
- }
398
- }
399
- }));
400
- /*jslint unparam: false*/
411
+ if (animationOptions) {
412
+ /*jslint unparam: true*/
413
+ graphic.animate(level.shapeArgs, H.merge(animationOptions, {
414
+ step: function (val, fx) {
415
+ if (fx.prop === 'start' && startColor.length === 4 && endColor.length === 4) {
416
+ this.attr({
417
+ fill: tweenColors(startColor, endColor, fx.pos)
418
+ });
419
+ }
420
+ },
421
+ complete: complete
422
+ }));
423
+ /*jslint unparam: false*/
424
+ } else {
425
+ graphic.attr(level.shapeArgs);
426
+ complete();
427
+ }
401
428
  }
402
429
  });
403
430
  };
@@ -426,10 +453,9 @@
426
453
  .attr(H.merge(animateFrom, {
427
454
  start: start + i * startAngle,
428
455
  end: start + (i + 1) * startAngle
429
- }))
430
- .animate(point.shapeArgs, H.merge(animationOptions, {
456
+ }))[animationOptions ? 'animate' : 'attr'](point.shapeArgs, H.merge(animationOptions, {
431
457
  step: function (val, fx) {
432
- if (fx.prop === 'start') {
458
+ if (fx.prop === 'start' && startColor.length === 4 && endColor.length === 4) {
433
459
  this.attr({
434
460
  fill: tweenColors(startColor, endColor, fx.pos)
435
461
  });
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v3.0.10 (2014-03-10)
2
+ * @license Highcharts JS v4.0.0 (2014-04-22)
3
3
  * Exporting module
4
4
  *
5
5
  * (c) 2010-2014 Torstein Honsi
@@ -22,6 +22,7 @@ var defaultOptions = Highcharts.getOptions(),
22
22
 
23
23
  // set default options
24
24
  defaultPlotOptions.funnel = merge(defaultPlotOptions.pie, {
25
+ animation: false,
25
26
  center: ['50%', '50%'],
26
27
  width: '90%',
27
28
  neckWidth: '30%',
@@ -1,60 +1,606 @@
1
- (function (H) {
2
- var seriesTypes = H.seriesTypes,
3
- each = H.each;
1
+ /**
2
+ * @license Highcharts JS v4.0.0 (2014-04-22)
3
+ *
4
+ * (c) 2011-2014 Torstein Honsi
5
+ *
6
+ * License: www.highcharts.com/license
7
+ */
8
+
9
+ /*global HighchartsAdapter*/
10
+ (function (Highcharts) {
11
+
12
+
13
+ var UNDEFINED,
14
+ Axis = Highcharts.Axis,
15
+ Chart = Highcharts.Chart,
16
+ Color = Highcharts.Color,
17
+ Legend = Highcharts.Legend,
18
+ LegendSymbolMixin = Highcharts.LegendSymbolMixin,
19
+ Series = Highcharts.Series,
4
20
 
5
- seriesTypes.heatmap = H.extendClass(seriesTypes.map, {
6
- useMapGeometry: false,
7
- pointArrayMap: ['y', 'value'],
8
- init: function () {
9
- seriesTypes.map.prototype.init.apply(this, arguments);
10
- this.pointRange = this.options.colsize || 1;
11
- // TODO: similar logic for the Y axis
12
- },
13
- translate: function () {
14
- var series = this,
15
- options = series.options,
16
- xAxis = series.xAxis,
17
- yAxis = series.yAxis;
21
+ defaultOptions = Highcharts.getOptions(),
22
+ each = Highcharts.each,
23
+ extend = Highcharts.extend,
24
+ extendClass = Highcharts.extendClass,
25
+ merge = Highcharts.merge,
26
+ pick = Highcharts.pick,
27
+ numberFormat = Highcharts.numberFormat,
28
+ seriesTypes = Highcharts.seriesTypes,
29
+ wrap = Highcharts.wrap,
30
+ noop = function () {};
18
31
 
19
- series.generatePoints();
20
32
 
21
- each(series.points, function (point) {
22
- var xPad = (options.colsize || 1) / 2,
23
- yPad = (options.rowsize || 1) / 2,
24
- x1 = Math.round(xAxis.len - xAxis.translate(point.x - xPad, 0, 1, 0, 1)),
25
- x2 = Math.round(xAxis.len - xAxis.translate(point.x + xPad, 0, 1, 0, 1)),
26
- y1 = Math.round(yAxis.translate(point.y - yPad, 0, 1, 0, 1)),
27
- y2 = Math.round(yAxis.translate(point.y + yPad, 0, 1, 0, 1));
28
-
29
-
30
- point.plotY = 1; // Pass test in Column.drawPoints
31
-
32
- point.shapeType = 'rect';
33
- point.shapeArgs = {
34
- x: Math.min(x1, x2),
35
- y: Math.min(y1, y2),
36
- width: Math.abs(x2 - x1),
37
- height: Math.abs(y2 - y1)
38
- };
39
- });
40
-
41
- series.pointRange = options.colsize || 1;
42
- series.translateColors();
33
+
34
+
35
+ /**
36
+ * The ColorAxis object for inclusion in gradient legends
37
+ */
38
+ var ColorAxis = Highcharts.ColorAxis = function () {
39
+ this.isColorAxis = true;
40
+ this.init.apply(this, arguments);
41
+ };
42
+ extend(ColorAxis.prototype, Axis.prototype);
43
+ extend(ColorAxis.prototype, {
44
+ defaultColorAxisOptions: {
45
+ lineWidth: 0,
46
+ gridLineWidth: 1,
47
+ tickPixelInterval: 72,
48
+ startOnTick: true,
49
+ endOnTick: true,
50
+ offset: 0,
51
+ marker: { // docs: use another name?
52
+ animation: {
53
+ duration: 50
54
+ },
55
+ color: 'gray',
56
+ width: 0.01
43
57
  },
44
-
45
- animate: function () {},
46
- getBox: function () {},
58
+ labels: {
59
+ overflow: 'justify'
60
+ },
61
+ minColor: '#EFEFFF',
62
+ maxColor: '#003875',
63
+ tickLength: 5
64
+ },
65
+ init: function (chart, userOptions) {
66
+ var horiz = chart.options.legend.layout !== 'vertical',
67
+ options;
68
+
69
+ // Build the options
70
+ options = merge(this.defaultColorAxisOptions, {
71
+ side: horiz ? 2 : 1,
72
+ reversed: !horiz
73
+ }, userOptions, {
74
+ isX: horiz,
75
+ opposite: !horiz,
76
+ showEmpty: false,
77
+ title: null,
78
+ isColor: true
79
+ });
80
+
81
+ Axis.prototype.init.call(this, chart, options);
47
82
 
48
- getExtremes: function () {
49
- // Get the extremes from the value data
50
- H.Series.prototype.getExtremes.call(this, this.valueData);
51
- this.valueMin = this.dataMin;
52
- this.valueMax = this.dataMax;
83
+ // Base init() pushes it to the xAxis array, now pop it again
84
+ //chart[this.isXAxis ? 'xAxis' : 'yAxis'].pop();
53
85
 
54
- // Get the extremes from the y data
55
- H.Series.prototype.getExtremes.call(this);
86
+ // Prepare data classes
87
+ if (userOptions.dataClasses) {
88
+ this.initDataClasses(userOptions);
56
89
  }
90
+ this.initStops(userOptions);
91
+
92
+ // Override original axis properties
93
+ this.isXAxis = true;
94
+ this.horiz = horiz;
95
+ this.zoomEnabled = false;
96
+ },
97
+
98
+ /*
99
+ * Return an intermediate color between two colors, according to pos where 0
100
+ * is the from color and 1 is the to color
101
+ */
102
+ tweenColors: function (from, to, pos) {
103
+ // Check for has alpha, because rgba colors perform worse due to lack of
104
+ // support in WebKit.
105
+ var hasAlpha = (to.rgba[3] !== 1 || from.rgba[3] !== 1);
106
+ return (hasAlpha ? 'rgba(' : 'rgb(') +
107
+ Math.round(to.rgba[0] + (from.rgba[0] - to.rgba[0]) * (1 - pos)) + ',' +
108
+ Math.round(to.rgba[1] + (from.rgba[1] - to.rgba[1]) * (1 - pos)) + ',' +
109
+ Math.round(to.rgba[2] + (from.rgba[2] - to.rgba[2]) * (1 - pos)) +
110
+ (hasAlpha ? (',' + (to.rgba[3] + (from.rgba[3] - to.rgba[3]) * (1 - pos))) : '') + ')';
111
+ },
112
+
113
+ initDataClasses: function (userOptions) {
114
+ var axis = this,
115
+ chart = this.chart,
116
+ dataClasses,
117
+ colorCounter = 0,
118
+ options = this.options;
119
+ this.dataClasses = dataClasses = [];
120
+
121
+ each(userOptions.dataClasses, function (dataClass, i) {
122
+ var colors;
123
+
124
+ dataClass = merge(dataClass);
125
+ dataClasses.push(dataClass);
126
+ if (!dataClass.color) {
127
+ if (options.dataClassColor === 'category') {
128
+ colors = chart.options.colors;
129
+ dataClass.color = colors[colorCounter++];
130
+ // loop back to zero
131
+ if (colorCounter === colors.length) {
132
+ colorCounter = 0;
133
+ }
134
+ } else {
135
+ dataClass.color = axis.tweenColors(Color(options.minColor), Color(options.maxColor), i / (userOptions.dataClasses.length - 1));
136
+ }
137
+ }
138
+ });
139
+ },
140
+
141
+ initStops: function (userOptions) {
142
+ this.stops = userOptions.stops || [
143
+ [0, this.options.minColor],
144
+ [1, this.options.maxColor]
145
+ ];
146
+ each(this.stops, function (stop) {
147
+ stop.color = Color(stop[1]);
148
+ });
149
+ },
150
+
151
+ /**
152
+ * Extend the setOptions method to process extreme colors and color
153
+ * stops.
154
+ */
155
+ setOptions: function (userOptions) {
156
+ Axis.prototype.setOptions.call(this, userOptions);
157
+
158
+ this.options.crosshair = this.options.marker;
159
+ this.coll = 'colorAxis';
160
+ },
161
+
162
+ setAxisSize: function () {
163
+ var symbol = this.legendSymbol,
164
+ chart = this.chart,
165
+ x,
166
+ y,
167
+ width,
168
+ height;
169
+
170
+ if (symbol) {
171
+ this.left = x = symbol.attr('x');
172
+ this.top = y = symbol.attr('y');
173
+ this.width = width = symbol.attr('width');
174
+ this.height = height = symbol.attr('height');
175
+ this.right = chart.chartWidth - x - width;
176
+ this.bottom = chart.chartHeight - y - height;
177
+
178
+ this.len = this.horiz ? width : height;
179
+ this.pos = this.horiz ? x : y;
180
+ }
181
+ },
182
+
183
+ /**
184
+ * Translate from a value to a color
185
+ */
186
+ toColor: function (value, point) {
187
+ var pos,
188
+ stops = this.stops,
189
+ from,
190
+ to,
191
+ color,
192
+ dataClasses = this.dataClasses,
193
+ dataClass,
194
+ i;
195
+
196
+ if (dataClasses) {
197
+ i = dataClasses.length;
198
+ while (i--) {
199
+ dataClass = dataClasses[i];
200
+ from = dataClass.from;
201
+ to = dataClass.to;
202
+ if ((from === UNDEFINED || value >= from) && (to === UNDEFINED || value <= to)) {
203
+ color = dataClass.color;
204
+ if (point) {
205
+ point.dataClass = i;
206
+ }
207
+ break;
208
+ }
209
+ }
210
+
211
+ } else {
212
+
213
+ if (this.isLog) {
214
+ value = this.val2lin(value);
215
+ }
216
+ pos = 1 - ((this.max - value) / (this.max - this.min));
217
+ i = stops.length;
218
+ while (i--) {
219
+ if (pos > stops[i][0]) {
220
+ break;
221
+ }
222
+ }
223
+ from = stops[i] || stops[i + 1];
224
+ to = stops[i + 1] || from;
225
+
226
+ // The position within the gradient
227
+ pos = 1 - (to[0] - pos) / ((to[0] - from[0]) || 1);
228
+
229
+ color = this.tweenColors(
230
+ from.color,
231
+ to.color,
232
+ pos
233
+ );
234
+ }
235
+ return color;
236
+ },
237
+
238
+ getOffset: function () {
239
+ var group = this.legendGroup;
240
+ if (group) {
241
+
242
+ Axis.prototype.getOffset.call(this);
57
243
 
58
- });
244
+ if (!this.axisGroup.parentGroup) {
245
+
246
+ // Move the axis elements inside the legend group
247
+ this.axisGroup.add(group);
248
+ this.gridGroup.add(group);
249
+ this.labelGroup.add(group);
250
+
251
+ this.added = true;
252
+ }
253
+ }
254
+ },
255
+
256
+ /**
257
+ * Create the color gradient
258
+ */
259
+ setLegendColor: function () {
260
+ var grad,
261
+ horiz = this.horiz,
262
+ options = this.options;
263
+
264
+ grad = horiz ? [0, 0, 1, 0] : [0, 0, 0, 1];
265
+ this.legendColor = {
266
+ linearGradient: { x1: grad[0], y1: grad[1], x2: grad[2], y2: grad[3] },
267
+ stops: options.stops || [
268
+ [0, options.minColor],
269
+ [1, options.maxColor]
270
+ ]
271
+ };
272
+ },
273
+
274
+ /**
275
+ * The color axis appears inside the legend and has its own legend symbol
276
+ */
277
+ drawLegendSymbol: function (legend, item) {
278
+ var padding = legend.padding,
279
+ legendOptions = legend.options,
280
+ horiz = this.horiz,
281
+ box,
282
+ width = pick(legendOptions.symbolWidth, horiz ? 200 : 12),
283
+ height = pick(legendOptions.symbolHeight, horiz ? 12 : 200),
284
+ labelPadding = pick(legendOptions.labelPadding, horiz ? 10 : 30);
285
+
286
+ this.setLegendColor();
287
+
288
+ // Create the gradient
289
+ item.legendSymbol = this.chart.renderer.rect(
290
+ 0,
291
+ legend.baseline - 11,
292
+ width,
293
+ height
294
+ ).attr({
295
+ zIndex: 1
296
+ }).add(item.legendGroup);
297
+ box = item.legendSymbol.getBBox();
298
+
299
+ // Set how much space this legend item takes up
300
+ this.legendItemWidth = width + padding + (horiz ? 0 : labelPadding);
301
+ this.legendItemHeight = height + padding + (horiz ? labelPadding : 0);
302
+ },
303
+ /**
304
+ * Fool the legend
305
+ */
306
+ setState: noop,
307
+ visible: true,
308
+ setVisible: noop,
309
+ getSeriesExtremes: function () {
310
+ var series;
311
+ if (this.series.length) {
312
+ series = this.series[0];
313
+ this.dataMin = series.valueMin;
314
+ this.dataMax = series.valueMax;
315
+ }
316
+ },
317
+ drawCrosshair: function (e, point) {
318
+ var newCross = !this.cross,
319
+ plotX = point && point.plotX,
320
+ plotY = point && point.plotY,
321
+ crossPos,
322
+ axisPos = this.pos,
323
+ axisLen = this.len;
324
+
325
+ if (point) {
326
+ crossPos = this.toPixels(point.value);
327
+ if (crossPos < axisPos) {
328
+ crossPos = axisPos - 2;
329
+ } else if (crossPos > axisPos + axisLen) {
330
+ crossPos = axisPos + axisLen + 2;
331
+ }
332
+
333
+ point.plotX = crossPos;
334
+ point.plotY = this.len - crossPos;
335
+ Axis.prototype.drawCrosshair.call(this, e, point);
336
+ point.plotX = plotX;
337
+ point.plotY = plotY;
338
+
339
+ if (!newCross && this.cross) {
340
+ this.cross
341
+ .attr({
342
+ fill: this.crosshair.color
343
+ })
344
+ .add(this.labelGroup);
345
+ }
346
+ }
347
+ },
348
+ getPlotLinePath: function (a, b, c, d, pos) {
349
+ if (pos) { // crosshairs only
350
+ return this.horiz ?
351
+ ['M', pos - 4, this.top - 6, 'L', pos + 4, this.top - 6, pos, this.top, 'Z'] :
352
+ ['M', this.left, pos, 'L', this.left - 6, pos + 6, this.left - 6, pos - 6, 'Z'];
353
+ } else {
354
+ return Axis.prototype.getPlotLinePath.call(this, a, b, c, d);
355
+ }
356
+ },
357
+
358
+ update: function (newOptions, redraw) {
359
+ each(this.series, function (series) {
360
+ series.isDirtyData = true; // Needed for Axis.update when choropleth colors change
361
+ });
362
+ Axis.prototype.update.call(this, newOptions, redraw);
363
+ if (this.legendItem) {
364
+ this.setLegendColor();
365
+ this.chart.legend.colorizeItem(this, true);
366
+ }
367
+ },
368
+
369
+ /**
370
+ * Get the legend item symbols for data classes
371
+ */
372
+ getDataClassLegendSymbols: function () {
373
+ var axis = this,
374
+ chart = this.chart,
375
+ legendItems = [],
376
+ legendOptions = chart.options.legend,
377
+ valueDecimals = legendOptions.valueDecimals,
378
+ valueSuffix = legendOptions.valueSuffix || '',
379
+ name;
380
+
381
+ each(this.dataClasses, function (dataClass, i) {
382
+ var vis = true,
383
+ from = dataClass.from,
384
+ to = dataClass.to;
385
+
386
+ // Assemble the default name. This can be overridden by legend.options.labelFormatter
387
+ name = '';
388
+ if (from === UNDEFINED) {
389
+ name = '< ';
390
+ } else if (to === UNDEFINED) {
391
+ name = '> ';
392
+ }
393
+ if (from !== UNDEFINED) {
394
+ name += numberFormat(from, valueDecimals) + valueSuffix;
395
+ }
396
+ if (from !== UNDEFINED && to !== UNDEFINED) {
397
+ name += ' - ';
398
+ }
399
+ if (to !== UNDEFINED) {
400
+ name += numberFormat(to, valueDecimals) + valueSuffix;
401
+ }
402
+
403
+ // Add a mock object to the legend items
404
+ legendItems.push(extend({
405
+ chart: chart,
406
+ name: name,
407
+ options: {},
408
+ drawLegendSymbol: LegendSymbolMixin.drawRectangle,
409
+ visible: true,
410
+ setState: noop,
411
+ setVisible: function () {
412
+ vis = this.visible = !vis;
413
+ each(axis.series, function (series) {
414
+ each(series.points, function (point) {
415
+ if (point.dataClass === i) {
416
+ point.setVisible(vis);
417
+ }
418
+ });
419
+ });
420
+
421
+ chart.legend.colorizeItem(this, vis);
422
+ }
423
+ }, dataClass));
424
+ });
425
+ return legendItems;
426
+ },
427
+ name: '' // Prevents 'undefined' in legend in IE8
428
+ });
429
+
430
+
431
+
432
+ /**
433
+ * Extend the chart getAxes method to also get the color axis
434
+ */
435
+ wrap(Chart.prototype, 'getAxes', function (proceed) {
436
+
437
+ var options = this.options,
438
+ colorAxisOptions = options.colorAxis;
439
+
440
+ proceed.call(this);
441
+
442
+ this.colorAxis = [];
443
+ if (colorAxisOptions) {
444
+ proceed = new ColorAxis(this, colorAxisOptions); // Fake assignment for jsLint
445
+ }
446
+ });
447
+
448
+
449
+ /**
450
+ * Wrap the legend getAllItems method to add the color axis. This also removes the
451
+ * axis' own series to prevent them from showing up individually.
452
+ */
453
+ wrap(Legend.prototype, 'getAllItems', function (proceed) {
454
+ var allItems = [],
455
+ colorAxis = this.chart.colorAxis[0];
456
+
457
+ if (colorAxis) {
458
+
459
+ // Data classes
460
+ if (colorAxis.options.dataClasses) {
461
+ allItems = allItems.concat(colorAxis.getDataClassLegendSymbols());
462
+ // Gradient legend
463
+ } else {
464
+ // Add this axis on top
465
+ allItems.push(colorAxis);
466
+ }
467
+
468
+ // Don't add the color axis' series
469
+ each(colorAxis.series, function (series) {
470
+ series.options.showInLegend = false;
471
+ });
472
+ }
473
+
474
+ return allItems.concat(proceed.call(this));
475
+ });/**
476
+ * Mixin for maps and heatmaps
477
+ */
478
+ var colorSeriesMixin = {
479
+
480
+ pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
481
+ stroke: 'borderColor',
482
+ 'stroke-width': 'borderWidth',
483
+ fill: 'color',
484
+ dashstyle: 'dashStyle'
485
+ },
486
+ pointArrayMap: ['value'],
487
+ axisTypes: ['xAxis', 'yAxis', 'colorAxis'],
488
+ optionalAxis: 'colorAxis',
489
+ trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'],
490
+ getSymbol: noop,
491
+ parallelArrays: ['x', 'y', 'value'],
59
492
 
493
+ /**
494
+ * In choropleth maps, the color is a result of the value, so this needs translation too
495
+ */
496
+ translateColors: function () {
497
+ var series = this,
498
+ nullColor = this.options.nullColor,
499
+ colorAxis = this.colorAxis;
500
+
501
+ each(this.data, function (point) {
502
+ var value = point.value,
503
+ color;
504
+
505
+ color = value === null ? nullColor : colorAxis ? colorAxis.toColor(value, point) : (point.color) || series.color;
506
+
507
+ if (color) {
508
+ point.color = color;
509
+ }
510
+ });
511
+ }
512
+ };
513
+ /**
514
+ * Extend the default options with map options
515
+ */
516
+ defaultOptions.plotOptions.heatmap = merge(defaultOptions.plotOptions.scatter, {
517
+ animation: false,
518
+ borderWidth: 0,
519
+ nullColor: '#F8F8F8',
520
+ dataLabels: {
521
+ format: '{point.value}',
522
+ verticalAlign: 'middle',
523
+ crop: false,
524
+ overflow: false,
525
+ style: {
526
+ color: 'white',
527
+ fontWeight: 'bold',
528
+ textShadow: '0 0 5px black'
529
+ }
530
+ },
531
+ marker: null,
532
+ tooltip: {
533
+ pointFormat: '{point.x}, {point.y}: {point.value}<br/>'
534
+ },
535
+ states: {
536
+ normal: {
537
+ animation: true
538
+ },
539
+ hover: {
540
+ brightness: 0.2
541
+ }
542
+ }
543
+ });
544
+
545
+ // The Heatmap series type
546
+ seriesTypes.heatmap = extendClass(seriesTypes.scatter, merge(colorSeriesMixin, {
547
+ type: 'heatmap',
548
+ pointArrayMap: ['y', 'value'],
549
+ hasPointSpecificOptions: true,
550
+ supportsDrilldown: true,
551
+ getExtremesFromAll: true,
552
+ init: function () {
553
+ seriesTypes.scatter.prototype.init.apply(this, arguments);
554
+ this.pointRange = this.options.colsize || 1;
555
+ this.yAxis.axisPointRange = this.options.rowsize || 1; // general point range
556
+ },
557
+ translate: function () {
558
+ var series = this,
559
+ options = series.options,
560
+ xAxis = series.xAxis,
561
+ yAxis = series.yAxis;
562
+
563
+ series.generatePoints();
564
+
565
+ each(series.points, function (point) {
566
+ var xPad = (options.colsize || 1) / 2,
567
+ yPad = (options.rowsize || 1) / 2,
568
+ x1 = Math.round(xAxis.len - xAxis.translate(point.x - xPad, 0, 1, 0, 1)),
569
+ x2 = Math.round(xAxis.len - xAxis.translate(point.x + xPad, 0, 1, 0, 1)),
570
+ y1 = Math.round(yAxis.translate(point.y - yPad, 0, 1, 0, 1)),
571
+ y2 = Math.round(yAxis.translate(point.y + yPad, 0, 1, 0, 1));
572
+
573
+ // Set plotX and plotY for use in K-D-Tree and more
574
+ point.plotX = (x1 + x2) / 2;
575
+ point.plotY = (y1 + y2) / 2;
576
+
577
+ point.shapeType = 'rect';
578
+ point.shapeArgs = {
579
+ x: Math.min(x1, x2),
580
+ y: Math.min(y1, y2),
581
+ width: Math.abs(x2 - x1),
582
+ height: Math.abs(y2 - y1)
583
+ };
584
+ });
585
+
586
+ series.translateColors();
587
+ },
588
+ drawPoints: seriesTypes.column.prototype.drawPoints,
589
+ animate: noop,
590
+ getBox: noop,
591
+ drawLegendSymbol: LegendSymbolMixin.drawRectangle,
592
+
593
+ getExtremes: function () {
594
+ // Get the extremes from the value data
595
+ Series.prototype.getExtremes.call(this, this.valueData);
596
+ this.valueMin = this.dataMin;
597
+ this.valueMax = this.dataMax;
598
+
599
+ // Get the extremes from the y data
600
+ Series.prototype.getExtremes.call(this);
601
+ }
602
+
603
+ }));
604
+
605
+
60
606
  }(Highcharts));