highcharts-rails 3.0.2 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|