highcharts-rails 3.0.2 → 3.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- checksums.yaml.gz.asc +18 -0
- data/CHANGELOG.markdown +4 -0
- data/Rakefile +29 -1
- data/app/assets/javascripts/highcharts/adapters/mootools.js +1 -1
- data/app/assets/javascripts/highcharts/adapters/prototype.js +1 -1
- data/app/assets/javascripts/highcharts/highcharts-more.js +118 -217
- data/app/assets/javascripts/highcharts/modules/annotations.js +74 -27
- data/app/assets/javascripts/highcharts/modules/canvas-tools.js +1 -1
- data/app/assets/javascripts/highcharts/modules/data.js +74 -29
- data/app/assets/javascripts/highcharts/modules/exporting.js +5 -8
- data/app/assets/javascripts/highcharts/modules/funnel.js +2 -2
- data/app/assets/javascripts/highcharts/modules/heatmap.js +57 -0
- data/app/assets/javascripts/highcharts/modules/map.js +576 -0
- data/app/assets/javascripts/highcharts.js +853 -497
- data/highcharts-rails.gemspec +1 -0
- data/lib/highcharts/version.rb +1 -1
- data.tar.gz.asc +14 -14
- metadata +18 -23
- metadata.gz.asc +14 -14
@@ -2,7 +2,7 @@
|
|
2
2
|
// @compilation_level SIMPLE_OPTIMIZATIONS
|
3
3
|
|
4
4
|
/**
|
5
|
-
* @license Highcharts JS v3.0.
|
5
|
+
* @license Highcharts JS v3.0.3 (2013-07-31)
|
6
6
|
*
|
7
7
|
* (c) 2009-2013 Torstein Hønsi
|
8
8
|
*
|
@@ -55,7 +55,7 @@ var UNDEFINED,
|
|
55
55
|
noop = function () {},
|
56
56
|
charts = [],
|
57
57
|
PRODUCT = 'Highcharts',
|
58
|
-
VERSION = '3.0.
|
58
|
+
VERSION = '3.0.3',
|
59
59
|
|
60
60
|
// some constants for frequently used strings
|
61
61
|
DIV = 'div',
|
@@ -149,15 +149,15 @@ function merge() {
|
|
149
149
|
doCopy = function (copy, original) {
|
150
150
|
var value, key;
|
151
151
|
|
152
|
+
// An object is replacing a primitive
|
153
|
+
if (typeof copy !== 'object') {
|
154
|
+
copy = {};
|
155
|
+
}
|
156
|
+
|
152
157
|
for (key in original) {
|
153
158
|
if (original.hasOwnProperty(key)) {
|
154
159
|
value = original[key];
|
155
160
|
|
156
|
-
// An object is replacing a primitive
|
157
|
-
if (typeof copy !== 'object') {
|
158
|
-
copy = {};
|
159
|
-
}
|
160
|
-
|
161
161
|
// Copy the contents of objects, but not arrays or DOM nodes
|
162
162
|
if (value && typeof value === 'object' && Object.prototype.toString.call(value) !== '[object Array]'
|
163
163
|
&& typeof value.nodeType !== 'number') {
|
@@ -387,14 +387,14 @@ function extendClass(parent, members) {
|
|
387
387
|
function numberFormat(number, decimals, decPoint, thousandsSep) {
|
388
388
|
var lang = defaultOptions.lang,
|
389
389
|
// http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_number_format/
|
390
|
-
n = number,
|
390
|
+
n = +number || 0,
|
391
391
|
c = decimals === -1 ?
|
392
|
-
(
|
392
|
+
(n.toString().split('.')[1] || '').length : // preserve decimals
|
393
393
|
(isNaN(decimals = mathAbs(decimals)) ? 2 : decimals),
|
394
394
|
d = decPoint === undefined ? lang.decimalPoint : decPoint,
|
395
395
|
t = thousandsSep === undefined ? lang.thousandsSep : thousandsSep,
|
396
396
|
s = n < 0 ? "-" : "",
|
397
|
-
i = String(pInt(n = mathAbs(
|
397
|
+
i = String(pInt(n = mathAbs(n).toFixed(c))),
|
398
398
|
j = i.length > 3 ? i.length % 3 : 0;
|
399
399
|
|
400
400
|
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) +
|
@@ -569,6 +569,13 @@ function format(str, ctx) {
|
|
569
569
|
return ret.join('');
|
570
570
|
}
|
571
571
|
|
572
|
+
/**
|
573
|
+
* Get the magnitude of a number
|
574
|
+
*/
|
575
|
+
function getMagnitude(num) {
|
576
|
+
return math.pow(10, mathFloor(math.log(num) / math.LN10));
|
577
|
+
}
|
578
|
+
|
572
579
|
/**
|
573
580
|
* Take an interval and normalize it to multiples of 1, 2, 2.5 and 5
|
574
581
|
* @param {Number} interval
|
@@ -681,7 +688,11 @@ function normalizeTimeTickInterval(tickInterval, unitsOption) {
|
|
681
688
|
}
|
682
689
|
|
683
690
|
// get the count
|
684
|
-
count = normalizeTickInterval(
|
691
|
+
count = normalizeTickInterval(
|
692
|
+
tickInterval / interval,
|
693
|
+
multiples,
|
694
|
+
unit[0] === YEAR ? getMagnitude(tickInterval / interval) : 1 // #1913
|
695
|
+
);
|
685
696
|
|
686
697
|
return {
|
687
698
|
unitRange: interval,
|
@@ -1146,7 +1157,7 @@ pathAnim = {
|
|
1146
1157
|
|
1147
1158
|
// Extend the opacity getter, needed for fading opacity with IE9 and jQuery 1.10+
|
1148
1159
|
wrap(opacityHook, 'get', function (proceed, elem, computed) {
|
1149
|
-
return elem.attr ? (elem.opacity ||
|
1160
|
+
return elem.attr ? (elem.opacity || 0) : proceed.call(this, elem, computed);
|
1150
1161
|
});
|
1151
1162
|
|
1152
1163
|
|
@@ -1462,7 +1473,7 @@ var
|
|
1462
1473
|
defaultLabelOptions = {
|
1463
1474
|
enabled: true,
|
1464
1475
|
// rotation: 0,
|
1465
|
-
align: 'center',
|
1476
|
+
// align: 'center',
|
1466
1477
|
x: 0,
|
1467
1478
|
y: 15,
|
1468
1479
|
/*formatter: function () {
|
@@ -1494,8 +1505,8 @@ defaultOptions = {
|
|
1494
1505
|
},
|
1495
1506
|
global: {
|
1496
1507
|
useUTC: true,
|
1497
|
-
canvasToolsURL: 'http://code.highcharts.com/3.0.
|
1498
|
-
VMLRadialGradientURL: 'http://code.highcharts.com/3.0.
|
1508
|
+
canvasToolsURL: 'http://code.highcharts.com/3.0.3/modules/canvas-tools.js',
|
1509
|
+
VMLRadialGradientURL: 'http://code.highcharts.com/3.0.3/gfx/vml-radial-gradient.png'
|
1499
1510
|
},
|
1500
1511
|
chart: {
|
1501
1512
|
//animation: true,
|
@@ -1546,10 +1557,10 @@ defaultOptions = {
|
|
1546
1557
|
text: 'Chart title',
|
1547
1558
|
align: 'center',
|
1548
1559
|
// floating: false,
|
1549
|
-
|
1560
|
+
margin: 15,
|
1550
1561
|
// x: 0,
|
1551
1562
|
// verticalAlign: 'top',
|
1552
|
-
y:
|
1563
|
+
// y: null,
|
1553
1564
|
style: {
|
1554
1565
|
color: '#274b6d',//#3E576F',
|
1555
1566
|
fontSize: '16px'
|
@@ -1562,7 +1573,7 @@ defaultOptions = {
|
|
1562
1573
|
// floating: false
|
1563
1574
|
// x: 0,
|
1564
1575
|
// verticalAlign: 'top',
|
1565
|
-
y:
|
1576
|
+
// y: null,
|
1566
1577
|
style: {
|
1567
1578
|
color: '#4d759e'
|
1568
1579
|
}
|
@@ -1608,9 +1619,10 @@ defaultOptions = {
|
|
1608
1619
|
events: {}
|
1609
1620
|
},
|
1610
1621
|
dataLabels: merge(defaultLabelOptions, {
|
1622
|
+
align: 'center',
|
1611
1623
|
enabled: false,
|
1612
1624
|
formatter: function () {
|
1613
|
-
return numberFormat(this.y, -1);
|
1625
|
+
return this.y === null ? '' : numberFormat(this.y, -1);
|
1614
1626
|
},
|
1615
1627
|
verticalAlign: 'bottom', // above singular point
|
1616
1628
|
y: 0
|
@@ -2158,7 +2170,7 @@ SVGElement.prototype = {
|
|
2158
2170
|
|
2159
2171
|
i = value.length;
|
2160
2172
|
while (i--) {
|
2161
|
-
value[i] = pInt(value[i]) * hash['stroke-width'];
|
2173
|
+
value[i] = pInt(value[i]) * pick(hash['stroke-width'], wrapper['stroke-width']);
|
2162
2174
|
}
|
2163
2175
|
value = value.join(',');
|
2164
2176
|
}
|
@@ -2216,7 +2228,7 @@ SVGElement.prototype = {
|
|
2216
2228
|
}
|
2217
2229
|
|
2218
2230
|
// let the shadow follow the main element
|
2219
|
-
if (shadows && /^(width|height|visibility|x|y|d|transform)$/.test(key)) {
|
2231
|
+
if (shadows && /^(width|height|visibility|x|y|d|transform|cx|cy|r)$/.test(key)) {
|
2220
2232
|
i = shadows.length;
|
2221
2233
|
while (i--) {
|
2222
2234
|
attr(
|
@@ -2271,7 +2283,12 @@ SVGElement.prototype = {
|
|
2271
2283
|
* Add a class name to an element
|
2272
2284
|
*/
|
2273
2285
|
addClass: function (className) {
|
2274
|
-
|
2286
|
+
var element = this.element,
|
2287
|
+
currentClassName = attr(element, 'class') || '';
|
2288
|
+
|
2289
|
+
if (currentClassName.indexOf(className) === -1) {
|
2290
|
+
attr(element, 'class', currentClassName + ' ' + className);
|
2291
|
+
}
|
2275
2292
|
return this;
|
2276
2293
|
},
|
2277
2294
|
/* hasClass and removeClass are not (yet) needed
|
@@ -2414,15 +2431,16 @@ SVGElement.prototype = {
|
|
2414
2431
|
* @param {Function} handler
|
2415
2432
|
*/
|
2416
2433
|
on: function (eventType, handler) {
|
2434
|
+
var element = this.element;
|
2417
2435
|
// touch
|
2418
2436
|
if (hasTouch && eventType === 'click') {
|
2419
|
-
|
2437
|
+
element.ontouchstart = function (e) {
|
2420
2438
|
e.preventDefault();
|
2421
|
-
handler();
|
2439
|
+
handler.call(element, e);
|
2422
2440
|
};
|
2423
2441
|
}
|
2424
2442
|
// simplest possible event model for internal use
|
2425
|
-
|
2443
|
+
element['on' + eventType] = handler;
|
2426
2444
|
return this;
|
2427
2445
|
},
|
2428
2446
|
|
@@ -2568,33 +2586,18 @@ SVGElement.prototype = {
|
|
2568
2586
|
textWidth = pInt(wrapper.textWidth),
|
2569
2587
|
xCorr = wrapper.xCorr || 0,
|
2570
2588
|
yCorr = wrapper.yCorr || 0,
|
2571
|
-
currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth].join(',')
|
2572
|
-
rotationStyle = {},
|
2573
|
-
cssTransformKey;
|
2589
|
+
currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth].join(',');
|
2574
2590
|
|
2575
2591
|
if (currentTextTransform !== wrapper.cTT) { // do the calculations and DOM access only if properties changed
|
2576
2592
|
|
2577
2593
|
if (defined(rotation)) {
|
2578
2594
|
|
2579
|
-
|
2580
|
-
|
2581
|
-
|
2582
|
-
|
2583
|
-
|
2584
|
-
|
2585
|
-
costheta = mathCos(radians);
|
2586
|
-
sintheta = mathSin(radians);
|
2587
|
-
|
2588
|
-
// Adjust for alignment and rotation. Rotation of useHTML content is not yet implemented
|
2589
|
-
// but it can probably be implemented for Firefox 3.5+ on user request. FF3.5+
|
2590
|
-
// has support for CSS3 transform. The getBBox method also needs to be updated
|
2591
|
-
// to compensate for the rotation, like it currently does for SVG.
|
2592
|
-
// Test case: http://highcharts.com/tests/?file=text-rotation
|
2593
|
-
rotationStyle.filter = rotation ? ['progid:DXImageTransform.Microsoft.Matrix(M11=', costheta,
|
2594
|
-
', M12=', -sintheta, ', M21=', sintheta, ', M22=', costheta,
|
2595
|
-
', sizingMethod=\'auto expand\')'].join('') : NONE;
|
2596
|
-
}
|
2597
|
-
css(elem, rotationStyle);
|
2595
|
+
radians = rotation * deg2rad; // deg to rad
|
2596
|
+
costheta = mathCos(radians);
|
2597
|
+
sintheta = mathSin(radians);
|
2598
|
+
|
2599
|
+
wrapper.setSpanRotation(rotation, sintheta, costheta);
|
2600
|
+
|
2598
2601
|
}
|
2599
2602
|
|
2600
2603
|
width = pick(wrapper.elemWidth, elem.offsetWidth);
|
@@ -2652,6 +2655,17 @@ SVGElement.prototype = {
|
|
2652
2655
|
}
|
2653
2656
|
},
|
2654
2657
|
|
2658
|
+
/**
|
2659
|
+
* Set the rotation of an individual HTML span
|
2660
|
+
*/
|
2661
|
+
setSpanRotation: function (rotation) {
|
2662
|
+
var rotationStyle = {},
|
2663
|
+
cssTransformKey = isIE ? '-ms-transform' : isWebKit ? '-webkit-transform' : isFirefox ? 'MozTransform' : isOpera ? '-o-transform' : '';
|
2664
|
+
|
2665
|
+
rotationStyle[cssTransformKey] = rotationStyle.transform = 'rotate(' + rotation + 'deg)';
|
2666
|
+
css(this.element, rotationStyle);
|
2667
|
+
},
|
2668
|
+
|
2655
2669
|
/**
|
2656
2670
|
* Private method to update the transform attribute based on internal
|
2657
2671
|
* properties
|
@@ -2954,6 +2968,8 @@ SVGElement.prototype = {
|
|
2954
2968
|
var wrapper = this,
|
2955
2969
|
element = wrapper.element || {},
|
2956
2970
|
shadows = wrapper.shadows,
|
2971
|
+
parentToClean = wrapper.renderer.isSVG && element.nodeName === 'SPAN' && element.parentNode,
|
2972
|
+
grandParent,
|
2957
2973
|
key,
|
2958
2974
|
i;
|
2959
2975
|
|
@@ -2983,6 +2999,13 @@ SVGElement.prototype = {
|
|
2983
2999
|
});
|
2984
3000
|
}
|
2985
3001
|
|
3002
|
+
// In case of useHTML, clean up empty containers emulating SVG groups (#1960).
|
3003
|
+
while (parentToClean && parentToClean.childNodes.length === 0) {
|
3004
|
+
grandParent = parentToClean.parentNode;
|
3005
|
+
wrapper.safeRemoveChild(parentToClean);
|
3006
|
+
parentToClean = grandParent;
|
3007
|
+
}
|
3008
|
+
|
2986
3009
|
// remove from alignObjects
|
2987
3010
|
if (wrapper.alignTo) {
|
2988
3011
|
erase(wrapper.renderer.alignedObjects, wrapper);
|
@@ -3071,18 +3094,24 @@ SVGRenderer.prototype = {
|
|
3071
3094
|
var renderer = this,
|
3072
3095
|
loc = location,
|
3073
3096
|
boxWrapper,
|
3097
|
+
element,
|
3074
3098
|
desc;
|
3075
3099
|
|
3076
3100
|
boxWrapper = renderer.createElement('svg')
|
3077
3101
|
.attr({
|
3078
|
-
xmlns: SVG_NS,
|
3079
3102
|
version: '1.1'
|
3080
3103
|
});
|
3081
|
-
|
3104
|
+
element = boxWrapper.element;
|
3105
|
+
container.appendChild(element);
|
3106
|
+
|
3107
|
+
// For browsers other than IE, add the namespace attribute (#1978)
|
3108
|
+
if (container.innerHTML.indexOf('xmlns') === -1) {
|
3109
|
+
attr(element, 'xmlns', SVG_NS);
|
3110
|
+
}
|
3082
3111
|
|
3083
3112
|
// object properties
|
3084
3113
|
renderer.isSVG = true;
|
3085
|
-
renderer.box =
|
3114
|
+
renderer.box = element;
|
3086
3115
|
renderer.boxWrapper = boxWrapper;
|
3087
3116
|
renderer.alignedObjects = [];
|
3088
3117
|
|
@@ -3203,7 +3232,7 @@ SVGRenderer.prototype = {
|
|
3203
3232
|
.split(/<br.*?>/g),
|
3204
3233
|
childNodes = textNode.childNodes,
|
3205
3234
|
styleRegex = /style="([^"]+)"/,
|
3206
|
-
hrefRegex = /href="([^"]+)"/,
|
3235
|
+
hrefRegex = /href="(http[^"]+)"/,
|
3207
3236
|
parentX = attr(textNode, 'x'),
|
3208
3237
|
textStyles = wrapper.styles,
|
3209
3238
|
width = textStyles && textStyles.width && pInt(textStyles.width),
|
@@ -3249,82 +3278,86 @@ SVGRenderer.prototype = {
|
|
3249
3278
|
.replace(/</g, '<')
|
3250
3279
|
.replace(/>/g, '>');
|
3251
3280
|
|
3252
|
-
//
|
3253
|
-
|
3254
|
-
|
3255
|
-
|
3256
|
-
|
3257
|
-
} else {
|
3258
|
-
attributes.dx = 0; // #16
|
3259
|
-
}
|
3281
|
+
// Nested tags aren't supported, and cause crash in Safari (#1596)
|
3282
|
+
if (span !== ' ') {
|
3283
|
+
|
3284
|
+
// add the text node
|
3285
|
+
tspan.appendChild(doc.createTextNode(span));
|
3260
3286
|
|
3261
|
-
|
3262
|
-
|
3287
|
+
if (!spanNo) { // first span in a line, align it to the left
|
3288
|
+
attributes.x = parentX;
|
3289
|
+
} else {
|
3290
|
+
attributes.dx = 0; // #16
|
3291
|
+
}
|
3263
3292
|
|
3264
|
-
|
3265
|
-
|
3293
|
+
// add attributes
|
3294
|
+
attr(tspan, attributes);
|
3266
3295
|
|
3267
|
-
//
|
3268
|
-
if (!
|
3269
|
-
css(tspan, { display: 'block' });
|
3270
|
-
}
|
3296
|
+
// first span on subsequent line, add the line height
|
3297
|
+
if (!spanNo && lineNo) {
|
3271
3298
|
|
3272
|
-
|
3273
|
-
|
3274
|
-
|
3275
|
-
|
3276
|
-
'dy',
|
3277
|
-
textLineHeight || renderer.fontMetrics(
|
3278
|
-
/px$/.test(tspan.style.fontSize) ?
|
3279
|
-
tspan.style.fontSize :
|
3280
|
-
textStyles.fontSize
|
3281
|
-
).h,
|
3282
|
-
// Safari 6.0.2 - too optimized for its own good (#1539)
|
3283
|
-
// TODO: revisit this with future versions of Safari
|
3284
|
-
isWebKit && tspan.offsetHeight
|
3285
|
-
);
|
3286
|
-
}
|
3299
|
+
// allow getting the right offset height in exporting in IE
|
3300
|
+
if (!hasSVG && forExport) {
|
3301
|
+
css(tspan, { display: 'block' });
|
3302
|
+
}
|
3287
3303
|
|
3288
|
-
|
3289
|
-
|
3304
|
+
// Set the line height based on the font size of either
|
3305
|
+
// the text element or the tspan element
|
3306
|
+
attr(
|
3307
|
+
tspan,
|
3308
|
+
'dy',
|
3309
|
+
textLineHeight || renderer.fontMetrics(
|
3310
|
+
/px$/.test(tspan.style.fontSize) ?
|
3311
|
+
tspan.style.fontSize :
|
3312
|
+
textStyles.fontSize
|
3313
|
+
).h,
|
3314
|
+
// Safari 6.0.2 - too optimized for its own good (#1539)
|
3315
|
+
// TODO: revisit this with future versions of Safari
|
3316
|
+
isWebKit && tspan.offsetHeight
|
3317
|
+
);
|
3318
|
+
}
|
3290
3319
|
|
3291
|
-
|
3320
|
+
// Append it
|
3321
|
+
textNode.appendChild(tspan);
|
3292
3322
|
|
3293
|
-
|
3294
|
-
if (width) {
|
3295
|
-
var words = span.replace(/([^\^])-/g, '$1- ').split(' '), // #1273
|
3296
|
-
tooLong,
|
3297
|
-
actualWidth,
|
3298
|
-
rest = [];
|
3323
|
+
spanNo++;
|
3299
3324
|
|
3300
|
-
|
3301
|
-
|
3302
|
-
|
3303
|
-
|
3304
|
-
|
3305
|
-
words = rest;
|
3325
|
+
// check width and apply soft breaks
|
3326
|
+
if (width) {
|
3327
|
+
var words = span.replace(/([^\^])-/g, '$1- ').split(' '), // #1273
|
3328
|
+
tooLong,
|
3329
|
+
actualWidth,
|
3306
3330
|
rest = [];
|
3307
|
-
if (words.length) {
|
3308
|
-
tspan = doc.createElementNS(SVG_NS, 'tspan');
|
3309
|
-
attr(tspan, {
|
3310
|
-
dy: textLineHeight || 16,
|
3311
|
-
x: parentX
|
3312
|
-
});
|
3313
|
-
if (spanStyle) { // #390
|
3314
|
-
attr(tspan, 'style', spanStyle);
|
3315
|
-
}
|
3316
|
-
textNode.appendChild(tspan);
|
3317
3331
|
|
3318
|
-
|
3319
|
-
|
3332
|
+
while (words.length || rest.length) {
|
3333
|
+
delete wrapper.bBox; // delete cache
|
3334
|
+
actualWidth = wrapper.getBBox().width;
|
3335
|
+
tooLong = actualWidth > width;
|
3336
|
+
if (!tooLong || words.length === 1) { // new line needed
|
3337
|
+
words = rest;
|
3338
|
+
rest = [];
|
3339
|
+
if (words.length) {
|
3340
|
+
tspan = doc.createElementNS(SVG_NS, 'tspan');
|
3341
|
+
attr(tspan, {
|
3342
|
+
dy: textLineHeight || 16,
|
3343
|
+
x: parentX
|
3344
|
+
});
|
3345
|
+
if (spanStyle) { // #390
|
3346
|
+
attr(tspan, 'style', spanStyle);
|
3347
|
+
}
|
3348
|
+
textNode.appendChild(tspan);
|
3349
|
+
|
3350
|
+
if (actualWidth > width) { // a single word is pressing it out
|
3351
|
+
width = actualWidth;
|
3352
|
+
}
|
3320
3353
|
}
|
3354
|
+
} else { // append to existing line tspan
|
3355
|
+
tspan.removeChild(tspan.firstChild);
|
3356
|
+
rest.unshift(words.pop());
|
3357
|
+
}
|
3358
|
+
if (words.length) {
|
3359
|
+
tspan.appendChild(doc.createTextNode(words.join(' ').replace(/- /g, '-')));
|
3321
3360
|
}
|
3322
|
-
} else { // append to existing line tspan
|
3323
|
-
tspan.removeChild(tspan.firstChild);
|
3324
|
-
rest.unshift(words.pop());
|
3325
|
-
}
|
3326
|
-
if (words.length) {
|
3327
|
-
tspan.appendChild(doc.createTextNode(words.join(' ').replace(/- /g, '-')));
|
3328
3361
|
}
|
3329
3362
|
}
|
3330
3363
|
}
|
@@ -3402,12 +3435,12 @@ SVGRenderer.prototype = {
|
|
3402
3435
|
pressedStyle = pressedState[STYLE];
|
3403
3436
|
delete pressedState[STYLE];
|
3404
3437
|
|
3405
|
-
//
|
3406
|
-
addEvent(label.element, 'mouseenter', function () {
|
3438
|
+
// Add the events. IE9 and IE10 need mouseover and mouseout to funciton (#667).
|
3439
|
+
addEvent(label.element, isIE ? 'mouseover' : 'mouseenter', function () {
|
3407
3440
|
label.attr(hoverState)
|
3408
3441
|
.css(hoverStyle);
|
3409
3442
|
});
|
3410
|
-
addEvent(label.element, 'mouseleave', function () {
|
3443
|
+
addEvent(label.element, isIE ? 'mouseout' : 'mouseleave', function () {
|
3411
3444
|
stateOptions = [normalState, hoverState, pressedState][curState];
|
3412
3445
|
stateStyle = [normalStyle, hoverStyle, pressedStyle][curState];
|
3413
3446
|
label.attr(stateOptions)
|
@@ -3496,8 +3529,7 @@ SVGRenderer.prototype = {
|
|
3496
3529
|
* @param {Number} end Ending angle
|
3497
3530
|
*/
|
3498
3531
|
arc: function (x, y, r, innerR, start, end) {
|
3499
|
-
|
3500
|
-
// attributes in attr and animate
|
3532
|
+
var arc;
|
3501
3533
|
|
3502
3534
|
if (isObject(x)) {
|
3503
3535
|
y = x.y;
|
@@ -3507,11 +3539,16 @@ SVGRenderer.prototype = {
|
|
3507
3539
|
end = x.end;
|
3508
3540
|
x = x.x;
|
3509
3541
|
}
|
3510
|
-
|
3542
|
+
|
3543
|
+
// Arcs are defined as symbols for the ability to set
|
3544
|
+
// attributes in attr and animate
|
3545
|
+
arc = this.symbol('arc', x || 0, y || 0, r || 0, r || 0, {
|
3511
3546
|
innerR: innerR || 0,
|
3512
3547
|
start: start || 0,
|
3513
3548
|
end: end || 0
|
3514
3549
|
});
|
3550
|
+
arc.r = r; // #959
|
3551
|
+
return arc;
|
3515
3552
|
},
|
3516
3553
|
|
3517
3554
|
/**
|
@@ -4537,6 +4574,22 @@ Highcharts.VMLElement = VMLElement = {
|
|
4537
4574
|
*/
|
4538
4575
|
updateTransform: SVGElement.prototype.htmlUpdateTransform,
|
4539
4576
|
|
4577
|
+
/**
|
4578
|
+
* Set the rotation of a span with oldIE's filter
|
4579
|
+
*/
|
4580
|
+
setSpanRotation: function (rotation, sintheta, costheta) {
|
4581
|
+
// Adjust for alignment and rotation. Rotation of useHTML content is not yet implemented
|
4582
|
+
// but it can probably be implemented for Firefox 3.5+ on user request. FF3.5+
|
4583
|
+
// has support for CSS3 transform. The getBBox method also needs to be updated
|
4584
|
+
// to compensate for the rotation, like it currently does for SVG.
|
4585
|
+
// Test case: http://highcharts.com/tests/?file=text-rotation
|
4586
|
+
css(this.element, {
|
4587
|
+
filter: rotation ? ['progid:DXImageTransform.Microsoft.Matrix(M11=', costheta,
|
4588
|
+
', M12=', -sintheta, ', M21=', sintheta, ', M22=', costheta,
|
4589
|
+
', sizingMethod=\'auto expand\')'].join('') : NONE
|
4590
|
+
});
|
4591
|
+
},
|
4592
|
+
|
4540
4593
|
/**
|
4541
4594
|
* Get or set attributes
|
4542
4595
|
*/
|
@@ -4759,7 +4812,9 @@ Highcharts.VMLElement = VMLElement = {
|
|
4759
4812
|
|
4760
4813
|
// rotation on VML elements
|
4761
4814
|
} else if (nodeName === 'shape' && key === 'rotation') {
|
4762
|
-
|
4815
|
+
|
4816
|
+
wrapper[key] = element.style[key] = value; // style is for #1873
|
4817
|
+
|
4763
4818
|
// Correction for the 1x1 size of the shape container. Used in gauge needles.
|
4764
4819
|
element.style.left = -mathRound(mathSin(value * deg2rad) + 1) + PX;
|
4765
4820
|
element.style.top = mathRound(mathCos(value * deg2rad)) + PX;
|
@@ -5669,7 +5724,7 @@ Tick.prototype = {
|
|
5669
5724
|
!labelOptions.step && !labelOptions.staggerLines &&
|
5670
5725
|
!labelOptions.rotation &&
|
5671
5726
|
chart.plotWidth / tickPositions.length) ||
|
5672
|
-
(!horiz && (chart.optionsMarginLeft || chart.
|
5727
|
+
(!horiz && (chart.optionsMarginLeft || chart.chartWidth * 0.33)), // #1580, #1931
|
5673
5728
|
isFirst = pos === tickPositions[0],
|
5674
5729
|
isLast = pos === tickPositions[tickPositions.length - 1],
|
5675
5730
|
css,
|
@@ -5708,7 +5763,7 @@ Tick.prototype = {
|
|
5708
5763
|
// first call
|
5709
5764
|
if (!defined(label)) {
|
5710
5765
|
attr = {
|
5711
|
-
align:
|
5766
|
+
align: axis.labelAlign
|
5712
5767
|
};
|
5713
5768
|
if (isNumber(labelOptions.rotation)) {
|
5714
5769
|
attr.rotation = labelOptions.rotation;
|
@@ -5757,7 +5812,7 @@ Tick.prototype = {
|
|
5757
5812
|
options = axis.options,
|
5758
5813
|
labelOptions = options.labels,
|
5759
5814
|
width = bBox.width,
|
5760
|
-
leftSide = width * { left: 0, center: 0.5, right: 1 }[
|
5815
|
+
leftSide = width * { left: 0, center: 0.5, right: 1 }[axis.labelAlign] - labelOptions.x;
|
5761
5816
|
|
5762
5817
|
return [-leftSide, width - leftSide];
|
5763
5818
|
},
|
@@ -5847,21 +5902,28 @@ Tick.prototype = {
|
|
5847
5902
|
var axis = this.axis,
|
5848
5903
|
transA = axis.transA,
|
5849
5904
|
reversed = axis.reversed,
|
5850
|
-
staggerLines = axis.staggerLines
|
5905
|
+
staggerLines = axis.staggerLines,
|
5906
|
+
baseline = axis.chart.renderer.fontMetrics(labelOptions.style.fontSize).b,
|
5907
|
+
rotation = labelOptions.rotation;
|
5851
5908
|
|
5852
5909
|
x = x + labelOptions.x - (tickmarkOffset && horiz ?
|
5853
5910
|
tickmarkOffset * transA * (reversed ? -1 : 1) : 0);
|
5854
5911
|
y = y + labelOptions.y - (tickmarkOffset && !horiz ?
|
5855
5912
|
tickmarkOffset * transA * (reversed ? 1 : -1) : 0);
|
5913
|
+
|
5914
|
+
// Correct for rotation (#1764)
|
5915
|
+
if (rotation && axis.side === 2) {
|
5916
|
+
y -= baseline - baseline * mathCos(rotation * deg2rad);
|
5917
|
+
}
|
5856
5918
|
|
5857
5919
|
// Vertically centered
|
5858
|
-
if (!defined(labelOptions.y)) {
|
5859
|
-
y +=
|
5920
|
+
if (!defined(labelOptions.y) && !rotation) { // #1951
|
5921
|
+
y += baseline - label.getBBox().height / 2;
|
5860
5922
|
}
|
5861
5923
|
|
5862
5924
|
// Correct for staggered labels
|
5863
5925
|
if (staggerLines) {
|
5864
|
-
y += (index / (step || 1) % staggerLines) *
|
5926
|
+
y += (index / (step || 1) % staggerLines) * (axis.labelOffset / staggerLines);
|
5865
5927
|
}
|
5866
5928
|
|
5867
5929
|
return {
|
@@ -6160,7 +6222,8 @@ PlotLineOrBand.prototype = {
|
|
6160
6222
|
plotLine.label = label = renderer.text(
|
6161
6223
|
optionsLabel.text,
|
6162
6224
|
0,
|
6163
|
-
0
|
6225
|
+
0,
|
6226
|
+
optionsLabel.useHTML // docs: useHTML for plotLines and plotBands
|
6164
6227
|
)
|
6165
6228
|
.attr({
|
6166
6229
|
align: optionsLabel.textAlign || optionsLabel.align,
|
@@ -6224,6 +6287,12 @@ function StackItem(axis, options, isNegative, x, stackOption, stacking) {
|
|
6224
6287
|
// Save the x value to be able to position the label later
|
6225
6288
|
this.x = x;
|
6226
6289
|
|
6290
|
+
// Initialize total value
|
6291
|
+
this.total = 0;
|
6292
|
+
|
6293
|
+
// This will keep each points' extremes stored by series.index
|
6294
|
+
this.points = {};
|
6295
|
+
|
6227
6296
|
// Save the stack option on the series configuration object, and whether to treat it as percent
|
6228
6297
|
this.stack = stackOption;
|
6229
6298
|
this.percent = stacking === 'percent';
|
@@ -6255,12 +6324,19 @@ StackItem.prototype = {
|
|
6255
6324
|
this.cum = total;
|
6256
6325
|
},
|
6257
6326
|
|
6327
|
+
/**
|
6328
|
+
* Adds value to stack total, this method takes care of correcting floats
|
6329
|
+
*/
|
6330
|
+
addValue: function (y) {
|
6331
|
+
this.setTotal(correctFloat(this.total + y));
|
6332
|
+
},
|
6333
|
+
|
6258
6334
|
/**
|
6259
6335
|
* Renders the stack total label and adds it to the stack label group.
|
6260
6336
|
*/
|
6261
6337
|
render: function (group) {
|
6262
6338
|
var options = this.options,
|
6263
|
-
formatOption = options.format,
|
6339
|
+
formatOption = options.format,
|
6264
6340
|
str = formatOption ?
|
6265
6341
|
format(formatOption, this) :
|
6266
6342
|
options.formatter.call(this); // format the text in the label
|
@@ -6282,6 +6358,10 @@ StackItem.prototype = {
|
|
6282
6358
|
}
|
6283
6359
|
},
|
6284
6360
|
|
6361
|
+
cacheExtremes: function (series, extremes) {
|
6362
|
+
this.points[series.index] = extremes;
|
6363
|
+
},
|
6364
|
+
|
6285
6365
|
/**
|
6286
6366
|
* Sets the offset that the stack has from the x value and repositions the label.
|
6287
6367
|
*/
|
@@ -6421,7 +6501,6 @@ Axis.prototype = {
|
|
6421
6501
|
tickPixelInterval: 72,
|
6422
6502
|
showLastLabel: true,
|
6423
6503
|
labels: {
|
6424
|
-
align: 'right',
|
6425
6504
|
x: -8,
|
6426
6505
|
y: 3
|
6427
6506
|
},
|
@@ -6454,7 +6533,6 @@ Axis.prototype = {
|
|
6454
6533
|
*/
|
6455
6534
|
defaultLeftAxisOptions: {
|
6456
6535
|
labels: {
|
6457
|
-
align: 'right',
|
6458
6536
|
x: -8,
|
6459
6537
|
y: null
|
6460
6538
|
},
|
@@ -6468,7 +6546,6 @@ Axis.prototype = {
|
|
6468
6546
|
*/
|
6469
6547
|
defaultRightAxisOptions: {
|
6470
6548
|
labels: {
|
6471
|
-
align: 'left',
|
6472
6549
|
x: 8,
|
6473
6550
|
y: null
|
6474
6551
|
},
|
@@ -6482,7 +6559,6 @@ Axis.prototype = {
|
|
6482
6559
|
*/
|
6483
6560
|
defaultBottomAxisOptions: {
|
6484
6561
|
labels: {
|
6485
|
-
align: 'center',
|
6486
6562
|
x: 0,
|
6487
6563
|
y: 14
|
6488
6564
|
// overflow: undefined,
|
@@ -6497,7 +6573,6 @@ Axis.prototype = {
|
|
6497
6573
|
*/
|
6498
6574
|
defaultTopAxisOptions: {
|
6499
6575
|
labels: {
|
6500
|
-
align: 'center',
|
6501
6576
|
x: 0,
|
6502
6577
|
y: -5
|
6503
6578
|
// overflow: undefined
|
@@ -6541,7 +6616,6 @@ Axis.prototype = {
|
|
6541
6616
|
|
6542
6617
|
|
6543
6618
|
// Flag, stagger lines or not
|
6544
|
-
axis.staggerLines = axis.horiz && options.labels.staggerLines;
|
6545
6619
|
axis.userOptions = userOptions;
|
6546
6620
|
|
6547
6621
|
//axis.axisTitleMargin = UNDEFINED,// = options.title.margin,
|
@@ -6619,8 +6693,13 @@ Axis.prototype = {
|
|
6619
6693
|
|
6620
6694
|
// Dictionary for stacks
|
6621
6695
|
axis.stacks = {};
|
6696
|
+
axis.oldStacks = {};
|
6697
|
+
|
6698
|
+
// Dictionary for stacks max values
|
6699
|
+
axis.stacksMax = {};
|
6700
|
+
|
6622
6701
|
axis._stacksTouched = 0;
|
6623
|
-
|
6702
|
+
|
6624
6703
|
// Min and max in the data
|
6625
6704
|
//axis.dataMin = UNDEFINED,
|
6626
6705
|
//axis.dataMax = UNDEFINED,
|
@@ -6691,10 +6770,10 @@ Axis.prototype = {
|
|
6691
6770
|
|
6692
6771
|
newOptions = chart.options[this.xOrY + 'Axis'][this.options.index] = merge(this.userOptions, newOptions);
|
6693
6772
|
|
6694
|
-
this.destroy();
|
6773
|
+
this.destroy(true);
|
6695
6774
|
this._addedPlotLB = false; // #1611
|
6696
6775
|
|
6697
|
-
this.init(chart, newOptions);
|
6776
|
+
this.init(chart, extend(newOptions, { events: UNDEFINED }));
|
6698
6777
|
|
6699
6778
|
chart.isDirtyBox = true;
|
6700
6779
|
if (pick(redraw, true)) {
|
@@ -6778,25 +6857,24 @@ Axis.prototype = {
|
|
6778
6857
|
|
6779
6858
|
return ret;
|
6780
6859
|
},
|
6781
|
-
|
6860
|
+
|
6782
6861
|
/**
|
6783
6862
|
* Get the minimum and maximum for the series of each axis
|
6784
6863
|
*/
|
6785
6864
|
getSeriesExtremes: function () {
|
6786
6865
|
var axis = this,
|
6787
|
-
chart = axis.chart
|
6788
|
-
|
6789
|
-
posStack = [],
|
6790
|
-
negStack = [],
|
6791
|
-
stacksTouched = axis._stacksTouched = axis._stacksTouched + 1,
|
6792
|
-
type,
|
6793
|
-
i;
|
6794
|
-
|
6866
|
+
chart = axis.chart;
|
6867
|
+
|
6795
6868
|
axis.hasVisibleSeries = false;
|
6796
6869
|
|
6797
6870
|
// reset dataMin and dataMax in case we're redrawing
|
6798
6871
|
axis.dataMin = axis.dataMax = null;
|
6799
6872
|
|
6873
|
+
// reset cached stacking extremes
|
6874
|
+
axis.stacksMax = {};
|
6875
|
+
|
6876
|
+
axis.buildStacks();
|
6877
|
+
|
6800
6878
|
// loop through this axis' series
|
6801
6879
|
each(axis.series, function (series) {
|
6802
6880
|
|
@@ -6804,27 +6882,16 @@ Axis.prototype = {
|
|
6804
6882
|
|
6805
6883
|
var seriesOptions = series.options,
|
6806
6884
|
stacking,
|
6807
|
-
posPointStack,
|
6808
|
-
negPointStack,
|
6809
|
-
stackKey,
|
6810
|
-
stackOption,
|
6811
|
-
negKey,
|
6812
6885
|
xData,
|
6813
|
-
yData,
|
6814
|
-
x,
|
6815
|
-
y,
|
6816
6886
|
threshold = seriesOptions.threshold,
|
6817
|
-
yDataLength,
|
6818
|
-
activeYData = [],
|
6819
6887
|
seriesDataMin,
|
6820
|
-
seriesDataMax
|
6821
|
-
|
6822
|
-
|
6823
|
-
|
6824
|
-
|
6888
|
+
seriesDataMax;
|
6889
|
+
|
6890
|
+
axis.hasVisibleSeries = true;
|
6891
|
+
|
6825
6892
|
// Validate threshold in logarithmic axes
|
6826
6893
|
if (axis.isLog && threshold <= 0) {
|
6827
|
-
threshold =
|
6894
|
+
threshold = null;
|
6828
6895
|
}
|
6829
6896
|
|
6830
6897
|
// Get dataMin and dataMax for X axes
|
@@ -6837,112 +6904,27 @@ Axis.prototype = {
|
|
6837
6904
|
|
6838
6905
|
// Get dataMin and dataMax for Y axes, as well as handle stacking and processed data
|
6839
6906
|
} else {
|
6840
|
-
var isNegative,
|
6841
|
-
pointStack,
|
6842
|
-
key,
|
6843
|
-
cropped = series.cropped,
|
6844
|
-
xExtremes = series.xAxis.getExtremes(),
|
6845
|
-
//findPointRange,
|
6846
|
-
//pointRange,
|
6847
|
-
j,
|
6848
|
-
hasModifyValue = !!series.modifyValue;
|
6849
6907
|
|
6850
6908
|
// Handle stacking
|
6851
6909
|
stacking = seriesOptions.stacking;
|
6852
6910
|
axis.usePercentage = stacking === 'percent';
|
6853
6911
|
|
6854
6912
|
// create a stack for this particular series type
|
6855
|
-
if (stacking) {
|
6856
|
-
stackOption = seriesOptions.stack;
|
6857
|
-
stackKey = series.type + pick(stackOption, '');
|
6858
|
-
negKey = '-' + stackKey;
|
6859
|
-
series.stackKey = stackKey; // used in translate
|
6860
|
-
|
6861
|
-
posPointStack = posStack[stackKey] || []; // contains the total values for each x
|
6862
|
-
posStack[stackKey] = posPointStack;
|
6863
|
-
|
6864
|
-
negPointStack = negStack[negKey] || [];
|
6865
|
-
negStack[negKey] = negPointStack;
|
6866
|
-
}
|
6867
6913
|
if (axis.usePercentage) {
|
6868
6914
|
axis.dataMin = 0;
|
6869
6915
|
axis.dataMax = 99;
|
6870
6916
|
}
|
6871
6917
|
|
6872
|
-
|
6873
|
-
//
|
6874
|
-
|
6875
|
-
|
6876
|
-
|
6877
|
-
yDataLength = yData.length;
|
6878
|
-
|
6879
|
-
// loop over the non-null y values and read them into a local array
|
6880
|
-
for (i = 0; i < yDataLength; i++) {
|
6881
|
-
x = xData[i];
|
6882
|
-
y = yData[i];
|
6883
|
-
|
6884
|
-
// Read stacked values into a stack based on the x value,
|
6885
|
-
// the sign of y and the stack key. Stacking is also handled for null values (#739)
|
6886
|
-
if (stacking) {
|
6887
|
-
isNegative = y < threshold;
|
6888
|
-
pointStack = isNegative ? negPointStack : posPointStack;
|
6889
|
-
key = isNegative ? negKey : stackKey;
|
6890
|
-
|
6891
|
-
// Set the stack value and y for extremes
|
6892
|
-
if (defined(pointStack[x])) { // we're adding to the stack
|
6893
|
-
pointStack[x] = correctFloat(pointStack[x] + y);
|
6894
|
-
y = [y, pointStack[x]]; // consider both the actual value and the stack (#1376)
|
6895
|
-
|
6896
|
-
} else { // it's the first point in the stack
|
6897
|
-
pointStack[x] = y;
|
6898
|
-
}
|
6899
|
-
|
6900
|
-
// add the series
|
6901
|
-
if (!stacks[key]) {
|
6902
|
-
stacks[key] = {};
|
6903
|
-
}
|
6904
|
-
|
6905
|
-
// If the StackItem is there, just update the values,
|
6906
|
-
// if not, create one first
|
6907
|
-
if (!stacks[key][x]) {
|
6908
|
-
stacks[key][x] = new StackItem(axis, axis.options.stackLabels, isNegative, x, stackOption, stacking);
|
6909
|
-
}
|
6910
|
-
stacks[key][x].setTotal(pointStack[x]);
|
6911
|
-
stacks[key][x].touched = stacksTouched;
|
6912
|
-
}
|
6913
|
-
|
6914
|
-
// Handle non null values
|
6915
|
-
if (y !== null && y !== UNDEFINED && (!axis.isLog || (y.length || y > 0))) {
|
6916
|
-
|
6917
|
-
// general hook, used for Highstock compare values feature
|
6918
|
-
if (hasModifyValue) {
|
6919
|
-
y = series.modifyValue(y);
|
6920
|
-
}
|
6921
|
-
|
6922
|
-
// For points within the visible range, including the first point outside the
|
6923
|
-
// visible range, consider y extremes
|
6924
|
-
if (series.getExtremesFromAll || cropped || ((xData[i + 1] || x) >= xExtremes.min &&
|
6925
|
-
(xData[i - 1] || x) <= xExtremes.max)) {
|
6926
|
-
|
6927
|
-
j = y.length;
|
6928
|
-
if (j) { // array, like ohlc or range data
|
6929
|
-
while (j--) {
|
6930
|
-
if (y[j] !== null) {
|
6931
|
-
activeYData[activeCounter++] = y[j];
|
6932
|
-
}
|
6933
|
-
}
|
6934
|
-
} else {
|
6935
|
-
activeYData[activeCounter++] = y;
|
6936
|
-
}
|
6937
|
-
}
|
6938
|
-
}
|
6939
|
-
}
|
6918
|
+
|
6919
|
+
// get this particular series extremes
|
6920
|
+
series.getExtremes();
|
6921
|
+
seriesDataMax = series.dataMax;
|
6922
|
+
seriesDataMin = series.dataMin;
|
6940
6923
|
|
6941
6924
|
// Get the dataMin and dataMax so far. If percentage is used, the min and max are
|
6942
|
-
// always 0 and 100. If
|
6943
|
-
|
6944
|
-
|
6945
|
-
series.dataMax = seriesDataMax = arrayMax(activeYData);
|
6925
|
+
// always 0 and 100. If seriesDataMin and seriesDataMax is null, then series
|
6926
|
+
// doesn't have active y data, we continue with nulls
|
6927
|
+
if (!axis.usePercentage && defined(seriesDataMin) && defined(seriesDataMax)) {
|
6946
6928
|
axis.dataMin = mathMin(pick(axis.dataMin, seriesDataMin), seriesDataMin);
|
6947
6929
|
axis.dataMax = mathMax(pick(axis.dataMax, seriesDataMax), seriesDataMax);
|
6948
6930
|
}
|
@@ -6960,24 +6942,13 @@ Axis.prototype = {
|
|
6960
6942
|
}
|
6961
6943
|
}
|
6962
6944
|
});
|
6963
|
-
|
6964
|
-
// Destroy unused stacks (#1044)
|
6965
|
-
for (type in stacks) {
|
6966
|
-
for (i in stacks[type]) {
|
6967
|
-
if (stacks[type][i].touched < stacksTouched) {
|
6968
|
-
stacks[type][i].destroy();
|
6969
|
-
delete stacks[type][i];
|
6970
|
-
}
|
6971
|
-
}
|
6972
|
-
}
|
6973
|
-
|
6974
6945
|
},
|
6975
6946
|
|
6976
6947
|
/**
|
6977
6948
|
* Translate from axis value to pixel position on the chart, or back
|
6978
6949
|
*
|
6979
6950
|
*/
|
6980
|
-
translate: function (val, backwards, cvsCoord, old, handleLog,
|
6951
|
+
translate: function (val, backwards, cvsCoord, old, handleLog, pointPlacement) {
|
6981
6952
|
var axis = this,
|
6982
6953
|
axisLength = axis.len,
|
6983
6954
|
sign = 1,
|
@@ -7020,9 +6991,11 @@ Axis.prototype = {
|
|
7020
6991
|
if (postTranslate) { // log and ordinal axes
|
7021
6992
|
val = axis.val2lin(val);
|
7022
6993
|
}
|
7023
|
-
|
6994
|
+
if (pointPlacement === 'between') {
|
6995
|
+
pointPlacement = 0.5;
|
6996
|
+
}
|
7024
6997
|
returnValue = sign * (val - localMin) * localA + cvsOffset + (sign * minPixelPadding) +
|
7025
|
-
(
|
6998
|
+
(isNumber(pointPlacement) ? localA * pointPlacement * axis.pointRange : 0);
|
7026
6999
|
}
|
7027
7000
|
|
7028
7001
|
return returnValue;
|
@@ -7226,7 +7199,7 @@ Axis.prototype = {
|
|
7226
7199
|
interval = normalizeTickInterval(
|
7227
7200
|
interval,
|
7228
7201
|
null,
|
7229
|
-
|
7202
|
+
getMagnitude(interval)
|
7230
7203
|
);
|
7231
7204
|
|
7232
7205
|
positions = map(axis.getLinearTickPositions(
|
@@ -7390,7 +7363,7 @@ Axis.prototype = {
|
|
7390
7363
|
var seriesPointRange = series.pointRange,
|
7391
7364
|
pointPlacement = series.options.pointPlacement,
|
7392
7365
|
seriesClosestPointRange = series.closestPointRange;
|
7393
|
-
|
7366
|
+
|
7394
7367
|
if (seriesPointRange > range) { // #1446
|
7395
7368
|
seriesPointRange = 0;
|
7396
7369
|
}
|
@@ -7401,7 +7374,7 @@ Axis.prototype = {
|
|
7401
7374
|
// is 'between' or 'on', this padding does not apply.
|
7402
7375
|
minPointOffset = mathMax(
|
7403
7376
|
minPointOffset,
|
7404
|
-
pointPlacement ? 0 : seriesPointRange / 2
|
7377
|
+
isString(pointPlacement) ? 0 : seriesPointRange / 2
|
7405
7378
|
);
|
7406
7379
|
|
7407
7380
|
// Determine the total padding needed to the length of the axis to make room for the
|
@@ -7456,7 +7429,6 @@ Axis.prototype = {
|
|
7456
7429
|
isXAxis = axis.isXAxis,
|
7457
7430
|
isLinked = axis.isLinked,
|
7458
7431
|
tickPositioner = axis.options.tickPositioner,
|
7459
|
-
magnitude,
|
7460
7432
|
maxPadding = options.maxPadding,
|
7461
7433
|
minPadding = options.minPadding,
|
7462
7434
|
length,
|
@@ -7555,6 +7527,11 @@ Axis.prototype = {
|
|
7555
7527
|
if (axis.postProcessTickInterval) {
|
7556
7528
|
axis.tickInterval = axis.postProcessTickInterval(axis.tickInterval);
|
7557
7529
|
}
|
7530
|
+
|
7531
|
+
// In column-like charts, don't cramp in more ticks than there are points (#1943)
|
7532
|
+
if (axis.pointRange) {
|
7533
|
+
axis.tickInterval = mathMax(axis.pointRange, axis.tickInterval);
|
7534
|
+
}
|
7558
7535
|
|
7559
7536
|
// Before normalizing the tick interval, handle minimum tick interval. This applies only if tickInterval is not defined.
|
7560
7537
|
if (!tickIntervalOption && axis.tickInterval < minTickIntervalOption) {
|
@@ -7563,9 +7540,8 @@ Axis.prototype = {
|
|
7563
7540
|
|
7564
7541
|
// for linear axes, get magnitude and normalize the interval
|
7565
7542
|
if (!isDatetimeAxis && !isLog) { // linear
|
7566
|
-
magnitude = math.pow(10, mathFloor(math.log(axis.tickInterval) / math.LN10));
|
7567
7543
|
if (!tickIntervalOption) {
|
7568
|
-
axis.tickInterval = normalizeTickInterval(axis.tickInterval, null,
|
7544
|
+
axis.tickInterval = normalizeTickInterval(axis.tickInterval, null, getMagnitude(axis.tickInterval), options);
|
7569
7545
|
}
|
7570
7546
|
}
|
7571
7547
|
|
@@ -7706,10 +7682,20 @@ Axis.prototype = {
|
|
7706
7682
|
isDirtyData = true;
|
7707
7683
|
}
|
7708
7684
|
});
|
7709
|
-
|
7685
|
+
|
7686
|
+
|
7710
7687
|
// do we really need to go through all this?
|
7711
7688
|
if (isDirtyAxisLength || isDirtyData || axis.isLinked || axis.forceRedraw ||
|
7712
7689
|
axis.userMin !== axis.oldUserMin || axis.userMax !== axis.oldUserMax) {
|
7690
|
+
|
7691
|
+
// reset stacks
|
7692
|
+
if (!axis.isXAxis) {
|
7693
|
+
for (type in stacks) {
|
7694
|
+
for (i in stacks[type]) {
|
7695
|
+
stacks[type][i].total = null;
|
7696
|
+
}
|
7697
|
+
}
|
7698
|
+
}
|
7713
7699
|
|
7714
7700
|
axis.forceRedraw = false;
|
7715
7701
|
|
@@ -7727,11 +7713,12 @@ Axis.prototype = {
|
|
7727
7713
|
if (!axis.isDirty) {
|
7728
7714
|
axis.isDirty = isDirtyAxisLength || axis.min !== axis.oldMin || axis.max !== axis.oldMax;
|
7729
7715
|
}
|
7730
|
-
}
|
7731
|
-
|
7732
|
-
|
7733
|
-
|
7734
|
-
|
7716
|
+
} else if (!axis.isXAxis) {
|
7717
|
+
if (axis.oldStacks) {
|
7718
|
+
stacks = axis.stacks = axis.oldStacks;
|
7719
|
+
}
|
7720
|
+
|
7721
|
+
// reset stacks
|
7735
7722
|
for (type in stacks) {
|
7736
7723
|
for (i in stacks[type]) {
|
7737
7724
|
stacks[type][i].cum = stacks[type][i].total;
|
@@ -7787,12 +7774,12 @@ Axis.prototype = {
|
|
7787
7774
|
*/
|
7788
7775
|
zoom: function (newMin, newMax) {
|
7789
7776
|
|
7790
|
-
// Prevent pinch zooming out of range
|
7777
|
+
// Prevent pinch zooming out of range. Check for defined is for #1946.
|
7791
7778
|
if (!this.allowZoomOutside) {
|
7792
|
-
if (newMin <= this.dataMin) {
|
7779
|
+
if (defined(this.dataMin) && newMin <= this.dataMin) {
|
7793
7780
|
newMin = UNDEFINED;
|
7794
7781
|
}
|
7795
|
-
if (newMax >= this.dataMax) {
|
7782
|
+
if (defined(this.dataMax) && newMax >= this.dataMax) {
|
7796
7783
|
newMax = UNDEFINED;
|
7797
7784
|
}
|
7798
7785
|
}
|
@@ -7903,6 +7890,24 @@ Axis.prototype = {
|
|
7903
7890
|
return obj;
|
7904
7891
|
},
|
7905
7892
|
|
7893
|
+
/**
|
7894
|
+
* Compute auto alignment for the axis label based on which side the axis is on
|
7895
|
+
* and the given rotation for the label
|
7896
|
+
*/
|
7897
|
+
autoLabelAlign: function (rotation) {
|
7898
|
+
var ret,
|
7899
|
+
angle = (pick(rotation, 0) - (this.side * 90) + 720) % 360;
|
7900
|
+
|
7901
|
+
if (angle > 15 && angle < 165) {
|
7902
|
+
ret = 'right';
|
7903
|
+
} else if (angle > 195 && angle < 345) {
|
7904
|
+
ret = 'left';
|
7905
|
+
} else {
|
7906
|
+
ret = 'center';
|
7907
|
+
}
|
7908
|
+
return ret;
|
7909
|
+
},
|
7910
|
+
|
7906
7911
|
/**
|
7907
7912
|
* Render the tick labels to a preliminary position to get their sizes
|
7908
7913
|
*/
|
@@ -7927,11 +7932,24 @@ Axis.prototype = {
|
|
7927
7932
|
axisOffset = chart.axisOffset,
|
7928
7933
|
clipOffset = chart.clipOffset,
|
7929
7934
|
directionFactor = [-1, 1, 1, -1][side],
|
7930
|
-
n
|
7935
|
+
n,
|
7936
|
+
i,
|
7937
|
+
autoStaggerLines = 1,
|
7938
|
+
maxStaggerLines = pick(labelOptions.maxStaggerLines, 5), // docs
|
7939
|
+
lastRight,
|
7940
|
+
overlap,
|
7941
|
+
pos,
|
7942
|
+
bBox,
|
7943
|
+
x,
|
7944
|
+
w,
|
7945
|
+
lineNo;
|
7931
7946
|
|
7932
7947
|
// For reuse in Axis.render
|
7933
7948
|
axis.hasData = hasData = (axis.hasVisibleSeries || (defined(axis.min) && defined(axis.max) && !!tickPositions));
|
7934
7949
|
axis.showAxis = showAxis = hasData || pick(options.showEmpty, true);
|
7950
|
+
|
7951
|
+
// Set/reset staggerLines
|
7952
|
+
axis.staggerLines = axis.horiz && labelOptions.staggerLines;
|
7935
7953
|
|
7936
7954
|
// Create the axisGroup and gridGroup elements on first iteration
|
7937
7955
|
if (!axis.axisGroup) {
|
@@ -7947,18 +7965,54 @@ Axis.prototype = {
|
|
7947
7965
|
}
|
7948
7966
|
|
7949
7967
|
if (hasData || axis.isLinked) {
|
7968
|
+
|
7969
|
+
// Set the explicit or automatic label alignment
|
7970
|
+
axis.labelAlign = pick(labelOptions.align || axis.autoLabelAlign(labelOptions.rotation));
|
7971
|
+
|
7950
7972
|
each(tickPositions, function (pos) {
|
7951
7973
|
if (!ticks[pos]) {
|
7952
7974
|
ticks[pos] = new Tick(axis, pos);
|
7953
7975
|
} else {
|
7954
7976
|
ticks[pos].addLabel(); // update labels depending on tick interval
|
7955
7977
|
}
|
7956
|
-
|
7957
7978
|
});
|
7958
7979
|
|
7980
|
+
// Handle automatic stagger lines
|
7981
|
+
if (axis.horiz && !axis.staggerLines && maxStaggerLines && !labelOptions.rotation) {
|
7982
|
+
while (autoStaggerLines < maxStaggerLines) {
|
7983
|
+
lastRight = [];
|
7984
|
+
overlap = false;
|
7985
|
+
|
7986
|
+
for (i = 0; i < tickPositions.length; i++) {
|
7987
|
+
pos = tickPositions[i];
|
7988
|
+
bBox = ticks[pos].label && ticks[pos].label.bBox;
|
7989
|
+
w = bBox ? bBox.width : 0;
|
7990
|
+
lineNo = i % autoStaggerLines;
|
7991
|
+
|
7992
|
+
if (w) {
|
7993
|
+
x = axis.translate(pos); // don't handle log
|
7994
|
+
if (lastRight[lineNo] !== UNDEFINED && x < lastRight[lineNo]) {
|
7995
|
+
overlap = true;
|
7996
|
+
}
|
7997
|
+
lastRight[lineNo] = x + w;
|
7998
|
+
}
|
7999
|
+
}
|
8000
|
+
if (overlap) {
|
8001
|
+
autoStaggerLines++;
|
8002
|
+
} else {
|
8003
|
+
break;
|
8004
|
+
}
|
8005
|
+
}
|
8006
|
+
|
8007
|
+
if (autoStaggerLines > 1) {
|
8008
|
+
axis.staggerLines = autoStaggerLines;
|
8009
|
+
}
|
8010
|
+
}
|
8011
|
+
|
8012
|
+
|
7959
8013
|
each(tickPositions, function (pos) {
|
7960
8014
|
// left side must be align: right and right side must have align: left for labels
|
7961
|
-
if (side === 0 || side === 2 || { 1: 'left', 3: 'right' }[side] ===
|
8015
|
+
if (side === 0 || side === 2 || { 1: 'left', 3: 'right' }[side] === axis.labelAlign) {
|
7962
8016
|
|
7963
8017
|
// get the highest offset
|
7964
8018
|
labelOffset = mathMax(
|
@@ -7968,10 +8022,11 @@ Axis.prototype = {
|
|
7968
8022
|
}
|
7969
8023
|
|
7970
8024
|
});
|
7971
|
-
|
7972
8025
|
if (axis.staggerLines) {
|
7973
|
-
labelOffset
|
8026
|
+
labelOffset *= axis.staggerLines;
|
8027
|
+
axis.labelOffset = labelOffset;
|
7974
8028
|
}
|
8029
|
+
|
7975
8030
|
|
7976
8031
|
} else { // doesn't have data
|
7977
8032
|
for (n in ticks) {
|
@@ -8326,12 +8381,23 @@ Axis.prototype = {
|
|
8326
8381
|
*/
|
8327
8382
|
removePlotBandOrLine: function (id) {
|
8328
8383
|
var plotLinesAndBands = this.plotLinesAndBands,
|
8384
|
+
options = this.options,
|
8385
|
+
userOptions = this.userOptions,
|
8329
8386
|
i = plotLinesAndBands.length;
|
8330
8387
|
while (i--) {
|
8331
8388
|
if (plotLinesAndBands[i].id === id) {
|
8332
8389
|
plotLinesAndBands[i].destroy();
|
8333
8390
|
}
|
8334
8391
|
}
|
8392
|
+
each([options.plotLines || [], userOptions.plotLines || [], options.plotBands || [], userOptions.plotBands || []], function (arr) {
|
8393
|
+
i = arr.length;
|
8394
|
+
while (i--) {
|
8395
|
+
if (arr[i].id === id) {
|
8396
|
+
erase(arr, arr[i]);
|
8397
|
+
}
|
8398
|
+
}
|
8399
|
+
});
|
8400
|
+
|
8335
8401
|
},
|
8336
8402
|
|
8337
8403
|
/**
|
@@ -8369,6 +8435,22 @@ Axis.prototype = {
|
|
8369
8435
|
|
8370
8436
|
},
|
8371
8437
|
|
8438
|
+
/**
|
8439
|
+
*
|
8440
|
+
*/
|
8441
|
+
buildStacks: function () {
|
8442
|
+
if (this.isXAxis) {
|
8443
|
+
return;
|
8444
|
+
}
|
8445
|
+
|
8446
|
+
var series = this.series,
|
8447
|
+
last = series.length - 1;
|
8448
|
+
|
8449
|
+
each(series, function (serie, i) {
|
8450
|
+
serie.setStackedPoints(i === last);
|
8451
|
+
});
|
8452
|
+
},
|
8453
|
+
|
8372
8454
|
/**
|
8373
8455
|
* Set new axis categories and optionally redraw
|
8374
8456
|
* @param {Array} categories
|
@@ -8381,13 +8463,15 @@ Axis.prototype = {
|
|
8381
8463
|
/**
|
8382
8464
|
* Destroys an Axis instance.
|
8383
8465
|
*/
|
8384
|
-
destroy: function () {
|
8466
|
+
destroy: function (keepEvents) {
|
8385
8467
|
var axis = this,
|
8386
8468
|
stacks = axis.stacks,
|
8387
8469
|
stackKey;
|
8388
8470
|
|
8389
8471
|
// Remove the events
|
8390
|
-
|
8472
|
+
if (!keepEvents) {
|
8473
|
+
removeEvent(axis);
|
8474
|
+
}
|
8391
8475
|
|
8392
8476
|
// Destroy each stack total
|
8393
8477
|
for (stackKey in stacks) {
|
@@ -8798,15 +8882,20 @@ Tooltip.prototype = {
|
|
8798
8882
|
i = crosshairsOptions.length,
|
8799
8883
|
attribs,
|
8800
8884
|
axis,
|
8801
|
-
val
|
8885
|
+
val,
|
8886
|
+
series;
|
8802
8887
|
|
8803
8888
|
while (i--) {
|
8804
|
-
|
8889
|
+
series = point.series;
|
8890
|
+
axis = series[i ? 'yAxis' : 'xAxis'];
|
8805
8891
|
if (crosshairsOptions[i] && axis) {
|
8806
8892
|
val = i ? pick(point.stackY, point.y) : point.x; // #814
|
8807
8893
|
if (axis.isLog) { // #1671
|
8808
8894
|
val = log2lin(val);
|
8809
8895
|
}
|
8896
|
+
if (series.modifyValue) { // #1205
|
8897
|
+
val = series.modifyValue(val);
|
8898
|
+
}
|
8810
8899
|
|
8811
8900
|
path = axis.getPlotLinePath(
|
8812
8901
|
val,
|
@@ -8908,8 +8997,6 @@ Pointer.prototype = {
|
|
8908
8997
|
*/
|
8909
8998
|
normalize: function (e) {
|
8910
8999
|
var chartPosition,
|
8911
|
-
chartX,
|
8912
|
-
chartY,
|
8913
9000
|
ePos;
|
8914
9001
|
|
8915
9002
|
// common IE normalizing
|
@@ -8927,18 +9014,10 @@ Pointer.prototype = {
|
|
8927
9014
|
// get mouse position
|
8928
9015
|
this.chartPosition = chartPosition = offset(this.chart.container);
|
8929
9016
|
|
8930
|
-
//
|
8931
|
-
if (ePos.pageX === UNDEFINED) { // IE < 9. #886.
|
8932
|
-
chartX = e.x;
|
8933
|
-
chartY = e.y;
|
8934
|
-
} else {
|
8935
|
-
chartX = ePos.pageX - chartPosition.left;
|
8936
|
-
chartY = ePos.pageY - chartPosition.top;
|
8937
|
-
}
|
8938
|
-
|
9017
|
+
// Old IE and compatibility mode use clientX. #886, #2005.
|
8939
9018
|
return extend(e, {
|
8940
|
-
chartX: mathRound(
|
8941
|
-
chartY: mathRound(
|
9019
|
+
chartX: mathRound(pick(ePos.pageX, ePos.clientX) - chartPosition.left),
|
9020
|
+
chartY: mathRound(pick(ePos.pageY, ePos.clientY) - chartPosition.top)
|
8942
9021
|
});
|
8943
9022
|
},
|
8944
9023
|
|
@@ -9097,18 +9176,20 @@ Pointer.prototype = {
|
|
9097
9176
|
*/
|
9098
9177
|
scaleGroups: function (attribs, clip) {
|
9099
9178
|
|
9100
|
-
var chart = this.chart
|
9179
|
+
var chart = this.chart,
|
9180
|
+
seriesAttribs;
|
9101
9181
|
|
9102
9182
|
// Scale each series
|
9103
9183
|
each(chart.series, function (series) {
|
9184
|
+
seriesAttribs = attribs || series.getPlotBox(); // #1701
|
9104
9185
|
if (series.xAxis && series.xAxis.zoomEnabled) {
|
9105
|
-
series.group.attr(
|
9186
|
+
series.group.attr(seriesAttribs);
|
9106
9187
|
if (series.markerGroup) {
|
9107
|
-
series.markerGroup.attr(
|
9188
|
+
series.markerGroup.attr(seriesAttribs);
|
9108
9189
|
series.markerGroup.clip(clip ? chart.clipRect : null);
|
9109
9190
|
}
|
9110
9191
|
if (series.dataLabelsGroup) {
|
9111
|
-
series.dataLabelsGroup.attr(
|
9192
|
+
series.dataLabelsGroup.attr(seriesAttribs);
|
9112
9193
|
}
|
9113
9194
|
}
|
9114
9195
|
});
|
@@ -9428,12 +9509,7 @@ Pointer.prototype = {
|
|
9428
9509
|
|
9429
9510
|
// Reset scaling preview
|
9430
9511
|
if (hasPinched) {
|
9431
|
-
this.scaleGroups(
|
9432
|
-
translateX: chart.plotLeft,
|
9433
|
-
translateY: chart.plotTop,
|
9434
|
-
scaleX: 1,
|
9435
|
-
scaleY: 1
|
9436
|
-
});
|
9512
|
+
this.scaleGroups();
|
9437
9513
|
}
|
9438
9514
|
}
|
9439
9515
|
|
@@ -9612,6 +9688,10 @@ Pointer.prototype = {
|
|
9612
9688
|
this.runPointActions(e);
|
9613
9689
|
|
9614
9690
|
this.pinch(e);
|
9691
|
+
|
9692
|
+
} else {
|
9693
|
+
// Hide the tooltip on touching outside the plot area (#1203)
|
9694
|
+
this.reset();
|
9615
9695
|
}
|
9616
9696
|
|
9617
9697
|
} else if (e.touches.length === 2) {
|
@@ -9763,7 +9843,6 @@ Legend.prototype = {
|
|
9763
9843
|
},
|
9764
9844
|
key,
|
9765
9845
|
val;
|
9766
|
-
|
9767
9846
|
|
9768
9847
|
if (legendItem) {
|
9769
9848
|
legendItem.css({ fill: textColor, color: textColor }); // color for #1553, oldIE
|
@@ -9775,7 +9854,7 @@ Legend.prototype = {
|
|
9775
9854
|
if (legendSymbol) {
|
9776
9855
|
|
9777
9856
|
// Apply marker options
|
9778
|
-
if (markerOptions) {
|
9857
|
+
if (markerOptions && legendSymbol.isMarker) { // #585
|
9779
9858
|
markerOptions = item.convertAttribs(markerOptions);
|
9780
9859
|
for (key in markerOptions) {
|
9781
9860
|
val = markerOptions[key];
|
@@ -9826,7 +9905,7 @@ Legend.prototype = {
|
|
9826
9905
|
// destroy SVG elements
|
9827
9906
|
each(['legendItem', 'legendLine', 'legendSymbol', 'legendGroup'], function (key) {
|
9828
9907
|
if (item[key]) {
|
9829
|
-
item[key].destroy();
|
9908
|
+
item[key] = item[key].destroy();
|
9830
9909
|
}
|
9831
9910
|
});
|
9832
9911
|
|
@@ -9885,7 +9964,8 @@ Legend.prototype = {
|
|
9885
9964
|
var options = this.options,
|
9886
9965
|
padding = this.padding,
|
9887
9966
|
titleOptions = options.title,
|
9888
|
-
titleHeight = 0
|
9967
|
+
titleHeight = 0,
|
9968
|
+
bBox;
|
9889
9969
|
|
9890
9970
|
if (titleOptions.text) {
|
9891
9971
|
if (!this.title) {
|
@@ -9894,7 +9974,9 @@ Legend.prototype = {
|
|
9894
9974
|
.css(titleOptions.style)
|
9895
9975
|
.add(this.group);
|
9896
9976
|
}
|
9897
|
-
|
9977
|
+
bBox = this.title.getBBox();
|
9978
|
+
titleHeight = bBox.height;
|
9979
|
+
this.offsetWidth = bBox.width; // #1717
|
9898
9980
|
this.contentGroup.attr({ translateY: titleHeight });
|
9899
9981
|
}
|
9900
9982
|
this.titleHeight = titleHeight;
|
@@ -9915,6 +9997,7 @@ Legend.prototype = {
|
|
9915
9997
|
itemStyle = legend.itemStyle,
|
9916
9998
|
itemHiddenStyle = legend.itemHiddenStyle,
|
9917
9999
|
padding = legend.padding,
|
10000
|
+
itemDistance = horizontal ? pick(options.itemDistance, 8) : 0, // docs
|
9918
10001
|
ltr = !options.rtl,
|
9919
10002
|
itemHeight,
|
9920
10003
|
widthOption = options.width,
|
@@ -10010,7 +10093,7 @@ Legend.prototype = {
|
|
10010
10093
|
bBox = li.getBBox();
|
10011
10094
|
|
10012
10095
|
itemWidth = item.legendItemWidth =
|
10013
|
-
options.itemWidth || symbolWidth + symbolPadding + bBox.width +
|
10096
|
+
options.itemWidth || symbolWidth + symbolPadding + bBox.width + itemDistance +
|
10014
10097
|
(showCheckbox ? 20 : 0);
|
10015
10098
|
legend.itemHeight = itemHeight = bBox.height;
|
10016
10099
|
|
@@ -10048,7 +10131,7 @@ Legend.prototype = {
|
|
10048
10131
|
|
10049
10132
|
// the width of the widest item
|
10050
10133
|
legend.offsetWidth = widthOption || mathMax(
|
10051
|
-
horizontal ? legend.itemX - initialItemX : itemWidth,
|
10134
|
+
(horizontal ? legend.itemX - initialItemX - itemDistance : itemWidth) + padding,
|
10052
10135
|
legend.offsetWidth
|
10053
10136
|
);
|
10054
10137
|
},
|
@@ -10385,7 +10468,7 @@ Chart.prototype = {
|
|
10385
10468
|
|
10386
10469
|
var chartEvents = optionsChart.events;
|
10387
10470
|
|
10388
|
-
this.runChartClick = chartEvents && !!chartEvents.click;
|
10471
|
+
//this.runChartClick = chartEvents && !!chartEvents.click;
|
10389
10472
|
this.bounds = { h: {}, v: {} }; // Pixel data bounds for touch zoom
|
10390
10473
|
|
10391
10474
|
this.callback = callback;
|
@@ -10520,7 +10603,8 @@ Chart.prototype = {
|
|
10520
10603
|
|
10521
10604
|
/*jslint unused: false*/
|
10522
10605
|
axis = new Axis(this, merge(options, {
|
10523
|
-
index: this[key].length
|
10606
|
+
index: this[key].length,
|
10607
|
+
isX: isX
|
10524
10608
|
}));
|
10525
10609
|
/*jslint unused: true*/
|
10526
10610
|
|
@@ -10576,6 +10660,7 @@ Chart.prototype = {
|
|
10576
10660
|
legend = chart.legend,
|
10577
10661
|
redrawLegend = chart.isDirtyLegend,
|
10578
10662
|
hasStackedSeries,
|
10663
|
+
hasDirtyStacks,
|
10579
10664
|
isDirtyBox = chart.isDirtyBox, // todo: check if it has actually changed?
|
10580
10665
|
seriesLength = series.length,
|
10581
10666
|
i = seriesLength,
|
@@ -10590,15 +10675,23 @@ Chart.prototype = {
|
|
10590
10675
|
chart.cloneRenderTo();
|
10591
10676
|
}
|
10592
10677
|
|
10678
|
+
// Adjust title layout (reflow multiline text)
|
10679
|
+
chart.layOutTitles();
|
10680
|
+
|
10593
10681
|
// link stacked series
|
10594
10682
|
while (i--) {
|
10595
10683
|
serie = series[i];
|
10596
|
-
|
10684
|
+
|
10685
|
+
if (serie.options.stacking) {
|
10597
10686
|
hasStackedSeries = true;
|
10598
|
-
|
10687
|
+
|
10688
|
+
if (serie.isDirty) {
|
10689
|
+
hasDirtyStacks = true;
|
10690
|
+
break;
|
10691
|
+
}
|
10599
10692
|
}
|
10600
10693
|
}
|
10601
|
-
if (
|
10694
|
+
if (hasDirtyStacks) { // mark others as dirty
|
10602
10695
|
i = seriesLength;
|
10603
10696
|
while (i--) {
|
10604
10697
|
serie = series[i];
|
@@ -10625,6 +10718,11 @@ Chart.prototype = {
|
|
10625
10718
|
chart.isDirtyLegend = false;
|
10626
10719
|
}
|
10627
10720
|
|
10721
|
+
// reset stacks
|
10722
|
+
if (hasStackedSeries) {
|
10723
|
+
chart.getStacks();
|
10724
|
+
}
|
10725
|
+
|
10628
10726
|
|
10629
10727
|
if (chart.hasCartesianSeries) {
|
10630
10728
|
if (!chart.isResizing) {
|
@@ -10636,6 +10734,11 @@ Chart.prototype = {
|
|
10636
10734
|
each(axes, function (axis) {
|
10637
10735
|
axis.setScale();
|
10638
10736
|
});
|
10737
|
+
} else {
|
10738
|
+
// build stacks
|
10739
|
+
each(axes, function (axis) {
|
10740
|
+
axis.buildStacks();
|
10741
|
+
});
|
10639
10742
|
}
|
10640
10743
|
chart.adjustTickAmounts();
|
10641
10744
|
chart.getMargins();
|
@@ -10665,7 +10768,6 @@ Chart.prototype = {
|
|
10665
10768
|
}
|
10666
10769
|
|
10667
10770
|
|
10668
|
-
|
10669
10771
|
// redraw affected series
|
10670
10772
|
each(series, function (serie) {
|
10671
10773
|
if (serie.isDirty && serie.visible &&
|
@@ -10861,6 +10963,26 @@ Chart.prototype = {
|
|
10861
10963
|
});
|
10862
10964
|
},
|
10863
10965
|
|
10966
|
+
/**
|
10967
|
+
* Generate stacks for each series and calculate stacks total values
|
10968
|
+
*/
|
10969
|
+
getStacks: function () {
|
10970
|
+
var chart = this;
|
10971
|
+
|
10972
|
+
// reset stacks for each yAxis
|
10973
|
+
each(chart.yAxis, function (axis) {
|
10974
|
+
if (axis.stacks && axis.hasVisibleSeries) {
|
10975
|
+
axis.oldStacks = axis.stacks;
|
10976
|
+
}
|
10977
|
+
});
|
10978
|
+
|
10979
|
+
each(chart.series, function (series) {
|
10980
|
+
if (series.options.stacking && (series.visible === true || chart.options.chart.ignoreHiddenSeries === false)) {
|
10981
|
+
series.stackKey = series.type + pick(series.options.stack, '');
|
10982
|
+
}
|
10983
|
+
});
|
10984
|
+
},
|
10985
|
+
|
10864
10986
|
/**
|
10865
10987
|
* Display the zoom button
|
10866
10988
|
*/
|
@@ -11013,11 +11135,49 @@ Chart.prototype = {
|
|
11013
11135
|
zIndex: chartTitleOptions.zIndex || 4
|
11014
11136
|
})
|
11015
11137
|
.css(chartTitleOptions.style)
|
11016
|
-
.add()
|
11017
|
-
|
11018
|
-
}
|
11138
|
+
.add();
|
11139
|
+
}
|
11019
11140
|
});
|
11141
|
+
chart.layOutTitles();
|
11142
|
+
},
|
11143
|
+
|
11144
|
+
/**
|
11145
|
+
* Lay out the chart titles and cache the full offset height for use in getMargins
|
11146
|
+
*/
|
11147
|
+
layOutTitles: function () {
|
11148
|
+
var titleOffset = 0,
|
11149
|
+
title = this.title,
|
11150
|
+
subtitle = this.subtitle,
|
11151
|
+
options = this.options,
|
11152
|
+
titleOptions = options.title,
|
11153
|
+
subtitleOptions = options.subtitle,
|
11154
|
+
autoWidth = this.spacingBox.width - 44; // 44 makes room for default context button
|
11155
|
+
|
11156
|
+
if (title) {
|
11157
|
+
title
|
11158
|
+
.css({ width: (titleOptions.width || autoWidth) + PX })
|
11159
|
+
.align(extend({ y: 15 }, titleOptions), false, 'spacingBox');
|
11160
|
+
|
11161
|
+
if (!titleOptions.floating && !titleOptions.verticalAlign) {
|
11162
|
+
titleOffset = title.getBBox().height;
|
11163
|
+
|
11164
|
+
// Adjust for browser consistency + backwards compat after #776 fix
|
11165
|
+
if (titleOffset >= 18 && titleOffset <= 25) {
|
11166
|
+
titleOffset = 15;
|
11167
|
+
}
|
11168
|
+
}
|
11169
|
+
}
|
11170
|
+
if (subtitle) {
|
11171
|
+
subtitle
|
11172
|
+
.css({ width: (subtitleOptions.width || autoWidth) + PX })
|
11173
|
+
.align(extend({ y: titleOffset + titleOptions.margin }, subtitleOptions), false, 'spacingBox');
|
11174
|
+
|
11175
|
+
if (!subtitleOptions.floating && !subtitleOptions.verticalAlign) {
|
11176
|
+
titleOffset = mathCeil(titleOffset + subtitle.getBBox().height);
|
11177
|
+
}
|
11178
|
+
}
|
11020
11179
|
|
11180
|
+
this.titleOffset = titleOffset; // used in getMargins
|
11021
11181
|
},
|
11022
11182
|
|
11023
11183
|
/**
|
@@ -11056,7 +11216,7 @@ Chart.prototype = {
|
|
11056
11216
|
|
11057
11217
|
// Set up the clone
|
11058
11218
|
} else {
|
11059
|
-
if (container) {
|
11219
|
+
if (container && container.parentNode === this.renderTo) {
|
11060
11220
|
this.renderTo.removeChild(container); // do not clone this
|
11061
11221
|
}
|
11062
11222
|
this.renderToClone = clone = this.renderTo.cloneNode(0);
|
@@ -11176,30 +11336,23 @@ Chart.prototype = {
|
|
11176
11336
|
optionsMarginLeft = chart.optionsMarginLeft,
|
11177
11337
|
optionsMarginRight = chart.optionsMarginRight,
|
11178
11338
|
optionsMarginBottom = chart.optionsMarginBottom,
|
11179
|
-
chartTitleOptions = chart.options.title,
|
11180
|
-
chartSubtitleOptions = chart.options.subtitle,
|
11181
11339
|
legendOptions = chart.options.legend,
|
11182
11340
|
legendMargin = pick(legendOptions.margin, 10),
|
11183
11341
|
legendX = legendOptions.x,
|
11184
11342
|
legendY = legendOptions.y,
|
11185
11343
|
align = legendOptions.align,
|
11186
11344
|
verticalAlign = legendOptions.verticalAlign,
|
11187
|
-
titleOffset;
|
11345
|
+
titleOffset = chart.titleOffset;
|
11188
11346
|
|
11189
11347
|
chart.resetMargins();
|
11190
11348
|
axisOffset = chart.axisOffset;
|
11191
11349
|
|
11192
|
-
//
|
11193
|
-
if (
|
11194
|
-
|
11195
|
-
(chart.title && !chartTitleOptions.floating && !chartTitleOptions.verticalAlign && chartTitleOptions.y) || 0,
|
11196
|
-
(chart.subtitle && !chartSubtitleOptions.floating && !chartSubtitleOptions.verticalAlign && chartSubtitleOptions.y) || 0
|
11197
|
-
);
|
11198
|
-
if (titleOffset) {
|
11199
|
-
chart.plotTop = mathMax(chart.plotTop, titleOffset + pick(chartTitleOptions.margin, 15) + spacingTop);
|
11200
|
-
}
|
11350
|
+
// Adjust for title and subtitle
|
11351
|
+
if (titleOffset && !defined(optionsMarginTop)) {
|
11352
|
+
chart.plotTop = mathMax(chart.plotTop, titleOffset + chart.options.title.margin + spacingTop);
|
11201
11353
|
}
|
11202
|
-
|
11354
|
+
|
11355
|
+
// Adjust for legend
|
11203
11356
|
if (legend.display && !legendOptions.floating) {
|
11204
11357
|
if (align === 'right') { // horizontal alignment handled first
|
11205
11358
|
if (!defined(optionsMarginRight)) {
|
@@ -11630,11 +11783,14 @@ Chart.prototype = {
|
|
11630
11783
|
// Legend
|
11631
11784
|
chart.legend = new Legend(chart, options.legend);
|
11632
11785
|
|
11786
|
+
chart.getStacks(); // render stacks
|
11787
|
+
|
11633
11788
|
// Get margins by pre-rendering axes
|
11634
11789
|
// set axes scales
|
11635
11790
|
each(axes, function (axis) {
|
11636
11791
|
axis.setScale();
|
11637
11792
|
});
|
11793
|
+
|
11638
11794
|
chart.getMargins();
|
11639
11795
|
|
11640
11796
|
chart.maxTicks = null; // reset for second pass
|
@@ -12177,7 +12333,8 @@ Point.prototype = {
|
|
12177
12333
|
graphic = point.graphic,
|
12178
12334
|
i,
|
12179
12335
|
data = series.data,
|
12180
|
-
chart = series.chart
|
12336
|
+
chart = series.chart,
|
12337
|
+
seriesOptions = series.options;
|
12181
12338
|
|
12182
12339
|
redraw = pick(redraw, true);
|
12183
12340
|
|
@@ -12199,11 +12356,13 @@ Point.prototype = {
|
|
12199
12356
|
series.xData[i] = point.x;
|
12200
12357
|
series.yData[i] = series.toYData ? series.toYData(point) : point.y;
|
12201
12358
|
series.zData[i] = point.z;
|
12202
|
-
|
12359
|
+
seriesOptions.data[i] = point.options;
|
12203
12360
|
|
12204
12361
|
// redraw
|
12205
|
-
series.isDirty = true;
|
12206
|
-
|
12362
|
+
series.isDirty = series.isDirtyData = chart.isDirtyBox = true;
|
12363
|
+
if (seriesOptions.legendType === 'point') { // #1831, #1885
|
12364
|
+
chart.legend.destroyItem(point);
|
12365
|
+
}
|
12207
12366
|
if (redraw) {
|
12208
12367
|
chart.redraw(animation);
|
12209
12368
|
}
|
@@ -12612,6 +12771,7 @@ Series.prototype = {
|
|
12612
12771
|
// register it
|
12613
12772
|
series.segments = segments;
|
12614
12773
|
},
|
12774
|
+
|
12615
12775
|
/**
|
12616
12776
|
* Set the series options by merging from the options tree
|
12617
12777
|
* @param {Object} itemOptions
|
@@ -12714,7 +12874,7 @@ Series.prototype = {
|
|
12714
12874
|
symbolWidth = legendOptions.symbolWidth,
|
12715
12875
|
renderer = this.chart.renderer,
|
12716
12876
|
legendItemGroup = this.legendGroup,
|
12717
|
-
|
12877
|
+
verticalCenter = legend.baseline - mathRound(renderer.fontMetrics(legendOptions.itemStyle.fontSize).b * 0.3),
|
12718
12878
|
attr;
|
12719
12879
|
|
12720
12880
|
// Draw the line
|
@@ -12728,10 +12888,10 @@ Series.prototype = {
|
|
12728
12888
|
this.legendLine = renderer.path([
|
12729
12889
|
M,
|
12730
12890
|
0,
|
12731
|
-
|
12891
|
+
verticalCenter,
|
12732
12892
|
L,
|
12733
12893
|
symbolWidth,
|
12734
|
-
|
12894
|
+
verticalCenter
|
12735
12895
|
])
|
12736
12896
|
.attr(attr)
|
12737
12897
|
.add(legendItemGroup);
|
@@ -12743,11 +12903,12 @@ Series.prototype = {
|
|
12743
12903
|
this.legendSymbol = legendSymbol = renderer.symbol(
|
12744
12904
|
this.symbol,
|
12745
12905
|
(symbolWidth / 2) - radius,
|
12746
|
-
|
12906
|
+
verticalCenter - radius,
|
12747
12907
|
2 * radius,
|
12748
12908
|
2 * radius
|
12749
12909
|
)
|
12750
12910
|
.add(legendItemGroup);
|
12911
|
+
legendSymbol.isMarker = true;
|
12751
12912
|
}
|
12752
12913
|
},
|
12753
12914
|
|
@@ -12778,13 +12939,14 @@ Series.prototype = {
|
|
12778
12939
|
setAnimation(animation, chart);
|
12779
12940
|
|
12780
12941
|
// Make graph animate sideways
|
12781
|
-
if (
|
12782
|
-
graph.
|
12942
|
+
if (shift) {
|
12943
|
+
each([graph, area, series.graphNeg, series.areaNeg], function (shape) {
|
12944
|
+
if (shape) {
|
12945
|
+
shape.shift = currentShift + 1;
|
12946
|
+
}
|
12947
|
+
});
|
12783
12948
|
}
|
12784
12949
|
if (area) {
|
12785
|
-
if (shift) { // #780
|
12786
|
-
area.shift = currentShift + 1;
|
12787
|
-
}
|
12788
12950
|
area.isArea = true; // needed in animation, both with and without shift
|
12789
12951
|
}
|
12790
12952
|
|
@@ -12821,12 +12983,12 @@ Series.prototype = {
|
|
12821
12983
|
dataOptions.shift();
|
12822
12984
|
}
|
12823
12985
|
}
|
12824
|
-
series.getAttribs();
|
12825
12986
|
|
12826
12987
|
// redraw
|
12827
12988
|
series.isDirty = true;
|
12828
12989
|
series.isDirtyData = true;
|
12829
12990
|
if (redraw) {
|
12991
|
+
series.getAttribs(); // #1937
|
12830
12992
|
chart.redraw();
|
12831
12993
|
}
|
12832
12994
|
},
|
@@ -12857,7 +13019,7 @@ Series.prototype = {
|
|
12857
13019
|
yData = [],
|
12858
13020
|
zData = [],
|
12859
13021
|
dataLength = data ? data.length : [],
|
12860
|
-
turboThreshold = options.turboThreshold
|
13022
|
+
turboThreshold = pick(options.turboThreshold, 1000), // docs: 0 to disable
|
12861
13023
|
pt,
|
12862
13024
|
pointArrayMap = series.pointArrayMap,
|
12863
13025
|
valueCount = pointArrayMap && pointArrayMap.length,
|
@@ -12867,7 +13029,7 @@ Series.prototype = {
|
|
12867
13029
|
// first value is tested, and we assume that all the rest are defined the same
|
12868
13030
|
// way. Although the 'for' loops are similar, they are repeated inside each
|
12869
13031
|
// if-else conditional for max performance.
|
12870
|
-
if (dataLength > turboThreshold) {
|
13032
|
+
if (turboThreshold && dataLength > turboThreshold) {
|
12871
13033
|
|
12872
13034
|
// find the first non-null point
|
12873
13035
|
i = 0;
|
@@ -12913,18 +13075,12 @@ Series.prototype = {
|
|
12913
13075
|
yData[i] = hasToYData ? series.toYData(pt) : pt.y;
|
12914
13076
|
zData[i] = pt.z;
|
12915
13077
|
if (names && pt.name) {
|
12916
|
-
names[
|
13078
|
+
names[pt.x] = pt.name; // #2046
|
12917
13079
|
}
|
12918
13080
|
}
|
12919
13081
|
}
|
12920
13082
|
}
|
12921
13083
|
|
12922
|
-
// Unsorted data is not supported by the line tooltip as well as data grouping and
|
12923
|
-
// navigation in Stock charts (#725)
|
12924
|
-
if (series.requireSorting && xData.length > 1 && xData[1] < xData[0]) {
|
12925
|
-
error(15);
|
12926
|
-
}
|
12927
|
-
|
12928
13084
|
// Forgetting to cast strings to numbers is a common caveat when handling CSV or JSON
|
12929
13085
|
if (isString(yData[0])) {
|
12930
13086
|
error(14, true);
|
@@ -13002,8 +13158,8 @@ Series.prototype = {
|
|
13002
13158
|
processedXData = series.xData, // copied during slice operation below
|
13003
13159
|
processedYData = series.yData,
|
13004
13160
|
dataLength = processedXData.length,
|
13161
|
+
croppedData,
|
13005
13162
|
cropStart = 0,
|
13006
|
-
cropEnd = dataLength,
|
13007
13163
|
cropped,
|
13008
13164
|
distance,
|
13009
13165
|
closestPointRange,
|
@@ -13018,12 +13174,12 @@ Series.prototype = {
|
|
13018
13174
|
if (isCartesian && !series.isDirty && !xAxis.isDirty && !series.yAxis.isDirty && !force) {
|
13019
13175
|
return false;
|
13020
13176
|
}
|
13177
|
+
|
13021
13178
|
|
13022
13179
|
// optionally filter out points outside the plot area
|
13023
13180
|
if (isCartesian && series.sorted && (!cropThreshold || dataLength > cropThreshold || series.forceCrop)) {
|
13024
|
-
var
|
13025
|
-
|
13026
|
-
max = extremes.max;
|
13181
|
+
var min = xAxis.min,
|
13182
|
+
max = xAxis.max;
|
13027
13183
|
|
13028
13184
|
// it's outside current extremes
|
13029
13185
|
if (processedXData[dataLength - 1] < min || processedXData[0] > max) {
|
@@ -13032,43 +13188,34 @@ Series.prototype = {
|
|
13032
13188
|
|
13033
13189
|
// only crop if it's actually spilling out
|
13034
13190
|
} else if (processedXData[0] < min || processedXData[dataLength - 1] > max) {
|
13035
|
-
|
13036
|
-
|
13037
|
-
|
13038
|
-
|
13039
|
-
cropStart = mathMax(0, i - 1);
|
13040
|
-
break;
|
13041
|
-
}
|
13042
|
-
}
|
13043
|
-
// proceed to find slice end
|
13044
|
-
for (; i < dataLength; i++) {
|
13045
|
-
if (processedXData[i] > max) {
|
13046
|
-
cropEnd = i + 1;
|
13047
|
-
break;
|
13048
|
-
}
|
13049
|
-
|
13050
|
-
}
|
13051
|
-
processedXData = processedXData.slice(cropStart, cropEnd);
|
13052
|
-
processedYData = processedYData.slice(cropStart, cropEnd);
|
13191
|
+
croppedData = this.cropData(series.xData, series.yData, min, max);
|
13192
|
+
processedXData = croppedData.xData;
|
13193
|
+
processedYData = croppedData.yData;
|
13194
|
+
cropStart = croppedData.start;
|
13053
13195
|
cropped = true;
|
13054
13196
|
}
|
13055
13197
|
}
|
13056
13198
|
|
13057
13199
|
|
13058
13200
|
// Find the closest distance between processed points
|
13059
|
-
for (i = processedXData.length - 1; i
|
13201
|
+
for (i = processedXData.length - 1; i >= 0; i--) {
|
13060
13202
|
distance = processedXData[i] - processedXData[i - 1];
|
13061
13203
|
if (distance > 0 && (closestPointRange === UNDEFINED || distance < closestPointRange)) {
|
13062
13204
|
closestPointRange = distance;
|
13205
|
+
|
13206
|
+
// Unsorted data is not supported by the line tooltip, as well as data grouping and
|
13207
|
+
// navigation in Stock charts (#725) and width calculation of columns (#1900)
|
13208
|
+
} else if (distance < 0 && series.requireSorting) {
|
13209
|
+
error(15);
|
13063
13210
|
}
|
13064
13211
|
}
|
13065
|
-
|
13212
|
+
|
13066
13213
|
// Record the properties
|
13067
13214
|
series.cropped = cropped; // undefined or true
|
13068
13215
|
series.cropStart = cropStart;
|
13069
13216
|
series.processedXData = processedXData;
|
13070
13217
|
series.processedYData = processedYData;
|
13071
|
-
|
13218
|
+
|
13072
13219
|
if (options.pointRange === null) { // null means auto, as for columns, candlesticks and OHLC
|
13073
13220
|
series.pointRange = closestPointRange || 1;
|
13074
13221
|
}
|
@@ -13076,6 +13223,41 @@ Series.prototype = {
|
|
13076
13223
|
|
13077
13224
|
},
|
13078
13225
|
|
13226
|
+
/**
|
13227
|
+
* Iterate over xData and crop values between min and max. Returns object containing crop start/end
|
13228
|
+
* cropped xData with corresponding part of yData, dataMin and dataMax within the cropped range
|
13229
|
+
*/
|
13230
|
+
cropData: function (xData, yData, min, max) {
|
13231
|
+
var dataLength = xData.length,
|
13232
|
+
cropStart = 0,
|
13233
|
+
cropEnd = dataLength,
|
13234
|
+
i;
|
13235
|
+
|
13236
|
+
// iterate up to find slice start
|
13237
|
+
for (i = 0; i < dataLength; i++) {
|
13238
|
+
if (xData[i] >= min) {
|
13239
|
+
cropStart = mathMax(0, i - 1);
|
13240
|
+
break;
|
13241
|
+
}
|
13242
|
+
}
|
13243
|
+
|
13244
|
+
// proceed to find slice end
|
13245
|
+
for (; i < dataLength; i++) {
|
13246
|
+
if (xData[i] > max) {
|
13247
|
+
cropEnd = i + 1;
|
13248
|
+
break;
|
13249
|
+
}
|
13250
|
+
}
|
13251
|
+
|
13252
|
+
return {
|
13253
|
+
xData: xData.slice(cropStart, cropEnd),
|
13254
|
+
yData: yData.slice(cropStart, cropEnd),
|
13255
|
+
start: cropStart,
|
13256
|
+
end: cropEnd
|
13257
|
+
};
|
13258
|
+
},
|
13259
|
+
|
13260
|
+
|
13079
13261
|
/**
|
13080
13262
|
* Generate the data point after the data has been processed by cropping away
|
13081
13263
|
* unused points and optionally grouped in Highcharts Stock.
|
@@ -13136,6 +13318,154 @@ Series.prototype = {
|
|
13136
13318
|
series.points = points;
|
13137
13319
|
},
|
13138
13320
|
|
13321
|
+
/**
|
13322
|
+
* Adds series' points value to corresponding stack
|
13323
|
+
*/
|
13324
|
+
setStackedPoints: function () {
|
13325
|
+
if (!this.options.stacking || (this.visible !== true && this.chart.options.chart.ignoreHiddenSeries !== false)) {
|
13326
|
+
return;
|
13327
|
+
}
|
13328
|
+
|
13329
|
+
var series = this,
|
13330
|
+
xData = series.processedXData,
|
13331
|
+
yData = series.processedYData,
|
13332
|
+
yDataLength = yData.length,
|
13333
|
+
seriesOptions = series.options,
|
13334
|
+
threshold = seriesOptions.threshold,
|
13335
|
+
stackOption = seriesOptions.stack,
|
13336
|
+
stacking = seriesOptions.stacking,
|
13337
|
+
stackKey = series.stackKey,
|
13338
|
+
negKey = '-' + stackKey,
|
13339
|
+
yAxis = series.yAxis,
|
13340
|
+
stacks = yAxis.stacks,
|
13341
|
+
oldStacks = yAxis.oldStacks,
|
13342
|
+
stacksMax = yAxis.stacksMax,
|
13343
|
+
isNegative,
|
13344
|
+
total,
|
13345
|
+
stack,
|
13346
|
+
key,
|
13347
|
+
i,
|
13348
|
+
x,
|
13349
|
+
y;
|
13350
|
+
|
13351
|
+
// loop over the non-null y values and read them into a local array
|
13352
|
+
for (i = 0; i < yDataLength; i++) {
|
13353
|
+
x = xData[i];
|
13354
|
+
y = yData[i];
|
13355
|
+
|
13356
|
+
// Read stacked values into a stack based on the x value,
|
13357
|
+
// the sign of y and the stack key. Stacking is also handled for null values (#739)
|
13358
|
+
isNegative = y < threshold;
|
13359
|
+
key = isNegative ? negKey : stackKey;
|
13360
|
+
|
13361
|
+
// Set default stacksMax value for this stack
|
13362
|
+
if (!stacksMax[key]) {
|
13363
|
+
stacksMax[key] = y;
|
13364
|
+
}
|
13365
|
+
|
13366
|
+
// Create empty object for this stack if it doesn't exist yet
|
13367
|
+
if (!stacks[key]) {
|
13368
|
+
stacks[key] = {};
|
13369
|
+
}
|
13370
|
+
|
13371
|
+
// Initialize StackItem for this x
|
13372
|
+
if (oldStacks[key] && oldStacks[key][x]) {
|
13373
|
+
stacks[key][x] = oldStacks[key][x];
|
13374
|
+
stacks[key][x].total = null;
|
13375
|
+
} else if (!stacks[key][x]) {
|
13376
|
+
stacks[key][x] = new StackItem(yAxis, yAxis.options.stackLabels, isNegative, x, stackOption, stacking);
|
13377
|
+
}
|
13378
|
+
|
13379
|
+
// If the StackItem doesn't exist, create it first
|
13380
|
+
stack = stacks[key][x];
|
13381
|
+
total = stack.total;
|
13382
|
+
|
13383
|
+
|
13384
|
+
// add value to the stack total
|
13385
|
+
stack.addValue(y);
|
13386
|
+
|
13387
|
+
stack.cacheExtremes(series, [total, total + y]);
|
13388
|
+
|
13389
|
+
|
13390
|
+
if (stack.total > stacksMax[key] && !isNegative) {
|
13391
|
+
stacksMax[key] = stack.total;
|
13392
|
+
} else if (stack.total < stacksMax[key] && isNegative) {
|
13393
|
+
stacksMax[key] = stack.total;
|
13394
|
+
}
|
13395
|
+
}
|
13396
|
+
|
13397
|
+
// reset old stacks
|
13398
|
+
yAxis.oldStacks = {};
|
13399
|
+
},
|
13400
|
+
|
13401
|
+
/**
|
13402
|
+
* Calculate x and y extremes for visible data
|
13403
|
+
*/
|
13404
|
+
getExtremes: function () {
|
13405
|
+
var xAxis = this.xAxis,
|
13406
|
+
yAxis = this.yAxis,
|
13407
|
+
stackKey = this.stackKey,
|
13408
|
+
options = this.options,
|
13409
|
+
threshold = options.threshold,
|
13410
|
+
xData = this.processedXData,
|
13411
|
+
yData = this.processedYData,
|
13412
|
+
yDataLength = yData.length,
|
13413
|
+
activeYData = [],
|
13414
|
+
activeCounter = 0,
|
13415
|
+
xMin = xAxis.min,
|
13416
|
+
xMax = xAxis.max,
|
13417
|
+
validValue,
|
13418
|
+
withinRange,
|
13419
|
+
dataMin,
|
13420
|
+
dataMax,
|
13421
|
+
x,
|
13422
|
+
y,
|
13423
|
+
i,
|
13424
|
+
j;
|
13425
|
+
|
13426
|
+
// For stacked series, get the value from the stack
|
13427
|
+
if (options.stacking) {
|
13428
|
+
dataMin = yAxis.stacksMax['-' + stackKey] || threshold;
|
13429
|
+
dataMax = yAxis.stacksMax[stackKey] || threshold;
|
13430
|
+
}
|
13431
|
+
|
13432
|
+
// If not stacking or threshold is null, iterate over values that are within the visible range
|
13433
|
+
if (!defined(dataMin) || !defined(dataMax)) {
|
13434
|
+
|
13435
|
+
for (i = 0; i < yDataLength; i++) {
|
13436
|
+
|
13437
|
+
x = xData[i];
|
13438
|
+
y = yData[i];
|
13439
|
+
|
13440
|
+
// For points within the visible range, including the first point outside the
|
13441
|
+
// visible range, consider y extremes
|
13442
|
+
validValue = y !== null && y !== UNDEFINED && (!yAxis.isLog || (y.length || y > 0));
|
13443
|
+
withinRange = this.getExtremesFromAll || this.cropped || ((xData[i + 1] || x) >= xMin &&
|
13444
|
+
(xData[i - 1] || x) <= xMax);
|
13445
|
+
|
13446
|
+
if (validValue && withinRange) {
|
13447
|
+
|
13448
|
+
j = y.length;
|
13449
|
+
if (j) { // array, like ohlc or range data
|
13450
|
+
while (j--) {
|
13451
|
+
if (y[j] !== null) {
|
13452
|
+
activeYData[activeCounter++] = y[j];
|
13453
|
+
}
|
13454
|
+
}
|
13455
|
+
} else {
|
13456
|
+
activeYData[activeCounter++] = y;
|
13457
|
+
}
|
13458
|
+
}
|
13459
|
+
}
|
13460
|
+
dataMin = pick(dataMin, arrayMin(activeYData));
|
13461
|
+
dataMax = pick(dataMax, arrayMax(activeYData));
|
13462
|
+
}
|
13463
|
+
|
13464
|
+
// Set
|
13465
|
+
this.dataMin = dataMin;
|
13466
|
+
this.dataMax = dataMax;
|
13467
|
+
},
|
13468
|
+
|
13139
13469
|
/**
|
13140
13470
|
* Translate data points from raw data values to chart specific positioning data
|
13141
13471
|
* needed later in drawPoints, drawGraph and drawTracker.
|
@@ -13154,27 +13484,11 @@ Series.prototype = {
|
|
13154
13484
|
points = series.points,
|
13155
13485
|
dataLength = points.length,
|
13156
13486
|
hasModifyValue = !!series.modifyValue,
|
13157
|
-
isBottomSeries,
|
13158
|
-
allStackSeries,
|
13159
13487
|
i,
|
13160
|
-
|
13488
|
+
pointPlacement = options.pointPlacement, // docs: accept numbers
|
13489
|
+
dynamicallyPlaced = pointPlacement === 'between' || isNumber(pointPlacement),
|
13161
13490
|
threshold = options.threshold;
|
13162
|
-
|
13163
|
-
|
13164
|
-
// Is it the last visible series? (#809, #1722).
|
13165
|
-
// TODO: After merging in the 'stacking' branch, this logic should probably be moved to Chart.getStacks
|
13166
|
-
allStackSeries = yAxis.series.sort(function (a, b) {
|
13167
|
-
return a.index - b.index;
|
13168
|
-
});
|
13169
|
-
i = allStackSeries.length;
|
13170
|
-
while (i--) {
|
13171
|
-
if (allStackSeries[i].visible) {
|
13172
|
-
if (allStackSeries[i] === series) { // #809
|
13173
|
-
isBottomSeries = true;
|
13174
|
-
}
|
13175
|
-
break;
|
13176
|
-
}
|
13177
|
-
}
|
13491
|
+
|
13178
13492
|
|
13179
13493
|
// Translate each point
|
13180
13494
|
for (i = 0; i < dataLength; i++) {
|
@@ -13192,16 +13506,18 @@ Series.prototype = {
|
|
13192
13506
|
}
|
13193
13507
|
|
13194
13508
|
// Get the plotX translation
|
13195
|
-
point.plotX = xAxis.translate(xValue, 0, 0, 0, 1,
|
13509
|
+
point.plotX = xAxis.translate(xValue, 0, 0, 0, 1, pointPlacement); // Math.round fixes #591
|
13196
13510
|
|
13197
13511
|
// Calculate the bottom y value for stacked series
|
13198
13512
|
if (stacking && series.visible && stack && stack[xValue]) {
|
13513
|
+
|
13514
|
+
|
13199
13515
|
pointStack = stack[xValue];
|
13200
13516
|
pointStackTotal = pointStack.total;
|
13201
13517
|
pointStack.cum = yBottom = pointStack.cum - yValue; // start from top
|
13202
13518
|
yValue = yBottom + yValue;
|
13203
13519
|
|
13204
|
-
if (
|
13520
|
+
if (pointStack.cum === 0) {
|
13205
13521
|
yBottom = pick(threshold, yAxis.min);
|
13206
13522
|
}
|
13207
13523
|
|
@@ -13217,6 +13533,10 @@ Series.prototype = {
|
|
13217
13533
|
point.percentage = pointStackTotal ? point.y * 100 / pointStackTotal : 0;
|
13218
13534
|
point.total = point.stackTotal = pointStackTotal;
|
13219
13535
|
point.stackY = yValue;
|
13536
|
+
|
13537
|
+
// Place the stack label
|
13538
|
+
pointStack.setOffset(series.pointXOffset || 0, series.barW || 0);
|
13539
|
+
|
13220
13540
|
}
|
13221
13541
|
|
13222
13542
|
// Set translated yBottom or remove it
|
@@ -13235,7 +13555,7 @@ Series.prototype = {
|
|
13235
13555
|
UNDEFINED;
|
13236
13556
|
|
13237
13557
|
// Set client related positions for mouse tracking
|
13238
|
-
point.clientX =
|
13558
|
+
point.clientX = dynamicallyPlaced ? xAxis.translate(xValue, 0, 0, 0, 1) : point.plotX; // #1514
|
13239
13559
|
|
13240
13560
|
point.negative = point.y < (threshold || 0);
|
13241
13561
|
|
@@ -13261,6 +13581,7 @@ Series.prototype = {
|
|
13261
13581
|
xAxis = series.xAxis,
|
13262
13582
|
axisLength = xAxis ? (xAxis.tooltipLen || xAxis.len) : series.chart.plotSizeX, // tooltipLen and tooltipPosName used in polar
|
13263
13583
|
point,
|
13584
|
+
nextPoint,
|
13264
13585
|
i,
|
13265
13586
|
tooltipPoints = []; // a lookup array for each pixel in the x dimension
|
13266
13587
|
|
@@ -13284,15 +13605,24 @@ Series.prototype = {
|
|
13284
13605
|
points = points.reverse();
|
13285
13606
|
}
|
13286
13607
|
|
13608
|
+
// Polar needs additional shaping
|
13609
|
+
if (series.orderTooltipPoints) {
|
13610
|
+
series.orderTooltipPoints(points);
|
13611
|
+
}
|
13612
|
+
|
13287
13613
|
// Assign each pixel position to the nearest point
|
13288
13614
|
pointsLength = points.length;
|
13289
13615
|
for (i = 0; i < pointsLength; i++) {
|
13290
13616
|
point = points[i];
|
13617
|
+
nextPoint = points[i + 1];
|
13618
|
+
|
13291
13619
|
// Set this range's low to the last range's high plus one
|
13292
13620
|
low = points[i - 1] ? high + 1 : 0;
|
13293
13621
|
// Now find the new high
|
13294
13622
|
high = points[i + 1] ?
|
13295
|
-
mathMax(0, mathFloor(
|
13623
|
+
mathMin(mathMax(0, mathFloor( // #2070
|
13624
|
+
(point.clientX + (nextPoint ? (nextPoint.wrappedClientX || nextPoint.clientX) : axisLength)) / 2
|
13625
|
+
)), axisLength) :
|
13296
13626
|
axisLength;
|
13297
13627
|
|
13298
13628
|
while (low >= 0 && low <= high) {
|
@@ -13512,7 +13842,7 @@ Series.prototype = {
|
|
13512
13842
|
i = points.length;
|
13513
13843
|
while (i--) {
|
13514
13844
|
point = points[i];
|
13515
|
-
plotX = point.plotX;
|
13845
|
+
plotX = mathFloor(point.plotX); // #1843
|
13516
13846
|
plotY = point.plotY;
|
13517
13847
|
graphic = point.graphic;
|
13518
13848
|
pointMarkerOptions = point.marker || {};
|
@@ -13738,7 +14068,7 @@ Series.prototype = {
|
|
13738
14068
|
animation: false,
|
13739
14069
|
index: this.index,
|
13740
14070
|
pointStart: this.xData[0] // when updating after addPoint
|
13741
|
-
}, newOptions);
|
14071
|
+
}, { data: this.options.data }, newOptions);
|
13742
14072
|
|
13743
14073
|
// Destroy the series and reinsert methods from the type prototype
|
13744
14074
|
this.remove(false);
|
@@ -13879,12 +14209,12 @@ Series.prototype = {
|
|
13879
14209
|
// in the point options, or if they fall outside the plot area.
|
13880
14210
|
} else if (enabled) {
|
13881
14211
|
|
13882
|
-
rotation = options.rotation;
|
13883
|
-
|
13884
14212
|
// Create individual options structure that can be extended without
|
13885
14213
|
// affecting others
|
13886
14214
|
options = merge(generalOptions, pointOptions);
|
13887
|
-
|
14215
|
+
|
14216
|
+
rotation = options.rotation;
|
14217
|
+
|
13888
14218
|
// Get the string
|
13889
14219
|
labelConfig = point.getLabelConfig();
|
13890
14220
|
str = options.format ?
|
@@ -13980,7 +14310,7 @@ Series.prototype = {
|
|
13980
14310
|
width: bBox.width,
|
13981
14311
|
height: bBox.height
|
13982
14312
|
});
|
13983
|
-
|
14313
|
+
|
13984
14314
|
// Allow a hook for changing alignment in the last moment, then do the alignment
|
13985
14315
|
if (options.rotation) { // Fancy box alignment isn't supported for rotated text
|
13986
14316
|
alignAttr = {
|
@@ -13996,7 +14326,8 @@ Series.prototype = {
|
|
13996
14326
|
|
13997
14327
|
// Show or hide based on the final aligned position
|
13998
14328
|
dataLabel.attr({
|
13999
|
-
visibility: options.crop === false ||
|
14329
|
+
visibility: options.crop === false ||
|
14330
|
+
(chart.isInsidePlot(alignAttr.x, alignAttr.y) && chart.isInsidePlot(alignAttr.x + bBox.width, alignAttr.y + bBox.height)) ?
|
14000
14331
|
(chart.renderer.isSVG ? 'inherit' : VISIBLE) :
|
14001
14332
|
HIDDEN
|
14002
14333
|
});
|
@@ -14143,7 +14474,7 @@ Series.prototype = {
|
|
14143
14474
|
var options = this.options,
|
14144
14475
|
chart = this.chart,
|
14145
14476
|
renderer = chart.renderer,
|
14146
|
-
negativeColor = options.negativeColor,
|
14477
|
+
negativeColor = options.negativeColor || options.negativeFillColor,
|
14147
14478
|
translatedThreshold,
|
14148
14479
|
posAttr,
|
14149
14480
|
negAttr,
|
@@ -14154,11 +14485,12 @@ Series.prototype = {
|
|
14154
14485
|
chartWidth = chart.chartWidth,
|
14155
14486
|
chartHeight = chart.chartHeight,
|
14156
14487
|
chartSizeMax = mathMax(chartWidth, chartHeight),
|
14488
|
+
yAxis = this.yAxis,
|
14157
14489
|
above,
|
14158
14490
|
below;
|
14159
14491
|
|
14160
14492
|
if (negativeColor && (graph || area)) {
|
14161
|
-
translatedThreshold =
|
14493
|
+
translatedThreshold = mathRound(yAxis.toPixels(options.threshold || 0, true));
|
14162
14494
|
above = {
|
14163
14495
|
x: 0,
|
14164
14496
|
y: 0,
|
@@ -14169,25 +14501,29 @@ Series.prototype = {
|
|
14169
14501
|
x: 0,
|
14170
14502
|
y: translatedThreshold,
|
14171
14503
|
width: chartSizeMax,
|
14172
|
-
height: chartSizeMax
|
14504
|
+
height: chartSizeMax
|
14173
14505
|
};
|
14174
14506
|
|
14175
|
-
if (chart.inverted
|
14176
|
-
|
14177
|
-
|
14178
|
-
|
14179
|
-
|
14180
|
-
|
14181
|
-
|
14182
|
-
|
14183
|
-
|
14184
|
-
|
14185
|
-
|
14186
|
-
|
14187
|
-
|
14507
|
+
if (chart.inverted) {
|
14508
|
+
|
14509
|
+
above.height = below.y = chart.plotWidth - translatedThreshold;
|
14510
|
+
if (renderer.isVML) {
|
14511
|
+
above = {
|
14512
|
+
x: chart.plotWidth - translatedThreshold - chart.plotLeft,
|
14513
|
+
y: 0,
|
14514
|
+
width: chartWidth,
|
14515
|
+
height: chartHeight
|
14516
|
+
};
|
14517
|
+
below = {
|
14518
|
+
x: translatedThreshold + chart.plotLeft - chartWidth,
|
14519
|
+
y: 0,
|
14520
|
+
width: chart.plotLeft + translatedThreshold,
|
14521
|
+
height: chartWidth
|
14522
|
+
};
|
14523
|
+
}
|
14188
14524
|
}
|
14189
14525
|
|
14190
|
-
if (
|
14526
|
+
if (yAxis.reversed) {
|
14191
14527
|
posAttr = below;
|
14192
14528
|
negAttr = above;
|
14193
14529
|
} else {
|
@@ -14203,7 +14539,7 @@ Series.prototype = {
|
|
14203
14539
|
this.posClip = posClip = renderer.clipRect(posAttr);
|
14204
14540
|
this.negClip = negClip = renderer.clipRect(negAttr);
|
14205
14541
|
|
14206
|
-
if (graph) {
|
14542
|
+
if (graph && this.graphNeg) {
|
14207
14543
|
graph.clip(posClip);
|
14208
14544
|
this.graphNeg.clip(negClip);
|
14209
14545
|
}
|
@@ -14260,14 +14596,11 @@ Series.prototype = {
|
|
14260
14596
|
*/
|
14261
14597
|
plotGroup: function (prop, name, visibility, zIndex, parent) {
|
14262
14598
|
var group = this[prop],
|
14263
|
-
isNew = !group
|
14264
|
-
chart = this.chart,
|
14265
|
-
xAxis = this.xAxis,
|
14266
|
-
yAxis = this.yAxis;
|
14599
|
+
isNew = !group;
|
14267
14600
|
|
14268
14601
|
// Generate it on first call
|
14269
14602
|
if (isNew) {
|
14270
|
-
this[prop] = group = chart.renderer.g(name)
|
14603
|
+
this[prop] = group = this.chart.renderer.g(name)
|
14271
14604
|
.attr({
|
14272
14605
|
visibility: visibility,
|
14273
14606
|
zIndex: zIndex || 0.1 // IE8 needs this
|
@@ -14275,14 +14608,20 @@ Series.prototype = {
|
|
14275
14608
|
.add(parent);
|
14276
14609
|
}
|
14277
14610
|
// Place it on first and subsequent (redraw) calls
|
14278
|
-
group[isNew ? 'attr' : 'animate'](
|
14279
|
-
|
14280
|
-
|
14611
|
+
group[isNew ? 'attr' : 'animate'](this.getPlotBox());
|
14612
|
+
return group;
|
14613
|
+
},
|
14614
|
+
|
14615
|
+
/**
|
14616
|
+
* Get the translation and scale for the plot area of this series
|
14617
|
+
*/
|
14618
|
+
getPlotBox: function () {
|
14619
|
+
return {
|
14620
|
+
translateX: this.xAxis ? this.xAxis.left : this.chart.plotLeft,
|
14621
|
+
translateY: this.yAxis ? this.yAxis.top : this.chart.plotTop,
|
14281
14622
|
scaleX: 1, // #1623
|
14282
14623
|
scaleY: 1
|
14283
|
-
}
|
14284
|
-
return group;
|
14285
|
-
|
14624
|
+
};
|
14286
14625
|
},
|
14287
14626
|
|
14288
14627
|
/**
|
@@ -14661,6 +15000,7 @@ var AreaSeries = extendClass(Series, {
|
|
14661
15000
|
plotX,
|
14662
15001
|
plotY,
|
14663
15002
|
points = this.points,
|
15003
|
+
val,
|
14664
15004
|
i,
|
14665
15005
|
x;
|
14666
15006
|
|
@@ -14688,7 +15028,8 @@ var AreaSeries = extendClass(Series, {
|
|
14688
15028
|
// correctly.
|
14689
15029
|
} else {
|
14690
15030
|
plotX = xAxis.translate(x);
|
14691
|
-
|
15031
|
+
val = stack[x].percent ? (stack[x].total ? stack[x].cum * 100 / stack[x].total : 0) : stack[x].cum; // #1991
|
15032
|
+
plotY = yAxis.toPixels(val, true);
|
14692
15033
|
segment.push({
|
14693
15034
|
y: null,
|
14694
15035
|
plotX: plotX,
|
@@ -14784,10 +15125,11 @@ var AreaSeries = extendClass(Series, {
|
|
14784
15125
|
areaPath = this.areaPath,
|
14785
15126
|
options = this.options,
|
14786
15127
|
negativeColor = options.negativeColor,
|
15128
|
+
negativeFillColor = options.negativeFillColor,
|
14787
15129
|
props = [['area', this.color, options.fillColor]]; // area name, main color, fill color
|
14788
15130
|
|
14789
|
-
if (negativeColor) {
|
14790
|
-
props.push(['areaNeg',
|
15131
|
+
if (negativeColor || negativeFillColor) {
|
15132
|
+
props.push(['areaNeg', negativeColor, negativeFillColor]);
|
14791
15133
|
}
|
14792
15134
|
|
14793
15135
|
each(props, function (prop) {
|
@@ -14803,7 +15145,7 @@ var AreaSeries = extendClass(Series, {
|
|
14803
15145
|
.attr({
|
14804
15146
|
fill: pick(
|
14805
15147
|
prop[2],
|
14806
|
-
Color(prop[1]).setOpacity(options.fillOpacity
|
15148
|
+
Color(prop[1]).setOpacity(pick(options.fillOpacity, 0.75)).get()
|
14807
15149
|
),
|
14808
15150
|
zIndex: 0 // #1069
|
14809
15151
|
}).add(series.group);
|
@@ -14973,7 +15315,8 @@ var areaProto = AreaSeries.prototype,
|
|
14973
15315
|
// Mix in methods from the area series
|
14974
15316
|
getSegmentPath: areaProto.getSegmentPath,
|
14975
15317
|
closeSegment: areaProto.closeSegment,
|
14976
|
-
drawGraph: areaProto.drawGraph
|
15318
|
+
drawGraph: areaProto.drawGraph,
|
15319
|
+
drawLegendSymbol: areaProto.drawLegendSymbol
|
14977
15320
|
});
|
14978
15321
|
seriesTypes.areaspline = AreaSplineSeries;
|
14979
15322
|
|
@@ -15019,7 +15362,6 @@ defaultPlotOptions.column = merge(defaultSeriesOptions, {
|
|
15019
15362
|
var ColumnSeries = extendClass(Series, {
|
15020
15363
|
type: 'column',
|
15021
15364
|
tooltipOutsidePlot: true,
|
15022
|
-
requireSorting: false,
|
15023
15365
|
pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
|
15024
15366
|
stroke: 'borderColor',
|
15025
15367
|
'stroke-width': 'borderWidth',
|
@@ -15055,7 +15397,6 @@ var ColumnSeries = extendClass(Series, {
|
|
15055
15397
|
getColumnMetrics: function () {
|
15056
15398
|
|
15057
15399
|
var series = this,
|
15058
|
-
chart = series.chart,
|
15059
15400
|
options = series.options,
|
15060
15401
|
xAxis = this.xAxis,
|
15061
15402
|
reversedXAxis = xAxis.reversed,
|
@@ -15070,7 +15411,7 @@ var ColumnSeries = extendClass(Series, {
|
|
15070
15411
|
if (options.grouping === false) {
|
15071
15412
|
columnCount = 1;
|
15072
15413
|
} else {
|
15073
|
-
each(
|
15414
|
+
each(series.yAxis.series, function (otherSeries) { // use Y axes separately, #642
|
15074
15415
|
var otherOptions = otherSeries.options;
|
15075
15416
|
if (otherSeries.type === series.type && otherSeries.visible &&
|
15076
15417
|
series.options.group === otherOptions.group) { // used in Stock charts navigator series
|
@@ -15121,7 +15462,6 @@ var ColumnSeries = extendClass(Series, {
|
|
15121
15462
|
var series = this,
|
15122
15463
|
chart = series.chart,
|
15123
15464
|
options = series.options,
|
15124
|
-
stacking = options.stacking,
|
15125
15465
|
borderWidth = options.borderWidth,
|
15126
15466
|
yAxis = series.yAxis,
|
15127
15467
|
threshold = options.threshold,
|
@@ -15129,8 +15469,8 @@ var ColumnSeries = extendClass(Series, {
|
|
15129
15469
|
minPointLength = pick(options.minPointLength, 5),
|
15130
15470
|
metrics = series.getColumnMetrics(),
|
15131
15471
|
pointWidth = metrics.width,
|
15132
|
-
barW = mathCeil(mathMax(pointWidth, 1 + 2 * borderWidth)), // rounded and postprocessed for border width
|
15133
|
-
pointXOffset = metrics.offset;
|
15472
|
+
barW = series.barW = mathCeil(mathMax(pointWidth, 1 + 2 * borderWidth)), // rounded and postprocessed for border width
|
15473
|
+
pointXOffset = series.pointXOffset = metrics.offset;
|
15134
15474
|
|
15135
15475
|
Series.prototype.translate.apply(series);
|
15136
15476
|
|
@@ -15141,22 +15481,16 @@ var ColumnSeries = extendClass(Series, {
|
|
15141
15481
|
barX = point.plotX + pointXOffset,
|
15142
15482
|
barY = mathCeil(mathMin(plotY, yBottom)),
|
15143
15483
|
barH = mathCeil(mathMax(plotY, yBottom) - barY),
|
15144
|
-
stack = yAxis.stacks[(point.y < 0 ? '-' : '') + series.stackKey],
|
15145
15484
|
shapeArgs;
|
15146
15485
|
|
15147
|
-
// Record the offset'ed position and width of the bar to be able to align the stacking total correctly
|
15148
|
-
if (stacking && series.visible && stack && stack[point.x]) {
|
15149
|
-
stack[point.x].setOffset(pointXOffset, barW);
|
15150
|
-
}
|
15151
|
-
|
15152
15486
|
// handle options.minPointLength
|
15153
15487
|
if (mathAbs(barH) < minPointLength) {
|
15154
15488
|
if (minPointLength) {
|
15155
15489
|
barH = minPointLength;
|
15156
15490
|
barY =
|
15157
|
-
mathAbs(barY - translatedThreshold) > minPointLength ? // stacked
|
15491
|
+
mathRound(mathAbs(barY - translatedThreshold) > minPointLength ? // stacked
|
15158
15492
|
yBottom - minPointLength : // keep position
|
15159
|
-
translatedThreshold - (yAxis.translate(point.y, 0, 1, 0, 1) <= translatedThreshold ? minPointLength : 0); // use exact yAxis.translation (#1485)
|
15493
|
+
translatedThreshold - (yAxis.translate(point.y, 0, 1, 0, 1) <= translatedThreshold ? minPointLength : 0)); // use exact yAxis.translation (#1485)
|
15160
15494
|
}
|
15161
15495
|
}
|
15162
15496
|
|
@@ -15232,20 +15566,22 @@ var ColumnSeries = extendClass(Series, {
|
|
15232
15566
|
*/
|
15233
15567
|
drawTracker: function () {
|
15234
15568
|
var series = this,
|
15235
|
-
|
15569
|
+
chart = series.chart,
|
15570
|
+
pointer = chart.pointer,
|
15236
15571
|
cursor = series.options.cursor,
|
15237
15572
|
css = cursor && { cursor: cursor },
|
15238
15573
|
onMouseOver = function (e) {
|
15239
15574
|
var target = e.target,
|
15240
15575
|
point;
|
15241
15576
|
|
15242
|
-
series
|
15243
|
-
|
15577
|
+
if (chart.hoverSeries !== series) {
|
15578
|
+
series.onMouseOver();
|
15579
|
+
}
|
15244
15580
|
while (target && !point) {
|
15245
15581
|
point = target.point;
|
15246
15582
|
target = target.parentNode;
|
15247
15583
|
}
|
15248
|
-
if (point !== UNDEFINED) { // undefined on graph in scatterchart
|
15584
|
+
if (point !== UNDEFINED && point !== chart.hoverPoint) { // undefined on graph in scatterchart
|
15249
15585
|
point.onMouseOver(e);
|
15250
15586
|
}
|
15251
15587
|
};
|
@@ -15495,8 +15831,8 @@ var PiePoint = extendClass(Point, {
|
|
15495
15831
|
});
|
15496
15832
|
|
15497
15833
|
// add event listener for select
|
15498
|
-
toggleSlice = function () {
|
15499
|
-
point.slice();
|
15834
|
+
toggleSlice = function (e) {
|
15835
|
+
point.slice(e.type === 'select');
|
15500
15836
|
};
|
15501
15837
|
addEvent(point, 'select', toggleSlice);
|
15502
15838
|
addEvent(point, 'unselect', toggleSlice);
|
@@ -15641,6 +15977,39 @@ var PieSeries = {
|
|
15641
15977
|
this.chart.redraw();
|
15642
15978
|
}
|
15643
15979
|
},
|
15980
|
+
|
15981
|
+
/**
|
15982
|
+
* Extend the generatePoints method by adding total and percentage properties to each point
|
15983
|
+
*/
|
15984
|
+
generatePoints: function () {
|
15985
|
+
var i,
|
15986
|
+
total = 0,
|
15987
|
+
points,
|
15988
|
+
len,
|
15989
|
+
point,
|
15990
|
+
ignoreHiddenPoint = this.options.ignoreHiddenPoint;
|
15991
|
+
|
15992
|
+
Series.prototype.generatePoints.call(this);
|
15993
|
+
|
15994
|
+
// Populate local vars
|
15995
|
+
points = this.points;
|
15996
|
+
len = points.length;
|
15997
|
+
|
15998
|
+
// Get the total sum
|
15999
|
+
for (i = 0; i < len; i++) {
|
16000
|
+
point = points[i];
|
16001
|
+
total += (ignoreHiddenPoint && !point.visible) ? 0 : point.y;
|
16002
|
+
}
|
16003
|
+
this.total = total;
|
16004
|
+
|
16005
|
+
// Set each point's properties
|
16006
|
+
for (i = 0; i < len; i++) {
|
16007
|
+
point = points[i];
|
16008
|
+
point.percentage = (point.y / total) * 100;
|
16009
|
+
point.total = total;
|
16010
|
+
}
|
16011
|
+
|
16012
|
+
},
|
15644
16013
|
|
15645
16014
|
/**
|
15646
16015
|
* Get the center of the pie based on the size and center options relative to the
|
@@ -15679,8 +16048,7 @@ var PieSeries = {
|
|
15679
16048
|
translate: function (positions) {
|
15680
16049
|
this.generatePoints();
|
15681
16050
|
|
15682
|
-
var
|
15683
|
-
series = this,
|
16051
|
+
var series = this,
|
15684
16052
|
cumulative = 0,
|
15685
16053
|
precision = 1000, // issue #172
|
15686
16054
|
options = series.options,
|
@@ -15692,7 +16060,6 @@ var PieSeries = {
|
|
15692
16060
|
startAngleRad = series.startAngleRad = mathPI / 180 * ((options.startAngle || 0) % 360 - 90),
|
15693
16061
|
points = series.points,
|
15694
16062
|
circ = 2 * mathPI,
|
15695
|
-
fraction,
|
15696
16063
|
radiusX, // the x component of the radius vector for a given point
|
15697
16064
|
radiusY,
|
15698
16065
|
labelDistance = options.dataLabels.distance,
|
@@ -15718,22 +16085,15 @@ var PieSeries = {
|
|
15718
16085
|
(mathCos(angle) * (positions[2] / 2 + labelDistance));
|
15719
16086
|
};
|
15720
16087
|
|
15721
|
-
// get the total sum
|
15722
|
-
for (i = 0; i < len; i++) {
|
15723
|
-
point = points[i];
|
15724
|
-
total += (ignoreHiddenPoint && !point.visible) ? 0 : point.y;
|
15725
|
-
}
|
15726
|
-
|
15727
16088
|
// Calculate the geometry for each point
|
15728
16089
|
for (i = 0; i < len; i++) {
|
15729
16090
|
|
15730
16091
|
point = points[i];
|
15731
16092
|
|
15732
16093
|
// set start and end angle
|
15733
|
-
fraction = total ? point.y / total : 0;
|
15734
16094
|
start = mathRound((startAngleRad + (cumulative * circ)) * precision) / precision;
|
15735
16095
|
if (!ignoreHiddenPoint || point.visible) {
|
15736
|
-
cumulative +=
|
16096
|
+
cumulative += point.percentage / 100;
|
15737
16097
|
}
|
15738
16098
|
end = mathRound((startAngleRad + (cumulative * circ)) * precision) / precision;
|
15739
16099
|
|
@@ -15783,10 +16143,6 @@ var PieSeries = {
|
|
15783
16143
|
point.half ? 'right' : 'left', // alignment
|
15784
16144
|
angle // center angle
|
15785
16145
|
];
|
15786
|
-
|
15787
|
-
// API properties
|
15788
|
-
point.percentage = fraction * 100;
|
15789
|
-
point.total = total;
|
15790
16146
|
|
15791
16147
|
}
|
15792
16148
|
|
@@ -15909,7 +16265,7 @@ var PieSeries = {
|
|
15909
16265
|
};
|
15910
16266
|
|
15911
16267
|
// get out if not enabled
|
15912
|
-
if (!options.enabled && !series._hasPointLabels) {
|
16268
|
+
if (!series.visible || (!options.enabled && !series._hasPointLabels)) {
|
15913
16269
|
return;
|
15914
16270
|
}
|
15915
16271
|
|