highcharts-rails 2.2.0 → 2.2.1
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 +4 -0
- data/README.markdown +6 -1
- data/lib/highcharts/version.rb +1 -1
- data/vendor/assets/images/highcharts/skies.jpg +0 -0
- data/vendor/assets/javascripts/highcharts.js +490 -238
- data/vendor/assets/javascripts/highcharts/adapters/mootools.js +1 -1
- data/vendor/assets/javascripts/highcharts/adapters/prototype.js +9 -3
- data/vendor/assets/javascripts/highcharts/modules/canvas-tools.js +472 -472
- data/vendor/assets/javascripts/highcharts/modules/exporting.js +9 -6
- data/vendor/assets/javascripts/highcharts/themes/skies.js +89 -0
- metadata +11 -8
data/CHANGELOG.markdown
ADDED
data/README.markdown
CHANGED
@@ -7,9 +7,13 @@ Highcharts is not free for commercial use, so make sure you have a [valid licens
|
|
7
7
|
|
8
8
|
Add the gem to the Gemfile
|
9
9
|
|
10
|
-
gem "highcharts-rails", "~> 2.1
|
10
|
+
gem "highcharts-rails", "~> 2.2.1"
|
11
11
|
# The gem version mirrors the included version of Highcharts
|
12
12
|
|
13
|
+
## Changes
|
14
|
+
|
15
|
+
Refer to the [Highcharts changelog](http://www.highcharts.com/documentation/changelog#highcharts)
|
16
|
+
|
13
17
|
## Usage
|
14
18
|
|
15
19
|
In your JavaScript manifest (e.g. `application.js`)
|
@@ -31,6 +35,7 @@ Or one of the themes
|
|
31
35
|
//= require highcharts/themes/dark-green
|
32
36
|
//= require highcharts/themes/gray
|
33
37
|
//= require highcharts/themes/grid
|
38
|
+
//= require highcharts/themes/skies
|
34
39
|
|
35
40
|
Other than that, refer to the [Highcharts documentation](http://highcharts.com/documentation/how-to-use)
|
36
41
|
|
data/lib/highcharts/version.rb
CHANGED
Binary file
|
@@ -2,7 +2,7 @@
|
|
2
2
|
// @compilation_level SIMPLE_OPTIMIZATIONS
|
3
3
|
|
4
4
|
/**
|
5
|
-
* @license Highcharts JS v2.2.
|
5
|
+
* @license Highcharts JS v2.2.1 (2012-03-15)
|
6
6
|
*
|
7
7
|
* (c) 2009-2011 Torstein Hønsi
|
8
8
|
*
|
@@ -368,6 +368,16 @@ function numberFormat(number, decimals, decPoint, thousandsSep) {
|
|
368
368
|
(c ? d + mathAbs(n - i).toFixed(c).slice(2) : "");
|
369
369
|
}
|
370
370
|
|
371
|
+
/**
|
372
|
+
* Pad a string to a given length by adding 0 to the beginning
|
373
|
+
* @param {Number} number
|
374
|
+
* @param {Number} length
|
375
|
+
*/
|
376
|
+
function pad(number, length) {
|
377
|
+
// Create an array of the remaining length +1 and join it with 0's
|
378
|
+
return new Array((length || 2) + 1 - String(number).length).join(0) + number;
|
379
|
+
}
|
380
|
+
|
371
381
|
/**
|
372
382
|
* Based on http://www.php.net/manual/en/function.strftime.php
|
373
383
|
* @param {String} format
|
@@ -375,16 +385,6 @@ function numberFormat(number, decimals, decPoint, thousandsSep) {
|
|
375
385
|
* @param {Boolean} capitalize
|
376
386
|
*/
|
377
387
|
dateFormat = function (format, timestamp, capitalize) {
|
378
|
-
function pad(number, length) {
|
379
|
-
// two digits
|
380
|
-
number = number.toString().replace(/^([0-9])$/, '0$1');
|
381
|
-
// three digits
|
382
|
-
if (length === 3) {
|
383
|
-
number = number.toString().replace(/^([0-9]{2})$/, '0$1');
|
384
|
-
}
|
385
|
-
return number;
|
386
|
-
}
|
387
|
-
|
388
388
|
if (!defined(timestamp) || isNaN(timestamp)) {
|
389
389
|
return 'Invalid date';
|
390
390
|
}
|
@@ -440,7 +440,7 @@ dateFormat = function (format, timestamp, capitalize) {
|
|
440
440
|
'p': hours < 12 ? 'AM' : 'PM', // Upper case AM or PM
|
441
441
|
'P': hours < 12 ? 'am' : 'pm', // Lower case AM or PM
|
442
442
|
'S': pad(date.getSeconds()), // Two digits seconds, 00 through 59
|
443
|
-
'L': pad(timestamp % 1000, 3) // Milliseconds (naming from Ruby)
|
443
|
+
'L': pad(mathRound(timestamp % 1000), 3) // Milliseconds (naming from Ruby)
|
444
444
|
};
|
445
445
|
|
446
446
|
|
@@ -595,9 +595,10 @@ function getTimeTicks(normalizedInterval, min, max, startOfWeek) {
|
|
595
595
|
interval = normalizedInterval.unitRange,
|
596
596
|
count = normalizedInterval.count;
|
597
597
|
|
598
|
-
|
598
|
+
|
599
599
|
|
600
600
|
if (interval >= timeUnits[SECOND]) { // second
|
601
|
+
minDate.setMilliseconds(0);
|
601
602
|
minDate.setSeconds(interval >= timeUnits[MINUTE] ? 0 :
|
602
603
|
count * mathFloor(minDate.getSeconds() / count));
|
603
604
|
}
|
@@ -1269,7 +1270,7 @@ defaultOptions = {
|
|
1269
1270
|
},
|
1270
1271
|
global: {
|
1271
1272
|
useUTC: true,
|
1272
|
-
canvasToolsURL: 'http://code.highcharts.com/2.2.
|
1273
|
+
canvasToolsURL: 'http://code.highcharts.com/2.2.1/modules/canvas-tools.js'
|
1273
1274
|
},
|
1274
1275
|
chart: {
|
1275
1276
|
//animation: true,
|
@@ -1386,6 +1387,12 @@ defaultOptions = {
|
|
1386
1387
|
formatter: function () {
|
1387
1388
|
return this.y;
|
1388
1389
|
}
|
1390
|
+
// backgroundColor: undefined,
|
1391
|
+
// borderColor: undefined,
|
1392
|
+
// borderRadius: undefined,
|
1393
|
+
// borderWidth: undefined,
|
1394
|
+
// padding: 3,
|
1395
|
+
// shadow: false
|
1389
1396
|
}),
|
1390
1397
|
cropThreshold: 300, // draw points outside the plot area when the number of points is less than this
|
1391
1398
|
pointRange: 0,
|
@@ -1666,7 +1673,8 @@ defaultBottomAxisOptions = { // horizontal axis
|
|
1666
1673
|
labels: {
|
1667
1674
|
align: 'center',
|
1668
1675
|
x: 0,
|
1669
|
-
y: 14
|
1676
|
+
y: 14,
|
1677
|
+
overflow: 'justify' // docs
|
1670
1678
|
// staggerLines: null
|
1671
1679
|
},
|
1672
1680
|
title: {
|
@@ -1675,7 +1683,8 @@ defaultBottomAxisOptions = { // horizontal axis
|
|
1675
1683
|
},
|
1676
1684
|
defaultTopAxisOptions = merge(defaultBottomAxisOptions, {
|
1677
1685
|
labels: {
|
1678
|
-
y: -5
|
1686
|
+
y: -5,
|
1687
|
+
overflow: 'justify'
|
1679
1688
|
// staggerLines: null
|
1680
1689
|
}
|
1681
1690
|
});
|
@@ -1741,7 +1750,8 @@ defaultPlotOptions.bar = merge(defaultPlotOptions.column, {
|
|
1741
1750
|
dataLabels: {
|
1742
1751
|
align: 'left',
|
1743
1752
|
x: 5,
|
1744
|
-
y:
|
1753
|
+
y: null,
|
1754
|
+
verticalAlign: 'middle'
|
1745
1755
|
}
|
1746
1756
|
});
|
1747
1757
|
defaultPlotOptions.pie = merge(defaultSeriesOptions, {
|
@@ -2436,6 +2446,7 @@ SVGElement.prototype = {
|
|
2436
2446
|
}
|
2437
2447
|
|
2438
2448
|
var wrapper = this,
|
2449
|
+
renderer = wrapper.renderer,
|
2439
2450
|
elem = wrapper.element,
|
2440
2451
|
translateX = wrapper.translateX || 0,
|
2441
2452
|
translateY = wrapper.translateY || 0,
|
@@ -2465,7 +2476,7 @@ SVGElement.prototype = {
|
|
2465
2476
|
// apply inversion
|
2466
2477
|
if (wrapper.inverted) { // wrapper is a group
|
2467
2478
|
each(elem.childNodes, function (child) {
|
2468
|
-
|
2479
|
+
renderer.invertChild(child, elem);
|
2469
2480
|
});
|
2470
2481
|
}
|
2471
2482
|
|
@@ -2473,7 +2484,7 @@ SVGElement.prototype = {
|
|
2473
2484
|
|
2474
2485
|
var width, height,
|
2475
2486
|
rotation = wrapper.rotation,
|
2476
|
-
|
2487
|
+
baseline,
|
2477
2488
|
radians = 0,
|
2478
2489
|
costheta = 1,
|
2479
2490
|
sintheta = 0,
|
@@ -2516,14 +2527,14 @@ SVGElement.prototype = {
|
|
2516
2527
|
}
|
2517
2528
|
|
2518
2529
|
// correct x and y
|
2519
|
-
|
2530
|
+
baseline = renderer.fontMetrics(elem.style.fontSize).b;
|
2520
2531
|
xCorr = costheta < 0 && -width;
|
2521
2532
|
yCorr = sintheta < 0 && -height;
|
2522
2533
|
|
2523
|
-
// correct for
|
2534
|
+
// correct for baseline and corners spilling out after rotation
|
2524
2535
|
quad = costheta * sintheta < 0;
|
2525
|
-
xCorr += sintheta *
|
2526
|
-
yCorr -= costheta *
|
2536
|
+
xCorr += sintheta * baseline * (quad ? 1 - alignCorrection : alignCorrection);
|
2537
|
+
yCorr -= costheta * baseline * (rotation ? (quad ? alignCorrection : 1 - alignCorrection) : 1);
|
2527
2538
|
|
2528
2539
|
// correct for the length/height of the text
|
2529
2540
|
if (nonLeft) {
|
@@ -2934,7 +2945,7 @@ SVGRenderer.prototype = {
|
|
2934
2945
|
renderer.boxWrapper = boxWrapper;
|
2935
2946
|
renderer.alignedObjects = [];
|
2936
2947
|
renderer.url = isIE ? '' : loc.href.replace(/#.*?$/, '')
|
2937
|
-
.replace(
|
2948
|
+
.replace(/([\('\)])/g, '\\$1'); // Page url used for internal references. #24, #672.
|
2938
2949
|
renderer.defs = this.createElement('defs').add();
|
2939
2950
|
renderer.forExport = forExport;
|
2940
2951
|
renderer.gradients = {}; // Object where gradient SvgElements are stored
|
@@ -3849,6 +3860,23 @@ SVGRenderer.prototype = {
|
|
3849
3860
|
return wrapper;
|
3850
3861
|
},
|
3851
3862
|
|
3863
|
+
/**
|
3864
|
+
* Utility to return the baseline offset and total line height from the font size
|
3865
|
+
*/
|
3866
|
+
fontMetrics: function (fontSize) {
|
3867
|
+
fontSize = pInt(fontSize || 11);
|
3868
|
+
|
3869
|
+
// Empirical values found by comparing font size and bounding box height.
|
3870
|
+
// Applies to the default font family. http://jsfiddle.net/highcharts/7xvn7/
|
3871
|
+
var lineHeight = fontSize < 24 ? fontSize + 4 : mathRound(fontSize * 1.2),
|
3872
|
+
baseline = mathRound(lineHeight * 0.8);
|
3873
|
+
|
3874
|
+
return {
|
3875
|
+
h: lineHeight,
|
3876
|
+
b: baseline
|
3877
|
+
};
|
3878
|
+
},
|
3879
|
+
|
3852
3880
|
/**
|
3853
3881
|
* Add a label, a text item that can hold a colored or gradient background
|
3854
3882
|
* as well as a border and shadow.
|
@@ -3859,8 +3887,10 @@ SVGRenderer.prototype = {
|
|
3859
3887
|
* @param {Number} anchorX In case the shape has a pointer, like a flag, this is the
|
3860
3888
|
* coordinates it should be pinned to
|
3861
3889
|
* @param {Number} anchorY
|
3890
|
+
* @param {Boolean} baseline Whether to position the label relative to the text baseline,
|
3891
|
+
* like renderer.text, or to the upper border of the rectangle.
|
3862
3892
|
*/
|
3863
|
-
label: function (str, x, y, shape, anchorX, anchorY, useHTML) {
|
3893
|
+
label: function (str, x, y, shape, anchorX, anchorY, useHTML, baseline) {
|
3864
3894
|
|
3865
3895
|
var renderer = this,
|
3866
3896
|
wrapper = renderer.g(),
|
@@ -3879,6 +3909,7 @@ SVGRenderer.prototype = {
|
|
3879
3909
|
wrapperY,
|
3880
3910
|
crispAdjust = 0,
|
3881
3911
|
deferredAttr = {},
|
3912
|
+
baselineOffset,
|
3882
3913
|
attrSetters = wrapper.attrSetters;
|
3883
3914
|
|
3884
3915
|
/**
|
@@ -3887,16 +3918,25 @@ SVGRenderer.prototype = {
|
|
3887
3918
|
* box and reflect it in the border box.
|
3888
3919
|
*/
|
3889
3920
|
function updateBoxSize() {
|
3921
|
+
var boxY,
|
3922
|
+
style = text.element.style;
|
3923
|
+
|
3890
3924
|
bBox = (width === undefined || height === undefined || wrapper.styles.textAlign) &&
|
3891
3925
|
text.getBBox(true);
|
3892
3926
|
wrapper.width = (width || bBox.width) + 2 * padding;
|
3893
3927
|
wrapper.height = (height || bBox.height) + 2 * padding;
|
3894
3928
|
|
3929
|
+
// update the label-scoped y offset
|
3930
|
+
baselineOffset = padding + renderer.fontMetrics(style && style.fontSize).b;
|
3931
|
+
|
3932
|
+
|
3895
3933
|
// create the border box if it is not already present
|
3896
3934
|
if (!box) {
|
3935
|
+
boxY = baseline ? -baselineOffset : 0;
|
3936
|
+
|
3897
3937
|
wrapper.box = box = shape ?
|
3898
|
-
renderer.symbol(shape, 0,
|
3899
|
-
renderer.rect(0,
|
3938
|
+
renderer.symbol(shape, 0, boxY, wrapper.width, wrapper.height) :
|
3939
|
+
renderer.rect(0, boxY, wrapper.width, wrapper.height, 0, deferredAttr[STROKE_WIDTH]);
|
3900
3940
|
box.add(wrapper);
|
3901
3941
|
}
|
3902
3942
|
|
@@ -3915,8 +3955,10 @@ SVGRenderer.prototype = {
|
|
3915
3955
|
var styles = wrapper.styles,
|
3916
3956
|
textAlign = styles && styles.textAlign,
|
3917
3957
|
x = padding,
|
3918
|
-
|
3919
|
-
|
3958
|
+
y;
|
3959
|
+
|
3960
|
+
// determin y based on the baseline
|
3961
|
+
y = baseline ? 0 : baselineOffset;
|
3920
3962
|
|
3921
3963
|
// compensate for alignment
|
3922
3964
|
if (defined(width) && (textAlign === 'center' || textAlign === 'right')) {
|
@@ -3979,8 +4021,10 @@ SVGRenderer.prototype = {
|
|
3979
4021
|
return false;
|
3980
4022
|
};
|
3981
4023
|
attrSetters.padding = function (value) {
|
3982
|
-
|
3983
|
-
|
4024
|
+
if (defined(value) && value !== padding) {
|
4025
|
+
padding = value;
|
4026
|
+
updateTextPadding();
|
4027
|
+
}
|
3984
4028
|
|
3985
4029
|
return false;
|
3986
4030
|
};
|
@@ -4022,15 +4066,15 @@ SVGRenderer.prototype = {
|
|
4022
4066
|
|
4023
4067
|
// rename attributes
|
4024
4068
|
attrSetters.x = function (value) {
|
4025
|
-
|
4026
|
-
wrapperX
|
4069
|
+
value -= { left: 0, center: 0.5, right: 1 }[align] * ((width || bBox.width) + padding);
|
4070
|
+
wrapperX = wrapper.x = mathRound(value); // wrapper.x is for animation getter
|
4027
4071
|
|
4028
|
-
wrapper.attr('translateX',
|
4072
|
+
wrapper.attr('translateX', wrapperX);
|
4029
4073
|
return false;
|
4030
4074
|
};
|
4031
4075
|
attrSetters.y = function (value) {
|
4032
|
-
wrapperY = value;
|
4033
|
-
wrapper.attr('translateY',
|
4076
|
+
wrapperY = wrapper.y = mathRound(value);
|
4077
|
+
wrapper.attr('translateY', value);
|
4034
4078
|
return false;
|
4035
4079
|
};
|
4036
4080
|
|
@@ -4111,7 +4155,7 @@ if (!hasSVG && !useCanVG) {
|
|
4111
4155
|
/**
|
4112
4156
|
* The VML element wrapper.
|
4113
4157
|
*/
|
4114
|
-
var
|
4158
|
+
var VMLElement = {
|
4115
4159
|
|
4116
4160
|
/**
|
4117
4161
|
* Initialize a new VML element wrapper. It builds the markup as a string
|
@@ -4179,7 +4223,7 @@ var VMLElementExtension = {
|
|
4179
4223
|
// align text after adding to be able to read offset
|
4180
4224
|
wrapper.added = true;
|
4181
4225
|
if (wrapper.alignOnAdd && !wrapper.deferUpdateTransform) {
|
4182
|
-
wrapper.
|
4226
|
+
wrapper.updateTransform();
|
4183
4227
|
}
|
4184
4228
|
|
4185
4229
|
// fire an event for internal hooks
|
@@ -4208,6 +4252,11 @@ var VMLElementExtension = {
|
|
4208
4252
|
}
|
4209
4253
|
},
|
4210
4254
|
|
4255
|
+
/**
|
4256
|
+
* VML always uses htmlUpdateTransform
|
4257
|
+
*/
|
4258
|
+
updateTransform: SVGElement.prototype.htmlUpdateTransform,
|
4259
|
+
|
4211
4260
|
/**
|
4212
4261
|
* Get or set attributes
|
4213
4262
|
*/
|
@@ -4267,7 +4316,6 @@ var VMLElementExtension = {
|
|
4267
4316
|
// check all the others only once for each call to an element's
|
4268
4317
|
// .attr() method
|
4269
4318
|
if (!hasSetSymbolSize) {
|
4270
|
-
|
4271
4319
|
wrapper.symbolAttr(hash);
|
4272
4320
|
|
4273
4321
|
hasSetSymbolSize = true;
|
@@ -4397,7 +4445,7 @@ var VMLElementExtension = {
|
|
4397
4445
|
// translation for animation
|
4398
4446
|
} else if (key === 'translateX' || key === 'translateY' || key === 'rotation') {
|
4399
4447
|
wrapper[key] = value;
|
4400
|
-
wrapper.
|
4448
|
+
wrapper.updateTransform();
|
4401
4449
|
|
4402
4450
|
skipAttr = true;
|
4403
4451
|
|
@@ -4563,13 +4611,13 @@ var VMLElementExtension = {
|
|
4563
4611
|
return this;
|
4564
4612
|
|
4565
4613
|
}
|
4566
|
-
}
|
4567
|
-
VMLElement = extendClass(SVGElement,
|
4614
|
+
};
|
4615
|
+
VMLElement = extendClass(SVGElement, VMLElement);
|
4568
4616
|
|
4569
4617
|
/**
|
4570
4618
|
* The VML renderer
|
4571
4619
|
*/
|
4572
|
-
VMLRendererExtension = { // inherit SVGRenderer
|
4620
|
+
var VMLRendererExtension = { // inherit SVGRenderer
|
4573
4621
|
|
4574
4622
|
Element: VMLElement,
|
4575
4623
|
isIE8: userAgent.indexOf('MSIE 8.0') > -1,
|
@@ -4583,16 +4631,19 @@ VMLRendererExtension = { // inherit SVGRenderer
|
|
4583
4631
|
*/
|
4584
4632
|
init: function (container, width, height) {
|
4585
4633
|
var renderer = this,
|
4586
|
-
boxWrapper
|
4634
|
+
boxWrapper,
|
4635
|
+
box;
|
4587
4636
|
|
4588
4637
|
renderer.alignedObjects = [];
|
4589
4638
|
|
4590
4639
|
boxWrapper = renderer.createElement(DIV);
|
4640
|
+
box = boxWrapper.element;
|
4641
|
+
box.style.position = RELATIVE; // for freeform drawing using renderer directly
|
4591
4642
|
container.appendChild(boxWrapper.element);
|
4592
4643
|
|
4593
4644
|
|
4594
4645
|
// generate the containing box
|
4595
|
-
renderer.box =
|
4646
|
+
renderer.box = box;
|
4596
4647
|
renderer.boxWrapper = boxWrapper;
|
4597
4648
|
|
4598
4649
|
|
@@ -4727,7 +4778,7 @@ VMLRendererExtension = { // inherit SVGRenderer
|
|
4727
4778
|
// are reversed.
|
4728
4779
|
markup = ['<fill colors="0% ', color1, ',100% ', color2, '" angle="', angle,
|
4729
4780
|
'" opacity="', opacity2, '" o:opacity2="', opacity1,
|
4730
|
-
'" type="gradient" focus="100%" method="
|
4781
|
+
'" type="gradient" focus="100%" method="sigma" />'];
|
4731
4782
|
createElement(this.prepVML(markup), null, null, elem);
|
4732
4783
|
|
4733
4784
|
// Gradients are not supported for VML stroke, return the first color. #722.
|
@@ -4909,13 +4960,12 @@ VMLRendererExtension = { // inherit SVGRenderer
|
|
4909
4960
|
cosEnd = mathCos(end),
|
4910
4961
|
sinEnd = mathSin(end),
|
4911
4962
|
innerRadius = options.innerR,
|
4912
|
-
circleCorrection = 0.
|
4913
|
-
innerCorrection = (innerRadius && 0.
|
4963
|
+
circleCorrection = 0.08 / radius, // #760
|
4964
|
+
innerCorrection = (innerRadius && 0.25 / innerRadius) || 0;
|
4914
4965
|
|
4915
4966
|
if (end - start === 0) { // no angle, don't show it.
|
4916
4967
|
return ['x'];
|
4917
4968
|
|
4918
|
-
//} else if (end - start == 2 * mathPI) { // full circle
|
4919
4969
|
} else if (2 * mathPI - end + start < circleCorrection) { // full circle
|
4920
4970
|
// empirical correction found by trying out the limits for different radii
|
4921
4971
|
cosEnd = -circleCorrection;
|
@@ -5117,13 +5167,14 @@ Renderer = VMLRenderer || CanVGRenderer || SVGRenderer;
|
|
5117
5167
|
* @param {Object} options
|
5118
5168
|
* @param {Function} callback Function to run when the chart has loaded
|
5119
5169
|
*/
|
5120
|
-
function Chart(
|
5170
|
+
function Chart(userOptions, callback) {
|
5121
5171
|
|
5122
5172
|
// Handle regular options
|
5123
|
-
var
|
5124
|
-
|
5125
|
-
|
5126
|
-
options
|
5173
|
+
var options,
|
5174
|
+
seriesOptions = userOptions.series; // skip merging data points to increase performance
|
5175
|
+
userOptions.series = null;
|
5176
|
+
options = merge(defaultOptions, userOptions); // do the merge
|
5177
|
+
options.series = userOptions.series = seriesOptions; // set back the series data
|
5127
5178
|
|
5128
5179
|
var optionsChart = options.chart,
|
5129
5180
|
optionsMargin = optionsChart.margin,
|
@@ -5174,7 +5225,6 @@ function Chart(options, callback) {
|
|
5174
5225
|
plotWidth,
|
5175
5226
|
tracker,
|
5176
5227
|
trackerGroup,
|
5177
|
-
placeTrackerGroup,
|
5178
5228
|
legend,
|
5179
5229
|
legendWidth,
|
5180
5230
|
legendHeight,
|
@@ -5403,7 +5453,76 @@ function Chart(options, callback) {
|
|
5403
5453
|
return label ?
|
5404
5454
|
((this.labelBBox = label.getBBox()))[horiz ? 'height' : 'width'] :
|
5405
5455
|
0;
|
5406
|
-
|
5456
|
+
},
|
5457
|
+
|
5458
|
+
/**
|
5459
|
+
* Find how far the labels extend to the right and left of the tick's x position. Used for anti-collision
|
5460
|
+
* detection with overflow logic.
|
5461
|
+
*/
|
5462
|
+
getLabelSides: function () {
|
5463
|
+
var bBox = this.labelBBox, // assume getLabelSize has run at this point
|
5464
|
+
labelOptions = options.labels,
|
5465
|
+
width = bBox.width,
|
5466
|
+
leftSide = width * { left: 0, center: 0.5, right: 1 }[labelOptions.align] - labelOptions.x;
|
5467
|
+
|
5468
|
+
return [-leftSide, width - leftSide];
|
5469
|
+
},
|
5470
|
+
|
5471
|
+
/**
|
5472
|
+
* Handle the label overflow by adjusting the labels to the left and right edge, or
|
5473
|
+
* hide them if they collide into the neighbour label.
|
5474
|
+
*/
|
5475
|
+
handleOverflow: function (index) {
|
5476
|
+
var show = true,
|
5477
|
+
isFirst = this.isFirst,
|
5478
|
+
isLast = this.isLast,
|
5479
|
+
label = this.label,
|
5480
|
+
x = label.x;
|
5481
|
+
|
5482
|
+
if (isFirst || isLast) {
|
5483
|
+
|
5484
|
+
var sides = this.getLabelSides(),
|
5485
|
+
leftSide = sides[0],
|
5486
|
+
rightSide = sides[1],
|
5487
|
+
plotLeft = chart.plotLeft,
|
5488
|
+
plotRight = plotLeft + axis.len,
|
5489
|
+
neighbour = ticks[tickPositions[index + (isFirst ? 1 : -1)]],
|
5490
|
+
neighbourEdge = neighbour && neighbour.label.x + neighbour.getLabelSides()[isFirst ? 0 : 1];
|
5491
|
+
|
5492
|
+
if ((isFirst && !reversed) || (isLast && reversed)) {
|
5493
|
+
// Is the label spilling out to the left of the plot area?
|
5494
|
+
if (x + leftSide < plotLeft) {
|
5495
|
+
|
5496
|
+
// Align it to plot left
|
5497
|
+
x = plotLeft - leftSide;
|
5498
|
+
|
5499
|
+
// Hide it if it now overlaps the neighbour label
|
5500
|
+
if (neighbour && x + rightSide > neighbourEdge) {
|
5501
|
+
show = false;
|
5502
|
+
}
|
5503
|
+
}
|
5504
|
+
|
5505
|
+
} else {
|
5506
|
+
// Is the label spilling out to the right of the plot area?
|
5507
|
+
if (x + rightSide > plotRight) {
|
5508
|
+
|
5509
|
+
// Align it to plot right
|
5510
|
+
x = plotRight - rightSide;
|
5511
|
+
|
5512
|
+
// Hide it if it now overlaps the neighbour label
|
5513
|
+
if (neighbour && x + leftSide < neighbourEdge) {
|
5514
|
+
show = false;
|
5515
|
+
}
|
5516
|
+
|
5517
|
+
}
|
5518
|
+
}
|
5519
|
+
|
5520
|
+
// Set the modified x position of the label
|
5521
|
+
label.x = x;
|
5522
|
+
}
|
5523
|
+
return show;
|
5524
|
+
},
|
5525
|
+
|
5407
5526
|
/**
|
5408
5527
|
* Put everything in place
|
5409
5528
|
*
|
@@ -5432,6 +5551,7 @@ function Chart(options, callback) {
|
|
5432
5551
|
step = labelOptions.step,
|
5433
5552
|
cHeight = (old && oldChartHeight) || chartHeight,
|
5434
5553
|
attribs,
|
5554
|
+
show = true,
|
5435
5555
|
x,
|
5436
5556
|
y;
|
5437
5557
|
|
@@ -5527,29 +5647,42 @@ function Chart(options, callback) {
|
|
5527
5647
|
y += (index / (step || 1) % staggerLines) * 16;
|
5528
5648
|
}
|
5529
5649
|
|
5650
|
+
// Cache x and y to be able to read final position before animation
|
5651
|
+
label.x = x;
|
5652
|
+
label.y = y;
|
5653
|
+
|
5530
5654
|
// apply show first and show last
|
5531
5655
|
if ((tick.isFirst && !pick(options.showFirstLabel, 1)) ||
|
5532
5656
|
(tick.isLast && !pick(options.showLastLabel, 1))) {
|
5533
|
-
|
5534
|
-
|
5535
|
-
|
5536
|
-
|
5657
|
+
show = false;
|
5658
|
+
|
5659
|
+
// Handle label overflow and show or hide accordingly
|
5660
|
+
} else if (!staggerLines && horiz && labelOptions.overflow === 'justify' && !tick.handleOverflow(index)) {
|
5661
|
+
show = false;
|
5537
5662
|
}
|
5538
5663
|
|
5539
5664
|
// apply step
|
5540
5665
|
if (step && index % step) {
|
5541
5666
|
// show those indices dividable by step
|
5542
|
-
|
5667
|
+
show = false;
|
5543
5668
|
}
|
5544
5669
|
|
5545
|
-
|
5546
|
-
|
5547
|
-
|
5548
|
-
|
5670
|
+
// Set the new position, and show or hide
|
5671
|
+
if (show) {
|
5672
|
+
label[tick.isNew ? 'attr' : 'animate']({
|
5673
|
+
x: label.x,
|
5674
|
+
y: label.y
|
5675
|
+
});
|
5676
|
+
label.show();
|
5677
|
+
tick.isNew = false;
|
5678
|
+
} else {
|
5679
|
+
label.hide();
|
5680
|
+
}
|
5549
5681
|
}
|
5550
5682
|
|
5551
|
-
|
5683
|
+
|
5552
5684
|
},
|
5685
|
+
|
5553
5686
|
/**
|
5554
5687
|
* Destructor for the tick prototype
|
5555
5688
|
*/
|
@@ -5995,7 +6128,7 @@ function Chart(options, callback) {
|
|
5995
6128
|
}
|
5996
6129
|
|
5997
6130
|
// Adjust to threshold
|
5998
|
-
if (threshold
|
6131
|
+
if (defined(threshold)) {
|
5999
6132
|
if (dataMin >= threshold) {
|
6000
6133
|
dataMin = threshold;
|
6001
6134
|
ignoreMinPadding = true;
|
@@ -6349,8 +6482,8 @@ function Chart(options, callback) {
|
|
6349
6482
|
}
|
6350
6483
|
|
6351
6484
|
if (isLog) {
|
6352
|
-
if (!secondPass && min <= 0) {
|
6353
|
-
error(10); // Can't plot negative values on log axis
|
6485
|
+
if (!secondPass && mathMin(min, dataMin) <= 0) {
|
6486
|
+
error(10, 1); // Can't plot negative values on log axis
|
6354
6487
|
}
|
6355
6488
|
min = log2lin(min);
|
6356
6489
|
max = log2lin(max);
|
@@ -6450,12 +6583,6 @@ function Chart(options, callback) {
|
|
6450
6583
|
}
|
6451
6584
|
}
|
6452
6585
|
|
6453
|
-
// post process positions, used in ordinal axes in Highstock.
|
6454
|
-
// TODO: combine with getNonLinearTimeTicks
|
6455
|
-
fireEvent(axis, 'afterSetTickPositions', {
|
6456
|
-
tickPositions: tickPositions
|
6457
|
-
});
|
6458
|
-
|
6459
6586
|
if (!isLinked) {
|
6460
6587
|
|
6461
6588
|
// reset min/max or remove extremes based on start/end on tick
|
@@ -6526,7 +6653,8 @@ function Chart(options, callback) {
|
|
6526
6653
|
function setScale() {
|
6527
6654
|
var type,
|
6528
6655
|
i,
|
6529
|
-
isDirtyData
|
6656
|
+
isDirtyData,
|
6657
|
+
isDirtyAxisLength;
|
6530
6658
|
|
6531
6659
|
oldMin = min;
|
6532
6660
|
oldMax = max;
|
@@ -6534,6 +6662,7 @@ function Chart(options, callback) {
|
|
6534
6662
|
|
6535
6663
|
// set the new axisLength
|
6536
6664
|
axisLength = horiz ? axisWidth : axisHeight;
|
6665
|
+
isDirtyAxisLength = axisLength !== oldAxisLength;
|
6537
6666
|
|
6538
6667
|
// is there new data?
|
6539
6668
|
each(axis.series, function (series) {
|
@@ -6544,7 +6673,7 @@ function Chart(options, callback) {
|
|
6544
6673
|
});
|
6545
6674
|
|
6546
6675
|
// do we really need to go through all this?
|
6547
|
-
if (
|
6676
|
+
if (isDirtyAxisLength || isDirtyData || isLinked ||
|
6548
6677
|
userMin !== oldUserMin || userMax !== oldUserMax) {
|
6549
6678
|
|
6550
6679
|
// get data extremes if needed
|
@@ -6568,7 +6697,7 @@ function Chart(options, callback) {
|
|
6568
6697
|
|
6569
6698
|
// Mark as dirty if it is not already set to dirty and extremes have changed. #595.
|
6570
6699
|
if (!axis.isDirty) {
|
6571
|
-
axis.isDirty =
|
6700
|
+
axis.isDirty = isDirtyAxisLength || min !== oldMin || max !== oldMax;
|
6572
6701
|
}
|
6573
6702
|
}
|
6574
6703
|
}
|
@@ -6580,20 +6709,28 @@ function Chart(options, callback) {
|
|
6580
6709
|
* @param {Boolean} redraw
|
6581
6710
|
* @param {Boolean|Object} animation Whether to apply animation, and optionally animation
|
6582
6711
|
* configuration
|
6712
|
+
* @param {Object} eventArguments
|
6583
6713
|
*
|
6584
6714
|
*/
|
6585
|
-
function setExtremes(newMin, newMax, redraw, animation) {
|
6715
|
+
function setExtremes(newMin, newMax, redraw, animation, eventArguments) {
|
6586
6716
|
|
6587
6717
|
redraw = pick(redraw, true); // defaults to true
|
6588
6718
|
|
6589
|
-
|
6719
|
+
// Extend the arguments with min and max
|
6720
|
+
eventArguments = extend(eventArguments, {
|
6590
6721
|
min: newMin,
|
6591
6722
|
max: newMax
|
6592
|
-
}
|
6723
|
+
});
|
6724
|
+
|
6725
|
+
// Fire the event
|
6726
|
+
fireEvent(axis, 'setExtremes', eventArguments, function () { // the default event handler
|
6593
6727
|
|
6594
6728
|
userMin = newMin;
|
6595
6729
|
userMax = newMax;
|
6596
6730
|
|
6731
|
+
// Mark for running afterSetExtremes
|
6732
|
+
axis.isDirtyExtremes = true;
|
6733
|
+
|
6597
6734
|
// redraw
|
6598
6735
|
if (redraw) {
|
6599
6736
|
chart.redraw(animation);
|
@@ -6716,6 +6853,7 @@ function Chart(options, callback) {
|
|
6716
6853
|
var hasData = axis.series.length && defined(min) && defined(max),
|
6717
6854
|
showAxis = hasData || pick(options.showEmpty, true),
|
6718
6855
|
titleOffset = 0,
|
6856
|
+
titleOffsetOption,
|
6719
6857
|
titleMargin = 0,
|
6720
6858
|
axisTitleOptions = options.title,
|
6721
6859
|
labelOptions = options.labels,
|
@@ -6790,6 +6928,7 @@ function Chart(options, callback) {
|
|
6790
6928
|
if (showAxis) {
|
6791
6929
|
titleOffset = axisTitle.getBBox()[horiz ? 'height' : 'width'];
|
6792
6930
|
titleMargin = pick(axisTitleOptions.margin, horiz ? 5 : 10);
|
6931
|
+
titleOffsetOption = axisTitleOptions.offset;
|
6793
6932
|
}
|
6794
6933
|
|
6795
6934
|
// hide or show the title depending on whether showEmpty is set
|
@@ -6802,7 +6941,7 @@ function Chart(options, callback) {
|
|
6802
6941
|
offset = directionFactor * pick(options.offset, axisOffset[side]);
|
6803
6942
|
|
6804
6943
|
axisTitleMargin =
|
6805
|
-
pick(
|
6944
|
+
pick(titleOffsetOption,
|
6806
6945
|
labelOffset + titleMargin +
|
6807
6946
|
(side !== 2 && labelOffset && directionFactor * options.labels[horiz ? 'y' : 'x'])
|
6808
6947
|
);
|
@@ -6853,8 +6992,13 @@ function Chart(options, callback) {
|
|
6853
6992
|
});
|
6854
6993
|
}
|
6855
6994
|
|
6856
|
-
//
|
6857
|
-
|
6995
|
+
// Major ticks. Pull out the first item and render it last so that
|
6996
|
+
// we can get the position of the neighbour label. #808.
|
6997
|
+
each(tickPositions.slice(1).concat([tickPositions[0]]), function (pos, i) {
|
6998
|
+
|
6999
|
+
// Reorganize the indices
|
7000
|
+
i = (i === tickPositions.length - 1) ? 0 : i + 1;
|
7001
|
+
|
6858
7002
|
// linked axes need an extra check to find out if
|
6859
7003
|
if (!isLinked || (pos >= min && pos <= max)) {
|
6860
7004
|
|
@@ -7448,8 +7592,10 @@ function Chart(options, callback) {
|
|
7448
7592
|
while (i--) {
|
7449
7593
|
axis = point.series[i ? 'yAxis' : 'xAxis'];
|
7450
7594
|
if (crosshairsOptions[i] && axis) {
|
7451
|
-
path = axis
|
7452
|
-
|
7595
|
+
path = axis.getPlotLinePath(
|
7596
|
+
i ? pick(point.stackY, point.y) : point.x, // #814
|
7597
|
+
1
|
7598
|
+
);
|
7453
7599
|
if (crosshairs[i]) {
|
7454
7600
|
crosshairs[i].attr({ d: path, visibility: VISIBLE });
|
7455
7601
|
|
@@ -7942,7 +8088,9 @@ function Chart(options, callback) {
|
|
7942
8088
|
|
7943
8089
|
|
7944
8090
|
if (!hasDragged) {
|
7945
|
-
|
8091
|
+
|
8092
|
+
// Detect clicks on trackers or tracker groups, #783
|
8093
|
+
if (hoverPoint && (attr(e.target, 'isTracker') || attr(e.target.parentNode, 'isTracker'))) {
|
7946
8094
|
var plotX = hoverPoint.plotX,
|
7947
8095
|
plotY = hoverPoint.plotY;
|
7948
8096
|
|
@@ -7993,33 +8141,15 @@ function Chart(options, callback) {
|
|
7993
8141
|
container.onclick = container.onmousedown = container.onmousemove = container.ontouchstart = container.ontouchend = container.ontouchmove = null;
|
7994
8142
|
}
|
7995
8143
|
|
7996
|
-
/**
|
7997
|
-
* Create the image map that listens for mouseovers
|
7998
|
-
*/
|
7999
|
-
placeTrackerGroup = function () {
|
8000
8144
|
|
8001
|
-
|
8002
|
-
if (!trackerGroup) {
|
8003
|
-
chart.trackerGroup = trackerGroup = renderer.g('tracker')
|
8004
|
-
.attr({ zIndex: 9 })
|
8005
|
-
.add();
|
8006
|
-
|
8007
|
-
// then position - this happens on load and after resizing and changing
|
8008
|
-
// axis or box positions
|
8009
|
-
} else {
|
8010
|
-
trackerGroup.translate(plotLeft, plotTop);
|
8011
|
-
if (inverted) {
|
8012
|
-
trackerGroup.attr({
|
8013
|
-
width: chart.plotWidth,
|
8014
|
-
height: chart.plotHeight
|
8015
|
-
}).invert();
|
8016
|
-
}
|
8017
|
-
}
|
8018
|
-
};
|
8145
|
+
// Run MouseTracker
|
8019
8146
|
|
8147
|
+
if (!trackerGroup) {
|
8148
|
+
chart.trackerGroup = trackerGroup = renderer.g('tracker')
|
8149
|
+
.attr({ zIndex: 9 })
|
8150
|
+
.add();
|
8151
|
+
}
|
8020
8152
|
|
8021
|
-
// Run MouseTracker
|
8022
|
-
placeTrackerGroup();
|
8023
8153
|
if (options.enabled) {
|
8024
8154
|
chart.tooltip = tooltip = Tooltip(options);
|
8025
8155
|
|
@@ -8066,14 +8196,16 @@ function Chart(options, callback) {
|
|
8066
8196
|
itemHiddenStyle = merge(itemStyle, options.itemHiddenStyle),
|
8067
8197
|
padding = options.padding || pInt(style.padding),
|
8068
8198
|
ltr = !options.rtl,
|
8199
|
+
itemMarginTop = options.itemMarginTop || 0,
|
8200
|
+
itemMarginBottom = options.itemMarginBottom || 0,
|
8069
8201
|
y = 18,
|
8202
|
+
maxItemWidth = 0,
|
8070
8203
|
initialItemX = 4 + padding + symbolWidth + symbolPadding,
|
8204
|
+
initialItemY = padding + itemMarginTop + y - 5, // 5 is the number of pixels above the text
|
8071
8205
|
itemX,
|
8072
8206
|
itemY,
|
8073
8207
|
lastItemY,
|
8074
8208
|
itemHeight = 0,
|
8075
|
-
itemMarginTop = options.itemMarginTop || 0,
|
8076
|
-
itemMarginBottom = options.itemMarginBottom || 0,
|
8077
8209
|
box,
|
8078
8210
|
legendBorderWidth = options.borderWidth,
|
8079
8211
|
legendBackgroundColor = options.backgroundColor,
|
@@ -8364,7 +8496,17 @@ function Chart(options, callback) {
|
|
8364
8496
|
itemX = initialItemX;
|
8365
8497
|
itemY += itemMarginTop + itemHeight + itemMarginBottom;
|
8366
8498
|
}
|
8367
|
-
|
8499
|
+
|
8500
|
+
// If the item exceeds the height, start a new column
|
8501
|
+
if (!horizontal && itemY + options.y + itemHeight > chartHeight - spacingTop - spacingBottom) {
|
8502
|
+
itemY = initialItemY;
|
8503
|
+
itemX += maxItemWidth;
|
8504
|
+
maxItemWidth = 0;
|
8505
|
+
}
|
8506
|
+
|
8507
|
+
// Set the edge positions
|
8508
|
+
maxItemWidth = mathMax(maxItemWidth, itemWidth);
|
8509
|
+
lastItemY = mathMax(lastItemY, itemY + itemMarginBottom);
|
8368
8510
|
|
8369
8511
|
// cache the position of the newly generated or reordered items
|
8370
8512
|
item._legendItemPos = [itemX, itemY];
|
@@ -8378,7 +8520,7 @@ function Chart(options, callback) {
|
|
8378
8520
|
|
8379
8521
|
// the width of the widest item
|
8380
8522
|
offsetWidth = widthOption || mathMax(
|
8381
|
-
|
8523
|
+
(itemX - initialItemX) + (horizontal ? 0 : itemWidth),
|
8382
8524
|
offsetWidth
|
8383
8525
|
);
|
8384
8526
|
|
@@ -8391,13 +8533,16 @@ function Chart(options, callback) {
|
|
8391
8533
|
*/
|
8392
8534
|
function renderLegend() {
|
8393
8535
|
itemX = initialItemX;
|
8394
|
-
itemY =
|
8536
|
+
itemY = initialItemY;
|
8395
8537
|
offsetWidth = 0;
|
8396
8538
|
lastItemY = 0;
|
8397
8539
|
|
8398
8540
|
if (!legendGroup) {
|
8399
8541
|
legendGroup = renderer.g('legend')
|
8400
|
-
.
|
8542
|
+
// #414, #759. Trackers will be drawn above the legend, but we have
|
8543
|
+
// to sacrifice that because tooltips need to be above the legend
|
8544
|
+
// and trackers above tooltips
|
8545
|
+
.attr({ zIndex: 7 })
|
8401
8546
|
.add();
|
8402
8547
|
}
|
8403
8548
|
|
@@ -8680,9 +8825,16 @@ function Chart(options, callback) {
|
|
8680
8825
|
|
8681
8826
|
// redraw axes
|
8682
8827
|
each(axes, function (axis) {
|
8683
|
-
|
8684
|
-
if
|
8828
|
+
|
8829
|
+
// Fire 'afterSetExtremes' only if extremes are set
|
8830
|
+
if (axis.isDirtyExtremes) { // #821
|
8831
|
+
axis.isDirtyExtremes = false;
|
8832
|
+
fireEvent(axis, 'afterSetExtremes', axis.getExtremes()); // #747, #751
|
8833
|
+
}
|
8834
|
+
|
8835
|
+
if (axis.isDirty || isDirtyBox) {
|
8685
8836
|
axis.redraw();
|
8837
|
+
isDirtyBox = true; // #792
|
8686
8838
|
}
|
8687
8839
|
});
|
8688
8840
|
|
@@ -8692,7 +8844,6 @@ function Chart(options, callback) {
|
|
8692
8844
|
// the plot areas size has changed
|
8693
8845
|
if (isDirtyBox) {
|
8694
8846
|
drawChartBox();
|
8695
|
-
placeTrackerGroup();
|
8696
8847
|
|
8697
8848
|
// move clip rect
|
8698
8849
|
if (clipRect) {
|
@@ -8919,8 +9070,7 @@ function Chart(options, callback) {
|
|
8919
9070
|
zoom = function (event) {
|
8920
9071
|
|
8921
9072
|
// add button to reset selection
|
8922
|
-
var
|
8923
|
-
hasZoomed;
|
9073
|
+
var hasZoomed;
|
8924
9074
|
|
8925
9075
|
if (chart.resetZoomEnabled !== false && !chart.resetZoomButton) { // hook for Stock charts etc.
|
8926
9076
|
showResetZoom();
|
@@ -8948,7 +9098,9 @@ function Chart(options, callback) {
|
|
8948
9098
|
|
8949
9099
|
// Redraw
|
8950
9100
|
if (hasZoomed) {
|
8951
|
-
redraw(
|
9101
|
+
redraw(
|
9102
|
+
pick(optionsChart.animation, chart.pointCount < 100) // animation
|
9103
|
+
);
|
8952
9104
|
}
|
8953
9105
|
};
|
8954
9106
|
|
@@ -9017,7 +9169,7 @@ function Chart(options, callback) {
|
|
9017
9169
|
.attr({
|
9018
9170
|
align: chartTitleOptions.align,
|
9019
9171
|
'class': PREFIX + name,
|
9020
|
-
zIndex:
|
9172
|
+
zIndex: chartTitleOptions.zIndex || 4
|
9021
9173
|
})
|
9022
9174
|
.css(chartTitleOptions.style)
|
9023
9175
|
.add()
|
@@ -9238,7 +9390,7 @@ function Chart(options, callback) {
|
|
9238
9390
|
function reflow(e) {
|
9239
9391
|
var width = optionsChart.width || renderTo.offsetWidth,
|
9240
9392
|
height = optionsChart.height || renderTo.offsetHeight,
|
9241
|
-
target = e.target;
|
9393
|
+
target = e ? e.target : win; // #805 - MooTools doesn't supply e
|
9242
9394
|
|
9243
9395
|
// Width and height checks for display:none. Target is doc in IE8 and Opera,
|
9244
9396
|
// win in Firefox, Chrome and IE9.
|
@@ -9587,17 +9739,9 @@ function Chart(options, callback) {
|
|
9587
9739
|
.align(credits.position);
|
9588
9740
|
}
|
9589
9741
|
|
9590
|
-
placeTrackerGroup();
|
9591
|
-
|
9592
9742
|
// Set flag
|
9593
9743
|
chart.hasRendered = true;
|
9594
9744
|
|
9595
|
-
// If the chart was rendered outside the top container, put it back in
|
9596
|
-
if (renderToClone) {
|
9597
|
-
renderTo.appendChild(container);
|
9598
|
-
discardElement(renderToClone);
|
9599
|
-
//updatePosition(container);
|
9600
|
-
}
|
9601
9745
|
}
|
9602
9746
|
|
9603
9747
|
/**
|
@@ -9750,6 +9894,13 @@ function Chart(options, callback) {
|
|
9750
9894
|
fn.apply(chart, [chart]);
|
9751
9895
|
});
|
9752
9896
|
|
9897
|
+
|
9898
|
+
// If the chart was rendered outside the top container, put it back in
|
9899
|
+
if (renderToClone) {
|
9900
|
+
renderTo.appendChild(container);
|
9901
|
+
discardElement(renderToClone);
|
9902
|
+
}
|
9903
|
+
|
9753
9904
|
fireEvent(chart, 'load');
|
9754
9905
|
|
9755
9906
|
}
|
@@ -10068,29 +10219,37 @@ Point.prototype = {
|
|
10068
10219
|
split = String(point.y).split('.'),
|
10069
10220
|
originalDecimals = split[1] ? split[1].length : 0,
|
10070
10221
|
match = pointFormat.match(/\{(series|point)\.[a-zA-Z]+\}/g),
|
10071
|
-
splitter = /[\.}]/,
|
10222
|
+
splitter = /[{\.}]/,
|
10072
10223
|
obj,
|
10073
10224
|
key,
|
10074
10225
|
replacement,
|
10226
|
+
parts,
|
10227
|
+
prop,
|
10075
10228
|
i;
|
10076
10229
|
|
10077
10230
|
// loop over the variables defined on the form {series.name}, {point.y} etc
|
10078
10231
|
for (i in match) {
|
10079
10232
|
key = match[i];
|
10080
|
-
|
10081
10233
|
if (isString(key) && key !== pointFormat) { // IE matches more than just the variables
|
10082
|
-
obj = key.indexOf('point') === 1 ? point : series;
|
10083
10234
|
|
10084
|
-
|
10235
|
+
// Split it further into parts
|
10236
|
+
parts = (' ' + key).split(splitter); // add empty string because IE and the rest handles it differently
|
10237
|
+
obj = { 'point': point, 'series': series }[parts[1]];
|
10238
|
+
prop = parts[2];
|
10239
|
+
|
10240
|
+
// Add some preformatting
|
10241
|
+
if (obj === point && (prop === 'y' || prop === 'open' || prop === 'high' ||
|
10242
|
+
prop === 'low' || prop === 'close')) {
|
10085
10243
|
replacement = (seriesTooltipOptions.valuePrefix || seriesTooltipOptions.yPrefix || '') +
|
10086
|
-
numberFormat(point
|
10244
|
+
numberFormat(point[prop], pick(seriesTooltipOptions.valueDecimals, seriesTooltipOptions.yDecimals, originalDecimals)) +
|
10087
10245
|
(seriesTooltipOptions.valueSuffix || seriesTooltipOptions.ySuffix || '');
|
10088
10246
|
|
10089
|
-
|
10090
|
-
|
10247
|
+
// Automatic replacement
|
10248
|
+
} else {
|
10249
|
+
replacement = obj[prop];
|
10091
10250
|
}
|
10092
10251
|
|
10093
|
-
pointFormat = pointFormat.replace(
|
10252
|
+
pointFormat = pointFormat.replace(key, replacement);
|
10094
10253
|
}
|
10095
10254
|
}
|
10096
10255
|
|
@@ -10282,7 +10441,7 @@ Point.prototype = {
|
|
10282
10441
|
|
10283
10442
|
// apply hover styles to the existing point
|
10284
10443
|
if (point.graphic) {
|
10285
|
-
radius = point.graphic.symbolName && pointAttr[state].r;
|
10444
|
+
radius = markerOptions && point.graphic.symbolName && pointAttr[state].r;
|
10286
10445
|
point.graphic.attr(merge(
|
10287
10446
|
pointAttr[state],
|
10288
10447
|
radius ? { // new symbol attributes (#507, #612)
|
@@ -10350,6 +10509,7 @@ Series.prototype = {
|
|
10350
10509
|
isCartesian: true,
|
10351
10510
|
type: 'line',
|
10352
10511
|
pointClass: Point,
|
10512
|
+
sorted: true, // requires the data to be sorted
|
10353
10513
|
pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
|
10354
10514
|
stroke: 'lineColor',
|
10355
10515
|
'stroke-width': 'lineWidth',
|
@@ -10484,7 +10644,9 @@ Series.prototype = {
|
|
10484
10644
|
points.splice(i, 1);
|
10485
10645
|
}
|
10486
10646
|
}
|
10487
|
-
|
10647
|
+
if (points.length) {
|
10648
|
+
segments = [points];
|
10649
|
+
}
|
10488
10650
|
|
10489
10651
|
// else, split on null points
|
10490
10652
|
} else {
|
@@ -10584,15 +10746,19 @@ Series.prototype = {
|
|
10584
10746
|
|
10585
10747
|
setAnimation(animation, chart);
|
10586
10748
|
|
10587
|
-
|
10749
|
+
// Make graph animate sideways
|
10750
|
+
if (graph && shift) {
|
10588
10751
|
graph.shift = currentShift + 1;
|
10589
10752
|
}
|
10590
10753
|
if (area) {
|
10591
|
-
|
10592
|
-
|
10754
|
+
if (shift) { // #780
|
10755
|
+
area.shift = currentShift + 1;
|
10756
|
+
}
|
10757
|
+
area.isArea = true; // needed in animation, both with and without shift
|
10593
10758
|
}
|
10594
|
-
redraw = pick(redraw, true);
|
10595
10759
|
|
10760
|
+
// Optional redraw, defaults to true
|
10761
|
+
redraw = pick(redraw, true);
|
10596
10762
|
|
10597
10763
|
// Get options and push the point to xData, yData and series.options. In series.generatePoints
|
10598
10764
|
// the Point instance will be created on demand and pushed to the series.data array.
|
@@ -10778,16 +10944,17 @@ Series.prototype = {
|
|
10778
10944
|
xAxis = series.xAxis,
|
10779
10945
|
i, // loop variable
|
10780
10946
|
options = series.options,
|
10781
|
-
cropThreshold = options.cropThreshold
|
10947
|
+
cropThreshold = options.cropThreshold,
|
10948
|
+
isCartesian = series.isCartesian;
|
10782
10949
|
|
10783
10950
|
// If the series data or axes haven't changed, don't go through this. Return false to pass
|
10784
10951
|
// the message on to override methods like in data grouping.
|
10785
|
-
if (
|
10952
|
+
if (isCartesian && !series.isDirty && !xAxis.isDirty && !series.yAxis.isDirty && !force) {
|
10786
10953
|
return false;
|
10787
10954
|
}
|
10788
10955
|
|
10789
10956
|
// optionally filter out points outside the plot area
|
10790
|
-
if (!cropThreshold || dataLength > cropThreshold || series.forceCrop) {
|
10957
|
+
if (isCartesian && series.sorted && (!cropThreshold || dataLength > cropThreshold || series.forceCrop)) {
|
10791
10958
|
var extremes = xAxis.getExtremes(),
|
10792
10959
|
min = extremes.min,
|
10793
10960
|
max = extremes.max;
|
@@ -10825,7 +10992,7 @@ Series.prototype = {
|
|
10825
10992
|
// Find the closest distance between processed points
|
10826
10993
|
for (i = processedXData.length - 1; i > 0; i--) {
|
10827
10994
|
distance = processedXData[i] - processedXData[i - 1];
|
10828
|
-
if (closestPointRange === UNDEFINED || distance < closestPointRange) {
|
10995
|
+
if (distance > 0 && (closestPointRange === UNDEFINED || distance < closestPointRange)) {
|
10829
10996
|
closestPointRange = distance;
|
10830
10997
|
}
|
10831
10998
|
}
|
@@ -10966,6 +11133,7 @@ Series.prototype = {
|
|
10966
11133
|
|
10967
11134
|
point.percentage = pointStackTotal ? point.y * 100 / pointStackTotal : 0;
|
10968
11135
|
point.stackTotal = pointStackTotal;
|
11136
|
+
point.stackY = yValue;
|
10969
11137
|
}
|
10970
11138
|
|
10971
11139
|
// Set translated yBottom or remove it
|
@@ -10978,10 +11146,10 @@ Series.prototype = {
|
|
10978
11146
|
yValue = series.modifyValue(yValue, point);
|
10979
11147
|
}
|
10980
11148
|
|
10981
|
-
//
|
10982
|
-
|
10983
|
-
|
10984
|
-
|
11149
|
+
// Set the the plotY value, reset it for redraws
|
11150
|
+
point.plotY = (typeof yValue === 'number') ?
|
11151
|
+
mathRound(yAxis.translate(yValue, 0, 1, 0, 1) * 10) / 10 : // Math.round fixes #591
|
11152
|
+
UNDEFINED;
|
10985
11153
|
|
10986
11154
|
// set client related positions for mouse tracking
|
10987
11155
|
point.clientX = chart.inverted ?
|
@@ -11473,9 +11641,18 @@ Series.prototype = {
|
|
11473
11641
|
isBarLike = seriesType === 'column' || seriesType === 'bar',
|
11474
11642
|
vAlignIsNull = options.verticalAlign === null,
|
11475
11643
|
yIsNull = options.y === null,
|
11476
|
-
|
11644
|
+
fontMetrics = renderer.fontMetrics(options.style.fontSize), // height and baseline
|
11645
|
+
fontLineHeight = fontMetrics.h,
|
11646
|
+
fontBaseline = fontMetrics.b,
|
11647
|
+
dataLabel,
|
11648
|
+
enabled;
|
11477
11649
|
|
11478
11650
|
if (isBarLike) {
|
11651
|
+
var defaultYs = {
|
11652
|
+
top: fontBaseline,
|
11653
|
+
middle: fontBaseline - fontLineHeight / 2,
|
11654
|
+
bottom: -fontLineHeight + fontBaseline
|
11655
|
+
};
|
11479
11656
|
if (stacking) {
|
11480
11657
|
// In stacked series the default label placement is inside the bars
|
11481
11658
|
if (vAlignIsNull) {
|
@@ -11484,13 +11661,18 @@ Series.prototype = {
|
|
11484
11661
|
|
11485
11662
|
// If no y delta is specified, try to create a good default
|
11486
11663
|
if (yIsNull) {
|
11487
|
-
options = merge(options, {y:
|
11664
|
+
options = merge(options, { y: defaultYs[options.verticalAlign]});
|
11488
11665
|
}
|
11489
11666
|
} else {
|
11490
11667
|
// In non stacked series the default label placement is on top of the bars
|
11491
11668
|
if (vAlignIsNull) {
|
11492
11669
|
options = merge(options, {verticalAlign: 'top'});
|
11670
|
+
|
11671
|
+
// If no y delta is specified, try to create a good default (like default bar)
|
11672
|
+
} else if (yIsNull) {
|
11673
|
+
options = merge(options, { y: defaultYs[options.verticalAlign]});
|
11493
11674
|
}
|
11675
|
+
|
11494
11676
|
}
|
11495
11677
|
}
|
11496
11678
|
|
@@ -11521,28 +11703,39 @@ Series.prototype = {
|
|
11521
11703
|
if (pointOptions && pointOptions.dataLabels) {
|
11522
11704
|
options = merge(options, pointOptions.dataLabels);
|
11523
11705
|
}
|
11706
|
+
enabled = options.enabled;
|
11707
|
+
|
11708
|
+
// Get the positions
|
11709
|
+
if (enabled) {
|
11710
|
+
var plotX = (point.barX && point.barX + point.barW / 2) || pick(point.plotX, -999),
|
11711
|
+
plotY = pick(point.plotY, -999),
|
11712
|
+
|
11713
|
+
// if options.y is null, which happens by default on column charts, set the position
|
11714
|
+
// above or below the column depending on the threshold
|
11715
|
+
individualYDelta = options.y === null ?
|
11716
|
+
(point.y >= seriesOptions.threshold ?
|
11717
|
+
-fontLineHeight + fontBaseline : // below the threshold
|
11718
|
+
fontBaseline) : // above the threshold
|
11719
|
+
options.y;
|
11720
|
+
|
11721
|
+
x = (inverted ? chart.plotWidth - plotY : plotX) + options.x;
|
11722
|
+
y = mathRound((inverted ? chart.plotHeight - plotX : plotY) + individualYDelta);
|
11524
11723
|
|
11525
|
-
|
11526
|
-
|
11724
|
+
}
|
11725
|
+
|
11726
|
+
// If the point is outside the plot area, destroy it. #678, #820
|
11727
|
+
if (dataLabel && series.isCartesian && (!chart.isInsidePlot(x, y) || !enabled)) {
|
11527
11728
|
point.dataLabel = dataLabel.destroy();
|
11528
11729
|
|
11529
11730
|
// Individual labels are disabled if the are explicitly disabled
|
11530
11731
|
// in the point options, or if they fall outside the plot area.
|
11531
|
-
} else if (
|
11732
|
+
} else if (enabled) {
|
11733
|
+
|
11734
|
+
var align = options.align;
|
11532
11735
|
|
11533
11736
|
// Get the string
|
11534
11737
|
str = options.formatter.call(point.getLabelConfig(), options);
|
11535
11738
|
|
11536
|
-
var barX = point.barX,
|
11537
|
-
plotX = (barX && barX + point.barW / 2) || point.plotX || -999,
|
11538
|
-
plotY = pick(point.plotY, -999),
|
11539
|
-
align = options.align,
|
11540
|
-
individualYDelta = yIsNull ? (point.y >= 0 ? -6 : 12) : options.y;
|
11541
|
-
|
11542
|
-
// Postprocess the positions
|
11543
|
-
x = (inverted ? chart.plotWidth - plotY : plotX) + options.x;
|
11544
|
-
y = (inverted ? chart.plotHeight - plotX : plotY) + individualYDelta;
|
11545
|
-
|
11546
11739
|
// in columns, align the string to the column
|
11547
11740
|
if (seriesType === 'column') {
|
11548
11741
|
x += { left: -1, right: 1 }[align] * point.barW / 2 || 0;
|
@@ -11560,9 +11753,6 @@ Series.prototype = {
|
|
11560
11753
|
// update existing label
|
11561
11754
|
if (dataLabel) {
|
11562
11755
|
// vertically centered
|
11563
|
-
if (inverted && !options.y) {
|
11564
|
-
y = y + pInt(dataLabel.styles.lineHeight) * 0.9 - dataLabel.getBBox().height / 2;
|
11565
|
-
}
|
11566
11756
|
dataLabel
|
11567
11757
|
.attr({
|
11568
11758
|
text: str
|
@@ -11572,29 +11762,34 @@ Series.prototype = {
|
|
11572
11762
|
});
|
11573
11763
|
// create new label
|
11574
11764
|
} else if (defined(str)) {
|
11575
|
-
dataLabel = point.dataLabel = renderer.text(
|
11765
|
+
dataLabel = point.dataLabel = renderer[options.rotation ? 'text' : 'label']( // labels don't support rotation
|
11576
11766
|
str,
|
11577
11767
|
x,
|
11578
11768
|
y,
|
11579
|
-
|
11769
|
+
null,
|
11770
|
+
null,
|
11771
|
+
null,
|
11772
|
+
options.useHTML,
|
11773
|
+
true // baseline for backwards compat
|
11580
11774
|
)
|
11581
11775
|
.attr({
|
11582
11776
|
align: align,
|
11777
|
+
fill: options.backgroundColor,
|
11778
|
+
stroke: options.borderColor,
|
11779
|
+
'stroke-width': options.borderWidth,
|
11780
|
+
r: options.borderRadius,
|
11583
11781
|
rotation: options.rotation,
|
11782
|
+
padding: options.padding,
|
11584
11783
|
zIndex: 1
|
11585
11784
|
})
|
11586
11785
|
.css(options.style)
|
11587
|
-
.add(dataLabelsGroup)
|
11588
|
-
|
11589
|
-
if (inverted && !options.y) {
|
11590
|
-
dataLabel.attr({
|
11591
|
-
y: y + pInt(dataLabel.styles.lineHeight) * 0.9 - dataLabel.getBBox().height / 2
|
11592
|
-
});
|
11593
|
-
}
|
11786
|
+
.add(dataLabelsGroup)
|
11787
|
+
.shadow(options.shadow);
|
11594
11788
|
}
|
11595
11789
|
|
11596
11790
|
if (isBarLike && seriesOptions.stacking && dataLabel) {
|
11597
|
-
var
|
11791
|
+
var barX = point.barX,
|
11792
|
+
barY = point.barY,
|
11598
11793
|
barW = point.barW,
|
11599
11794
|
barH = point.barH;
|
11600
11795
|
|
@@ -11759,6 +11954,42 @@ Series.prototype = {
|
|
11759
11954
|
}
|
11760
11955
|
},
|
11761
11956
|
|
11957
|
+
/**
|
11958
|
+
* Initialize and perform group inversion on series.group and series.trackerGroup
|
11959
|
+
*/
|
11960
|
+
invertGroups: function () {
|
11961
|
+
var series = this,
|
11962
|
+
group = series.group,
|
11963
|
+
trackerGroup = series.trackerGroup,
|
11964
|
+
chart = series.chart;
|
11965
|
+
|
11966
|
+
// A fixed size is needed for inversion to work
|
11967
|
+
function setInvert() {
|
11968
|
+
var size = {
|
11969
|
+
width: series.yAxis.len,
|
11970
|
+
height: series.xAxis.len
|
11971
|
+
};
|
11972
|
+
|
11973
|
+
// Set the series.group size
|
11974
|
+
group.attr(size).invert();
|
11975
|
+
|
11976
|
+
// Set the tracker group size
|
11977
|
+
if (trackerGroup) {
|
11978
|
+
trackerGroup.attr(size).invert();
|
11979
|
+
}
|
11980
|
+
}
|
11981
|
+
|
11982
|
+
addEvent(chart, 'resize', setInvert); // do it on resize
|
11983
|
+
addEvent(series, 'destroy', function () {
|
11984
|
+
removeEvent(chart, 'resize', setInvert);
|
11985
|
+
});
|
11986
|
+
|
11987
|
+
// Do it now
|
11988
|
+
setInvert(); // do it now
|
11989
|
+
|
11990
|
+
// On subsequent render and redraw, just do setInvert without setting up events again
|
11991
|
+
series.invertGroups = setInvert;
|
11992
|
+
},
|
11762
11993
|
|
11763
11994
|
/**
|
11764
11995
|
* Render the graph and markers
|
@@ -11767,7 +11998,6 @@ Series.prototype = {
|
|
11767
11998
|
var series = this,
|
11768
11999
|
chart = series.chart,
|
11769
12000
|
group,
|
11770
|
-
setInvert,
|
11771
12001
|
options = series.options,
|
11772
12002
|
doClip = options.clip !== false,
|
11773
12003
|
animation = options.animation,
|
@@ -11797,24 +12027,6 @@ Series.prototype = {
|
|
11797
12027
|
if (!series.group) {
|
11798
12028
|
group = series.group = renderer.g('series');
|
11799
12029
|
|
11800
|
-
if (chart.inverted) {
|
11801
|
-
setInvert = function () {
|
11802
|
-
group.attr({
|
11803
|
-
width: chart.plotWidth,
|
11804
|
-
height: chart.plotHeight
|
11805
|
-
}).invert();
|
11806
|
-
};
|
11807
|
-
|
11808
|
-
setInvert(); // do it now
|
11809
|
-
addEvent(chart, 'resize', setInvert); // do it on resize
|
11810
|
-
addEvent(series, 'destroy', function () {
|
11811
|
-
removeEvent(chart, 'resize', setInvert);
|
11812
|
-
});
|
11813
|
-
}
|
11814
|
-
|
11815
|
-
if (doClip) {
|
11816
|
-
group.clip(clipRect);
|
11817
|
-
}
|
11818
12030
|
group.attr({
|
11819
12031
|
visibility: series.visible ? VISIBLE : HIDDEN,
|
11820
12032
|
zIndex: options.zIndex
|
@@ -11846,6 +12058,20 @@ Series.prototype = {
|
|
11846
12058
|
series.drawTracker();
|
11847
12059
|
}
|
11848
12060
|
|
12061
|
+
// Handle inverted series and tracker groups
|
12062
|
+
if (chart.inverted) {
|
12063
|
+
series.invertGroups();
|
12064
|
+
}
|
12065
|
+
|
12066
|
+
// Do the initial clipping. This must be done after inverting for VML.
|
12067
|
+
if (doClip && !series.hasRendered) {
|
12068
|
+
group.clip(clipRect);
|
12069
|
+
if (series.trackerGroup) {
|
12070
|
+
series.trackerGroup.clip(chart.clipRect);
|
12071
|
+
}
|
12072
|
+
}
|
12073
|
+
|
12074
|
+
|
11849
12075
|
// run the animation
|
11850
12076
|
if (doAnimation) {
|
11851
12077
|
series.animate();
|
@@ -11865,7 +12091,7 @@ Series.prototype = {
|
|
11865
12091
|
|
11866
12092
|
series.isDirty = series.isDirtyData = false; // means data is in accordance with what you see
|
11867
12093
|
// (See #322) series.isDirty = series.isDirtyData = false; // means data is in accordance with what you see
|
11868
|
-
|
12094
|
+
series.hasRendered = true;
|
11869
12095
|
},
|
11870
12096
|
|
11871
12097
|
/**
|
@@ -12038,6 +12264,32 @@ Series.prototype = {
|
|
12038
12264
|
fireEvent(series, selected ? 'select' : 'unselect');
|
12039
12265
|
},
|
12040
12266
|
|
12267
|
+
/**
|
12268
|
+
* Create a group that holds the tracking object or objects. This allows for
|
12269
|
+
* individual clipping and placement of each series tracker.
|
12270
|
+
*/
|
12271
|
+
drawTrackerGroup: function () {
|
12272
|
+
var trackerGroup = this.trackerGroup,
|
12273
|
+
chart = this.chart;
|
12274
|
+
|
12275
|
+
if (this.isCartesian) {
|
12276
|
+
|
12277
|
+
// Generate it on first call
|
12278
|
+
if (!trackerGroup) {
|
12279
|
+
this.trackerGroup = trackerGroup = chart.renderer.g()
|
12280
|
+
.attr({
|
12281
|
+
zIndex: this.options.zIndex || 1
|
12282
|
+
})
|
12283
|
+
.add(chart.trackerGroup);
|
12284
|
+
|
12285
|
+
}
|
12286
|
+
// Place it on first and subsequent (redraw) calls
|
12287
|
+
trackerGroup.translate(this.xAxis.left, this.yAxis.top);
|
12288
|
+
|
12289
|
+
}
|
12290
|
+
|
12291
|
+
return trackerGroup;
|
12292
|
+
},
|
12041
12293
|
|
12042
12294
|
/**
|
12043
12295
|
* Draw the tracker object that sits above all data labels and markers to
|
@@ -12057,7 +12309,7 @@ Series.prototype = {
|
|
12057
12309
|
cursor = options.cursor,
|
12058
12310
|
css = cursor && { cursor: cursor },
|
12059
12311
|
singlePoints = series.singlePoints,
|
12060
|
-
|
12312
|
+
trackerGroup = series.drawTrackerGroup(),
|
12061
12313
|
singlePoint,
|
12062
12314
|
i;
|
12063
12315
|
|
@@ -12089,9 +12341,6 @@ Series.prototype = {
|
|
12089
12341
|
tracker.attr({ d: trackerPath });
|
12090
12342
|
|
12091
12343
|
} else { // create
|
12092
|
-
group = renderer.g()
|
12093
|
-
.clip(chart.clipRect)
|
12094
|
-
.add(chart.trackerGroup);
|
12095
12344
|
|
12096
12345
|
series.tracker = renderer.path(trackerPath)
|
12097
12346
|
.attr({
|
@@ -12100,8 +12349,7 @@ Series.prototype = {
|
|
12100
12349
|
fill: NONE,
|
12101
12350
|
'stroke-linejoin': 'bevel',
|
12102
12351
|
'stroke-width' : options.lineWidth + 2 * snap,
|
12103
|
-
visibility: series.visible ? VISIBLE : HIDDEN
|
12104
|
-
zIndex: options.zIndex || 1
|
12352
|
+
visibility: series.visible ? VISIBLE : HIDDEN
|
12105
12353
|
})
|
12106
12354
|
.on(hasTouch ? 'touchstart' : 'mouseover', function () {
|
12107
12355
|
if (chart.hoverSeries !== series) {
|
@@ -12114,7 +12362,7 @@ Series.prototype = {
|
|
12114
12362
|
}
|
12115
12363
|
})
|
12116
12364
|
.css(css)
|
12117
|
-
.add(
|
12365
|
+
.add(trackerGroup);
|
12118
12366
|
}
|
12119
12367
|
|
12120
12368
|
}
|
@@ -12311,7 +12559,7 @@ var ColumnSeries = extendClass(Series, {
|
|
12311
12559
|
optionPointWidth = options.pointWidth,
|
12312
12560
|
pointPadding = defined(optionPointWidth) ? (pointOffsetWidth - optionPointWidth) / 2 :
|
12313
12561
|
pointOffsetWidth * options.pointPadding,
|
12314
|
-
pointWidth = mathCeil(mathMax(pick(optionPointWidth, pointOffsetWidth - 2 * pointPadding), 1)),
|
12562
|
+
pointWidth = mathCeil(mathMax(pick(optionPointWidth, pointOffsetWidth - 2 * pointPadding), 1 + 2 * borderWidth)),
|
12315
12563
|
colIndex = (reversedXAxis ? columnCount -
|
12316
12564
|
series.columnIndex : series.columnIndex) || 0,
|
12317
12565
|
pointXOffset = pointPadding + (groupPadding + colIndex *
|
@@ -12324,7 +12572,7 @@ var ColumnSeries = extendClass(Series, {
|
|
12324
12572
|
// record the new values
|
12325
12573
|
each(points, function (point) {
|
12326
12574
|
var plotY = point.plotY,
|
12327
|
-
yBottom = point.yBottom
|
12575
|
+
yBottom = pick(point.yBottom, translatedThreshold),
|
12328
12576
|
barX = point.plotX + pointXOffset,
|
12329
12577
|
barY = mathCeil(mathMin(plotY, yBottom)),
|
12330
12578
|
barH = mathCeil(mathMax(plotY, yBottom) - barY),
|
@@ -12356,15 +12604,15 @@ var ColumnSeries = extendClass(Series, {
|
|
12356
12604
|
|
12357
12605
|
// create shape type and shape args that are reused in drawPoints and drawTracker
|
12358
12606
|
point.shapeType = 'rect';
|
12359
|
-
shapeArgs =
|
12360
|
-
|
12361
|
-
|
12362
|
-
|
12363
|
-
|
12364
|
-
|
12365
|
-
|
12366
|
-
|
12367
|
-
|
12607
|
+
shapeArgs = {
|
12608
|
+
x: barX,
|
12609
|
+
y: barY,
|
12610
|
+
width: pointWidth,
|
12611
|
+
height: barH,
|
12612
|
+
r: options.borderRadius,
|
12613
|
+
strokeWidth: borderWidth
|
12614
|
+
};
|
12615
|
+
|
12368
12616
|
if (borderWidth % 2) { // correct for shorting in crisp method, visible in stacked columns with 1px border
|
12369
12617
|
shapeArgs.y -= 1;
|
12370
12618
|
shapeArgs.height += 1;
|
@@ -12409,13 +12657,20 @@ var ColumnSeries = extendClass(Series, {
|
|
12409
12657
|
shapeArgs = point.shapeArgs;
|
12410
12658
|
if (graphic) { // update
|
12411
12659
|
stop(graphic);
|
12412
|
-
graphic.animate(
|
12660
|
+
graphic.animate(renderer.Element.prototype.crisp.apply({}, [
|
12661
|
+
shapeArgs.strokeWidth,
|
12662
|
+
shapeArgs.x,
|
12663
|
+
shapeArgs.y,
|
12664
|
+
shapeArgs.width,
|
12665
|
+
shapeArgs.height
|
12666
|
+
]));
|
12413
12667
|
|
12414
12668
|
} else {
|
12415
12669
|
point.graphic = graphic = renderer[point.shapeType](shapeArgs)
|
12416
12670
|
.attr(point.pointAttr[point.selected ? SELECT_STATE : NORMAL_STATE])
|
12417
12671
|
.add(series.group)
|
12418
12672
|
.shadow(options.shadow);
|
12673
|
+
|
12419
12674
|
}
|
12420
12675
|
|
12421
12676
|
}
|
@@ -12435,16 +12690,9 @@ var ColumnSeries = extendClass(Series, {
|
|
12435
12690
|
options = series.options,
|
12436
12691
|
cursor = options.cursor,
|
12437
12692
|
css = cursor && { cursor: cursor },
|
12438
|
-
|
12693
|
+
trackerGroup = series.drawTrackerGroup(),
|
12439
12694
|
rel;
|
12440
12695
|
|
12441
|
-
// Add a series specific group to allow clipping the trackers
|
12442
|
-
if (series.isCartesian) {
|
12443
|
-
group = renderer.g()
|
12444
|
-
.clip(chart.clipRect)
|
12445
|
-
.add(chart.trackerGroup);
|
12446
|
-
}
|
12447
|
-
|
12448
12696
|
each(series.points, function (point) {
|
12449
12697
|
tracker = point.tracker;
|
12450
12698
|
shapeArgs = point.trackerArgs || point.shapeArgs;
|
@@ -12459,8 +12707,7 @@ var ColumnSeries = extendClass(Series, {
|
|
12459
12707
|
.attr({
|
12460
12708
|
isTracker: trackerLabel,
|
12461
12709
|
fill: TRACKER_FILL,
|
12462
|
-
visibility: series.visible ? VISIBLE : HIDDEN
|
12463
|
-
zIndex: options.zIndex || 1
|
12710
|
+
visibility: series.visible ? VISIBLE : HIDDEN
|
12464
12711
|
})
|
12465
12712
|
.on(hasTouch ? 'touchstart' : 'mouseover', function (event) {
|
12466
12713
|
rel = event.relatedTarget || event.fromElement;
|
@@ -12479,7 +12726,7 @@ var ColumnSeries = extendClass(Series, {
|
|
12479
12726
|
}
|
12480
12727
|
})
|
12481
12728
|
.css(css)
|
12482
|
-
.add(point.group ||
|
12729
|
+
.add(point.group || trackerGroup); // pies have point group - see issue #118
|
12483
12730
|
}
|
12484
12731
|
}
|
12485
12732
|
});
|
@@ -12569,7 +12816,7 @@ seriesTypes.bar = BarSeries;
|
|
12569
12816
|
*/
|
12570
12817
|
var ScatterSeries = extendClass(Series, {
|
12571
12818
|
type: 'scatter',
|
12572
|
-
|
12819
|
+
sorted: false,
|
12573
12820
|
/**
|
12574
12821
|
* Extend the base Series' translate method by adding shape type and
|
12575
12822
|
* arguments for the point trackers
|
@@ -12605,16 +12852,21 @@ var ScatterSeries = extendClass(Series, {
|
|
12605
12852
|
while (i--) {
|
12606
12853
|
graphic = points[i].graphic;
|
12607
12854
|
if (graphic) { // doesn't exist for null points
|
12608
|
-
graphic.element.
|
12855
|
+
graphic.element._i = i;
|
12609
12856
|
}
|
12610
12857
|
}
|
12611
12858
|
|
12612
12859
|
// Add the event listeners, we need to do this only once
|
12613
12860
|
if (!series._hasTracking) {
|
12614
12861
|
series.group
|
12862
|
+
.attr({
|
12863
|
+
isTracker: true
|
12864
|
+
})
|
12615
12865
|
.on(hasTouch ? 'touchstart' : 'mouseover', function (e) {
|
12616
12866
|
series.onMouseOver();
|
12617
|
-
|
12867
|
+
if (e.target._i !== UNDEFINED) { // undefined on graph in scatterchart
|
12868
|
+
points[e.target._i].onMouseOver();
|
12869
|
+
}
|
12618
12870
|
})
|
12619
12871
|
.on('mouseout', function () {
|
12620
12872
|
if (!series.options.stickyTracking) {
|
@@ -13061,7 +13313,7 @@ var PieSeries = extendClass(Series, {
|
|
13061
13313
|
};
|
13062
13314
|
|
13063
13315
|
// assume equal label heights
|
13064
|
-
labelHeight = halves[0][0] && halves[0][0].dataLabel &&
|
13316
|
+
labelHeight = halves[0][0] && halves[0][0].dataLabel && halves[0][0].dataLabel.getBBox().height;
|
13065
13317
|
|
13066
13318
|
/* Loop over the points in each quartile, starting from the top and bottom
|
13067
13319
|
* of the pie to detect overlapping labels.
|
@@ -13286,6 +13538,6 @@ extend(Highcharts, {
|
|
13286
13538
|
extendClass: extendClass,
|
13287
13539
|
placeBox: placeBox,
|
13288
13540
|
product: 'Highcharts',
|
13289
|
-
version: '2.2.
|
13541
|
+
version: '2.2.1'
|
13290
13542
|
});
|
13291
13543
|
}());
|