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