highcharts-rails 2.3.0 → 2.3.2

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.
data/CHANGELOG.markdown CHANGED
@@ -1,3 +1,7 @@
1
+ ## 2.3.2 (2012-08-31)
2
+
3
+ * Updated Highcharts to 2.3.2
4
+
1
5
  ## 2.3.0 (2012-08-27)
2
6
 
3
7
  * Updated Highcharts to 2.3.0
@@ -1,3 +1,3 @@
1
1
  module Highcharts
2
- VERSION = "2.3.0"
2
+ VERSION = "2.3.2"
3
3
  end
@@ -2,7 +2,7 @@
2
2
  // @compilation_level SIMPLE_OPTIMIZATIONS
3
3
 
4
4
  /**
5
- * @license Highcharts JS v2.3.0 (2012-08-24)
5
+ * @license Highcharts JS v2.3.2 (2012-08-31)
6
6
  *
7
7
  * (c) 2009-2011 Torstein Hønsi
8
8
  *
@@ -32,7 +32,8 @@ var UNDEFINED,
32
32
 
33
33
  // some variables
34
34
  userAgent = navigator.userAgent,
35
- isIE = /msie/i.test(userAgent) && !win.opera,
35
+ isOpera = win.opera,
36
+ isIE = /msie/i.test(userAgent) && !isOpera,
36
37
  docMode8 = doc.documentMode === 8,
37
38
  isWebKit = /AppleWebKit/.test(userAgent),
38
39
  isFirefox = /Firefox/.test(userAgent),
@@ -1070,6 +1071,25 @@ pathAnim = {
1070
1071
  Step.d = dSetter;
1071
1072
  }
1072
1073
 
1074
+ /**
1075
+ * Utility for iterating over an array. Parameters are reversed compared to jQuery.
1076
+ * @param {Array} arr
1077
+ * @param {Function} fn
1078
+ */
1079
+ this.each = Array.prototype.forEach ?
1080
+ function (arr, fn) { // modern browsers
1081
+ return Array.prototype.forEach.call(arr, fn);
1082
+
1083
+ } :
1084
+ function (arr, fn) { // legacy
1085
+ var i = 0,
1086
+ len = arr.length;
1087
+ for (; i < len; i++) {
1088
+ if (fn.call(arr[i], arr[i], i, arr) === false) {
1089
+ return i;
1090
+ }
1091
+ }
1092
+ };
1073
1093
 
1074
1094
  // Register Highcharts as a jQuery plugin
1075
1095
  // TODO: MooTools and prototype as well?
@@ -1102,21 +1122,6 @@ pathAnim = {
1102
1122
  return $(elem)[method]();
1103
1123
  },
1104
1124
 
1105
- /**
1106
- * Utility for iterating over an array. Parameters are reversed compared to jQuery.
1107
- * @param {Array} arr
1108
- * @param {Function} fn
1109
- */
1110
- each: function (arr, fn) {
1111
- var i = 0,
1112
- len = arr.length;
1113
- for (; i < len; i++) {
1114
- if (fn.call(arr[i], arr[i], i, arr) === false) {
1115
- return i;
1116
- }
1117
- }
1118
- },
1119
-
1120
1125
  /**
1121
1126
  * Filter an array
1122
1127
  */
