highcharts-rails 2.3.0 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.
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
  }());