@@ -1288,12 +1293,18 @@ pathAnim = {
1288
1293
 
1289
1294
  // check for a custom HighchartsAdapter defined prior to this file
1290
1295
  var globalAdapter = win.HighchartsAdapter,
1291
- adapter = globalAdapter || {},
1296
+ adapter = globalAdapter || {};
1297
+
1298
+ // Initialize the adapter
1299
+ if (globalAdapter) {
1300
+ globalAdapter.init.call(globalAdapter, pathAnim);
1301
+ }
1302
+
1292
1303
 
1293
1304
  // Utility functions. If the HighchartsAdapter is not defined, adapter is an empty object
1294
1305
  // and all the utility functions will be null. In that case they are populated by the
1295
1306
  // default adapters below.
1296
- adapterRun = adapter.adapterRun,
1307
+ var adapterRun = adapter.adapterRun,
1297
1308
  getScript = adapter.getScript,
1298
1309
  inArray = adapter.inArray,
1299
1310
  each = adapter.each,
@@ -1308,15 +1319,6 @@ var globalAdapter = win.HighchartsAdapter,
1308
1319
  animate = adapter.animate,
1309
1320
  stop = adapter.stop;
1310
1321
 
1311
- /*
1312
- * Define the adapter for frameworks. If an external adapter is not defined,
1313
- * Highcharts reverts to the built-in jQuery adapter.
1314
- */
1315
- if (globalAdapter && globalAdapter.init) {
1316
- // Initialize the adapter with the pathAnim object that takes care
1317
- // of path animations.
1318
- globalAdapter.init(pathAnim);
1319
- }
1320
1322
 
1321
1323
 
1322
1324
  /* ****************************************************************************
@@ -1358,8 +1360,8 @@ defaultOptions = {
1358
1360
  },
1359
1361
  global: {
1360
1362
  useUTC: true,
1361
- canvasToolsURL: 'http://code.highcharts.com/2.3.0/modules/canvas-tools.js',
1362
- VMLRadialGradientURL: 'http://code.highcharts.com/2.3.0/gfx/vml-radial-gradient.png'
1363
+ canvasToolsURL: 'http://code.highcharts.com/2.3.2/modules/canvas-tools.js',
1364
+ VMLRadialGradientURL: 'http://code.highcharts.com/2.3.2/gfx/vml-radial-gradient.png'
1363
1365
  },
1364
1366
  chart: {
1365
1367
  //animation: true,
@@ -2061,7 +2063,10 @@ SVGElement.prototype = {
2061
2063
 
2062
2064
 
2063
2065
  if (key === 'text') {
2064
- // only one node allowed
2066
+ // Delete bBox memo when the text changes
2067
+ if (value !== wrapper.textStr) {
2068
+ delete wrapper.bBox;
2069
+ }
2065
2070
  wrapper.textStr = value;
2066
2071
  if (wrapper.added) {
2067
2072
  renderer.buildText(wrapper);
@@ -2168,7 +2173,7 @@ SVGElement.prototype = {
2168
2173
 
2169
2174
  // store object
2170
2175
  elemWrapper.styles = styles;
2171
-
2176
+
2172
2177
  // serialize and set style attribute
2173
2178
  if (isIE && !hasSVG) { // legacy IE doesn't support setting style attribute
2174
2179
  if (textWidth) {
@@ -2276,13 +2281,13 @@ SVGElement.prototype = {
2276
2281
  * @return {Object} A hash containing values for x, y, width and height
2277
2282
  */
2278
2283
 
2279
- htmlGetBBox: function (refresh) {
2284
+ htmlGetBBox: function () {
2280
2285
  var wrapper = this,
2281
2286
  element = wrapper.element,
2282
2287
  bBox = wrapper.bBox;
2283
2288
 
2284
2289
  // faking getBBox in exported SVG in legacy IE
2285
- if (!bBox || refresh) {
2290
+ if (!bBox) {
2286
2291
  // faking getBBox in exported SVG in legacy IE (is this a duplicate of the fix for #1079?)
2287
2292
  if (element.nodeName === 'text') {
2288
2293
  element.style.position = ABSOLUTE;
@@ -2357,25 +2362,34 @@ SVGElement.prototype = {
2357
2362
  textWidth = pInt(wrapper.textWidth),
2358
2363
  xCorr = wrapper.xCorr || 0,
2359
2364
  yCorr = wrapper.yCorr || 0,
2360
- currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth].join(',');
2365
+ currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth].join(','),
2366
+ rotationStyle = {},
2367
+ prefix;
2361
2368
 
2362
2369
  if (currentTextTransform !== wrapper.cTT) { // do the calculations and DOM access only if properties changed
2363
2370
 
2364
2371
  if (defined(rotation)) {
2365
- radians = rotation * deg2rad; // deg to rad
2366
- costheta = mathCos(radians);
2367
- sintheta = mathSin(radians);
2368
-
2369
- // Adjust for alignment and rotation. Rotation of useHTML content is not yet implemented
2370
- // but it can probably be implemented for Firefox 3.5+ on user request. FF3.5+
2371
- // has support for CSS3 transform. The getBBox method also needs to be updated
2372
- // to compensate for the rotation, like it currently does for SVG.
2373
- // Test case: http://highcharts.com/tests/?file=text-rotation
2374
- css(elem, {
2375
- filter: rotation ? ['progid:DXImageTransform.Microsoft.Matrix(M11=', costheta,
2376
- ', M12=', -sintheta, ', M21=', sintheta, ', M22=', costheta,
2377
- ', sizingMethod=\'auto expand\')'].join('') : NONE
2378
- });
2372
+
2373
+ if (renderer.isSVG) { // #916
2374
+ prefix = isIE ? '-ms' : isWebKit ? '-webkit' : isFirefox ? '-moz' : isOpera ? '-o' : '';
2375
+ rotationStyle[prefix + '-transform'] = rotationStyle.transform = 'rotate(' + rotation + 'deg)';
2376
+
2377
+ } else {
2378
+ radians = rotation * deg2rad; // deg to rad
2379
+ costheta = mathCos(radians);
2380
+ sintheta = mathSin(radians);
2381
+
2382
+ // Adjust for alignment and rotation. Rotation of useHTML content is not yet implemented
2383
+ // but it can probably be implemented for Firefox 3.5+ on user request. FF3.5+
2384
+ // has support for CSS3 transform. The getBBox method also needs to be updated
2385
+ // to compensate for the rotation, like it currently does for SVG.
2386
+ // Test case: http://highcharts.com/tests/?file=text-rotation
2387
+ rotationStyle.filter = rotation ? ['progid:DXImageTransform.Microsoft.Matrix(M11=', costheta,
2388
+ ', M12=', -sintheta, ', M21=', sintheta, ', M22=', costheta,
2389
+ ', sizingMethod=\'auto expand\')'].join('') : NONE;
2390
+ }
2391
+
2392
+ css(elem, rotationStyle);
2379
2393
  }
2380
2394
 
2381
2395
  width = pick(wrapper.elemWidth, elem.offsetWidth);
@@ -2531,50 +2545,61 @@ SVGElement.prototype = {
2531
2545
  /**
2532
2546
  * Get the bounding box (width, height, x and y) for the element
2533
2547
  */
2534
- getBBox: function (refresh) {
2548
+ getBBox: function () {
2535
2549
  var wrapper = this,
2536
- bBox,
2550
+ bBox = wrapper.bBox,
2551
+ renderer = wrapper.renderer,
2537
2552
  width,
2538
2553
  height,
2539
2554
  rotation = wrapper.rotation,
2540
2555
  element = wrapper.element,
2541
2556
  rad = rotation * deg2rad;
2542
2557
 
2543
- // SVG elements
2544
- if (element.namespaceURI === SVG_NS || wrapper.renderer.forExport) {
2545
- try { // Fails in Firefox if the container has display: none.
2558
+ if (!bBox) {
2559
+ // SVG elements
2560
+ if (element.namespaceURI === SVG_NS || renderer.forExport) {
2561
+ try { // Fails in Firefox if the container has display: none.
2562
+
2563
+ bBox = element.getBBox ?
2564
+ // SVG: use extend because IE9 is not allowed to change width and height in case
2565
+ // of rotation (below)
2566
+ extend({}, element.getBBox()) :
2567
+ // Canvas renderer and legacy IE in export mode
2568
+ {
2569
+ width: element.offsetWidth,
2570
+ height: element.offsetHeight
2571
+ };
2572
+ } catch (e) {}
2573
+
2574
+ // If the bBox is not set, the try-catch block above failed. The other condition
2575
+ // is for Opera that returns a width of -Infinity on hidden elements.
2576
+ if (!bBox || bBox.width < 0) {
2577
+ bBox = { width: 0, height: 0 };
2578
+ }
2579
+
2580
+
2581
+ // VML Renderer or useHTML within SVG
2582
+ } else {
2583
+
2584
+ bBox = wrapper.htmlGetBBox();
2546
2585
 
2547
- bBox = element.getBBox ?
2548
- // SVG: use extend because IE9 is not allowed to change width and height in case
2549
- // of rotation (below)
2550
- extend({}, element.getBBox()) :
2551
- // Canvas renderer and legacy IE in export mode
2552
- {
2553
- width: element.offsetWidth,
2554
- height: element.offsetHeight
2555
- };
2556
- } catch (e) {}
2557
-
2558
- // If the bBox is not set, the try-catch block above failed. The other condition
2559
- // is for Opera that returns a width of -Infinity on hidden elements.
2560
- if (!bBox || bBox.width < 0) {
2561
- bBox = { width: 0, height: 0 };
2562
2586
  }
2563
2587
 
2564
- width = bBox.width;
2565
- height = bBox.height;
2566
-
2567
- // adjust for rotated text
2568
- if (rotation) {
2569
- bBox.width = mathAbs(height * mathSin(rad)) + mathAbs(width * mathCos(rad));
2570
- bBox.height = mathAbs(height * mathCos(rad)) + mathAbs(width * mathSin(rad));
2588
+ // True SVG elements as well as HTML elements in modern browsers using the .useHTML option
2589
+ // need to compensated for rotation
2590
+ if (renderer.isSVG) {
2591
+ width = bBox.width;
2592
+ height = bBox.height;
2593
+
2594
+ // Adjust for rotated text
2595
+ if (rotation) {
2596
+ bBox.width = mathAbs(height * mathSin(rad)) + mathAbs(width * mathCos(rad));
2597
+ bBox.height = mathAbs(height * mathCos(rad)) + mathAbs(width * mathSin(rad));
2598
+ }
2571
2599
  }
2572
-
2573
- // VML Renderer or useHTML within SVG
2574
- } else {
2575
- bBox = wrapper.htmlGetBBox(refresh);
2600
+
2601
+ wrapper.bBox = bBox;
2576
2602
  }
2577
-
2578
2603
  return bBox;
2579
2604
  },
2580
2605
 
@@ -3054,6 +3079,7 @@ SVGRenderer.prototype = {
3054
3079
  rest = [];
3055
3080
 
3056
3081
  while (words.length || rest.length) {
3082
+ delete wrapper.bBox; // delete cache
3057
3083
  actualWidth = wrapper.getBBox().width;
3058
3084
  tooLong = actualWidth > width;
3059
3085
  if (!tooLong || words.length === 1) { // new line needed
@@ -3748,6 +3774,9 @@ SVGRenderer.prototype = {
3748
3774
 
3749
3775
  // Text setter
3750
3776
  attrSetters.text = function (value) {
3777
+ if (value !== element.innerHTML) {
3778
+ delete this.bBox;
3779
+ }
3751
3780
  element.innerHTML = value;
3752
3781
  return false;
3753
3782
  };
@@ -3916,7 +3945,7 @@ SVGRenderer.prototype = {
3916
3945
  style = text.element.style;
3917
3946
 
3918
3947
  bBox = (width === undefined || height === undefined || wrapper.styles.textAlign) &&
3919
- text.getBBox(true);
3948
+ text.getBBox();
3920
3949
  wrapper.width = (width || bBox.width || 0) + 2 * padding;
3921
3950
  wrapper.height = (height || bBox.height || 0) + 2 * padding;
3922
3951
 
@@ -4213,11 +4242,6 @@ var VMLElement = {
4213
4242
  renderer.invertChild(element, parentNode);
4214
4243
  }
4215
4244
 
4216
- // issue #140 workaround - related to #61 and #74
4217
- if (docMode8 && parentNode.gVis === HIDDEN) {
4218
- css(element, { visibility: HIDDEN });
4219
- }
4220
-
4221
4245
  // append it
4222
4246
  parentNode.appendChild(element);
4223
4247
 
@@ -4233,26 +4257,6 @@ var VMLElement = {
4233
4257
  return wrapper;
4234
4258
  },
4235
4259
 
4236
- /**
4237
- * In IE8 documentMode 8, we need to recursively set the visibility down in the DOM
4238
- * tree for nested groups. Related to #61, #586.
4239
- */
4240
- toggleChildren: function (element, visibility) {
4241
- var childNodes = element.childNodes,
4242
- i = childNodes.length;
4243
-
4244
- while (i--) {
4245
-
4246
- // apply the visibility
4247
- css(childNodes[i], { visibility: visibility });
4248
-
4249
- // we have a nested group, apply it to its children again
4250
- if (childNodes[i].nodeName === 'DIV') {
4251
- this.toggleChildren(childNodes[i], visibility);
4252
- }
4253
- }
4254
- },
4255
-
4256
4260
  /**
4257
4261
  * VML always uses htmlUpdateTransform
4258
4262
  */
@@ -4356,24 +4360,33 @@ var VMLElement = {
4356
4360
  }
4357
4361
  skipAttr = true;
4358
4362
 
4359
- // directly mapped to css
4360
- } else if (key === 'zIndex' || key === 'visibility') {
4361
-
4362
- // workaround for #61 and #586
4363
- if (docMode8 && key === 'visibility' && nodeName === 'DIV') {
4364
- element.gVis = value;
4365
- wrapper.toggleChildren(element, value);
4366
- if (value === VISIBLE) { // #74
4367
- value = null;
4363
+ // handle visibility
4364
+ } else if (key === 'visibility') {
4365
+
4366
+ // let the shadow follow the main element
4367
+ if (shadows) {
4368
+ i = shadows.length;
4369
+ while (i--) {
4370
+ shadows[i].style[key] = value;
4368
4371
  }
4369
4372
  }
4373
+
4374
+ // Instead of toggling the visibility CSS property, move the div out of the viewport.
4375
+ // This works around #61 and #586
4376
+ if (nodeName === 'DIV') {
4377
+ value = value === HIDDEN ? '-999em' : 0;
4378
+ key = 'top';
4379
+ }
4380
+
4381
+ elemStyle[key] = value;
4382
+ skipAttr = true;
4383
+
4384
+ // directly mapped to css
4385
+ } else if (key === 'zIndex') {
4370
4386
 
4371
4387
  if (value) {
4372
4388
  elemStyle[key] = value;
4373
4389
  }
4374
-
4375
-
4376
-
4377
4390
  skipAttr = true;
4378
4391
 
4379
4392
  // width and height
@@ -4463,16 +4476,6 @@ var VMLElement = {
4463
4476
  skipAttr = true;
4464
4477
  }
4465
4478
 
4466
- // let the shadow follow the main element
4467
- if (shadows && key === 'visibility') {
4468
- i = shadows.length;
4469
- while (i--) {
4470
- shadows[i].style[key] = value;
4471
- }
4472
- }
4473
-
4474
-
4475
-
4476
4479
  if (!skipAttr) {
4477
4480
  if (docMode8) { // IE8 setAttribute bug
4478
4481
  element[key] = value;
@@ -4496,7 +4499,8 @@ var VMLElement = {
4496
4499
  var wrapper = this,
4497
4500
  clipMembers,
4498
4501
  element = wrapper.element,
4499
- parentNode = element.parentNode;
4502
+ parentNode = element.parentNode,
4503
+ cssRet;
4500
4504
 
4501
4505
  if (clipRect) {
4502
4506
  clipMembers = clipRect.members;
@@ -4508,12 +4512,17 @@ var VMLElement = {
4508
4512
  if (parentNode && parentNode.className === 'highcharts-tracker' && !docMode8) {
4509
4513
  css(element, { visibility: HIDDEN });
4510
4514
  }
4515
+ cssRet = clipRect.getCSS(wrapper);
4511
4516
 
4512
- } else if (wrapper.destroyClip) {
4513
- wrapper.destroyClip();
4517
+ } else {
4518
+ if (wrapper.destroyClip) {
4519
+ wrapper.destroyClip();
4520
+ }
4521
+ cssRet = { clip: docMode8 ? 'inherit' : 'rect(auto)' }; // #1214
4514
4522
  }
4515
4523
 
4516
- return wrapper.css(clipRect ? clipRect.getCSS(wrapper) : { clip: 'inherit' });
4524
+ return wrapper.css(cssRet);
4525
+
4517
4526
  },
4518
4527
 
4519
4528
  /**
@@ -4529,8 +4538,7 @@ var VMLElement = {
4529
4538
  safeRemoveChild: function (element) {
4530
4539
  // discardElement will detach the node from its parent before attaching it
4531
4540
  // to the garbage bin. Therefore it is important that the node is attached and have parent.
4532
- var parentNode = element.parentNode;
4533
- if (parentNode) {
4541
+ if (element.parentNode) {
4534
4542
  discardElement(element);
4535
4543
  }
4536
4544
  },
@@ -4539,13 +4547,11 @@ var VMLElement = {
4539
4547
  * Extend element.destroy by removing it from the clip members array
4540
4548
  */
4541
4549
  destroy: function () {
4542
- var wrapper = this;
4543
-
4544
- if (wrapper.destroyClip) {
4545
- wrapper.destroyClip();
4550
+ if (this.destroyClip) {
4551
+ this.destroyClip();
4546
4552
  }
4547
4553
 
4548
- return SVGElement.prototype.destroy.apply(wrapper);
4554
+ return SVGElement.prototype.destroy.apply(this);
4549
4555
  },
4550
4556
 
4551
4557
  /**
@@ -5442,7 +5448,7 @@ Tick.prototype = {
5442
5448
  var label = this.label,
5443
5449
  axis = this.axis;
5444
5450
  return label ?
5445
- ((this.labelBBox = label.getBBox(true)))[axis.horiz ? 'height' : 'width'] :
5451
+ ((this.labelBBox = label.getBBox()))[axis.horiz ? 'height' : 'width'] :
5446
5452
  0;
5447
5453
  },
5448
5454
 
@@ -5616,7 +5622,7 @@ Tick.prototype = {
5616
5622
  step = labelOptions.step,
5617
5623
  attribs,
5618
5624
  show = true,
5619
- tickmarkOffset = (options.categories && options.tickmarkPlacement === 'between') ? 0.5 : 0,
5625
+ tickmarkOffset = axis.tickmarkOffset,
5620
5626
  xy = tick.getPosition(horiz, pos, tickmarkOffset, old),
5621
5627
  x = xy.x,
5622
5628
  y = xy.y,
@@ -6259,6 +6265,8 @@ Axis.prototype = {
6259
6265
  // Tick intervals
6260
6266
  //axis.tickInterval = UNDEFINED;
6261
6267
  //axis.minorTickInterval = UNDEFINED;
6268
+
6269
+ axis.tickmarkOffset = (options.categories && options.tickmarkPlacement === 'between') ? 0.5 : 0;
6262
6270
 
6263
6271
  // Major ticks
6264
6272
  axis.ticks = {};
@@ -7336,6 +7344,15 @@ Axis.prototype = {
7336
7344
  });
7337
7345
  },
7338
7346
 
7347
+ /**
7348
+ * Overridable method for zooming chart. Pulled out in a separate method to allow overriding
7349
+ * in stock charts.
7350
+ */
7351
+ zoom: function (newMin, newMax) {
7352
+ this.setExtremes(newMin, newMax, false, UNDEFINED, { trigger: 'zoom' });
7353
+ return true;
7354
+ },
7355
+
7339
7356
  /**
7340
7357
  * Update the axis metrics
7341
7358
  */
@@ -7540,6 +7557,8 @@ Axis.prototype = {
7540
7557
  horiz = this.horiz,
7541
7558
  lineLeft = this.left + (opposite ? this.width : 0) + offset,
7542
7559
  lineTop = chart.chartHeight - this.bottom - (opposite ? this.height : 0) + offset;
7560
+
7561
+ this.lineTop = lineTop; // used by flag series
7543
7562
 
7544
7563
  return chart.renderer.crispLine([
7545
7564
  M,
@@ -7617,6 +7636,7 @@ Axis.prototype = {
7617
7636
  alternateBands = axis.alternateBands,
7618
7637
  stackLabelOptions = options.stackLabels,
7619
7638
  alternateGridColor = options.alternateGridColor,
7639
+ tickmarkOffset = axis.tickmarkOffset,
7620
7640
  lineWidth = options.lineWidth,
7621
7641
  linePath,
7622
7642
  hasRendered = chart.hasRendered,
@@ -7679,8 +7699,8 @@ Axis.prototype = {
7679
7699
  if (!alternateBands[pos]) {
7680
7700
  alternateBands[pos] = new PlotLineOrBand(axis);
7681
7701
  }
7682
- from = pos;
7683
- to = tickPositions[i + 1] !== UNDEFINED ? tickPositions[i + 1] : axis.max;
7702
+ from = pos + tickmarkOffset; // #949
7703
+ to = tickPositions[i + 1] !== UNDEFINED ? tickPositions[i + 1] + tickmarkOffset : axis.max;
7684
7704
  alternateBands[pos].options = {
7685
7705
  from: isLog ? lin2log(from) : from,
7686
7706
  to: isLog ? lin2log(to) : to,
@@ -9302,7 +9322,7 @@ Legend.prototype = {
9302
9322
 
9303
9323
  // sort by legendIndex
9304
9324
  stableSort(allItems, function (a, b) {
9305
- return (a.options.legendIndex || 0) - (b.options.legendIndex || 0);
9325
+ return ((a.options && a.options.legendIndex) || 0) - ((b.options && b.options.legendIndex) || 0);
9306
9326
  });
9307
9327
 
9308
9328
  // reversed legend
@@ -10008,22 +10028,12 @@ Chart.prototype = {
10008
10028
  */
10009
10029
  zoom: function (event) {
10010
10030
  var chart = this,
10011
- optionsChart = chart.options.chart;
10012
-
10013
- // add button to reset selection
10014
- var hasZoomed;
10015
-
10016
- if (chart.resetZoomEnabled !== false && !chart.resetZoomButton) { // hook for Stock charts etc.
10017
- chart.showResetZoom();
10018
- }
10031
+ hasZoomed;
10019
10032
 
10020
10033
  // if zoom is called with no arguments, reset the axes
10021
10034
  if (!event || event.resetSelection) {
10022
10035
  each(chart.axes, function (axis) {
10023
- if (axis.options.zoomEnabled !== false) {
10024
- axis.setExtremes(null, null, false, UNDEFINED, { trigger: 'zoomout' });
10025
- hasZoomed = true;
10026
- }
10036
+ hasZoomed = axis.zoom();
10027
10037
  });
10028
10038
  } else { // else, zoom in on all axes
10029
10039
  each(event.xAxis.concat(event.yAxis), function (axisData) {
@@ -10031,16 +10041,21 @@ Chart.prototype = {
10031
10041
 
10032
10042
  // don't zoom more than minRange
10033
10043
  if (chart.tracker[axis.isXAxis ? 'zoomX' : 'zoomY']) {
10034
- axis.setExtremes(axisData.min, axisData.max, false, UNDEFINED, { trigger: 'zoom' });
10035
- hasZoomed = true;
10044
+ hasZoomed = axis.zoom(axisData.min, axisData.max);
10036
10045
  }
10037
10046
  });
10038
10047
  }
10048
+
10049
+ // Show the Reset zoom button
10050
+ if (!chart.resetZoomButton) {
10051
+ chart.showResetZoom();
10052
+ }
10053
+
10039
10054
 
10040
10055
  // Redraw
10041
10056
  if (hasZoomed) {
10042
10057
  chart.redraw(
10043
- pick(optionsChart.animation, chart.pointCount < 100) // animation
10058
+ pick(chart.options.chart.animation, chart.pointCount < 100) // animation
10044
10059
  );
10045
10060
  }
10046
10061
  },
@@ -10771,8 +10786,8 @@ Chart.prototype = {
10771
10786
 
10772
10787
  // Labels
10773
10788
  if (labels.items) {
10774
- each(labels.items, function () {
10775
- var style = extend(labels.style, this.style),
10789
+ each(labels.items, function (label) {
10790
+ var style = extend(labels.style, label.style),
10776
10791
  x = pInt(style.left) + chart.plotLeft,
10777
10792
  y = pInt(style.top) + chart.plotTop + 12;
10778
10793
 
@@ -10781,7 +10796,7 @@ Chart.prototype = {
10781
10796
  delete style.top;
10782
10797
 
10783
10798
  renderer.text(
10784
- this.html,
10799
+ label.html,
10785
10800
  x,
10786
10801
  y
10787
10802
  )
@@ -11064,10 +11079,7 @@ Point.prototype = {
11064
11079
 
11065
11080
  if (series.options.colorByPoint) {
11066
11081
  defaultColors = series.chart.options.colors;
11067
- if (!point.options) {
11068
- point.options = {};
11069
- }
11070
- point.color = point.options.color = point.color || defaultColors[counters.color++];
11082
+ point.color = point.color || defaultColors[counters.color++];
11071
11083
 
11072
11084
  // loop back to zero
11073
11085
  counters.wrapColor(defaultColors.length);
@@ -11643,7 +11655,7 @@ Series.prototype = {
11643
11655
  chart.series.push(series);
11644
11656
 
11645
11657
  // Sort series according to index option (#248, #1123)
11646
- chart.series.sort(function (a, b) {
11658
+ stableSort(chart.series, function (a, b) {
11647
11659
  return (a.options.index || 0) - (b.options.index || 0);
11648
11660
  });
11649
11661
  each(chart.series, function (series, i) {
@@ -12286,7 +12298,7 @@ Series.prototype = {
12286
12298
  yValue = yBottom + yValue;
12287
12299
 
12288
12300
  if (isBottomSeries) {
12289
- yBottom = pick(options.threshold, yAxis.min);
12301
+ yBottom = pick(options.threshold, yAxis.isLog ? null : yAxis.min); // #1200
12290
12302
  }
12291
12303
 
12292
12304
  if (stacking === 'percent') {
@@ -12541,18 +12553,13 @@ Series.prototype = {
12541
12553
  afterAnimate: function () {
12542
12554
  var chart = this.chart,
12543
12555
  sharedClipKey = this.sharedClipKey,
12544
- group = this.group,
12545
- trackerGroup = this.trackerGroup;
12556
+ group = this.group;
12546
12557
 
12547
12558
  if (group && this.options.clip !== false) {
12548
12559
  group.clip(chart.clipRect);
12549
12560
  this.markerGroup.clip(); // no clip
12550
12561
  }
12551
12562
 
12552
- if (trackerGroup) {
12553
- trackerGroup.clip(chart.clipRect);
12554
- }
12555
-
12556
12563
  // Remove the shared clipping rectancgle when all series are shown
12557
12564
  setTimeout(function () {
12558
12565
  if (sharedClipKey && chart[sharedClipKey]) {
@@ -12725,8 +12732,8 @@ Series.prototype = {
12725
12732
  if (normalOptions && normalOptions.enabled === false) {
12726
12733
  normalOptions.radius = 0;
12727
12734
  }
12728
- hasPointSpecificOptions = false;
12729
-
12735
+ hasPointSpecificOptions = series.options.colorByPoint; // #868
12736
+
12730
12737
  // check if the point has specific visual options
12731
12738
  if (point.options) {
12732
12739
  for (key in pointAttrToOptions) {
@@ -12741,22 +12748,25 @@ Series.prototype = {
12741
12748
  // a specific marker config object is defined for the individual point:
12742
12749
  // create it's own attribute collection
12743
12750
  if (hasPointSpecificOptions) {
12744
-
12751
+ normalOptions = normalOptions || {};
12745
12752
  pointAttr = [];
12746
12753
  stateOptions = normalOptions.states || {}; // reassign for individual point
12747
12754
  pointStateOptionsHover = stateOptions[HOVER_STATE] = stateOptions[HOVER_STATE] || {};
12748
12755
 
12749
- // if no hover color is given, brighten the normal color
12756
+ // Handle colors for column and pies
12750
12757
  if (!series.options.marker) { // column, bar, point
12758
+ // if no hover color is given, brighten the normal color
12751
12759
  pointStateOptionsHover.color =
12752
- Color(pointStateOptionsHover.color || point.options.color)
12760
+ Color(pointStateOptionsHover.color || point.color)
12753
12761
  .brighten(pointStateOptionsHover.brightness ||
12754
12762
  stateOptionsHover.brightness).get();
12755
12763
 
12756
12764
  }
12757
12765
 
12758
12766
  // normal point state inherits series wide normal state
12759
- pointAttr[NORMAL_STATE] = series.convertAttribs(normalOptions, seriesPointAttr[NORMAL_STATE]);
12767
+ pointAttr[NORMAL_STATE] = series.convertAttribs(extend({
12768
+ color: point.color // #868
12769
+ }, normalOptions), seriesPointAttr[NORMAL_STATE]);
12760
12770
 
12761
12771
  // inherit from point normal and series hover
12762
12772
  pointAttr[HOVER_STATE] = series.convertAttribs(
@@ -12885,9 +12895,7 @@ Series.prototype = {
12885
12895
  yIsNull = options.y === null,
12886
12896
  fontMetrics = renderer.fontMetrics(options.style.fontSize), // height and baseline
12887
12897
  fontLineHeight = fontMetrics.h,
12888
- fontBaseline = fontMetrics.b,
12889
- dataLabel,
12890
- enabled;
12898
+ fontBaseline = fontMetrics.b;
12891
12899
 
12892
12900
  if (isBarLike) {
12893
12901
  var defaultYs = {
@@ -12931,7 +12939,11 @@ Series.prototype = {
12931
12939
  generalOptions = options;
12932
12940
  each(points, function (point) {
12933
12941
 
12934
- dataLabel = point.dataLabel;
12942
+ var plotX,
12943
+ plotY,
12944
+ individualYDelta,
12945
+ enabled,
12946
+ dataLabel = point.dataLabel;
12935
12947
 
12936
12948
  // Merge in individual options from point
12937
12949
  options = generalOptions; // reset changes from previous points
@@ -12943,24 +12955,30 @@ Series.prototype = {
12943
12955
 
12944
12956
  // Get the positions
12945
12957
  if (enabled) {
12946
- var plotX = (point.barX && point.barX + point.barW / 2) || pick(point.plotX, -999),
12947
- plotY = pick(point.plotY, -999),
12958
+ plotX = (point.barX && point.barX + point.barW / 2) || pick(point.plotX, -999);
12959
+ plotY = pick(point.plotY, -999);
12948
12960
 
12949
- // if options.y is null, which happens by default on column charts, set the position
12950
- // above or below the column depending on the threshold
12951
- individualYDelta = options.y === null ?
12952
- (point.y >= seriesOptions.threshold ?
12953
- -fontLineHeight + fontBaseline : // below the threshold
12954
- fontBaseline) : // above the threshold
12955
- options.y;
12961
+ // if options.y is null, which happens by default on column charts, set the position
12962
+ // above or below the column depending on the threshold
12963
+ individualYDelta = options.y === null ?
12964
+ (point.y >= seriesOptions.threshold ?
12965
+ -fontLineHeight + fontBaseline : // below the threshold
12966
+ fontBaseline) : // above the threshold
12967
+ options.y;
12956
12968
 
12957
12969
  x = (inverted ? chart.plotWidth - plotY : plotX) + options.x;
12958
12970
  y = mathRound((inverted ? chart.plotHeight - plotX : plotY) + individualYDelta);
12959
12971
 
12960
12972
  }
12961
12973
 
12974
+ // Check if the individual label must be disabled due to either falling
12975
+ // ouside the plot area, or the enabled option being switched off
12976
+ if (series.isCartesian && !chart.isInsidePlot(x - options.x, y)) {
12977
+ enabled = false;
12978
+ }
12979
+
12962
12980
  // If the point is outside the plot area, destroy it. #678, #820
12963
- if (dataLabel && series.isCartesian && (!chart.isInsidePlot(x, y) || !enabled)) {
12981
+ if (dataLabel && !enabled) {
12964
12982
  point.dataLabel = dataLabel.destroy();
12965
12983
 
12966
12984
  // Individual labels are disabled if the are explicitly disabled
@@ -13286,6 +13304,9 @@ Series.prototype = {
13286
13304
  // Initial clipping, must be defined after inverting groups for VML
13287
13305
  if (options.clip !== false && !series.sharedClipKey && !hasRendered) {
13288
13306
  group.clip(chart.clipRect);
13307
+ if (this.trackerGroup) {
13308
+ this.trackerGroup.clip(chart.clipRect);
13309
+ }
13289
13310
  }
13290
13311
 
13291
13312
  // Run the animation
@@ -14368,7 +14389,8 @@ var PiePoint = extendClass(Point, {
14368
14389
  */
14369
14390
  setVisible: function (vis) {
14370
14391
  var point = this,
14371
- chart = point.series.chart,
14392
+ series = point.series,
14393
+ chart = series.chart,
14372
14394
  tracker = point.tracker,
14373
14395
  dataLabel = point.dataLabel,
14374
14396
  connector = point.connector,
@@ -14396,6 +14418,12 @@ var PiePoint = extendClass(Point, {
14396
14418
  if (point.legendItem) {
14397
14419
  chart.legend.colorizeItem(point, vis);
14398
14420
  }
14421
+
14422
+ // Handle ignore hidden slices
14423
+ if (!series.isDirty && series.options.ignoreHiddenPoint) {
14424
+ series.isDirty = true;
14425
+ chart.redraw();
14426
+ }
14399
14427
  },
14400
14428
 
14401
14429
  /**
@@ -14549,7 +14577,8 @@ var PieSeries = {
14549
14577
  fraction,
14550
14578
  radiusX, // the x component of the radius vector for a given point
14551
14579
  radiusY,
14552
- labelDistance = options.dataLabels.distance;
14580
+ labelDistance = options.dataLabels.distance,
14581
+ ignoreHiddenPoint = options.ignoreHiddenPoint;
14553
14582
 
14554
14583
  // get positions - either an integer or a percentage string must be given
14555
14584
  series.center = positions = series.getCenter();
@@ -14566,14 +14595,16 @@ var PieSeries = {
14566
14595
 
14567
14596
  // get the total sum
14568
14597
  each(points, function (point) {
14569
- total += point.y;
14598
+ total += (ignoreHiddenPoint && !point.visible) ? 0 : point.y;
14570
14599
  });
14571
14600
 
14572
14601
  each(points, function (point) {
14573
14602
  // set start and end angle
14574
14603
  fraction = total ? point.y / total : 0;
14575
14604
  start = mathRound(cumulative * circ * precision) / precision;
14576
- cumulative += fraction;
14605
+ if (!ignoreHiddenPoint || point.visible) {
14606
+ cumulative += fraction;
14607
+ }
14577
14608
  end = mathRound(cumulative * circ * precision) / precision;
14578
14609
 
14579
14610
  // set the shape
@@ -15030,6 +15061,6 @@ extend(Highcharts, {
15030
15061
  canvas: useCanVG,
15031
15062
  vml: !hasSVG && !useCanVG,
15032
15063
  product: 'Highcharts',
15033
- version: '2.3.0'
15064
+ version: '2.3.2'
15034
15065
  });
15035
15066
  }());