contour 2.1.0.beta16 → 2.1.0.beta17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -1
- data/app/assets/javascripts/contour.js +1 -1
- data/app/assets/javascripts/external/{highcharts-3.0.2.src.js → highcharts-3.0.5.src.js} +1135 -641
- data/contour.gemspec +1 -1
- data/lib/contour/version.rb +1 -1
- data/lib/generators/contour/scaffold/templates/_paginate.html.erb +1 -1
- data/lib/generators/contour/scaffold/templates/controller.rb +1 -1
- data/lib/generators/contour/scaffold/templates/show.html.erb +2 -2
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/test.log +392 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/0a38cde2d72ff579969b2cad3683287d +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/0a9add3e4b179c763a81d057c1237324 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/0b793dc498fe65856d1b31a805f114dc +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/1a4771f9c62410bd2e9883cbf32c7ab2 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/202ee3e470074d921a4ebc990afe1182 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/2104a43b6b7d1d60519dc2deb62ae47b +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/2479163ee9d4e495176d9585da79e9dd +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/408c90980fca5a250881bafa3ef0ca63 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/4326df7424da5275c5236fd4615801e8 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/4e3cde93d4ff732fa65037906a330288 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/6666059cb20313a69e518d351e00eb1f +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/722eaf6263f7819374cc8215ee7c854b +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/795f142066419901b557f2d610607b6b +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/848658619cb4b7da3735feeb70b87d5c +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/92654af24f38bd4ce2b3e67eac84f17f +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/a7b222735fc6d94f5713fa8e4c00feec +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/aebdc1b314bd6ea5185ab5d39bf75d87 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/b0d8276a1c6457dcb0798d0f676b1298 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/bffe970187601e005684626d70560050 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/c62ff8b966094d815ee8799210a70413 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/cffe43e7509735b14b54b6ac19fd08d5 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/e2a43f58b4eed6258f424ad79d34e5c1 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- metadata +33 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06c1f851aa201f8b055336424f8f786f4428c090
|
4
|
+
data.tar.gz: 6dcb4f35ccf617568aaa820907a2583efec5124d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f7d6c9c0640d083d851c3ab42d9291e68cd1fce9582904d35b4a1d39745062b3ee6ed38693c8f3464b6fea6f9c2455ad4359a5afe12a4199d2e59f4a0c91e4f
|
7
|
+
data.tar.gz: 76bd1bf6ebcc9f160c919073b5f819834d9ae7ae831c95b62f7bc5b33b7e6a8451ed02b51680e4d2d4125a4b08846cc8891c60a877c74e26c50fee938074e83e
|
data/CHANGELOG.md
CHANGED
@@ -6,8 +6,9 @@
|
|
6
6
|
- Menu dropdowns can now have headers
|
7
7
|
- `links: [ ..., { header: 'Dropdown header' }, ... ]`
|
8
8
|
- Removed bootstrap-scroll-modal since it collided with BS3's implementation
|
9
|
+
- Updated HighCharts to 3.0.5
|
9
10
|
- **Gem Changes**
|
10
|
-
- Updated to Devise 3.0.
|
11
|
+
- Updated to Devise 3.0.3
|
11
12
|
|
12
13
|
## 2.0.0 (July 25, 2013)
|
13
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.5 (2013-08-23)
|
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.5',
|
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
|
|
@@ -1412,6 +1423,9 @@ pathAnim = {
|
|
1412
1423
|
}
|
1413
1424
|
|
1414
1425
|
$el.stop();
|
1426
|
+
if (params.opacity !== UNDEFINED && el.attr) {
|
1427
|
+
params.opacity += 'px'; // force jQuery to use same logic as width and height (#2161)
|
1428
|
+
}
|
1415
1429
|
$el.animate(params, options);
|
1416
1430
|
|
1417
1431
|
},
|
@@ -1462,7 +1476,7 @@ var
|
|
1462
1476
|
defaultLabelOptions = {
|
1463
1477
|
enabled: true,
|
1464
1478
|
// rotation: 0,
|
1465
|
-
align: 'center',
|
1479
|
+
// align: 'center',
|
1466
1480
|
x: 0,
|
1467
1481
|
y: 15,
|
1468
1482
|
/*formatter: function () {
|
@@ -1494,8 +1508,8 @@ defaultOptions = {
|
|
1494
1508
|
},
|
1495
1509
|
global: {
|
1496
1510
|
useUTC: true,
|
1497
|
-
canvasToolsURL: 'http://code.highcharts.com/3.0.
|
1498
|
-
VMLRadialGradientURL: 'http://code.highcharts.com/3.0.
|
1511
|
+
canvasToolsURL: 'http://code.highcharts.com/3.0.5/modules/canvas-tools.js',
|
1512
|
+
VMLRadialGradientURL: 'http://code.highcharts.com/3.0.5/gfx/vml-radial-gradient.png'
|
1499
1513
|
},
|
1500
1514
|
chart: {
|
1501
1515
|
//animation: true,
|
@@ -1546,10 +1560,10 @@ defaultOptions = {
|
|
1546
1560
|
text: 'Chart title',
|
1547
1561
|
align: 'center',
|
1548
1562
|
// floating: false,
|
1549
|
-
|
1563
|
+
margin: 15,
|
1550
1564
|
// x: 0,
|
1551
1565
|
// verticalAlign: 'top',
|
1552
|
-
y:
|
1566
|
+
// y: null,
|
1553
1567
|
style: {
|
1554
1568
|
color: '#274b6d',//#3E576F',
|
1555
1569
|
fontSize: '16px'
|
@@ -1562,7 +1576,7 @@ defaultOptions = {
|
|
1562
1576
|
// floating: false
|
1563
1577
|
// x: 0,
|
1564
1578
|
// verticalAlign: 'top',
|
1565
|
-
y:
|
1579
|
+
// y: null,
|
1566
1580
|
style: {
|
1567
1581
|
color: '#4d759e'
|
1568
1582
|
}
|
@@ -1608,9 +1622,10 @@ defaultOptions = {
|
|
1608
1622
|
events: {}
|
1609
1623
|
},
|
1610
1624
|
dataLabels: merge(defaultLabelOptions, {
|
1625
|
+
align: 'center',
|
1611
1626
|
enabled: false,
|
1612
1627
|
formatter: function () {
|
1613
|
-
return numberFormat(this.y, -1);
|
1628
|
+
return this.y === null ? '' : numberFormat(this.y, -1);
|
1614
1629
|
},
|
1615
1630
|
verticalAlign: 'bottom', // above singular point
|
1616
1631
|
y: 0
|
@@ -2158,7 +2173,7 @@ SVGElement.prototype = {
|
|
2158
2173
|
|
2159
2174
|
i = value.length;
|
2160
2175
|
while (i--) {
|
2161
|
-
value[i] = pInt(value[i]) * hash['stroke-width'];
|
2176
|
+
value[i] = pInt(value[i]) * pick(hash['stroke-width'], wrapper['stroke-width']);
|
2162
2177
|
}
|
2163
2178
|
value = value.join(',');
|
2164
2179
|
}
|
@@ -2216,7 +2231,7 @@ SVGElement.prototype = {
|
|
2216
2231
|
}
|
2217
2232
|
|
2218
2233
|
// let the shadow follow the main element
|
2219
|
-
if (shadows && /^(width|height|visibility|x|y|d|transform)$/.test(key)) {
|
2234
|
+
if (shadows && /^(width|height|visibility|x|y|d|transform|cx|cy|r)$/.test(key)) {
|
2220
2235
|
i = shadows.length;
|
2221
2236
|
while (i--) {
|
2222
2237
|
attr(
|
@@ -2271,7 +2286,12 @@ SVGElement.prototype = {
|
|
2271
2286
|
* Add a class name to an element
|
2272
2287
|
*/
|
2273
2288
|
addClass: function (className) {
|
2274
|
-
|
2289
|
+
var element = this.element,
|
2290
|
+
currentClassName = attr(element, 'class') || '';
|
2291
|
+
|
2292
|
+
if (currentClassName.indexOf(className) === -1) {
|
2293
|
+
attr(element, 'class', currentClassName + ' ' + className);
|
2294
|
+
}
|
2275
2295
|
return this;
|
2276
2296
|
},
|
2277
2297
|
/* hasClass and removeClass are not (yet) needed
|
@@ -2414,15 +2434,16 @@ SVGElement.prototype = {
|
|
2414
2434
|
* @param {Function} handler
|
2415
2435
|
*/
|
2416
2436
|
on: function (eventType, handler) {
|
2437
|
+
var element = this.element;
|
2417
2438
|
// touch
|
2418
2439
|
if (hasTouch && eventType === 'click') {
|
2419
|
-
|
2440
|
+
element.ontouchstart = function (e) {
|
2420
2441
|
e.preventDefault();
|
2421
|
-
handler();
|
2442
|
+
handler.call(element, e);
|
2422
2443
|
};
|
2423
2444
|
}
|
2424
2445
|
// simplest possible event model for internal use
|
2425
|
-
|
2446
|
+
element['on' + eventType] = handler;
|
2426
2447
|
return this;
|
2427
2448
|
},
|
2428
2449
|
|
@@ -2568,33 +2589,18 @@ SVGElement.prototype = {
|
|
2568
2589
|
textWidth = pInt(wrapper.textWidth),
|
2569
2590
|
xCorr = wrapper.xCorr || 0,
|
2570
2591
|
yCorr = wrapper.yCorr || 0,
|
2571
|
-
currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth].join(',')
|
2572
|
-
rotationStyle = {},
|
2573
|
-
cssTransformKey;
|
2592
|
+
currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth].join(',');
|
2574
2593
|
|
2575
2594
|
if (currentTextTransform !== wrapper.cTT) { // do the calculations and DOM access only if properties changed
|
2576
2595
|
|
2577
2596
|
if (defined(rotation)) {
|
2578
2597
|
|
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);
|
2598
|
+
radians = rotation * deg2rad; // deg to rad
|
2599
|
+
costheta = mathCos(radians);
|
2600
|
+
sintheta = mathSin(radians);
|
2601
|
+
|
2602
|
+
wrapper.setSpanRotation(rotation, sintheta, costheta);
|
2603
|
+
|
2598
2604
|
}
|
2599
2605
|
|
2600
2606
|
width = pick(wrapper.elemWidth, elem.offsetWidth);
|
@@ -2652,6 +2658,17 @@ SVGElement.prototype = {
|
|
2652
2658
|
}
|
2653
2659
|
},
|
2654
2660
|
|
2661
|
+
/**
|
2662
|
+
* Set the rotation of an individual HTML span
|
2663
|
+
*/
|
2664
|
+
setSpanRotation: function (rotation) {
|
2665
|
+
var rotationStyle = {},
|
2666
|
+
cssTransformKey = isIE ? '-ms-transform' : isWebKit ? '-webkit-transform' : isFirefox ? 'MozTransform' : isOpera ? '-o-transform' : '';
|
2667
|
+
|
2668
|
+
rotationStyle[cssTransformKey] = rotationStyle.transform = 'rotate(' + rotation + 'deg)';
|
2669
|
+
css(this.element, rotationStyle);
|
2670
|
+
},
|
2671
|
+
|
2655
2672
|
/**
|
2656
2673
|
* Private method to update the transform attribute based on internal
|
2657
2674
|
* properties
|
@@ -2954,6 +2971,8 @@ SVGElement.prototype = {
|
|
2954
2971
|
var wrapper = this,
|
2955
2972
|
element = wrapper.element || {},
|
2956
2973
|
shadows = wrapper.shadows,
|
2974
|
+
parentToClean = wrapper.renderer.isSVG && element.nodeName === 'SPAN' && element.parentNode,
|
2975
|
+
grandParent,
|
2957
2976
|
key,
|
2958
2977
|
i;
|
2959
2978
|
|
@@ -2983,6 +3002,13 @@ SVGElement.prototype = {
|
|
2983
3002
|
});
|
2984
3003
|
}
|
2985
3004
|
|
3005
|
+
// In case of useHTML, clean up empty containers emulating SVG groups (#1960).
|
3006
|
+
while (parentToClean && parentToClean.childNodes.length === 0) {
|
3007
|
+
grandParent = parentToClean.parentNode;
|
3008
|
+
wrapper.safeRemoveChild(parentToClean);
|
3009
|
+
parentToClean = grandParent;
|
3010
|
+
}
|
3011
|
+
|
2986
3012
|
// remove from alignObjects
|
2987
3013
|
if (wrapper.alignTo) {
|
2988
3014
|
erase(wrapper.renderer.alignedObjects, wrapper);
|
@@ -3071,18 +3097,24 @@ SVGRenderer.prototype = {
|
|
3071
3097
|
var renderer = this,
|
3072
3098
|
loc = location,
|
3073
3099
|
boxWrapper,
|
3100
|
+
element,
|
3074
3101
|
desc;
|
3075
3102
|
|
3076
3103
|
boxWrapper = renderer.createElement('svg')
|
3077
3104
|
.attr({
|
3078
|
-
xmlns: SVG_NS,
|
3079
3105
|
version: '1.1'
|
3080
3106
|
});
|
3081
|
-
|
3107
|
+
element = boxWrapper.element;
|
3108
|
+
container.appendChild(element);
|
3109
|
+
|
3110
|
+
// For browsers other than IE, add the namespace attribute (#1978)
|
3111
|
+
if (container.innerHTML.indexOf('xmlns') === -1) {
|
3112
|
+
attr(element, 'xmlns', SVG_NS);
|
3113
|
+
}
|
3082
3114
|
|
3083
3115
|
// object properties
|
3084
3116
|
renderer.isSVG = true;
|
3085
|
-
renderer.box =
|
3117
|
+
renderer.box = element;
|
3086
3118
|
renderer.boxWrapper = boxWrapper;
|
3087
3119
|
renderer.alignedObjects = [];
|
3088
3120
|
|
@@ -3203,7 +3235,7 @@ SVGRenderer.prototype = {
|
|
3203
3235
|
.split(/<br.*?>/g),
|
3204
3236
|
childNodes = textNode.childNodes,
|
3205
3237
|
styleRegex = /style="([^"]+)"/,
|
3206
|
-
hrefRegex = /href="([^"]+)"/,
|
3238
|
+
hrefRegex = /href="(http[^"]+)"/,
|
3207
3239
|
parentX = attr(textNode, 'x'),
|
3208
3240
|
textStyles = wrapper.styles,
|
3209
3241
|
width = textStyles && textStyles.width && pInt(textStyles.width),
|
@@ -3249,82 +3281,86 @@ SVGRenderer.prototype = {
|
|
3249
3281
|
.replace(/</g, '<')
|
3250
3282
|
.replace(/>/g, '>');
|
3251
3283
|
|
3252
|
-
//
|
3253
|
-
|
3254
|
-
|
3255
|
-
|
3256
|
-
|
3257
|
-
} else {
|
3258
|
-
attributes.dx = 0; // #16
|
3259
|
-
}
|
3284
|
+
// Nested tags aren't supported, and cause crash in Safari (#1596)
|
3285
|
+
if (span !== ' ') {
|
3286
|
+
|
3287
|
+
// add the text node
|
3288
|
+
tspan.appendChild(doc.createTextNode(span));
|
3260
3289
|
|
3261
|
-
|
3262
|
-
|
3290
|
+
if (!spanNo) { // first span in a line, align it to the left
|
3291
|
+
attributes.x = parentX;
|
3292
|
+
} else {
|
3293
|
+
attributes.dx = 0; // #16
|
3294
|
+
}
|
3263
3295
|
|
3264
|
-
|
3265
|
-
|
3296
|
+
// add attributes
|
3297
|
+
attr(tspan, attributes);
|
3266
3298
|
|
3267
|
-
//
|
3268
|
-
if (!
|
3269
|
-
css(tspan, { display: 'block' });
|
3270
|
-
}
|
3299
|
+
// first span on subsequent line, add the line height
|
3300
|
+
if (!spanNo && lineNo) {
|
3271
3301
|
|
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
|
-
}
|
3302
|
+
// allow getting the right offset height in exporting in IE
|
3303
|
+
if (!hasSVG && forExport) {
|
3304
|
+
css(tspan, { display: 'block' });
|
3305
|
+
}
|
3287
3306
|
|
3288
|
-
|
3289
|
-
|
3307
|
+
// Set the line height based on the font size of either
|
3308
|
+
// the text element or the tspan element
|
3309
|
+
attr(
|
3310
|
+
tspan,
|
3311
|
+
'dy',
|
3312
|
+
textLineHeight || renderer.fontMetrics(
|
3313
|
+
/px$/.test(tspan.style.fontSize) ?
|
3314
|
+
tspan.style.fontSize :
|
3315
|
+
textStyles.fontSize
|
3316
|
+
).h,
|
3317
|
+
// Safari 6.0.2 - too optimized for its own good (#1539)
|
3318
|
+
// TODO: revisit this with future versions of Safari
|
3319
|
+
isWebKit && tspan.offsetHeight
|
3320
|
+
);
|
3321
|
+
}
|
3290
3322
|
|
3291
|
-
|
3323
|
+
// Append it
|
3324
|
+
textNode.appendChild(tspan);
|
3292
3325
|
|
3293
|
-
|
3294
|
-
if (width) {
|
3295
|
-
var words = span.replace(/([^\^])-/g, '$1- ').split(' '), // #1273
|
3296
|
-
tooLong,
|
3297
|
-
actualWidth,
|
3298
|
-
rest = [];
|
3326
|
+
spanNo++;
|
3299
3327
|
|
3300
|
-
|
3301
|
-
|
3302
|
-
|
3303
|
-
|
3304
|
-
|
3305
|
-
words = rest;
|
3328
|
+
// check width and apply soft breaks
|
3329
|
+
if (width) {
|
3330
|
+
var words = span.replace(/([^\^])-/g, '$1- ').split(' '), // #1273
|
3331
|
+
tooLong,
|
3332
|
+
actualWidth,
|
3306
3333
|
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
3334
|
|
3318
|
-
|
3319
|
-
|
3335
|
+
while (words.length || rest.length) {
|
3336
|
+
delete wrapper.bBox; // delete cache
|
3337
|
+
actualWidth = wrapper.getBBox().width;
|
3338
|
+
tooLong = actualWidth > width;
|
3339
|
+
if (!tooLong || words.length === 1) { // new line needed
|
3340
|
+
words = rest;
|
3341
|
+
rest = [];
|
3342
|
+
if (words.length) {
|
3343
|
+
tspan = doc.createElementNS(SVG_NS, 'tspan');
|
3344
|
+
attr(tspan, {
|
3345
|
+
dy: textLineHeight || 16,
|
3346
|
+
x: parentX
|
3347
|
+
});
|
3348
|
+
if (spanStyle) { // #390
|
3349
|
+
attr(tspan, 'style', spanStyle);
|
3350
|
+
}
|
3351
|
+
textNode.appendChild(tspan);
|
3352
|
+
|
3353
|
+
if (actualWidth > width) { // a single word is pressing it out
|
3354
|
+
width = actualWidth;
|
3355
|
+
}
|
3320
3356
|
}
|
3357
|
+
} else { // append to existing line tspan
|
3358
|
+
tspan.removeChild(tspan.firstChild);
|
3359
|
+
rest.unshift(words.pop());
|
3360
|
+
}
|
3361
|
+
if (words.length) {
|
3362
|
+
tspan.appendChild(doc.createTextNode(words.join(' ').replace(/- /g, '-')));
|
3321
3363
|
}
|
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
3364
|
}
|
3329
3365
|
}
|
3330
3366
|
}
|
@@ -3343,7 +3379,7 @@ SVGRenderer.prototype = {
|
|
3343
3379
|
* @param {Object} hoverState
|
3344
3380
|
* @param {Object} pressedState
|
3345
3381
|
*/
|
3346
|
-
button: function (text, x, y, callback, normalState, hoverState, pressedState) {
|
3382
|
+
button: function (text, x, y, callback, normalState, hoverState, pressedState, disabledState) {
|
3347
3383
|
var label = this.label(text, x, y, null, null, null, null, null, 'button'),
|
3348
3384
|
curState = 0,
|
3349
3385
|
stateOptions,
|
@@ -3351,6 +3387,7 @@ SVGRenderer.prototype = {
|
|
3351
3387
|
normalStyle,
|
3352
3388
|
hoverStyle,
|
3353
3389
|
pressedStyle,
|
3390
|
+
disabledStyle,
|
3354
3391
|
STYLE = 'style',
|
3355
3392
|
verticalGradient = { x1: 0, y1: 0, x2: 0, y2: 1 };
|
3356
3393
|
|
@@ -3402,32 +3439,50 @@ SVGRenderer.prototype = {
|
|
3402
3439
|
pressedStyle = pressedState[STYLE];
|
3403
3440
|
delete pressedState[STYLE];
|
3404
3441
|
|
3405
|
-
//
|
3406
|
-
|
3407
|
-
|
3408
|
-
|
3442
|
+
// Disabled state
|
3443
|
+
disabledState = merge(normalState, {
|
3444
|
+
style: {
|
3445
|
+
color: '#CCC'
|
3446
|
+
}
|
3447
|
+
}, disabledState);
|
3448
|
+
disabledStyle = disabledState[STYLE];
|
3449
|
+
delete disabledState[STYLE];
|
3450
|
+
|
3451
|
+
// Add the events. IE9 and IE10 need mouseover and mouseout to funciton (#667).
|
3452
|
+
addEvent(label.element, isIE ? 'mouseover' : 'mouseenter', function () {
|
3453
|
+
if (curState !== 3) {
|
3454
|
+
label.attr(hoverState)
|
3455
|
+
.css(hoverStyle);
|
3456
|
+
}
|
3409
3457
|
});
|
3410
|
-
addEvent(label.element, 'mouseleave', function () {
|
3411
|
-
|
3412
|
-
|
3413
|
-
|
3414
|
-
.
|
3458
|
+
addEvent(label.element, isIE ? 'mouseout' : 'mouseleave', function () {
|
3459
|
+
if (curState !== 3) {
|
3460
|
+
stateOptions = [normalState, hoverState, pressedState][curState];
|
3461
|
+
stateStyle = [normalStyle, hoverStyle, pressedStyle][curState];
|
3462
|
+
label.attr(stateOptions)
|
3463
|
+
.css(stateStyle);
|
3464
|
+
}
|
3415
3465
|
});
|
3416
3466
|
|
3417
3467
|
label.setState = function (state) {
|
3418
|
-
curState = state;
|
3468
|
+
label.state = curState = state;
|
3419
3469
|
if (!state) {
|
3420
3470
|
label.attr(normalState)
|
3421
3471
|
.css(normalStyle);
|
3422
3472
|
} else if (state === 2) {
|
3423
3473
|
label.attr(pressedState)
|
3424
3474
|
.css(pressedStyle);
|
3475
|
+
} else if (state === 3) {
|
3476
|
+
label.attr(disabledState)
|
3477
|
+
.css(disabledStyle);
|
3425
3478
|
}
|
3426
3479
|
};
|
3427
3480
|
|
3428
3481
|
return label
|
3429
3482
|
.on('click', function () {
|
3430
|
-
|
3483
|
+
if (curState !== 3) {
|
3484
|
+
callback.call(label);
|
3485
|
+
}
|
3431
3486
|
})
|
3432
3487
|
.attr(normalState)
|
3433
3488
|
.css(extend({ cursor: 'default' }, normalStyle));
|
@@ -3496,8 +3551,7 @@ SVGRenderer.prototype = {
|
|
3496
3551
|
* @param {Number} end Ending angle
|
3497
3552
|
*/
|
3498
3553
|
arc: function (x, y, r, innerR, start, end) {
|
3499
|
-
|
3500
|
-
// attributes in attr and animate
|
3554
|
+
var arc;
|
3501
3555
|
|
3502
3556
|
if (isObject(x)) {
|
3503
3557
|
y = x.y;
|
@@ -3507,11 +3561,16 @@ SVGRenderer.prototype = {
|
|
3507
3561
|
end = x.end;
|
3508
3562
|
x = x.x;
|
3509
3563
|
}
|
3510
|
-
|
3564
|
+
|
3565
|
+
// Arcs are defined as symbols for the ability to set
|
3566
|
+
// attributes in attr and animate
|
3567
|
+
arc = this.symbol('arc', x || 0, y || 0, r || 0, r || 0, {
|
3511
3568
|
innerR: innerR || 0,
|
3512
3569
|
start: start || 0,
|
3513
3570
|
end: end || 0
|
3514
3571
|
});
|
3572
|
+
arc.r = r; // #959
|
3573
|
+
return arc;
|
3515
3574
|
},
|
3516
3575
|
|
3517
3576
|
/**
|
@@ -4079,7 +4138,7 @@ SVGRenderer.prototype = {
|
|
4079
4138
|
// Ensure dynamically updating position when any parent is translated
|
4080
4139
|
each(parents.reverse(), function (parentGroup) {
|
4081
4140
|
var htmlGroupStyle;
|
4082
|
-
|
4141
|
+
|
4083
4142
|
// Create a HTML div and append it to the parent div to emulate
|
4084
4143
|
// the SVG group structure
|
4085
4144
|
htmlGroup = parentGroup.div = parentGroup.div || createElement(DIV, {
|
@@ -4382,7 +4441,7 @@ SVGRenderer.prototype = {
|
|
4382
4441
|
if (styles) {
|
4383
4442
|
var textStyles = {};
|
4384
4443
|
styles = merge(styles); // create a copy to avoid altering the original object (#537)
|
4385
|
-
each(['fontSize', 'fontWeight', 'fontFamily', 'color', 'lineHeight', 'width', 'textDecoration'], function (prop) {
|
4444
|
+
each(['fontSize', 'fontWeight', 'fontFamily', 'color', 'lineHeight', 'width', 'textDecoration', 'textShadow'], function (prop) {
|
4386
4445
|
if (styles[prop] !== UNDEFINED) {
|
4387
4446
|
textStyles[prop] = styles[prop];
|
4388
4447
|
delete styles[prop];
|
@@ -4537,6 +4596,72 @@ Highcharts.VMLElement = VMLElement = {
|
|
4537
4596
|
*/
|
4538
4597
|
updateTransform: SVGElement.prototype.htmlUpdateTransform,
|
4539
4598
|
|
4599
|
+
/**
|
4600
|
+
* Set the rotation of a span with oldIE's filter
|
4601
|
+
*/
|
4602
|
+
setSpanRotation: function (rotation, sintheta, costheta) {
|
4603
|
+
// Adjust for alignment and rotation. Rotation of useHTML content is not yet implemented
|
4604
|
+
// but it can probably be implemented for Firefox 3.5+ on user request. FF3.5+
|
4605
|
+
// has support for CSS3 transform. The getBBox method also needs to be updated
|
4606
|
+
// to compensate for the rotation, like it currently does for SVG.
|
4607
|
+
// Test case: http://highcharts.com/tests/?file=text-rotation
|
4608
|
+
css(this.element, {
|
4609
|
+
filter: rotation ? ['progid:DXImageTransform.Microsoft.Matrix(M11=', costheta,
|
4610
|
+
', M12=', -sintheta, ', M21=', sintheta, ', M22=', costheta,
|
4611
|
+
', sizingMethod=\'auto expand\')'].join('') : NONE
|
4612
|
+
});
|
4613
|
+
},
|
4614
|
+
|
4615
|
+
/**
|
4616
|
+
* Converts a subset of an SVG path definition to its VML counterpart. Takes an array
|
4617
|
+
* as the parameter and returns a string.
|
4618
|
+
*/
|
4619
|
+
pathToVML: function (value) {
|
4620
|
+
// convert paths
|
4621
|
+
var i = value.length,
|
4622
|
+
path = [],
|
4623
|
+
clockwise;
|
4624
|
+
|
4625
|
+
while (i--) {
|
4626
|
+
|
4627
|
+
// Multiply by 10 to allow subpixel precision.
|
4628
|
+
// Substracting half a pixel seems to make the coordinates
|
4629
|
+
// align with SVG, but this hasn't been tested thoroughly
|
4630
|
+
if (isNumber(value[i])) {
|
4631
|
+
path[i] = mathRound(value[i] * 10) - 5;
|
4632
|
+
} else if (value[i] === 'Z') { // close the path
|
4633
|
+
path[i] = 'x';
|
4634
|
+
} else {
|
4635
|
+
path[i] = value[i];
|
4636
|
+
|
4637
|
+
// When the start X and end X coordinates of an arc are too close,
|
4638
|
+
// they are rounded to the same value above. In this case, substract 1 from the end X
|
4639
|
+
// position. #760, #1371.
|
4640
|
+
if (value.isArc && (value[i] === 'wa' || value[i] === 'at')) {
|
4641
|
+
clockwise = value[i] === 'wa' ? 1 : -1; // #1642
|
4642
|
+
if (path[i + 5] === path[i + 7]) {
|
4643
|
+
path[i + 7] -= clockwise;
|
4644
|
+
}
|
4645
|
+
// Start and end Y (#1410)
|
4646
|
+
if (path[i + 6] === path[i + 8]) {
|
4647
|
+
path[i + 8] -= clockwise;
|
4648
|
+
}
|
4649
|
+
}
|
4650
|
+
}
|
4651
|
+
}
|
4652
|
+
// Loop up again to handle path shortcuts (#2132)
|
4653
|
+
/*while (i++ < path.length) {
|
4654
|
+
if (path[i] === 'H') { // horizontal line to
|
4655
|
+
path[i] = 'L';
|
4656
|
+
path.splice(i + 2, 0, path[i - 1]);
|
4657
|
+
} else if (path[i] === 'V') { // vertical line to
|
4658
|
+
path[i] = 'L';
|
4659
|
+
path.splice(i + 1, 0, path[i - 2]);
|
4660
|
+
}
|
4661
|
+
}*/
|
4662
|
+
return path.join(' ') || 'x';
|
4663
|
+
},
|
4664
|
+
|
4540
4665
|
/**
|
4541
4666
|
* Get or set attributes
|
4542
4667
|
*/
|
@@ -4606,40 +4731,7 @@ Highcharts.VMLElement = VMLElement = {
|
|
4606
4731
|
value = value || [];
|
4607
4732
|
wrapper.d = value.join(' '); // used in getter for animation
|
4608
4733
|
|
4609
|
-
|
4610
|
-
i = value.length;
|
4611
|
-
var convertedPath = [],
|
4612
|
-
clockwise;
|
4613
|
-
while (i--) {
|
4614
|
-
|
4615
|
-
// Multiply by 10 to allow subpixel precision.
|
4616
|
-
// Substracting half a pixel seems to make the coordinates
|
4617
|
-
// align with SVG, but this hasn't been tested thoroughly
|
4618
|
-
if (isNumber(value[i])) {
|
4619
|
-
convertedPath[i] = mathRound(value[i] * 10) - 5;
|
4620
|
-
} else if (value[i] === 'Z') { // close the path
|
4621
|
-
convertedPath[i] = 'x';
|
4622
|
-
} else {
|
4623
|
-
convertedPath[i] = value[i];
|
4624
|
-
|
4625
|
-
// When the start X and end X coordinates of an arc are too close,
|
4626
|
-
// they are rounded to the same value above. In this case, substract 1 from the end X
|
4627
|
-
// position. #760, #1371.
|
4628
|
-
if (value.isArc && (value[i] === 'wa' || value[i] === 'at')) {
|
4629
|
-
clockwise = value[i] === 'wa' ? 1 : -1; // #1642
|
4630
|
-
if (convertedPath[i + 5] === convertedPath[i + 7]) {
|
4631
|
-
convertedPath[i + 7] -= clockwise;
|
4632
|
-
}
|
4633
|
-
// Start and end Y (#1410)
|
4634
|
-
if (convertedPath[i + 6] === convertedPath[i + 8]) {
|
4635
|
-
convertedPath[i + 8] -= clockwise;
|
4636
|
-
}
|
4637
|
-
}
|
4638
|
-
}
|
4639
|
-
|
4640
|
-
}
|
4641
|
-
value = convertedPath.join(' ') || 'x';
|
4642
|
-
element.path = value;
|
4734
|
+
element.path = value = wrapper.pathToVML(value);
|
4643
4735
|
|
4644
4736
|
// update shadows
|
4645
4737
|
if (shadows) {
|
@@ -4759,7 +4851,9 @@ Highcharts.VMLElement = VMLElement = {
|
|
4759
4851
|
|
4760
4852
|
// rotation on VML elements
|
4761
4853
|
} else if (nodeName === 'shape' && key === 'rotation') {
|
4762
|
-
|
4854
|
+
|
4855
|
+
wrapper[key] = element.style[key] = value; // style is for #1873
|
4856
|
+
|
4763
4857
|
// Correction for the 1x1 size of the shape container. Used in gauge needles.
|
4764
4858
|
element.style.left = -mathRound(mathSin(value * deg2rad) + 1) + PX;
|
4765
4859
|
element.style.top = mathRound(mathCos(value * deg2rad)) + PX;
|
@@ -5036,10 +5130,10 @@ var VMLRendererExtension = { // inherit SVGRenderer
|
|
5036
5130
|
// mimic a rectangle with its style object for automatic updating in attr
|
5037
5131
|
return extend(clipRect, {
|
5038
5132
|
members: [],
|
5039
|
-
left: isObj ? x.x : x,
|
5040
|
-
top: isObj ? x.y : y,
|
5041
|
-
width: isObj ? x.width : width,
|
5042
|
-
height: isObj ? x.height : height,
|
5133
|
+
left: (isObj ? x.x : x) + 1,
|
5134
|
+
top: (isObj ? x.y : y) + 1,
|
5135
|
+
width: (isObj ? x.width : width) - 1,
|
5136
|
+
height: (isObj ? x.height : height) - 1,
|
5043
5137
|
getCSS: function (wrapper) {
|
5044
5138
|
var element = wrapper.element,
|
5045
5139
|
nodeName = element.nodeName,
|
@@ -5371,17 +5465,16 @@ var VMLRendererExtension = { // inherit SVGRenderer
|
|
5371
5465
|
*/
|
5372
5466
|
rect: function (x, y, width, height, r, strokeWidth) {
|
5373
5467
|
|
5374
|
-
if (isObject(x)) {
|
5375
|
-
y = x.y;
|
5376
|
-
width = x.width;
|
5377
|
-
height = x.height;
|
5378
|
-
strokeWidth = x.strokeWidth;
|
5379
|
-
x = x.x;
|
5380
|
-
}
|
5381
5468
|
var wrapper = this.symbol('rect');
|
5382
|
-
wrapper.r = r;
|
5469
|
+
wrapper.r = isObject(x) ? x.r : r;
|
5383
5470
|
|
5384
|
-
return wrapper.attr(wrapper.crisp(strokeWidth, x, y, mathMax(width, 0), mathMax(height, 0)));
|
5471
|
+
//return wrapper.attr(wrapper.crisp(strokeWidth, x, y, mathMax(width, 0), mathMax(height, 0)));
|
5472
|
+
return wrapper.attr(
|
5473
|
+
isObject(x) ?
|
5474
|
+
x :
|
5475
|
+
// do not crispify when an object is passed in (as in column charts)
|
5476
|
+
wrapper.crisp(strokeWidth, x, y, mathMax(width, 0), mathMax(height, 0))
|
5477
|
+
);
|
5385
5478
|
},
|
5386
5479
|
|
5387
5480
|
/**
|
@@ -5669,7 +5762,7 @@ Tick.prototype = {
|
|
5669
5762
|
!labelOptions.step && !labelOptions.staggerLines &&
|
5670
5763
|
!labelOptions.rotation &&
|
5671
5764
|
chart.plotWidth / tickPositions.length) ||
|
5672
|
-
(!horiz && (chart.optionsMarginLeft || chart.
|
5765
|
+
(!horiz && (chart.optionsMarginLeft || chart.chartWidth * 0.33)), // #1580, #1931
|
5673
5766
|
isFirst = pos === tickPositions[0],
|
5674
5767
|
isLast = pos === tickPositions[tickPositions.length - 1],
|
5675
5768
|
css,
|
@@ -5708,7 +5801,7 @@ Tick.prototype = {
|
|
5708
5801
|
// first call
|
5709
5802
|
if (!defined(label)) {
|
5710
5803
|
attr = {
|
5711
|
-
align:
|
5804
|
+
align: axis.labelAlign
|
5712
5805
|
};
|
5713
5806
|
if (isNumber(labelOptions.rotation)) {
|
5714
5807
|
attr.rotation = labelOptions.rotation;
|
@@ -5757,7 +5850,7 @@ Tick.prototype = {
|
|
5757
5850
|
options = axis.options,
|
5758
5851
|
labelOptions = options.labels,
|
5759
5852
|
width = bBox.width,
|
5760
|
-
leftSide = width * { left: 0, center: 0.5, right: 1 }[
|
5853
|
+
leftSide = width * { left: 0, center: 0.5, right: 1 }[axis.labelAlign] - labelOptions.x;
|
5761
5854
|
|
5762
5855
|
return [-leftSide, width - leftSide];
|
5763
5856
|
},
|
@@ -5847,21 +5940,28 @@ Tick.prototype = {
|
|
5847
5940
|
var axis = this.axis,
|
5848
5941
|
transA = axis.transA,
|
5849
5942
|
reversed = axis.reversed,
|
5850
|
-
staggerLines = axis.staggerLines
|
5943
|
+
staggerLines = axis.staggerLines,
|
5944
|
+
baseline = axis.chart.renderer.fontMetrics(labelOptions.style.fontSize).b,
|
5945
|
+
rotation = labelOptions.rotation;
|
5851
5946
|
|
5852
5947
|
x = x + labelOptions.x - (tickmarkOffset && horiz ?
|
5853
5948
|
tickmarkOffset * transA * (reversed ? -1 : 1) : 0);
|
5854
5949
|
y = y + labelOptions.y - (tickmarkOffset && !horiz ?
|
5855
5950
|
tickmarkOffset * transA * (reversed ? 1 : -1) : 0);
|
5951
|
+
|
5952
|
+
// Correct for rotation (#1764)
|
5953
|
+
if (rotation && axis.side === 2) {
|
5954
|
+
y -= baseline - baseline * mathCos(rotation * deg2rad);
|
5955
|
+
}
|
5856
5956
|
|
5857
5957
|
// Vertically centered
|
5858
|
-
if (!defined(labelOptions.y)) {
|
5859
|
-
y +=
|
5958
|
+
if (!defined(labelOptions.y) && !rotation) { // #1951
|
5959
|
+
y += baseline - label.getBBox().height / 2;
|
5860
5960
|
}
|
5861
5961
|
|
5862
5962
|
// Correct for staggered labels
|
5863
5963
|
if (staggerLines) {
|
5864
|
-
y += (index / (step || 1) % staggerLines) *
|
5964
|
+
y += (index / (step || 1) % staggerLines) * (axis.labelOffset / staggerLines);
|
5865
5965
|
}
|
5866
5966
|
|
5867
5967
|
return {
|
@@ -5921,7 +6021,7 @@ Tick.prototype = {
|
|
5921
6021
|
xy = tick.getPosition(horiz, pos, tickmarkOffset, old),
|
5922
6022
|
x = xy.x,
|
5923
6023
|
y = xy.y,
|
5924
|
-
reverseCrisp = ((horiz && x === axis.pos) || (!horiz && y === axis.pos
|
6024
|
+
reverseCrisp = ((horiz && x === axis.pos + axis.len) || (!horiz && y === axis.pos)) ? -1 : 1, // #1480, #1687
|
5925
6025
|
staggerLines = axis.staggerLines;
|
5926
6026
|
|
5927
6027
|
this.isActive = true;
|
@@ -5994,9 +6094,10 @@ Tick.prototype = {
|
|
5994
6094
|
if (label && !isNaN(x)) {
|
5995
6095
|
label.xy = xy = tick.getLabelPosition(x, y, label, horiz, labelOptions, tickmarkOffset, index, step);
|
5996
6096
|
|
5997
|
-
//
|
5998
|
-
|
5999
|
-
|
6097
|
+
// Apply show first and show last. If the tick is both first and last, it is
|
6098
|
+
// a single centered tick, in which case we show the label anyway (#2100).
|
6099
|
+
if ((tick.isFirst && !tick.isLast && !pick(options.showFirstLabel, 1)) ||
|
6100
|
+
(tick.isLast && !tick.isFirst && !pick(options.showLastLabel, 1))) {
|
6000
6101
|
show = false;
|
6001
6102
|
|
6002
6103
|
// Handle label overflow and show or hide accordingly
|
@@ -6160,7 +6261,8 @@ PlotLineOrBand.prototype = {
|
|
6160
6261
|
plotLine.label = label = renderer.text(
|
6161
6262
|
optionsLabel.text,
|
6162
6263
|
0,
|
6163
|
-
0
|
6264
|
+
0,
|
6265
|
+
optionsLabel.useHTML
|
6164
6266
|
)
|
6165
6267
|
.attr({
|
6166
6268
|
align: optionsLabel.textAlign || optionsLabel.align,
|
@@ -6197,13 +6299,11 @@ PlotLineOrBand.prototype = {
|
|
6197
6299
|
* Remove the plot line or band
|
6198
6300
|
*/
|
6199
6301
|
destroy: function () {
|
6200
|
-
var plotLine = this,
|
6201
|
-
axis = plotLine.axis;
|
6202
|
-
|
6203
6302
|
// remove it from the lookup
|
6204
|
-
erase(axis.plotLinesAndBands,
|
6205
|
-
|
6206
|
-
|
6303
|
+
erase(this.axis.plotLinesAndBands, this);
|
6304
|
+
|
6305
|
+
delete this.axis;
|
6306
|
+
destroyObjectProperties(this);
|
6207
6307
|
}
|
6208
6308
|
};
|
6209
6309
|
/**
|
@@ -6224,6 +6324,12 @@ function StackItem(axis, options, isNegative, x, stackOption, stacking) {
|
|
6224
6324
|
// Save the x value to be able to position the label later
|
6225
6325
|
this.x = x;
|
6226
6326
|
|
6327
|
+
// Initialize total value
|
6328
|
+
this.total = null;
|
6329
|
+
|
6330
|
+
// This will keep each points' extremes stored by series.index
|
6331
|
+
this.points = {};
|
6332
|
+
|
6227
6333
|
// Save the stack option on the series configuration object, and whether to treat it as percent
|
6228
6334
|
this.stack = stackOption;
|
6229
6335
|
this.percent = stacking === 'percent';
|
@@ -6255,12 +6361,19 @@ StackItem.prototype = {
|
|
6255
6361
|
this.cum = total;
|
6256
6362
|
},
|
6257
6363
|
|
6364
|
+
/**
|
6365
|
+
* Adds value to stack total, this method takes care of correcting floats
|
6366
|
+
*/
|
6367
|
+
addValue: function (y) {
|
6368
|
+
this.setTotal(correctFloat(this.total + y));
|
6369
|
+
},
|
6370
|
+
|
6258
6371
|
/**
|
6259
6372
|
* Renders the stack total label and adds it to the stack label group.
|
6260
6373
|
*/
|
6261
6374
|
render: function (group) {
|
6262
6375
|
var options = this.options,
|
6263
|
-
formatOption = options.format,
|
6376
|
+
formatOption = options.format,
|
6264
6377
|
str = formatOption ?
|
6265
6378
|
format(formatOption, this) :
|
6266
6379
|
options.formatter.call(this); // format the text in the label
|
@@ -6282,6 +6395,10 @@ StackItem.prototype = {
|
|
6282
6395
|
}
|
6283
6396
|
},
|
6284
6397
|
|
6398
|
+
cacheExtremes: function (series, extremes) {
|
6399
|
+
this.points[series.index] = extremes;
|
6400
|
+
},
|
6401
|
+
|
6285
6402
|
/**
|
6286
6403
|
* Sets the offset that the stack has from the x value and repositions the label.
|
6287
6404
|
*/
|
@@ -6421,7 +6538,6 @@ Axis.prototype = {
|
|
6421
6538
|
tickPixelInterval: 72,
|
6422
6539
|
showLastLabel: true,
|
6423
6540
|
labels: {
|
6424
|
-
align: 'right',
|
6425
6541
|
x: -8,
|
6426
6542
|
y: 3
|
6427
6543
|
},
|
@@ -6454,7 +6570,6 @@ Axis.prototype = {
|
|
6454
6570
|
*/
|
6455
6571
|
defaultLeftAxisOptions: {
|
6456
6572
|
labels: {
|
6457
|
-
align: 'right',
|
6458
6573
|
x: -8,
|
6459
6574
|
y: null
|
6460
6575
|
},
|
@@ -6468,7 +6583,6 @@ Axis.prototype = {
|
|
6468
6583
|
*/
|
6469
6584
|
defaultRightAxisOptions: {
|
6470
6585
|
labels: {
|
6471
|
-
align: 'left',
|
6472
6586
|
x: 8,
|
6473
6587
|
y: null
|
6474
6588
|
},
|
@@ -6482,7 +6596,6 @@ Axis.prototype = {
|
|
6482
6596
|
*/
|
6483
6597
|
defaultBottomAxisOptions: {
|
6484
6598
|
labels: {
|
6485
|
-
align: 'center',
|
6486
6599
|
x: 0,
|
6487
6600
|
y: 14
|
6488
6601
|
// overflow: undefined,
|
@@ -6497,7 +6610,6 @@ Axis.prototype = {
|
|
6497
6610
|
*/
|
6498
6611
|
defaultTopAxisOptions: {
|
6499
6612
|
labels: {
|
6500
|
-
align: 'center',
|
6501
6613
|
x: 0,
|
6502
6614
|
y: -5
|
6503
6615
|
// overflow: undefined
|
@@ -6541,7 +6653,6 @@ Axis.prototype = {
|
|
6541
6653
|
|
6542
6654
|
|
6543
6655
|
// Flag, stagger lines or not
|
6544
|
-
axis.staggerLines = axis.horiz && options.labels.staggerLines;
|
6545
6656
|
axis.userOptions = userOptions;
|
6546
6657
|
|
6547
6658
|
//axis.axisTitleMargin = UNDEFINED,// = options.title.margin,
|
@@ -6619,8 +6730,11 @@ Axis.prototype = {
|
|
6619
6730
|
|
6620
6731
|
// Dictionary for stacks
|
6621
6732
|
axis.stacks = {};
|
6622
|
-
axis.
|
6623
|
-
|
6733
|
+
axis.oldStacks = {};
|
6734
|
+
|
6735
|
+
// Dictionary for stacks max values
|
6736
|
+
axis.stackExtremes = {};
|
6737
|
+
|
6624
6738
|
// Min and max in the data
|
6625
6739
|
//axis.dataMin = UNDEFINED,
|
6626
6740
|
//axis.dataMax = UNDEFINED,
|
@@ -6691,10 +6805,10 @@ Axis.prototype = {
|
|
6691
6805
|
|
6692
6806
|
newOptions = chart.options[this.xOrY + 'Axis'][this.options.index] = merge(this.userOptions, newOptions);
|
6693
6807
|
|
6694
|
-
this.destroy();
|
6808
|
+
this.destroy(true);
|
6695
6809
|
this._addedPlotLB = false; // #1611
|
6696
6810
|
|
6697
|
-
this.init(chart, newOptions);
|
6811
|
+
this.init(chart, extend(newOptions, { events: UNDEFINED }));
|
6698
6812
|
|
6699
6813
|
chart.isDirtyBox = true;
|
6700
6814
|
if (pick(redraw, true)) {
|
@@ -6778,25 +6892,24 @@ Axis.prototype = {
|
|
6778
6892
|
|
6779
6893
|
return ret;
|
6780
6894
|
},
|
6781
|
-
|
6895
|
+
|
6782
6896
|
/**
|
6783
6897
|
* Get the minimum and maximum for the series of each axis
|
6784
6898
|
*/
|
6785
6899
|
getSeriesExtremes: function () {
|
6786
6900
|
var axis = this,
|
6787
|
-
chart = axis.chart
|
6788
|
-
|
6789
|
-
posStack = [],
|
6790
|
-
negStack = [],
|
6791
|
-
stacksTouched = axis._stacksTouched = axis._stacksTouched + 1,
|
6792
|
-
type,
|
6793
|
-
i;
|
6794
|
-
|
6901
|
+
chart = axis.chart;
|
6902
|
+
|
6795
6903
|
axis.hasVisibleSeries = false;
|
6796
6904
|
|
6797
6905
|
// reset dataMin and dataMax in case we're redrawing
|
6798
6906
|
axis.dataMin = axis.dataMax = null;
|
6799
6907
|
|
6908
|
+
// reset cached stacking extremes
|
6909
|
+
axis.stackExtremes = {};
|
6910
|
+
|
6911
|
+
axis.buildStacks();
|
6912
|
+
|
6800
6913
|
// loop through this axis' series
|
6801
6914
|
each(axis.series, function (series) {
|
6802
6915
|
|
@@ -6804,27 +6917,16 @@ Axis.prototype = {
|
|
6804
6917
|
|
6805
6918
|
var seriesOptions = series.options,
|
6806
6919
|
stacking,
|
6807
|
-
posPointStack,
|
6808
|
-
negPointStack,
|
6809
|
-
stackKey,
|
6810
|
-
stackOption,
|
6811
|
-
negKey,
|
6812
6920
|
xData,
|
6813
|
-
yData,
|
6814
|
-
x,
|
6815
|
-
y,
|
6816
6921
|
threshold = seriesOptions.threshold,
|
6817
|
-
yDataLength,
|
6818
|
-
activeYData = [],
|
6819
6922
|
seriesDataMin,
|
6820
|
-
seriesDataMax
|
6821
|
-
|
6822
|
-
|
6823
|
-
|
6824
|
-
|
6923
|
+
seriesDataMax;
|
6924
|
+
|
6925
|
+
axis.hasVisibleSeries = true;
|
6926
|
+
|
6825
6927
|
// Validate threshold in logarithmic axes
|
6826
6928
|
if (axis.isLog && threshold <= 0) {
|
6827
|
-
threshold =
|
6929
|
+
threshold = null;
|
6828
6930
|
}
|
6829
6931
|
|
6830
6932
|
// Get dataMin and dataMax for X axes
|
@@ -6837,112 +6939,27 @@ Axis.prototype = {
|
|
6837
6939
|
|
6838
6940
|
// Get dataMin and dataMax for Y axes, as well as handle stacking and processed data
|
6839
6941
|
} 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
6942
|
|
6850
6943
|
// Handle stacking
|
6851
6944
|
stacking = seriesOptions.stacking;
|
6852
6945
|
axis.usePercentage = stacking === 'percent';
|
6853
6946
|
|
6854
6947
|
// 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
6948
|
if (axis.usePercentage) {
|
6868
6949
|
axis.dataMin = 0;
|
6869
6950
|
axis.dataMax = 99;
|
6870
6951
|
}
|
6871
6952
|
|
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
|
-
}
|
6953
|
+
|
6954
|
+
// get this particular series extremes
|
6955
|
+
series.getExtremes();
|
6956
|
+
seriesDataMax = series.dataMax;
|
6957
|
+
seriesDataMin = series.dataMin;
|
6940
6958
|
|
6941
6959
|
// 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);
|
6960
|
+
// always 0 and 100. If seriesDataMin and seriesDataMax is null, then series
|
6961
|
+
// doesn't have active y data, we continue with nulls
|
6962
|
+
if (!axis.usePercentage && defined(seriesDataMin) && defined(seriesDataMax)) {
|
6946
6963
|
axis.dataMin = mathMin(pick(axis.dataMin, seriesDataMin), seriesDataMin);
|
6947
6964
|
axis.dataMax = mathMax(pick(axis.dataMax, seriesDataMax), seriesDataMax);
|
6948
6965
|
}
|
@@ -6960,24 +6977,13 @@ Axis.prototype = {
|
|
6960
6977
|
}
|
6961
6978
|
}
|
6962
6979
|
});
|
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
6980
|
},
|
6975
6981
|
|
6976
6982
|
/**
|
6977
6983
|
* Translate from axis value to pixel position on the chart, or back
|
6978
6984
|
*
|
6979
6985
|
*/
|
6980
|
-
translate: function (val, backwards, cvsCoord, old, handleLog,
|
6986
|
+
translate: function (val, backwards, cvsCoord, old, handleLog, pointPlacement) {
|
6981
6987
|
var axis = this,
|
6982
6988
|
axisLength = axis.len,
|
6983
6989
|
sign = 1,
|
@@ -7020,9 +7026,11 @@ Axis.prototype = {
|
|
7020
7026
|
if (postTranslate) { // log and ordinal axes
|
7021
7027
|
val = axis.val2lin(val);
|
7022
7028
|
}
|
7023
|
-
|
7029
|
+
if (pointPlacement === 'between') {
|
7030
|
+
pointPlacement = 0.5;
|
7031
|
+
}
|
7024
7032
|
returnValue = sign * (val - localMin) * localA + cvsOffset + (sign * minPixelPadding) +
|
7025
|
-
(
|
7033
|
+
(isNumber(pointPlacement) ? localA * pointPlacement * axis.pointRange : 0);
|
7026
7034
|
}
|
7027
7035
|
|
7028
7036
|
return returnValue;
|
@@ -7226,7 +7234,7 @@ Axis.prototype = {
|
|
7226
7234
|
interval = normalizeTickInterval(
|
7227
7235
|
interval,
|
7228
7236
|
null,
|
7229
|
-
|
7237
|
+
getMagnitude(interval)
|
7230
7238
|
);
|
7231
7239
|
|
7232
7240
|
positions = map(axis.getLinearTickPositions(
|
@@ -7390,7 +7398,7 @@ Axis.prototype = {
|
|
7390
7398
|
var seriesPointRange = series.pointRange,
|
7391
7399
|
pointPlacement = series.options.pointPlacement,
|
7392
7400
|
seriesClosestPointRange = series.closestPointRange;
|
7393
|
-
|
7401
|
+
|
7394
7402
|
if (seriesPointRange > range) { // #1446
|
7395
7403
|
seriesPointRange = 0;
|
7396
7404
|
}
|
@@ -7401,7 +7409,7 @@ Axis.prototype = {
|
|
7401
7409
|
// is 'between' or 'on', this padding does not apply.
|
7402
7410
|
minPointOffset = mathMax(
|
7403
7411
|
minPointOffset,
|
7404
|
-
pointPlacement ? 0 : seriesPointRange / 2
|
7412
|
+
isString(pointPlacement) ? 0 : seriesPointRange / 2
|
7405
7413
|
);
|
7406
7414
|
|
7407
7415
|
// Determine the total padding needed to the length of the axis to make room for the
|
@@ -7456,7 +7464,6 @@ Axis.prototype = {
|
|
7456
7464
|
isXAxis = axis.isXAxis,
|
7457
7465
|
isLinked = axis.isLinked,
|
7458
7466
|
tickPositioner = axis.options.tickPositioner,
|
7459
|
-
magnitude,
|
7460
7467
|
maxPadding = options.maxPadding,
|
7461
7468
|
minPadding = options.minPadding,
|
7462
7469
|
length,
|
@@ -7555,6 +7562,11 @@ Axis.prototype = {
|
|
7555
7562
|
if (axis.postProcessTickInterval) {
|
7556
7563
|
axis.tickInterval = axis.postProcessTickInterval(axis.tickInterval);
|
7557
7564
|
}
|
7565
|
+
|
7566
|
+
// In column-like charts, don't cramp in more ticks than there are points (#1943)
|
7567
|
+
if (axis.pointRange) {
|
7568
|
+
axis.tickInterval = mathMax(axis.pointRange, axis.tickInterval);
|
7569
|
+
}
|
7558
7570
|
|
7559
7571
|
// Before normalizing the tick interval, handle minimum tick interval. This applies only if tickInterval is not defined.
|
7560
7572
|
if (!tickIntervalOption && axis.tickInterval < minTickIntervalOption) {
|
@@ -7563,9 +7575,8 @@ Axis.prototype = {
|
|
7563
7575
|
|
7564
7576
|
// for linear axes, get magnitude and normalize the interval
|
7565
7577
|
if (!isDatetimeAxis && !isLog) { // linear
|
7566
|
-
magnitude = math.pow(10, mathFloor(math.log(axis.tickInterval) / math.LN10));
|
7567
7578
|
if (!tickIntervalOption) {
|
7568
|
-
axis.tickInterval = normalizeTickInterval(axis.tickInterval, null,
|
7579
|
+
axis.tickInterval = normalizeTickInterval(axis.tickInterval, null, getMagnitude(axis.tickInterval), options);
|
7569
7580
|
}
|
7570
7581
|
}
|
7571
7582
|
|
@@ -7578,6 +7589,12 @@ Axis.prototype = {
|
|
7578
7589
|
[].concat(options.tickPositions) : // Work on a copy (#1565)
|
7579
7590
|
(tickPositioner && tickPositioner.apply(axis, [axis.min, axis.max]));
|
7580
7591
|
if (!tickPositions) {
|
7592
|
+
|
7593
|
+
// Too many ticks
|
7594
|
+
if ((axis.max - axis.min) / axis.tickInterval > 2 * axis.len) {
|
7595
|
+
error(19, true);
|
7596
|
+
}
|
7597
|
+
|
7581
7598
|
if (isDatetimeAxis) {
|
7582
7599
|
tickPositions = (axis.getNonLinearTimeTicks || getTimeTicks)(
|
7583
7600
|
normalizeTimeTickInterval(axis.tickInterval, options.units),
|
@@ -7706,10 +7723,19 @@ Axis.prototype = {
|
|
7706
7723
|
isDirtyData = true;
|
7707
7724
|
}
|
7708
7725
|
});
|
7709
|
-
|
7726
|
+
|
7710
7727
|
// do we really need to go through all this?
|
7711
7728
|
if (isDirtyAxisLength || isDirtyData || axis.isLinked || axis.forceRedraw ||
|
7712
7729
|
axis.userMin !== axis.oldUserMin || axis.userMax !== axis.oldUserMax) {
|
7730
|
+
|
7731
|
+
// reset stacks
|
7732
|
+
if (!axis.isXAxis) {
|
7733
|
+
for (type in stacks) {
|
7734
|
+
for (i in stacks[type]) {
|
7735
|
+
stacks[type][i].total = null;
|
7736
|
+
}
|
7737
|
+
}
|
7738
|
+
}
|
7713
7739
|
|
7714
7740
|
axis.forceRedraw = false;
|
7715
7741
|
|
@@ -7727,11 +7753,12 @@ Axis.prototype = {
|
|
7727
7753
|
if (!axis.isDirty) {
|
7728
7754
|
axis.isDirty = isDirtyAxisLength || axis.min !== axis.oldMin || axis.max !== axis.oldMax;
|
7729
7755
|
}
|
7730
|
-
}
|
7731
|
-
|
7732
|
-
|
7733
|
-
|
7734
|
-
|
7756
|
+
} else if (!axis.isXAxis) {
|
7757
|
+
if (axis.oldStacks) {
|
7758
|
+
stacks = axis.stacks = axis.oldStacks;
|
7759
|
+
}
|
7760
|
+
|
7761
|
+
// reset stacks
|
7735
7762
|
for (type in stacks) {
|
7736
7763
|
for (i in stacks[type]) {
|
7737
7764
|
stacks[type][i].cum = stacks[type][i].total;
|
@@ -7787,12 +7814,12 @@ Axis.prototype = {
|
|
7787
7814
|
*/
|
7788
7815
|
zoom: function (newMin, newMax) {
|
7789
7816
|
|
7790
|
-
// Prevent pinch zooming out of range
|
7817
|
+
// Prevent pinch zooming out of range. Check for defined is for #1946.
|
7791
7818
|
if (!this.allowZoomOutside) {
|
7792
|
-
if (newMin <= this.dataMin) {
|
7819
|
+
if (defined(this.dataMin) && newMin <= this.dataMin) {
|
7793
7820
|
newMin = UNDEFINED;
|
7794
7821
|
}
|
7795
|
-
if (newMax >= this.dataMax) {
|
7822
|
+
if (defined(this.dataMax) && newMax >= this.dataMax) {
|
7796
7823
|
newMax = UNDEFINED;
|
7797
7824
|
}
|
7798
7825
|
}
|
@@ -7903,6 +7930,24 @@ Axis.prototype = {
|
|
7903
7930
|
return obj;
|
7904
7931
|
},
|
7905
7932
|
|
7933
|
+
/**
|
7934
|
+
* Compute auto alignment for the axis label based on which side the axis is on
|
7935
|
+
* and the given rotation for the label
|
7936
|
+
*/
|
7937
|
+
autoLabelAlign: function (rotation) {
|
7938
|
+
var ret,
|
7939
|
+
angle = (pick(rotation, 0) - (this.side * 90) + 720) % 360;
|
7940
|
+
|
7941
|
+
if (angle > 15 && angle < 165) {
|
7942
|
+
ret = 'right';
|
7943
|
+
} else if (angle > 195 && angle < 345) {
|
7944
|
+
ret = 'left';
|
7945
|
+
} else {
|
7946
|
+
ret = 'center';
|
7947
|
+
}
|
7948
|
+
return ret;
|
7949
|
+
},
|
7950
|
+
|
7906
7951
|
/**
|
7907
7952
|
* Render the tick labels to a preliminary position to get their sizes
|
7908
7953
|
*/
|
@@ -7927,11 +7972,25 @@ Axis.prototype = {
|
|
7927
7972
|
axisOffset = chart.axisOffset,
|
7928
7973
|
clipOffset = chart.clipOffset,
|
7929
7974
|
directionFactor = [-1, 1, 1, -1][side],
|
7930
|
-
n
|
7975
|
+
n,
|
7976
|
+
i,
|
7977
|
+
autoStaggerLines = 1,
|
7978
|
+
maxStaggerLines = pick(labelOptions.maxStaggerLines, 5),
|
7979
|
+
sortedPositions,
|
7980
|
+
lastRight,
|
7981
|
+
overlap,
|
7982
|
+
pos,
|
7983
|
+
bBox,
|
7984
|
+
x,
|
7985
|
+
w,
|
7986
|
+
lineNo;
|
7931
7987
|
|
7932
7988
|
// For reuse in Axis.render
|
7933
7989
|
axis.hasData = hasData = (axis.hasVisibleSeries || (defined(axis.min) && defined(axis.max) && !!tickPositions));
|
7934
7990
|
axis.showAxis = showAxis = hasData || pick(options.showEmpty, true);
|
7991
|
+
|
7992
|
+
// Set/reset staggerLines
|
7993
|
+
axis.staggerLines = axis.horiz && labelOptions.staggerLines;
|
7935
7994
|
|
7936
7995
|
// Create the axisGroup and gridGroup elements on first iteration
|
7937
7996
|
if (!axis.axisGroup) {
|
@@ -7947,18 +8006,55 @@ Axis.prototype = {
|
|
7947
8006
|
}
|
7948
8007
|
|
7949
8008
|
if (hasData || axis.isLinked) {
|
8009
|
+
|
8010
|
+
// Set the explicit or automatic label alignment
|
8011
|
+
axis.labelAlign = pick(labelOptions.align || axis.autoLabelAlign(labelOptions.rotation));
|
8012
|
+
|
7950
8013
|
each(tickPositions, function (pos) {
|
7951
8014
|
if (!ticks[pos]) {
|
7952
8015
|
ticks[pos] = new Tick(axis, pos);
|
7953
8016
|
} else {
|
7954
8017
|
ticks[pos].addLabel(); // update labels depending on tick interval
|
7955
8018
|
}
|
7956
|
-
|
7957
8019
|
});
|
7958
8020
|
|
8021
|
+
// Handle automatic stagger lines
|
8022
|
+
if (axis.horiz && !axis.staggerLines && maxStaggerLines && !labelOptions.rotation) {
|
8023
|
+
sortedPositions = axis.reversed ? [].concat(tickPositions).reverse() : tickPositions;
|
8024
|
+
while (autoStaggerLines < maxStaggerLines) {
|
8025
|
+
lastRight = [];
|
8026
|
+
overlap = false;
|
8027
|
+
|
8028
|
+
for (i = 0; i < sortedPositions.length; i++) {
|
8029
|
+
pos = sortedPositions[i];
|
8030
|
+
bBox = ticks[pos].label && ticks[pos].label.bBox;
|
8031
|
+
w = bBox ? bBox.width : 0;
|
8032
|
+
lineNo = i % autoStaggerLines;
|
8033
|
+
|
8034
|
+
if (w) {
|
8035
|
+
x = axis.translate(pos); // don't handle log
|
8036
|
+
if (lastRight[lineNo] !== UNDEFINED && x < lastRight[lineNo]) {
|
8037
|
+
overlap = true;
|
8038
|
+
}
|
8039
|
+
lastRight[lineNo] = x + w;
|
8040
|
+
}
|
8041
|
+
}
|
8042
|
+
if (overlap) {
|
8043
|
+
autoStaggerLines++;
|
8044
|
+
} else {
|
8045
|
+
break;
|
8046
|
+
}
|
8047
|
+
}
|
8048
|
+
|
8049
|
+
if (autoStaggerLines > 1) {
|
8050
|
+
axis.staggerLines = autoStaggerLines;
|
8051
|
+
}
|
8052
|
+
}
|
8053
|
+
|
8054
|
+
|
7959
8055
|
each(tickPositions, function (pos) {
|
7960
8056
|
// 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] ===
|
8057
|
+
if (side === 0 || side === 2 || { 1: 'left', 3: 'right' }[side] === axis.labelAlign) {
|
7962
8058
|
|
7963
8059
|
// get the highest offset
|
7964
8060
|
labelOffset = mathMax(
|
@@ -7968,10 +8064,11 @@ Axis.prototype = {
|
|
7968
8064
|
}
|
7969
8065
|
|
7970
8066
|
});
|
7971
|
-
|
7972
8067
|
if (axis.staggerLines) {
|
7973
|
-
labelOffset
|
8068
|
+
labelOffset *= axis.staggerLines;
|
8069
|
+
axis.labelOffset = labelOffset;
|
7974
8070
|
}
|
8071
|
+
|
7975
8072
|
|
7976
8073
|
} else { // doesn't have data
|
7977
8074
|
for (n in ticks) {
|
@@ -8023,8 +8120,7 @@ Axis.prototype = {
|
|
8023
8120
|
axisOffset[side],
|
8024
8121
|
axis.axisTitleMargin + titleOffset + directionFactor * axis.offset
|
8025
8122
|
);
|
8026
|
-
clipOffset[invertedSide] = mathMax(clipOffset[invertedSide], options.lineWidth);
|
8027
|
-
|
8123
|
+
clipOffset[invertedSide] = mathMax(clipOffset[invertedSide], mathFloor(options.lineWidth / 2) * 2);
|
8028
8124
|
},
|
8029
8125
|
|
8030
8126
|
/**
|
@@ -8039,8 +8135,8 @@ Axis.prototype = {
|
|
8039
8135
|
lineTop = chart.chartHeight - this.bottom - (opposite ? this.height : 0) + offset;
|
8040
8136
|
|
8041
8137
|
this.lineTop = lineTop; // used by flag series
|
8042
|
-
if (
|
8043
|
-
lineWidth *= -1; // crispify the other way - #1480
|
8138
|
+
if (opposite) {
|
8139
|
+
lineWidth *= -1; // crispify the other way - #1480, #1687
|
8044
8140
|
}
|
8045
8141
|
|
8046
8142
|
return chart.renderer.crispLine([
|
@@ -8326,12 +8422,23 @@ Axis.prototype = {
|
|
8326
8422
|
*/
|
8327
8423
|
removePlotBandOrLine: function (id) {
|
8328
8424
|
var plotLinesAndBands = this.plotLinesAndBands,
|
8425
|
+
options = this.options,
|
8426
|
+
userOptions = this.userOptions,
|
8329
8427
|
i = plotLinesAndBands.length;
|
8330
8428
|
while (i--) {
|
8331
8429
|
if (plotLinesAndBands[i].id === id) {
|
8332
8430
|
plotLinesAndBands[i].destroy();
|
8333
8431
|
}
|
8334
8432
|
}
|
8433
|
+
each([options.plotLines || [], userOptions.plotLines || [], options.plotBands || [], userOptions.plotBands || []], function (arr) {
|
8434
|
+
i = arr.length;
|
8435
|
+
while (i--) {
|
8436
|
+
if (arr[i].id === id) {
|
8437
|
+
erase(arr, arr[i]);
|
8438
|
+
}
|
8439
|
+
}
|
8440
|
+
});
|
8441
|
+
|
8335
8442
|
},
|
8336
8443
|
|
8337
8444
|
/**
|
@@ -8369,6 +8476,19 @@ Axis.prototype = {
|
|
8369
8476
|
|
8370
8477
|
},
|
8371
8478
|
|
8479
|
+
/**
|
8480
|
+
*
|
8481
|
+
*/
|
8482
|
+
buildStacks: function () {
|
8483
|
+
if (this.isXAxis) {
|
8484
|
+
return;
|
8485
|
+
}
|
8486
|
+
|
8487
|
+
each(this.series, function (series) {
|
8488
|
+
series.setStackedPoints();
|
8489
|
+
});
|
8490
|
+
},
|
8491
|
+
|
8372
8492
|
/**
|
8373
8493
|
* Set new axis categories and optionally redraw
|
8374
8494
|
* @param {Array} categories
|
@@ -8381,13 +8501,17 @@ Axis.prototype = {
|
|
8381
8501
|
/**
|
8382
8502
|
* Destroys an Axis instance.
|
8383
8503
|
*/
|
8384
|
-
destroy: function () {
|
8504
|
+
destroy: function (keepEvents) {
|
8385
8505
|
var axis = this,
|
8386
8506
|
stacks = axis.stacks,
|
8387
|
-
stackKey
|
8507
|
+
stackKey,
|
8508
|
+
plotLinesAndBands = axis.plotLinesAndBands,
|
8509
|
+
i;
|
8388
8510
|
|
8389
8511
|
// Remove the events
|
8390
|
-
|
8512
|
+
if (!keepEvents) {
|
8513
|
+
removeEvent(axis);
|
8514
|
+
}
|
8391
8515
|
|
8392
8516
|
// Destroy each stack total
|
8393
8517
|
for (stackKey in stacks) {
|
@@ -8397,9 +8521,13 @@ Axis.prototype = {
|
|
8397
8521
|
}
|
8398
8522
|
|
8399
8523
|
// Destroy collections
|
8400
|
-
each([axis.ticks, axis.minorTicks, axis.alternateBands
|
8524
|
+
each([axis.ticks, axis.minorTicks, axis.alternateBands], function (coll) {
|
8401
8525
|
destroyObjectProperties(coll);
|
8402
8526
|
});
|
8527
|
+
i = plotLinesAndBands.length;
|
8528
|
+
while (i--) { // #1975
|
8529
|
+
plotLinesAndBands[i].destroy();
|
8530
|
+
}
|
8403
8531
|
|
8404
8532
|
// Destroy local variables
|
8405
8533
|
each(['stackTotalGroup', 'axisLine', 'axisGroup', 'gridGroup', 'labelGroup', 'axisTitle'], function (prop) {
|
@@ -8705,7 +8833,6 @@ Tooltip.prototype = {
|
|
8705
8833
|
options = tooltip.options,
|
8706
8834
|
x,
|
8707
8835
|
y,
|
8708
|
-
show,
|
8709
8836
|
anchor,
|
8710
8837
|
textConfig = {},
|
8711
8838
|
text,
|
@@ -8759,12 +8886,8 @@ Tooltip.prototype = {
|
|
8759
8886
|
// register the current series
|
8760
8887
|
currentSeries = point.series;
|
8761
8888
|
|
8762
|
-
|
8763
|
-
// For line type series, hide tooltip if the point falls outside the plot
|
8764
|
-
show = shared || !currentSeries.isCartesian || currentSeries.tooltipOutsidePlot || chart.isInsidePlot(x, y);
|
8765
|
-
|
8766
8889
|
// update the inner HTML
|
8767
|
-
if (text === false
|
8890
|
+
if (text === false) {
|
8768
8891
|
this.hide();
|
8769
8892
|
} else {
|
8770
8893
|
|
@@ -8798,15 +8921,20 @@ Tooltip.prototype = {
|
|
8798
8921
|
i = crosshairsOptions.length,
|
8799
8922
|
attribs,
|
8800
8923
|
axis,
|
8801
|
-
val
|
8924
|
+
val,
|
8925
|
+
series;
|
8802
8926
|
|
8803
8927
|
while (i--) {
|
8804
|
-
|
8928
|
+
series = point.series;
|
8929
|
+
axis = series[i ? 'yAxis' : 'xAxis'];
|
8805
8930
|
if (crosshairsOptions[i] && axis) {
|
8806
8931
|
val = i ? pick(point.stackY, point.y) : point.x; // #814
|
8807
8932
|
if (axis.isLog) { // #1671
|
8808
8933
|
val = log2lin(val);
|
8809
8934
|
}
|
8935
|
+
if (series.modifyValue) { // #1205
|
8936
|
+
val = series.modifyValue(val);
|
8937
|
+
}
|
8810
8938
|
|
8811
8939
|
path = axis.getPlotLinePath(
|
8812
8940
|
val,
|
@@ -8929,7 +9057,8 @@ Pointer.prototype = {
|
|
8929
9057
|
|
8930
9058
|
// chartX and chartY
|
8931
9059
|
if (ePos.pageX === UNDEFINED) { // IE < 9. #886.
|
8932
|
-
chartX = e.x;
|
9060
|
+
chartX = mathMax(e.x, e.clientX - chartPosition.left); // #2005, #2129: the second case is
|
9061
|
+
// for IE10 quirks mode within framesets
|
8933
9062
|
chartY = e.y;
|
8934
9063
|
} else {
|
8935
9064
|
chartX = ePos.pageX - chartPosition.left;
|
@@ -9097,18 +9226,20 @@ Pointer.prototype = {
|
|
9097
9226
|
*/
|
9098
9227
|
scaleGroups: function (attribs, clip) {
|
9099
9228
|
|
9100
|
-
var chart = this.chart
|
9229
|
+
var chart = this.chart,
|
9230
|
+
seriesAttribs;
|
9101
9231
|
|
9102
9232
|
// Scale each series
|
9103
9233
|
each(chart.series, function (series) {
|
9234
|
+
seriesAttribs = attribs || series.getPlotBox(); // #1701
|
9104
9235
|
if (series.xAxis && series.xAxis.zoomEnabled) {
|
9105
|
-
series.group.attr(
|
9236
|
+
series.group.attr(seriesAttribs);
|
9106
9237
|
if (series.markerGroup) {
|
9107
|
-
series.markerGroup.attr(
|
9238
|
+
series.markerGroup.attr(seriesAttribs);
|
9108
9239
|
series.markerGroup.clip(clip ? chart.clipRect : null);
|
9109
9240
|
}
|
9110
9241
|
if (series.dataLabelsGroup) {
|
9111
|
-
series.dataLabelsGroup.attr(
|
9242
|
+
series.dataLabelsGroup.attr(seriesAttribs);
|
9112
9243
|
}
|
9113
9244
|
}
|
9114
9245
|
});
|
@@ -9215,11 +9346,9 @@ Pointer.prototype = {
|
|
9215
9346
|
transform = {},
|
9216
9347
|
clip = {};
|
9217
9348
|
|
9218
|
-
//
|
9219
|
-
if (
|
9220
|
-
|
9221
|
-
e.preventDefault();
|
9222
|
-
}
|
9349
|
+
// If we're capturing touch, prevent pseudo click events from happening
|
9350
|
+
if (followTouchMove || hasZoom) {
|
9351
|
+
e.preventDefault();
|
9223
9352
|
}
|
9224
9353
|
|
9225
9354
|
// Normalize each touch
|
@@ -9293,7 +9422,7 @@ Pointer.prototype = {
|
|
9293
9422
|
chart.mouseIsDown = e.type;
|
9294
9423
|
chart.cancelClick = false;
|
9295
9424
|
chart.mouseDownX = this.mouseDownX = e.chartX;
|
9296
|
-
this.mouseDownY = e.chartY;
|
9425
|
+
chart.mouseDownY = this.mouseDownY = e.chartY;
|
9297
9426
|
},
|
9298
9427
|
|
9299
9428
|
/**
|
@@ -9375,7 +9504,7 @@ Pointer.prototype = {
|
|
9375
9504
|
|
9376
9505
|
// panning
|
9377
9506
|
if (clickedInside && !this.selectionMarker && chartOptions.panning) {
|
9378
|
-
chart.pan(
|
9507
|
+
chart.pan(e, chartOptions.panning);
|
9379
9508
|
}
|
9380
9509
|
}
|
9381
9510
|
},
|
@@ -9428,12 +9557,7 @@ Pointer.prototype = {
|
|
9428
9557
|
|
9429
9558
|
// Reset scaling preview
|
9430
9559
|
if (hasPinched) {
|
9431
|
-
this.scaleGroups(
|
9432
|
-
translateX: chart.plotLeft,
|
9433
|
-
translateY: chart.plotTop,
|
9434
|
-
scaleX: 1,
|
9435
|
-
scaleY: 1
|
9436
|
-
});
|
9560
|
+
this.scaleGroups();
|
9437
9561
|
}
|
9438
9562
|
}
|
9439
9563
|
|
@@ -9477,7 +9601,7 @@ Pointer.prototype = {
|
|
9477
9601
|
e = washMouseEvent(e);
|
9478
9602
|
|
9479
9603
|
// If we're outside, hide the tooltip
|
9480
|
-
if (chartPosition && hoverSeries &&
|
9604
|
+
if (chartPosition && hoverSeries && !this.inClass(e.target, 'highcharts-tracker') &&
|
9481
9605
|
!chart.isInsidePlot(e.pageX - chartPosition.left - chart.plotLeft,
|
9482
9606
|
e.pageY - chartPosition.top - chart.plotTop)) {
|
9483
9607
|
this.reset();
|
@@ -9509,7 +9633,8 @@ Pointer.prototype = {
|
|
9509
9633
|
}
|
9510
9634
|
|
9511
9635
|
// Show the tooltip and run mouse over events (#977)
|
9512
|
-
if (
|
9636
|
+
if ((this.inClass(e.target, 'highcharts-tracker') ||
|
9637
|
+
chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) && !chart.openMenu) {
|
9513
9638
|
this.runPointActions(e);
|
9514
9639
|
}
|
9515
9640
|
},
|
@@ -9612,10 +9737,14 @@ Pointer.prototype = {
|
|
9612
9737
|
this.runPointActions(e);
|
9613
9738
|
|
9614
9739
|
this.pinch(e);
|
9740
|
+
|
9741
|
+
} else {
|
9742
|
+
// Hide the tooltip on touching outside the plot area (#1203)
|
9743
|
+
this.reset();
|
9615
9744
|
}
|
9616
9745
|
|
9617
9746
|
} else if (e.touches.length === 2) {
|
9618
|
-
this.pinch(e);
|
9747
|
+
this.pinch(e);
|
9619
9748
|
}
|
9620
9749
|
},
|
9621
9750
|
|
@@ -9763,7 +9892,6 @@ Legend.prototype = {
|
|
9763
9892
|
},
|
9764
9893
|
key,
|
9765
9894
|
val;
|
9766
|
-
|
9767
9895
|
|
9768
9896
|
if (legendItem) {
|
9769
9897
|
legendItem.css({ fill: textColor, color: textColor }); // color for #1553, oldIE
|
@@ -9775,7 +9903,7 @@ Legend.prototype = {
|
|
9775
9903
|
if (legendSymbol) {
|
9776
9904
|
|
9777
9905
|
// Apply marker options
|
9778
|
-
if (markerOptions) {
|
9906
|
+
if (markerOptions && legendSymbol.isMarker) { // #585
|
9779
9907
|
markerOptions = item.convertAttribs(markerOptions);
|
9780
9908
|
for (key in markerOptions) {
|
9781
9909
|
val = markerOptions[key];
|
@@ -9826,7 +9954,7 @@ Legend.prototype = {
|
|
9826
9954
|
// destroy SVG elements
|
9827
9955
|
each(['legendItem', 'legendLine', 'legendSymbol', 'legendGroup'], function (key) {
|
9828
9956
|
if (item[key]) {
|
9829
|
-
item[key].destroy();
|
9957
|
+
item[key] = item[key].destroy();
|
9830
9958
|
}
|
9831
9959
|
});
|
9832
9960
|
|
@@ -9885,7 +10013,8 @@ Legend.prototype = {
|
|
9885
10013
|
var options = this.options,
|
9886
10014
|
padding = this.padding,
|
9887
10015
|
titleOptions = options.title,
|
9888
|
-
titleHeight = 0
|
10016
|
+
titleHeight = 0,
|
10017
|
+
bBox;
|
9889
10018
|
|
9890
10019
|
if (titleOptions.text) {
|
9891
10020
|
if (!this.title) {
|
@@ -9894,7 +10023,9 @@ Legend.prototype = {
|
|
9894
10023
|
.css(titleOptions.style)
|
9895
10024
|
.add(this.group);
|
9896
10025
|
}
|
9897
|
-
|
10026
|
+
bBox = this.title.getBBox();
|
10027
|
+
titleHeight = bBox.height;
|
10028
|
+
this.offsetWidth = bBox.width; // #1717
|
9898
10029
|
this.contentGroup.attr({ translateY: titleHeight });
|
9899
10030
|
}
|
9900
10031
|
this.titleHeight = titleHeight;
|
@@ -9915,6 +10046,7 @@ Legend.prototype = {
|
|
9915
10046
|
itemStyle = legend.itemStyle,
|
9916
10047
|
itemHiddenStyle = legend.itemHiddenStyle,
|
9917
10048
|
padding = legend.padding,
|
10049
|
+
itemDistance = horizontal ? pick(options.itemDistance, 8) : 0,
|
9918
10050
|
ltr = !options.rtl,
|
9919
10051
|
itemHeight,
|
9920
10052
|
widthOption = options.width,
|
@@ -10010,7 +10142,7 @@ Legend.prototype = {
|
|
10010
10142
|
bBox = li.getBBox();
|
10011
10143
|
|
10012
10144
|
itemWidth = item.legendItemWidth =
|
10013
|
-
options.itemWidth || symbolWidth + symbolPadding + bBox.width +
|
10145
|
+
options.itemWidth || symbolWidth + symbolPadding + bBox.width + itemDistance +
|
10014
10146
|
(showCheckbox ? 20 : 0);
|
10015
10147
|
legend.itemHeight = itemHeight = bBox.height;
|
10016
10148
|
|
@@ -10048,7 +10180,7 @@ Legend.prototype = {
|
|
10048
10180
|
|
10049
10181
|
// the width of the widest item
|
10050
10182
|
legend.offsetWidth = widthOption || mathMax(
|
10051
|
-
horizontal ? legend.itemX - initialItemX : itemWidth,
|
10183
|
+
(horizontal ? legend.itemX - initialItemX - itemDistance : itemWidth) + padding,
|
10052
10184
|
legend.offsetWidth
|
10053
10185
|
);
|
10054
10186
|
},
|
@@ -10385,7 +10517,7 @@ Chart.prototype = {
|
|
10385
10517
|
|
10386
10518
|
var chartEvents = optionsChart.events;
|
10387
10519
|
|
10388
|
-
this.runChartClick = chartEvents && !!chartEvents.click;
|
10520
|
+
//this.runChartClick = chartEvents && !!chartEvents.click;
|
10389
10521
|
this.bounds = { h: {}, v: {} }; // Pixel data bounds for touch zoom
|
10390
10522
|
|
10391
10523
|
this.callback = callback;
|
@@ -10499,6 +10631,7 @@ Chart.prototype = {
|
|
10499
10631
|
series = chart.initSeries(options);
|
10500
10632
|
|
10501
10633
|
chart.isDirtyLegend = true; // the series array is out of sync with the display
|
10634
|
+
chart.linkSeries();
|
10502
10635
|
if (redraw) {
|
10503
10636
|
chart.redraw(animation);
|
10504
10637
|
}
|
@@ -10520,7 +10653,8 @@ Chart.prototype = {
|
|
10520
10653
|
|
10521
10654
|
/*jslint unused: false*/
|
10522
10655
|
axis = new Axis(this, merge(options, {
|
10523
|
-
index: this[key].length
|
10656
|
+
index: this[key].length,
|
10657
|
+
isX: isX
|
10524
10658
|
}));
|
10525
10659
|
/*jslint unused: true*/
|
10526
10660
|
|
@@ -10576,6 +10710,7 @@ Chart.prototype = {
|
|
10576
10710
|
legend = chart.legend,
|
10577
10711
|
redrawLegend = chart.isDirtyLegend,
|
10578
10712
|
hasStackedSeries,
|
10713
|
+
hasDirtyStacks,
|
10579
10714
|
isDirtyBox = chart.isDirtyBox, // todo: check if it has actually changed?
|
10580
10715
|
seriesLength = series.length,
|
10581
10716
|
i = seriesLength,
|
@@ -10590,15 +10725,23 @@ Chart.prototype = {
|
|
10590
10725
|
chart.cloneRenderTo();
|
10591
10726
|
}
|
10592
10727
|
|
10728
|
+
// Adjust title layout (reflow multiline text)
|
10729
|
+
chart.layOutTitles();
|
10730
|
+
|
10593
10731
|
// link stacked series
|
10594
10732
|
while (i--) {
|
10595
10733
|
serie = series[i];
|
10596
|
-
|
10734
|
+
|
10735
|
+
if (serie.options.stacking) {
|
10597
10736
|
hasStackedSeries = true;
|
10598
|
-
|
10737
|
+
|
10738
|
+
if (serie.isDirty) {
|
10739
|
+
hasDirtyStacks = true;
|
10740
|
+
break;
|
10741
|
+
}
|
10599
10742
|
}
|
10600
10743
|
}
|
10601
|
-
if (
|
10744
|
+
if (hasDirtyStacks) { // mark others as dirty
|
10602
10745
|
i = seriesLength;
|
10603
10746
|
while (i--) {
|
10604
10747
|
serie = series[i];
|
@@ -10625,6 +10768,11 @@ Chart.prototype = {
|
|
10625
10768
|
chart.isDirtyLegend = false;
|
10626
10769
|
}
|
10627
10770
|
|
10771
|
+
// reset stacks
|
10772
|
+
if (hasStackedSeries) {
|
10773
|
+
chart.getStacks();
|
10774
|
+
}
|
10775
|
+
|
10628
10776
|
|
10629
10777
|
if (chart.hasCartesianSeries) {
|
10630
10778
|
if (!chart.isResizing) {
|
@@ -10637,9 +10785,17 @@ Chart.prototype = {
|
|
10637
10785
|
axis.setScale();
|
10638
10786
|
});
|
10639
10787
|
}
|
10788
|
+
|
10640
10789
|
chart.adjustTickAmounts();
|
10641
10790
|
chart.getMargins();
|
10642
10791
|
|
10792
|
+
// If one axis is dirty, all axes must be redrawn (#792, #2169)
|
10793
|
+
each(axes, function (axis) {
|
10794
|
+
if (axis.isDirty) {
|
10795
|
+
isDirtyBox = true;
|
10796
|
+
}
|
10797
|
+
});
|
10798
|
+
|
10643
10799
|
// redraw axes
|
10644
10800
|
each(axes, function (axis) {
|
10645
10801
|
|
@@ -10650,10 +10806,9 @@ Chart.prototype = {
|
|
10650
10806
|
fireEvent(axis, 'afterSetExtremes', axis.getExtremes()); // #747, #751
|
10651
10807
|
});
|
10652
10808
|
}
|
10653
|
-
|
10654
|
-
if (
|
10809
|
+
|
10810
|
+
if (isDirtyBox || hasStackedSeries) {
|
10655
10811
|
axis.redraw();
|
10656
|
-
isDirtyBox = true; // #792
|
10657
10812
|
}
|
10658
10813
|
});
|
10659
10814
|
|
@@ -10665,7 +10820,6 @@ Chart.prototype = {
|
|
10665
10820
|
}
|
10666
10821
|
|
10667
10822
|
|
10668
|
-
|
10669
10823
|
// redraw affected series
|
10670
10824
|
each(series, function (serie) {
|
10671
10825
|
if (serie.isDirty && serie.visible &&
|
@@ -10861,6 +11015,26 @@ Chart.prototype = {
|
|
10861
11015
|
});
|
10862
11016
|
},
|
10863
11017
|
|
11018
|
+
/**
|
11019
|
+
* Generate stacks for each series and calculate stacks total values
|
11020
|
+
*/
|
11021
|
+
getStacks: function () {
|
11022
|
+
var chart = this;
|
11023
|
+
|
11024
|
+
// reset stacks for each yAxis
|
11025
|
+
each(chart.yAxis, function (axis) {
|
11026
|
+
if (axis.stacks && axis.hasVisibleSeries) {
|
11027
|
+
axis.oldStacks = axis.stacks;
|
11028
|
+
}
|
11029
|
+
});
|
11030
|
+
|
11031
|
+
each(chart.series, function (series) {
|
11032
|
+
if (series.options.stacking && (series.visible === true || chart.options.chart.ignoreHiddenSeries === false)) {
|
11033
|
+
series.stackKey = series.type + pick(series.options.stack, '');
|
11034
|
+
}
|
11035
|
+
});
|
11036
|
+
},
|
11037
|
+
|
10864
11038
|
/**
|
10865
11039
|
* Display the zoom button
|
10866
11040
|
*/
|
@@ -10945,15 +11119,11 @@ Chart.prototype = {
|
|
10945
11119
|
* on mouse move, and the distance to pan is computed from chartX compared to
|
10946
11120
|
* the first chartX position in the dragging operation.
|
10947
11121
|
*/
|
10948
|
-
pan: function (
|
11122
|
+
pan: function (e, panning) {
|
11123
|
+
|
10949
11124
|
var chart = this,
|
10950
|
-
|
10951
|
-
|
10952
|
-
halfPointRange = xAxis.pointRange / 2,
|
10953
|
-
extremes = xAxis.getExtremes(),
|
10954
|
-
newMin = xAxis.translate(mouseDownX - chartX, true) + halfPointRange,
|
10955
|
-
newMax = xAxis.translate(mouseDownX + chart.plotWidth - chartX, true) - halfPointRange,
|
10956
|
-
hoverPoints = chart.hoverPoints;
|
11125
|
+
hoverPoints = chart.hoverPoints,
|
11126
|
+
doRedraw;
|
10957
11127
|
|
10958
11128
|
// remove active points for shared tooltip
|
10959
11129
|
if (hoverPoints) {
|
@@ -10962,11 +11132,26 @@ Chart.prototype = {
|
|
10962
11132
|
});
|
10963
11133
|
}
|
10964
11134
|
|
10965
|
-
|
10966
|
-
|
10967
|
-
|
11135
|
+
each(panning === 'xy' ? [1, 0] : [1], function (isX) { // docs: panning xy
|
11136
|
+
var mousePos = e[isX ? 'chartX' : 'chartY'],
|
11137
|
+
axis = chart[isX ? 'xAxis' : 'yAxis'][0],
|
11138
|
+
startPos = chart[isX ? 'mouseDownX' : 'mouseDownY'],
|
11139
|
+
halfPointRange = (axis.pointRange || 0) / 2,
|
11140
|
+
extremes = axis.getExtremes(),
|
11141
|
+
newMin = axis.toValue(startPos - mousePos, true) + halfPointRange,
|
11142
|
+
newMax = axis.toValue(startPos + chart[isX ? 'plotWidth' : 'plotHeight'] - mousePos, true) - halfPointRange;
|
10968
11143
|
|
10969
|
-
|
11144
|
+
if (axis.series.length && newMin > mathMin(extremes.dataMin, extremes.min) && newMax < mathMax(extremes.dataMax, extremes.max)) {
|
11145
|
+
axis.setExtremes(newMin, newMax, false, false, { trigger: 'pan' });
|
11146
|
+
doRedraw = true;
|
11147
|
+
}
|
11148
|
+
|
11149
|
+
chart[isX ? 'mouseDownX' : 'mouseDownY'] = mousePos; // set new reference for next run
|
11150
|
+
});
|
11151
|
+
|
11152
|
+
if (doRedraw) {
|
11153
|
+
chart.redraw(false);
|
11154
|
+
}
|
10970
11155
|
css(chart.container, { cursor: 'move' });
|
10971
11156
|
},
|
10972
11157
|
|
@@ -11013,11 +11198,49 @@ Chart.prototype = {
|
|
11013
11198
|
zIndex: chartTitleOptions.zIndex || 4
|
11014
11199
|
})
|
11015
11200
|
.css(chartTitleOptions.style)
|
11016
|
-
.add()
|
11017
|
-
|
11018
|
-
}
|
11201
|
+
.add();
|
11202
|
+
}
|
11019
11203
|
});
|
11204
|
+
chart.layOutTitles();
|
11205
|
+
},
|
11206
|
+
|
11207
|
+
/**
|
11208
|
+
* Lay out the chart titles and cache the full offset height for use in getMargins
|
11209
|
+
*/
|
11210
|
+
layOutTitles: function () {
|
11211
|
+
var titleOffset = 0,
|
11212
|
+
title = this.title,
|
11213
|
+
subtitle = this.subtitle,
|
11214
|
+
options = this.options,
|
11215
|
+
titleOptions = options.title,
|
11216
|
+
subtitleOptions = options.subtitle,
|
11217
|
+
autoWidth = this.spacingBox.width - 44; // 44 makes room for default context button
|
11218
|
+
|
11219
|
+
if (title) {
|
11220
|
+
title
|
11221
|
+
.css({ width: (titleOptions.width || autoWidth) + PX })
|
11222
|
+
.align(extend({ y: 15 }, titleOptions), false, 'spacingBox');
|
11223
|
+
|
11224
|
+
if (!titleOptions.floating && !titleOptions.verticalAlign) {
|
11225
|
+
titleOffset = title.getBBox().height;
|
11226
|
+
|
11227
|
+
// Adjust for browser consistency + backwards compat after #776 fix
|
11228
|
+
if (titleOffset >= 18 && titleOffset <= 25) {
|
11229
|
+
titleOffset = 15;
|
11230
|
+
}
|
11231
|
+
}
|
11232
|
+
}
|
11233
|
+
if (subtitle) {
|
11234
|
+
subtitle
|
11235
|
+
.css({ width: (subtitleOptions.width || autoWidth) + PX })
|
11236
|
+
.align(extend({ y: titleOffset + titleOptions.margin }, subtitleOptions), false, 'spacingBox');
|
11237
|
+
|
11238
|
+
if (!subtitleOptions.floating && !subtitleOptions.verticalAlign) {
|
11239
|
+
titleOffset = mathCeil(titleOffset + subtitle.getBBox().height);
|
11240
|
+
}
|
11241
|
+
}
|
11020
11242
|
|
11243
|
+
this.titleOffset = titleOffset; // used in getMargins
|
11021
11244
|
},
|
11022
11245
|
|
11023
11246
|
/**
|
@@ -11056,7 +11279,7 @@ Chart.prototype = {
|
|
11056
11279
|
|
11057
11280
|
// Set up the clone
|
11058
11281
|
} else {
|
11059
|
-
if (container) {
|
11282
|
+
if (container && container.parentNode === this.renderTo) {
|
11060
11283
|
this.renderTo.removeChild(container); // do not clone this
|
11061
11284
|
}
|
11062
11285
|
this.renderToClone = clone = this.renderTo.cloneNode(0);
|
@@ -11176,30 +11399,23 @@ Chart.prototype = {
|
|
11176
11399
|
optionsMarginLeft = chart.optionsMarginLeft,
|
11177
11400
|
optionsMarginRight = chart.optionsMarginRight,
|
11178
11401
|
optionsMarginBottom = chart.optionsMarginBottom,
|
11179
|
-
chartTitleOptions = chart.options.title,
|
11180
|
-
chartSubtitleOptions = chart.options.subtitle,
|
11181
11402
|
legendOptions = chart.options.legend,
|
11182
11403
|
legendMargin = pick(legendOptions.margin, 10),
|
11183
11404
|
legendX = legendOptions.x,
|
11184
11405
|
legendY = legendOptions.y,
|
11185
11406
|
align = legendOptions.align,
|
11186
11407
|
verticalAlign = legendOptions.verticalAlign,
|
11187
|
-
titleOffset;
|
11408
|
+
titleOffset = chart.titleOffset;
|
11188
11409
|
|
11189
11410
|
chart.resetMargins();
|
11190
11411
|
axisOffset = chart.axisOffset;
|
11191
11412
|
|
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
|
-
}
|
11413
|
+
// Adjust for title and subtitle
|
11414
|
+
if (titleOffset && !defined(optionsMarginTop)) {
|
11415
|
+
chart.plotTop = mathMax(chart.plotTop, titleOffset + chart.options.title.margin + spacingTop);
|
11201
11416
|
}
|
11202
|
-
|
11417
|
+
|
11418
|
+
// Adjust for legend
|
11203
11419
|
if (legend.display && !legendOptions.floating) {
|
11204
11420
|
if (align === 'right') { // horizontal alignment handled first
|
11205
11421
|
if (!defined(optionsMarginRight)) {
|
@@ -11410,7 +11626,7 @@ Chart.prototype = {
|
|
11410
11626
|
chart.plotSizeX = inverted ? plotHeight : plotWidth;
|
11411
11627
|
chart.plotSizeY = inverted ? plotWidth : plotHeight;
|
11412
11628
|
|
11413
|
-
chart.plotBorderWidth =
|
11629
|
+
chart.plotBorderWidth = optionsChart.plotBorderWidth || 0;
|
11414
11630
|
|
11415
11631
|
// Set boxes used for alignment
|
11416
11632
|
chart.spacingBox = renderer.spacingBox = {
|
@@ -11425,6 +11641,8 @@ Chart.prototype = {
|
|
11425
11641
|
width: plotWidth,
|
11426
11642
|
height: plotHeight
|
11427
11643
|
};
|
11644
|
+
|
11645
|
+
plotBorderWidth = 2 * mathFloor(chart.plotBorderWidth / 2);
|
11428
11646
|
clipX = mathCeil(mathMax(plotBorderWidth, clipOffset[3]) / 2);
|
11429
11647
|
clipY = mathCeil(mathMax(plotBorderWidth, clipOffset[0]) / 2);
|
11430
11648
|
chart.clipBox = {
|
@@ -11551,7 +11769,7 @@ Chart.prototype = {
|
|
11551
11769
|
// Plot area border
|
11552
11770
|
if (plotBorderWidth) {
|
11553
11771
|
if (!plotBorder) {
|
11554
|
-
chart.plotBorder = renderer.rect(plotLeft, plotTop, plotWidth, plotHeight, 0, plotBorderWidth)
|
11772
|
+
chart.plotBorder = renderer.rect(plotLeft, plotTop, plotWidth, plotHeight, 0, -plotBorderWidth)
|
11555
11773
|
.attr({
|
11556
11774
|
stroke: optionsChart.plotBorderColor,
|
11557
11775
|
'stroke-width': plotBorderWidth,
|
@@ -11610,6 +11828,36 @@ Chart.prototype = {
|
|
11610
11828
|
|
11611
11829
|
},
|
11612
11830
|
|
11831
|
+
/**
|
11832
|
+
* Link two or more series together. This is done initially from Chart.render,
|
11833
|
+
* and after Chart.addSeries and Series.remove.
|
11834
|
+
*/
|
11835
|
+
linkSeries: function () {
|
11836
|
+
var chart = this,
|
11837
|
+
chartSeries = chart.series;
|
11838
|
+
|
11839
|
+
// Reset links
|
11840
|
+
each(chartSeries, function (series) {
|
11841
|
+
series.linkedSeries.length = 0;
|
11842
|
+
});
|
11843
|
+
|
11844
|
+
// Apply new links
|
11845
|
+
each(chartSeries, function (series) {
|
11846
|
+
var linkedTo = series.options.linkedTo;
|
11847
|
+
if (isString(linkedTo)) {
|
11848
|
+
if (linkedTo === ':previous') {
|
11849
|
+
linkedTo = chart.series[series.index - 1];
|
11850
|
+
} else {
|
11851
|
+
linkedTo = chart.get(linkedTo);
|
11852
|
+
}
|
11853
|
+
if (linkedTo) {
|
11854
|
+
linkedTo.linkedSeries.push(series);
|
11855
|
+
series.linkedParent = linkedTo;
|
11856
|
+
}
|
11857
|
+
}
|
11858
|
+
});
|
11859
|
+
},
|
11860
|
+
|
11613
11861
|
/**
|
11614
11862
|
* Render all graphics for the chart
|
11615
11863
|
*/
|
@@ -11630,11 +11878,14 @@ Chart.prototype = {
|
|
11630
11878
|
// Legend
|
11631
11879
|
chart.legend = new Legend(chart, options.legend);
|
11632
11880
|
|
11881
|
+
chart.getStacks(); // render stacks
|
11882
|
+
|
11633
11883
|
// Get margins by pre-rendering axes
|
11634
11884
|
// set axes scales
|
11635
11885
|
each(axes, function (axis) {
|
11636
11886
|
axis.setScale();
|
11637
11887
|
});
|
11888
|
+
|
11638
11889
|
chart.getMargins();
|
11639
11890
|
|
11640
11891
|
chart.maxTicks = null; // reset for second pass
|
@@ -11843,6 +12094,8 @@ Chart.prototype = {
|
|
11843
12094
|
chart.initSeries(serieOptions);
|
11844
12095
|
});
|
11845
12096
|
|
12097
|
+
chart.linkSeries();
|
12098
|
+
|
11846
12099
|
// Run an event after axes and series are initialized, but before render. At this stage,
|
11847
12100
|
// the series data is indexed and cached in the xData and yData arrays, so we can access
|
11848
12101
|
// those before rendering. Used in Highstock.
|
@@ -12177,7 +12430,8 @@ Point.prototype = {
|
|
12177
12430
|
graphic = point.graphic,
|
12178
12431
|
i,
|
12179
12432
|
data = series.data,
|
12180
|
-
chart = series.chart
|
12433
|
+
chart = series.chart,
|
12434
|
+
seriesOptions = series.options;
|
12181
12435
|
|
12182
12436
|
redraw = pick(redraw, true);
|
12183
12437
|
|
@@ -12190,7 +12444,11 @@ Point.prototype = {
|
|
12190
12444
|
if (isObject(options)) {
|
12191
12445
|
series.getAttribs();
|
12192
12446
|
if (graphic) {
|
12193
|
-
|
12447
|
+
if (options.marker && options.marker.symbol) {
|
12448
|
+
point.graphic = graphic.destroy();
|
12449
|
+
} else {
|
12450
|
+
graphic.attr(point.pointAttr[series.state]);
|
12451
|
+
}
|
12194
12452
|
}
|
12195
12453
|
}
|
12196
12454
|
|
@@ -12199,11 +12457,13 @@ Point.prototype = {
|
|
12199
12457
|
series.xData[i] = point.x;
|
12200
12458
|
series.yData[i] = series.toYData ? series.toYData(point) : point.y;
|
12201
12459
|
series.zData[i] = point.z;
|
12202
|
-
|
12460
|
+
seriesOptions.data[i] = point.options;
|
12203
12461
|
|
12204
12462
|
// redraw
|
12205
|
-
series.isDirty = true;
|
12206
|
-
|
12463
|
+
series.isDirty = series.isDirtyData = chart.isDirtyBox = true;
|
12464
|
+
if (seriesOptions.legendType === 'point') { // #1831, #1885
|
12465
|
+
chart.legend.destroyItem(point);
|
12466
|
+
}
|
12207
12467
|
if (redraw) {
|
12208
12468
|
chart.redraw(animation);
|
12209
12469
|
}
|
@@ -12431,11 +12691,11 @@ Series.prototype = {
|
|
12431
12691
|
var series = this,
|
12432
12692
|
eventType,
|
12433
12693
|
events,
|
12434
|
-
linkedTo,
|
12435
12694
|
chartSeries = chart.series;
|
12436
12695
|
|
12437
12696
|
series.chart = chart;
|
12438
12697
|
series.options = options = series.setOptions(options); // merge with plotOptions
|
12698
|
+
series.linkedSeries = [];
|
12439
12699
|
|
12440
12700
|
// bind the axes
|
12441
12701
|
series.bindAxes();
|
@@ -12491,20 +12751,6 @@ Series.prototype = {
|
|
12491
12751
|
series.name = series.name || 'Series ' + (i + 1);
|
12492
12752
|
});
|
12493
12753
|
|
12494
|
-
// Linked series
|
12495
|
-
linkedTo = options.linkedTo;
|
12496
|
-
series.linkedSeries = [];
|
12497
|
-
if (isString(linkedTo)) {
|
12498
|
-
if (linkedTo === ':previous') {
|
12499
|
-
linkedTo = chartSeries[series.index - 1];
|
12500
|
-
} else {
|
12501
|
-
linkedTo = chart.get(linkedTo);
|
12502
|
-
}
|
12503
|
-
if (linkedTo) {
|
12504
|
-
linkedTo.linkedSeries.push(series);
|
12505
|
-
series.linkedParent = linkedTo;
|
12506
|
-
}
|
12507
|
-
}
|
12508
12754
|
},
|
12509
12755
|
|
12510
12756
|
/**
|
@@ -12612,6 +12858,7 @@ Series.prototype = {
|
|
12612
12858
|
// register it
|
12613
12859
|
series.segments = segments;
|
12614
12860
|
},
|
12861
|
+
|
12615
12862
|
/**
|
12616
12863
|
* Set the series options by merging from the options tree
|
12617
12864
|
* @param {Object} itemOptions
|
@@ -12714,7 +12961,7 @@ Series.prototype = {
|
|
12714
12961
|
symbolWidth = legendOptions.symbolWidth,
|
12715
12962
|
renderer = this.chart.renderer,
|
12716
12963
|
legendItemGroup = this.legendGroup,
|
12717
|
-
|
12964
|
+
verticalCenter = legend.baseline - mathRound(renderer.fontMetrics(legendOptions.itemStyle.fontSize).b * 0.3),
|
12718
12965
|
attr;
|
12719
12966
|
|
12720
12967
|
// Draw the line
|
@@ -12728,10 +12975,10 @@ Series.prototype = {
|
|
12728
12975
|
this.legendLine = renderer.path([
|
12729
12976
|
M,
|
12730
12977
|
0,
|
12731
|
-
|
12978
|
+
verticalCenter,
|
12732
12979
|
L,
|
12733
12980
|
symbolWidth,
|
12734
|
-
|
12981
|
+
verticalCenter
|
12735
12982
|
])
|
12736
12983
|
.attr(attr)
|
12737
12984
|
.add(legendItemGroup);
|
@@ -12743,11 +12990,12 @@ Series.prototype = {
|
|
12743
12990
|
this.legendSymbol = legendSymbol = renderer.symbol(
|
12744
12991
|
this.symbol,
|
12745
12992
|
(symbolWidth / 2) - radius,
|
12746
|
-
|
12993
|
+
verticalCenter - radius,
|
12747
12994
|
2 * radius,
|
12748
12995
|
2 * radius
|
12749
12996
|
)
|
12750
12997
|
.add(legendItemGroup);
|
12998
|
+
legendSymbol.isMarker = true;
|
12751
12999
|
}
|
12752
13000
|
},
|
12753
13001
|
|
@@ -12778,13 +13026,14 @@ Series.prototype = {
|
|
12778
13026
|
setAnimation(animation, chart);
|
12779
13027
|
|
12780
13028
|
// Make graph animate sideways
|
12781
|
-
if (
|
12782
|
-
graph.
|
13029
|
+
if (shift) {
|
13030
|
+
each([graph, area, series.graphNeg, series.areaNeg], function (shape) {
|
13031
|
+
if (shape) {
|
13032
|
+
shape.shift = currentShift + 1;
|
13033
|
+
}
|
13034
|
+
});
|
12783
13035
|
}
|
12784
13036
|
if (area) {
|
12785
|
-
if (shift) { // #780
|
12786
|
-
area.shift = currentShift + 1;
|
12787
|
-
}
|
12788
13037
|
area.isArea = true; // needed in animation, both with and without shift
|
12789
13038
|
}
|
12790
13039
|
|
@@ -12821,12 +13070,12 @@ Series.prototype = {
|
|
12821
13070
|
dataOptions.shift();
|
12822
13071
|
}
|
12823
13072
|
}
|
12824
|
-
series.getAttribs();
|
12825
13073
|
|
12826
13074
|
// redraw
|
12827
13075
|
series.isDirty = true;
|
12828
13076
|
series.isDirtyData = true;
|
12829
13077
|
if (redraw) {
|
13078
|
+
series.getAttribs(); // #1937
|
12830
13079
|
chart.redraw();
|
12831
13080
|
}
|
12832
13081
|
},
|
@@ -12857,7 +13106,7 @@ Series.prototype = {
|
|
12857
13106
|
yData = [],
|
12858
13107
|
zData = [],
|
12859
13108
|
dataLength = data ? data.length : [],
|
12860
|
-
turboThreshold = options.turboThreshold
|
13109
|
+
turboThreshold = pick(options.turboThreshold, 1000),
|
12861
13110
|
pt,
|
12862
13111
|
pointArrayMap = series.pointArrayMap,
|
12863
13112
|
valueCount = pointArrayMap && pointArrayMap.length,
|
@@ -12867,7 +13116,7 @@ Series.prototype = {
|
|
12867
13116
|
// first value is tested, and we assume that all the rest are defined the same
|
12868
13117
|
// way. Although the 'for' loops are similar, they are repeated inside each
|
12869
13118
|
// if-else conditional for max performance.
|
12870
|
-
if (dataLength > turboThreshold) {
|
13119
|
+
if (turboThreshold && dataLength > turboThreshold) {
|
12871
13120
|
|
12872
13121
|
// find the first non-null point
|
12873
13122
|
i = 0;
|
@@ -12901,9 +13150,9 @@ Series.prototype = {
|
|
12901
13150
|
yData[i] = pt[1];
|
12902
13151
|
}
|
12903
13152
|
}
|
12904
|
-
}
|
13153
|
+
} else {
|
12905
13154
|
error(12); // Highcharts expects configs to be numbers or arrays in turbo mode
|
12906
|
-
}
|
13155
|
+
}
|
12907
13156
|
} else {
|
12908
13157
|
for (i = 0; i < dataLength; i++) {
|
12909
13158
|
if (data[i] !== UNDEFINED) { // stray commas in oldIE
|
@@ -12913,18 +13162,12 @@ Series.prototype = {
|
|
12913
13162
|
yData[i] = hasToYData ? series.toYData(pt) : pt.y;
|
12914
13163
|
zData[i] = pt.z;
|
12915
13164
|
if (names && pt.name) {
|
12916
|
-
names[
|
13165
|
+
names[pt.x] = pt.name; // #2046
|
12917
13166
|
}
|
12918
13167
|
}
|
12919
13168
|
}
|
12920
13169
|
}
|
12921
13170
|
|
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
13171
|
// Forgetting to cast strings to numbers is a common caveat when handling CSV or JSON
|
12929
13172
|
if (isString(yData[0])) {
|
12930
13173
|
error(14, true);
|
@@ -12984,6 +13227,8 @@ Series.prototype = {
|
|
12984
13227
|
|
12985
13228
|
// redraw
|
12986
13229
|
chart.isDirtyLegend = chart.isDirtyBox = true;
|
13230
|
+
chart.linkSeries();
|
13231
|
+
|
12987
13232
|
if (redraw) {
|
12988
13233
|
chart.redraw(animation);
|
12989
13234
|
}
|
@@ -13002,8 +13247,8 @@ Series.prototype = {
|
|
13002
13247
|
processedXData = series.xData, // copied during slice operation below
|
13003
13248
|
processedYData = series.yData,
|
13004
13249
|
dataLength = processedXData.length,
|
13250
|
+
croppedData,
|
13005
13251
|
cropStart = 0,
|
13006
|
-
cropEnd = dataLength,
|
13007
13252
|
cropped,
|
13008
13253
|
distance,
|
13009
13254
|
closestPointRange,
|
@@ -13018,12 +13263,12 @@ Series.prototype = {
|
|
13018
13263
|
if (isCartesian && !series.isDirty && !xAxis.isDirty && !series.yAxis.isDirty && !force) {
|
13019
13264
|
return false;
|
13020
13265
|
}
|
13266
|
+
|
13021
13267
|
|
13022
13268
|
// optionally filter out points outside the plot area
|
13023
13269
|
if (isCartesian && series.sorted && (!cropThreshold || dataLength > cropThreshold || series.forceCrop)) {
|
13024
|
-
var
|
13025
|
-
|
13026
|
-
max = extremes.max;
|
13270
|
+
var min = xAxis.min,
|
13271
|
+
max = xAxis.max;
|
13027
13272
|
|
13028
13273
|
// it's outside current extremes
|
13029
13274
|
if (processedXData[dataLength - 1] < min || processedXData[0] > max) {
|
@@ -13032,43 +13277,34 @@ Series.prototype = {
|
|
13032
13277
|
|
13033
13278
|
// only crop if it's actually spilling out
|
13034
13279
|
} 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);
|
13280
|
+
croppedData = this.cropData(series.xData, series.yData, min, max);
|
13281
|
+
processedXData = croppedData.xData;
|
13282
|
+
processedYData = croppedData.yData;
|
13283
|
+
cropStart = croppedData.start;
|
13053
13284
|
cropped = true;
|
13054
13285
|
}
|
13055
13286
|
}
|
13056
13287
|
|
13057
13288
|
|
13058
13289
|
// Find the closest distance between processed points
|
13059
|
-
for (i = processedXData.length - 1; i
|
13290
|
+
for (i = processedXData.length - 1; i >= 0; i--) {
|
13060
13291
|
distance = processedXData[i] - processedXData[i - 1];
|
13061
13292
|
if (distance > 0 && (closestPointRange === UNDEFINED || distance < closestPointRange)) {
|
13062
13293
|
closestPointRange = distance;
|
13294
|
+
|
13295
|
+
// Unsorted data is not supported by the line tooltip, as well as data grouping and
|
13296
|
+
// navigation in Stock charts (#725) and width calculation of columns (#1900)
|
13297
|
+
} else if (distance < 0 && series.requireSorting) {
|
13298
|
+
error(15);
|
13063
13299
|
}
|
13064
13300
|
}
|
13065
|
-
|
13301
|
+
|
13066
13302
|
// Record the properties
|
13067
13303
|
series.cropped = cropped; // undefined or true
|
13068
13304
|
series.cropStart = cropStart;
|
13069
13305
|
series.processedXData = processedXData;
|
13070
13306
|
series.processedYData = processedYData;
|
13071
|
-
|
13307
|
+
|
13072
13308
|
if (options.pointRange === null) { // null means auto, as for columns, candlesticks and OHLC
|
13073
13309
|
series.pointRange = closestPointRange || 1;
|
13074
13310
|
}
|
@@ -13076,6 +13312,41 @@ Series.prototype = {
|
|
13076
13312
|
|
13077
13313
|
},
|
13078
13314
|
|
13315
|
+
/**
|
13316
|
+
* Iterate over xData and crop values between min and max. Returns object containing crop start/end
|
13317
|
+
* cropped xData with corresponding part of yData, dataMin and dataMax within the cropped range
|
13318
|
+
*/
|
13319
|
+
cropData: function (xData, yData, min, max) {
|
13320
|
+
var dataLength = xData.length,
|
13321
|
+
cropStart = 0,
|
13322
|
+
cropEnd = dataLength,
|
13323
|
+
i;
|
13324
|
+
|
13325
|
+
// iterate up to find slice start
|
13326
|
+
for (i = 0; i < dataLength; i++) {
|
13327
|
+
if (xData[i] >= min) {
|
13328
|
+
cropStart = mathMax(0, i - 1);
|
13329
|
+
break;
|
13330
|
+
}
|
13331
|
+
}
|
13332
|
+
|
13333
|
+
// proceed to find slice end
|
13334
|
+
for (; i < dataLength; i++) {
|
13335
|
+
if (xData[i] > max) {
|
13336
|
+
cropEnd = i + 1;
|
13337
|
+
break;
|
13338
|
+
}
|
13339
|
+
}
|
13340
|
+
|
13341
|
+
return {
|
13342
|
+
xData: xData.slice(cropStart, cropEnd),
|
13343
|
+
yData: yData.slice(cropStart, cropEnd),
|
13344
|
+
start: cropStart,
|
13345
|
+
end: cropEnd
|
13346
|
+
};
|
13347
|
+
},
|
13348
|
+
|
13349
|
+
|
13079
13350
|
/**
|
13080
13351
|
* Generate the data point after the data has been processed by cropping away
|
13081
13352
|
* unused points and optionally grouped in Highcharts Stock.
|
@@ -13136,6 +13407,165 @@ Series.prototype = {
|
|
13136
13407
|
series.points = points;
|
13137
13408
|
},
|
13138
13409
|
|
13410
|
+
/**
|
13411
|
+
* Adds series' points value to corresponding stack
|
13412
|
+
*/
|
13413
|
+
setStackedPoints: function () {
|
13414
|
+
if (!this.options.stacking || (this.visible !== true && this.chart.options.chart.ignoreHiddenSeries !== false)) {
|
13415
|
+
return;
|
13416
|
+
}
|
13417
|
+
|
13418
|
+
var series = this,
|
13419
|
+
xData = series.processedXData,
|
13420
|
+
yData = series.processedYData,
|
13421
|
+
yDataLength = yData.length,
|
13422
|
+
seriesOptions = series.options,
|
13423
|
+
threshold = seriesOptions.threshold,
|
13424
|
+
stackOption = seriesOptions.stack,
|
13425
|
+
stacking = seriesOptions.stacking,
|
13426
|
+
stackKey = series.stackKey,
|
13427
|
+
negKey = '-' + stackKey,
|
13428
|
+
yAxis = series.yAxis,
|
13429
|
+
stacks = yAxis.stacks,
|
13430
|
+
oldStacks = yAxis.oldStacks,
|
13431
|
+
stackExtremes = yAxis.stackExtremes,
|
13432
|
+
isNegative,
|
13433
|
+
total,
|
13434
|
+
stack,
|
13435
|
+
key,
|
13436
|
+
i,
|
13437
|
+
x,
|
13438
|
+
y;
|
13439
|
+
|
13440
|
+
// loop over the non-null y values and read them into a local array
|
13441
|
+
for (i = 0; i < yDataLength; i++) {
|
13442
|
+
x = xData[i];
|
13443
|
+
y = yData[i];
|
13444
|
+
|
13445
|
+
// Read stacked values into a stack based on the x value,
|
13446
|
+
// the sign of y and the stack key. Stacking is also handled for null values (#739)
|
13447
|
+
isNegative = series.negStacks && y < threshold;
|
13448
|
+
key = isNegative ? negKey : stackKey;
|
13449
|
+
|
13450
|
+
// Set default stackExtremes value for this stack
|
13451
|
+
if (typeof y === 'number' && !stackExtremes[stackKey]) {
|
13452
|
+
stackExtremes[stackKey] = {
|
13453
|
+
dataMin: y,
|
13454
|
+
dataMax: y
|
13455
|
+
};
|
13456
|
+
}
|
13457
|
+
|
13458
|
+
// Create empty object for this stack if it doesn't exist yet
|
13459
|
+
if (!stacks[key]) {
|
13460
|
+
stacks[key] = {};
|
13461
|
+
}
|
13462
|
+
|
13463
|
+
// Initialize StackItem for this x
|
13464
|
+
if (!stacks[key][x]) {
|
13465
|
+
if (oldStacks[key] && oldStacks[key][x]) {
|
13466
|
+
stacks[key][x] = oldStacks[key][x];
|
13467
|
+
stacks[key][x].total = null;
|
13468
|
+
} else {
|
13469
|
+
stacks[key][x] = new StackItem(yAxis, yAxis.options.stackLabels, isNegative, x, stackOption, stacking);
|
13470
|
+
}
|
13471
|
+
}
|
13472
|
+
|
13473
|
+
// If the StackItem doesn't exist, create it first
|
13474
|
+
stack = stacks[key][x];
|
13475
|
+
total = stack.total;
|
13476
|
+
|
13477
|
+
|
13478
|
+
// add value to the stack total
|
13479
|
+
stack.addValue(y || 0);
|
13480
|
+
stack.cacheExtremes(series, [total, total + (y || 0)]);
|
13481
|
+
|
13482
|
+
if (typeof y === 'number') {
|
13483
|
+
stackExtremes[stackKey].dataMin = mathMin(stackExtremes[stackKey].dataMin, stack.total, y);
|
13484
|
+
stackExtremes[stackKey].dataMax = mathMax(stackExtremes[stackKey].dataMax, stack.total, y);
|
13485
|
+
}
|
13486
|
+
|
13487
|
+
}
|
13488
|
+
|
13489
|
+
// reset old stacks
|
13490
|
+
yAxis.oldStacks = {};
|
13491
|
+
},
|
13492
|
+
|
13493
|
+
/**
|
13494
|
+
* Calculate Y extremes for visible data
|
13495
|
+
*/
|
13496
|
+
getExtremes: function () {
|
13497
|
+
var xAxis = this.xAxis,
|
13498
|
+
yAxis = this.yAxis,
|
13499
|
+
stackKey = this.stackKey,
|
13500
|
+
stackExtremes,
|
13501
|
+
stackMin,
|
13502
|
+
stackMax,
|
13503
|
+
options = this.options,
|
13504
|
+
threshold = yAxis.isLog ? null : options.threshold,
|
13505
|
+
xData = this.processedXData,
|
13506
|
+
yData = this.processedYData,
|
13507
|
+
yDataLength = yData.length,
|
13508
|
+
activeYData = [],
|
13509
|
+
activeCounter = 0,
|
13510
|
+
xExtremes = xAxis.getExtremes(), // #2117, need to compensate for log X axis
|
13511
|
+
xMin = xExtremes.min,
|
13512
|
+
xMax = xExtremes.max,
|
13513
|
+
validValue,
|
13514
|
+
withinRange,
|
13515
|
+
dataMin,
|
13516
|
+
dataMax,
|
13517
|
+
x,
|
13518
|
+
y,
|
13519
|
+
i,
|
13520
|
+
j;
|
13521
|
+
|
13522
|
+
// For stacked series, get the value from the stack
|
13523
|
+
if (options.stacking) {
|
13524
|
+
stackExtremes = yAxis.stackExtremes[stackKey];
|
13525
|
+
stackMin = stackExtremes.dataMin;
|
13526
|
+
stackMax = stackExtremes.dataMax;
|
13527
|
+
|
13528
|
+
dataMin = mathMin(stackMin, pick(threshold, stackMin));
|
13529
|
+
dataMax = mathMax(stackMax, pick(threshold, stackMax));
|
13530
|
+
}
|
13531
|
+
|
13532
|
+
// If not stacking or threshold is null, iterate over values that are within the visible range
|
13533
|
+
if (!defined(dataMin) || !defined(dataMax)) {
|
13534
|
+
|
13535
|
+
for (i = 0; i < yDataLength; i++) {
|
13536
|
+
|
13537
|
+
x = xData[i];
|
13538
|
+
y = yData[i];
|
13539
|
+
|
13540
|
+
// For points within the visible range, including the first point outside the
|
13541
|
+
// visible range, consider y extremes
|
13542
|
+
validValue = y !== null && y !== UNDEFINED && (!yAxis.isLog || (y.length || y > 0));
|
13543
|
+
withinRange = this.getExtremesFromAll || this.cropped || ((xData[i + 1] || x) >= xMin &&
|
13544
|
+
(xData[i - 1] || x) <= xMax);
|
13545
|
+
|
13546
|
+
if (validValue && withinRange) {
|
13547
|
+
|
13548
|
+
j = y.length;
|
13549
|
+
if (j) { // array, like ohlc or range data
|
13550
|
+
while (j--) {
|
13551
|
+
if (y[j] !== null) {
|
13552
|
+
activeYData[activeCounter++] = y[j];
|
13553
|
+
}
|
13554
|
+
}
|
13555
|
+
} else {
|
13556
|
+
activeYData[activeCounter++] = y;
|
13557
|
+
}
|
13558
|
+
}
|
13559
|
+
}
|
13560
|
+
dataMin = pick(dataMin, arrayMin(activeYData));
|
13561
|
+
dataMax = pick(dataMax, arrayMax(activeYData));
|
13562
|
+
}
|
13563
|
+
|
13564
|
+
// Set
|
13565
|
+
this.dataMin = dataMin;
|
13566
|
+
this.dataMax = dataMax;
|
13567
|
+
},
|
13568
|
+
|
13139
13569
|
/**
|
13140
13570
|
* Translate data points from raw data values to chart specific positioning data
|
13141
13571
|
* needed later in drawPoints, drawGraph and drawTracker.
|
@@ -13154,27 +13584,11 @@ Series.prototype = {
|
|
13154
13584
|
points = series.points,
|
13155
13585
|
dataLength = points.length,
|
13156
13586
|
hasModifyValue = !!series.modifyValue,
|
13157
|
-
isBottomSeries,
|
13158
|
-
allStackSeries,
|
13159
13587
|
i,
|
13160
|
-
|
13588
|
+
pointPlacement = options.pointPlacement,
|
13589
|
+
dynamicallyPlaced = pointPlacement === 'between' || isNumber(pointPlacement),
|
13161
13590
|
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
|
-
}
|
13591
|
+
|
13178
13592
|
|
13179
13593
|
// Translate each point
|
13180
13594
|
for (i = 0; i < dataLength; i++) {
|
@@ -13182,7 +13596,7 @@ Series.prototype = {
|
|
13182
13596
|
xValue = point.x,
|
13183
13597
|
yValue = point.y,
|
13184
13598
|
yBottom = point.low,
|
13185
|
-
stack = yAxis.stacks[(yValue < threshold ? '-' : '') + series.stackKey],
|
13599
|
+
stack = yAxis.stacks[(series.negStacks && yValue < threshold ? '-' : '') + series.stackKey],
|
13186
13600
|
pointStack,
|
13187
13601
|
pointStackTotal;
|
13188
13602
|
|
@@ -13192,16 +13606,18 @@ Series.prototype = {
|
|
13192
13606
|
}
|
13193
13607
|
|
13194
13608
|
// Get the plotX translation
|
13195
|
-
point.plotX = xAxis.translate(xValue, 0, 0, 0, 1,
|
13609
|
+
point.plotX = xAxis.translate(xValue, 0, 0, 0, 1, pointPlacement); // Math.round fixes #591
|
13196
13610
|
|
13197
13611
|
// Calculate the bottom y value for stacked series
|
13198
13612
|
if (stacking && series.visible && stack && stack[xValue]) {
|
13613
|
+
|
13614
|
+
|
13199
13615
|
pointStack = stack[xValue];
|
13200
13616
|
pointStackTotal = pointStack.total;
|
13201
13617
|
pointStack.cum = yBottom = pointStack.cum - yValue; // start from top
|
13202
13618
|
yValue = yBottom + yValue;
|
13203
13619
|
|
13204
|
-
if (
|
13620
|
+
if (pointStack.cum === 0) {
|
13205
13621
|
yBottom = pick(threshold, yAxis.min);
|
13206
13622
|
}
|
13207
13623
|
|
@@ -13217,6 +13633,10 @@ Series.prototype = {
|
|
13217
13633
|
point.percentage = pointStackTotal ? point.y * 100 / pointStackTotal : 0;
|
13218
13634
|
point.total = point.stackTotal = pointStackTotal;
|
13219
13635
|
point.stackY = yValue;
|
13636
|
+
|
13637
|
+
// Place the stack label
|
13638
|
+
pointStack.setOffset(series.pointXOffset || 0, series.barW || 0);
|
13639
|
+
|
13220
13640
|
}
|
13221
13641
|
|
13222
13642
|
// Set translated yBottom or remove it
|
@@ -13231,11 +13651,12 @@ Series.prototype = {
|
|
13231
13651
|
|
13232
13652
|
// Set the the plotY value, reset it for redraws
|
13233
13653
|
point.plotY = (typeof yValue === 'number' && yValue !== Infinity) ?
|
13234
|
-
mathRound(yAxis.translate(yValue, 0, 1, 0, 1) * 10) / 10 : // Math.round fixes #591
|
13654
|
+
//mathRound(yAxis.translate(yValue, 0, 1, 0, 1) * 10) / 10 : // Math.round fixes #591
|
13655
|
+
yAxis.translate(yValue, 0, 1, 0, 1) :
|
13235
13656
|
UNDEFINED;
|
13236
13657
|
|
13237
13658
|
// Set client related positions for mouse tracking
|
13238
|
-
point.clientX =
|
13659
|
+
point.clientX = dynamicallyPlaced ? xAxis.translate(xValue, 0, 0, 0, 1) : point.plotX; // #1514
|
13239
13660
|
|
13240
13661
|
point.negative = point.y < (threshold || 0);
|
13241
13662
|
|
@@ -13261,6 +13682,7 @@ Series.prototype = {
|
|
13261
13682
|
xAxis = series.xAxis,
|
13262
13683
|
axisLength = xAxis ? (xAxis.tooltipLen || xAxis.len) : series.chart.plotSizeX, // tooltipLen and tooltipPosName used in polar
|
13263
13684
|
point,
|
13685
|
+
nextPoint,
|
13264
13686
|
i,
|
13265
13687
|
tooltipPoints = []; // a lookup array for each pixel in the x dimension
|
13266
13688
|
|
@@ -13284,15 +13706,24 @@ Series.prototype = {
|
|
13284
13706
|
points = points.reverse();
|
13285
13707
|
}
|
13286
13708
|
|
13709
|
+
// Polar needs additional shaping
|
13710
|
+
if (series.orderTooltipPoints) {
|
13711
|
+
series.orderTooltipPoints(points);
|
13712
|
+
}
|
13713
|
+
|
13287
13714
|
// Assign each pixel position to the nearest point
|
13288
13715
|
pointsLength = points.length;
|
13289
13716
|
for (i = 0; i < pointsLength; i++) {
|
13290
13717
|
point = points[i];
|
13718
|
+
nextPoint = points[i + 1];
|
13719
|
+
|
13291
13720
|
// Set this range's low to the last range's high plus one
|
13292
13721
|
low = points[i - 1] ? high + 1 : 0;
|
13293
13722
|
// Now find the new high
|
13294
13723
|
high = points[i + 1] ?
|
13295
|
-
mathMax(0, mathFloor(
|
13724
|
+
mathMin(mathMax(0, mathFloor( // #2070
|
13725
|
+
(point.clientX + (nextPoint ? (nextPoint.wrappedClientX || nextPoint.clientX) : axisLength)) / 2
|
13726
|
+
)), axisLength) :
|
13296
13727
|
axisLength;
|
13297
13728
|
|
13298
13729
|
while (low >= 0 && low <= high) {
|
@@ -13512,7 +13943,7 @@ Series.prototype = {
|
|
13512
13943
|
i = points.length;
|
13513
13944
|
while (i--) {
|
13514
13945
|
point = points[i];
|
13515
|
-
plotX = point.plotX;
|
13946
|
+
plotX = mathFloor(point.plotX); // #1843
|
13516
13947
|
plotY = point.plotY;
|
13517
13948
|
graphic = point.graphic;
|
13518
13949
|
pointMarkerOptions = point.marker || {};
|
@@ -13738,7 +14169,7 @@ Series.prototype = {
|
|
13738
14169
|
animation: false,
|
13739
14170
|
index: this.index,
|
13740
14171
|
pointStart: this.xData[0] // when updating after addPoint
|
13741
|
-
}, newOptions);
|
14172
|
+
}, { data: this.options.data }, newOptions);
|
13742
14173
|
|
13743
14174
|
// Destroy the series and reinsert methods from the type prototype
|
13744
14175
|
this.remove(false);
|
@@ -13879,12 +14310,12 @@ Series.prototype = {
|
|
13879
14310
|
// in the point options, or if they fall outside the plot area.
|
13880
14311
|
} else if (enabled) {
|
13881
14312
|
|
13882
|
-
rotation = options.rotation;
|
13883
|
-
|
13884
14313
|
// Create individual options structure that can be extended without
|
13885
14314
|
// affecting others
|
13886
14315
|
options = merge(generalOptions, pointOptions);
|
13887
|
-
|
14316
|
+
|
14317
|
+
rotation = options.rotation;
|
14318
|
+
|
13888
14319
|
// Get the string
|
13889
14320
|
labelConfig = point.getLabelConfig();
|
13890
14321
|
str = options.format ?
|
@@ -13980,7 +14411,7 @@ Series.prototype = {
|
|
13980
14411
|
width: bBox.width,
|
13981
14412
|
height: bBox.height
|
13982
14413
|
});
|
13983
|
-
|
14414
|
+
|
13984
14415
|
// Allow a hook for changing alignment in the last moment, then do the alignment
|
13985
14416
|
if (options.rotation) { // Fancy box alignment isn't supported for rotated text
|
13986
14417
|
alignAttr = {
|
@@ -13996,7 +14427,8 @@ Series.prototype = {
|
|
13996
14427
|
|
13997
14428
|
// Show or hide based on the final aligned position
|
13998
14429
|
dataLabel.attr({
|
13999
|
-
visibility: options.crop === false ||
|
14430
|
+
visibility: options.crop === false ||
|
14431
|
+
(chart.isInsidePlot(alignAttr.x, alignAttr.y) && chart.isInsidePlot(alignAttr.x + bBox.width, alignAttr.y + bBox.height)) ?
|
14000
14432
|
(chart.renderer.isSVG ? 'inherit' : VISIBLE) :
|
14001
14433
|
HIDDEN
|
14002
14434
|
});
|
@@ -14143,7 +14575,7 @@ Series.prototype = {
|
|
14143
14575
|
var options = this.options,
|
14144
14576
|
chart = this.chart,
|
14145
14577
|
renderer = chart.renderer,
|
14146
|
-
negativeColor = options.negativeColor,
|
14578
|
+
negativeColor = options.negativeColor || options.negativeFillColor,
|
14147
14579
|
translatedThreshold,
|
14148
14580
|
posAttr,
|
14149
14581
|
negAttr,
|
@@ -14154,11 +14586,12 @@ Series.prototype = {
|
|
14154
14586
|
chartWidth = chart.chartWidth,
|
14155
14587
|
chartHeight = chart.chartHeight,
|
14156
14588
|
chartSizeMax = mathMax(chartWidth, chartHeight),
|
14589
|
+
yAxis = this.yAxis,
|
14157
14590
|
above,
|
14158
14591
|
below;
|
14159
14592
|
|
14160
14593
|
if (negativeColor && (graph || area)) {
|
14161
|
-
translatedThreshold =
|
14594
|
+
translatedThreshold = mathRound(yAxis.toPixels(options.threshold || 0, true));
|
14162
14595
|
above = {
|
14163
14596
|
x: 0,
|
14164
14597
|
y: 0,
|
@@ -14169,25 +14602,29 @@ Series.prototype = {
|
|
14169
14602
|
x: 0,
|
14170
14603
|
y: translatedThreshold,
|
14171
14604
|
width: chartSizeMax,
|
14172
|
-
height: chartSizeMax
|
14605
|
+
height: chartSizeMax
|
14173
14606
|
};
|
14174
14607
|
|
14175
|
-
if (chart.inverted
|
14176
|
-
|
14177
|
-
|
14178
|
-
|
14179
|
-
|
14180
|
-
|
14181
|
-
|
14182
|
-
|
14183
|
-
|
14184
|
-
|
14185
|
-
|
14186
|
-
|
14187
|
-
|
14608
|
+
if (chart.inverted) {
|
14609
|
+
|
14610
|
+
above.height = below.y = chart.plotWidth - translatedThreshold;
|
14611
|
+
if (renderer.isVML) {
|
14612
|
+
above = {
|
14613
|
+
x: chart.plotWidth - translatedThreshold - chart.plotLeft,
|
14614
|
+
y: 0,
|
14615
|
+
width: chartWidth,
|
14616
|
+
height: chartHeight
|
14617
|
+
};
|
14618
|
+
below = {
|
14619
|
+
x: translatedThreshold + chart.plotLeft - chartWidth,
|
14620
|
+
y: 0,
|
14621
|
+
width: chart.plotLeft + translatedThreshold,
|
14622
|
+
height: chartWidth
|
14623
|
+
};
|
14624
|
+
}
|
14188
14625
|
}
|
14189
14626
|
|
14190
|
-
if (
|
14627
|
+
if (yAxis.reversed) {
|
14191
14628
|
posAttr = below;
|
14192
14629
|
negAttr = above;
|
14193
14630
|
} else {
|
@@ -14203,7 +14640,7 @@ Series.prototype = {
|
|
14203
14640
|
this.posClip = posClip = renderer.clipRect(posAttr);
|
14204
14641
|
this.negClip = negClip = renderer.clipRect(negAttr);
|
14205
14642
|
|
14206
|
-
if (graph) {
|
14643
|
+
if (graph && this.graphNeg) {
|
14207
14644
|
graph.clip(posClip);
|
14208
14645
|
this.graphNeg.clip(negClip);
|
14209
14646
|
}
|
@@ -14260,14 +14697,11 @@ Series.prototype = {
|
|
14260
14697
|
*/
|
14261
14698
|
plotGroup: function (prop, name, visibility, zIndex, parent) {
|
14262
14699
|
var group = this[prop],
|
14263
|
-
isNew = !group
|
14264
|
-
chart = this.chart,
|
14265
|
-
xAxis = this.xAxis,
|
14266
|
-
yAxis = this.yAxis;
|
14700
|
+
isNew = !group;
|
14267
14701
|
|
14268
14702
|
// Generate it on first call
|
14269
14703
|
if (isNew) {
|
14270
|
-
this[prop] = group = chart.renderer.g(name)
|
14704
|
+
this[prop] = group = this.chart.renderer.g(name)
|
14271
14705
|
.attr({
|
14272
14706
|
visibility: visibility,
|
14273
14707
|
zIndex: zIndex || 0.1 // IE8 needs this
|
@@ -14275,14 +14709,20 @@ Series.prototype = {
|
|
14275
14709
|
.add(parent);
|
14276
14710
|
}
|
14277
14711
|
// Place it on first and subsequent (redraw) calls
|
14278
|
-
group[isNew ? 'attr' : 'animate'](
|
14279
|
-
|
14280
|
-
|
14712
|
+
group[isNew ? 'attr' : 'animate'](this.getPlotBox());
|
14713
|
+
return group;
|
14714
|
+
},
|
14715
|
+
|
14716
|
+
/**
|
14717
|
+
* Get the translation and scale for the plot area of this series
|
14718
|
+
*/
|
14719
|
+
getPlotBox: function () {
|
14720
|
+
return {
|
14721
|
+
translateX: this.xAxis ? this.xAxis.left : this.chart.plotLeft,
|
14722
|
+
translateY: this.yAxis ? this.yAxis.top : this.chart.plotTop,
|
14281
14723
|
scaleX: 1, // #1623
|
14282
14724
|
scaleY: 1
|
14283
|
-
}
|
14284
|
-
return group;
|
14285
|
-
|
14725
|
+
};
|
14286
14726
|
},
|
14287
14727
|
|
14288
14728
|
/**
|
@@ -14596,9 +15036,8 @@ Series.prototype = {
|
|
14596
15036
|
|
14597
15037
|
} else { // create
|
14598
15038
|
|
14599
|
-
series.tracker =
|
15039
|
+
series.tracker = renderer.path(trackerPath)
|
14600
15040
|
.attr({
|
14601
|
-
'class': PREFIX + 'tracker',
|
14602
15041
|
'stroke-linejoin': 'round', // #1225
|
14603
15042
|
visibility: series.visible ? VISIBLE : HIDDEN,
|
14604
15043
|
stroke: TRACKER_FILL,
|
@@ -14606,15 +15045,20 @@ Series.prototype = {
|
|
14606
15045
|
'stroke-width' : options.lineWidth + (trackByArea ? 0 : 2 * snap),
|
14607
15046
|
zIndex: 2
|
14608
15047
|
})
|
14609
|
-
.
|
14610
|
-
.on('mouseover', onMouseOver)
|
14611
|
-
.on('mouseout', function (e) { pointer.onTrackerMouseOut(e); })
|
14612
|
-
.css(css)
|
14613
|
-
.add(series.markerGroup);
|
15048
|
+
.add(series.group);
|
14614
15049
|
|
14615
|
-
|
14616
|
-
|
14617
|
-
|
15050
|
+
// The tracker is added to the series group, which is clipped, but is covered
|
15051
|
+
// by the marker group. So the marker group also needs to capture events.
|
15052
|
+
each([series.tracker, series.markerGroup], function (tracker) {
|
15053
|
+
tracker.addClass(PREFIX + 'tracker')
|
15054
|
+
.on('mouseover', onMouseOver)
|
15055
|
+
.on('mouseout', function (e) { pointer.onTrackerMouseOut(e); })
|
15056
|
+
.css(css);
|
15057
|
+
|
15058
|
+
if (hasTouch) {
|
15059
|
+
tracker.on('touchstart', onMouseOver);
|
15060
|
+
}
|
15061
|
+
});
|
14618
15062
|
}
|
14619
15063
|
|
14620
15064
|
}
|
@@ -14661,6 +15105,7 @@ var AreaSeries = extendClass(Series, {
|
|
14661
15105
|
plotX,
|
14662
15106
|
plotY,
|
14663
15107
|
points = this.points,
|
15108
|
+
val,
|
14664
15109
|
i,
|
14665
15110
|
x;
|
14666
15111
|
|
@@ -14688,7 +15133,8 @@ var AreaSeries = extendClass(Series, {
|
|
14688
15133
|
// correctly.
|
14689
15134
|
} else {
|
14690
15135
|
plotX = xAxis.translate(x);
|
14691
|
-
|
15136
|
+
val = stack[x].percent ? (stack[x].total ? stack[x].cum * 100 / stack[x].total : 0) : stack[x].cum; // #1991
|
15137
|
+
plotY = yAxis.toPixels(val, true);
|
14692
15138
|
segment.push({
|
14693
15139
|
y: null,
|
14694
15140
|
plotX: plotX,
|
@@ -14784,10 +15230,11 @@ var AreaSeries = extendClass(Series, {
|
|
14784
15230
|
areaPath = this.areaPath,
|
14785
15231
|
options = this.options,
|
14786
15232
|
negativeColor = options.negativeColor,
|
15233
|
+
negativeFillColor = options.negativeFillColor,
|
14787
15234
|
props = [['area', this.color, options.fillColor]]; // area name, main color, fill color
|
14788
15235
|
|
14789
|
-
if (negativeColor) {
|
14790
|
-
props.push(['areaNeg',
|
15236
|
+
if (negativeColor || negativeFillColor) {
|
15237
|
+
props.push(['areaNeg', negativeColor, negativeFillColor]);
|
14791
15238
|
}
|
14792
15239
|
|
14793
15240
|
each(props, function (prop) {
|
@@ -14803,7 +15250,7 @@ var AreaSeries = extendClass(Series, {
|
|
14803
15250
|
.attr({
|
14804
15251
|
fill: pick(
|
14805
15252
|
prop[2],
|
14806
|
-
Color(prop[1]).setOpacity(options.fillOpacity
|
15253
|
+
Color(prop[1]).setOpacity(pick(options.fillOpacity, 0.75)).get()
|
14807
15254
|
),
|
14808
15255
|
zIndex: 0 // #1069
|
14809
15256
|
}).add(series.group);
|
@@ -14973,7 +15420,8 @@ var areaProto = AreaSeries.prototype,
|
|
14973
15420
|
// Mix in methods from the area series
|
14974
15421
|
getSegmentPath: areaProto.getSegmentPath,
|
14975
15422
|
closeSegment: areaProto.closeSegment,
|
14976
|
-
drawGraph: areaProto.drawGraph
|
15423
|
+
drawGraph: areaProto.drawGraph,
|
15424
|
+
drawLegendSymbol: areaProto.drawLegendSymbol
|
14977
15425
|
});
|
14978
15426
|
seriesTypes.areaspline = AreaSplineSeries;
|
14979
15427
|
|
@@ -15018,8 +15466,6 @@ defaultPlotOptions.column = merge(defaultSeriesOptions, {
|
|
15018
15466
|
*/
|
15019
15467
|
var ColumnSeries = extendClass(Series, {
|
15020
15468
|
type: 'column',
|
15021
|
-
tooltipOutsidePlot: true,
|
15022
|
-
requireSorting: false,
|
15023
15469
|
pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
|
15024
15470
|
stroke: 'borderColor',
|
15025
15471
|
'stroke-width': 'borderWidth',
|
@@ -15027,6 +15473,8 @@ var ColumnSeries = extendClass(Series, {
|
|
15027
15473
|
r: 'borderRadius'
|
15028
15474
|
},
|
15029
15475
|
trackerGroups: ['group', 'dataLabelsGroup'],
|
15476
|
+
negStacks: true, // use separate negative stacks, unlike area stacks where a negative
|
15477
|
+
// point is substracted from previous (#1910)
|
15030
15478
|
|
15031
15479
|
/**
|
15032
15480
|
* Initialize the series
|
@@ -15055,9 +15503,9 @@ var ColumnSeries = extendClass(Series, {
|
|
15055
15503
|
getColumnMetrics: function () {
|
15056
15504
|
|
15057
15505
|
var series = this,
|
15058
|
-
chart = series.chart,
|
15059
15506
|
options = series.options,
|
15060
|
-
xAxis =
|
15507
|
+
xAxis = series.xAxis,
|
15508
|
+
yAxis = series.yAxis,
|
15061
15509
|
reversedXAxis = xAxis.reversed,
|
15062
15510
|
stackKey,
|
15063
15511
|
stackGroups = {},
|
@@ -15070,10 +15518,11 @@ var ColumnSeries = extendClass(Series, {
|
|
15070
15518
|
if (options.grouping === false) {
|
15071
15519
|
columnCount = 1;
|
15072
15520
|
} else {
|
15073
|
-
each(chart.series, function (otherSeries) {
|
15074
|
-
var otherOptions = otherSeries.options
|
15521
|
+
each(series.chart.series, function (otherSeries) {
|
15522
|
+
var otherOptions = otherSeries.options,
|
15523
|
+
otherYAxis = otherSeries.yAxis;
|
15075
15524
|
if (otherSeries.type === series.type && otherSeries.visible &&
|
15076
|
-
|
15525
|
+
yAxis.len === otherYAxis.len && yAxis.pos === otherYAxis.pos) { // #642, #2086
|
15077
15526
|
if (otherOptions.stacking) {
|
15078
15527
|
stackKey = otherSeries.stackKey;
|
15079
15528
|
if (stackGroups[stackKey] === UNDEFINED) {
|
@@ -15121,7 +15570,6 @@ var ColumnSeries = extendClass(Series, {
|
|
15121
15570
|
var series = this,
|
15122
15571
|
chart = series.chart,
|
15123
15572
|
options = series.options,
|
15124
|
-
stacking = options.stacking,
|
15125
15573
|
borderWidth = options.borderWidth,
|
15126
15574
|
yAxis = series.yAxis,
|
15127
15575
|
threshold = options.threshold,
|
@@ -15129,8 +15577,14 @@ var ColumnSeries = extendClass(Series, {
|
|
15129
15577
|
minPointLength = pick(options.minPointLength, 5),
|
15130
15578
|
metrics = series.getColumnMetrics(),
|
15131
15579
|
pointWidth = metrics.width,
|
15132
|
-
barW = mathCeil(mathMax(pointWidth, 1 + 2 * borderWidth)), // rounded and postprocessed for border width
|
15133
|
-
pointXOffset = metrics.offset
|
15580
|
+
seriesBarW = series.barW = mathCeil(mathMax(pointWidth, 1 + 2 * borderWidth)), // rounded and postprocessed for border width
|
15581
|
+
pointXOffset = series.pointXOffset = metrics.offset,
|
15582
|
+
xCrisp = -(borderWidth % 2 ? 0.5 : 0),
|
15583
|
+
yCrisp = borderWidth % 2 ? 0.5 : 1;
|
15584
|
+
|
15585
|
+
if (chart.renderer.isVML && chart.inverted) {
|
15586
|
+
yCrisp += 1;
|
15587
|
+
}
|
15134
15588
|
|
15135
15589
|
Series.prototype.translate.apply(series);
|
15136
15590
|
|
@@ -15139,39 +15593,59 @@ var ColumnSeries = extendClass(Series, {
|
|
15139
15593
|
var plotY = mathMin(mathMax(-999, point.plotY), yAxis.len + 999), // Don't draw too far outside plot area (#1303)
|
15140
15594
|
yBottom = pick(point.yBottom, translatedThreshold),
|
15141
15595
|
barX = point.plotX + pointXOffset,
|
15142
|
-
|
15143
|
-
|
15144
|
-
|
15145
|
-
|
15146
|
-
|
15147
|
-
|
15148
|
-
|
15149
|
-
|
15150
|
-
|
15151
|
-
|
15152
|
-
// handle options.minPointLength
|
15596
|
+
barW = seriesBarW,
|
15597
|
+
barY = mathMin(plotY, yBottom),
|
15598
|
+
right,
|
15599
|
+
bottom,
|
15600
|
+
fromTop,
|
15601
|
+
fromLeft,
|
15602
|
+
barH = mathMax(plotY, yBottom) - barY;
|
15603
|
+
|
15604
|
+
// Handle options.minPointLength
|
15153
15605
|
if (mathAbs(barH) < minPointLength) {
|
15154
15606
|
if (minPointLength) {
|
15155
15607
|
barH = minPointLength;
|
15156
15608
|
barY =
|
15157
|
-
mathAbs(barY - translatedThreshold) > minPointLength ? // stacked
|
15609
|
+
mathRound(mathAbs(barY - translatedThreshold) > minPointLength ? // stacked
|
15158
15610
|
yBottom - minPointLength : // keep position
|
15159
|
-
translatedThreshold - (yAxis.translate(point.y, 0, 1, 0, 1) <= translatedThreshold ? minPointLength : 0); // use exact yAxis.translation (#1485)
|
15611
|
+
translatedThreshold - (yAxis.translate(point.y, 0, 1, 0, 1) <= translatedThreshold ? minPointLength : 0)); // use exact yAxis.translation (#1485)
|
15160
15612
|
}
|
15161
15613
|
}
|
15162
15614
|
|
15615
|
+
// Cache for access in polar
|
15163
15616
|
point.barX = barX;
|
15164
15617
|
point.pointWidth = pointWidth;
|
15165
15618
|
|
15166
|
-
|
15167
|
-
|
15168
|
-
|
15169
|
-
|
15170
|
-
|
15171
|
-
|
15172
|
-
|
15619
|
+
|
15620
|
+
// Round off to obtain crisp edges
|
15621
|
+
fromLeft = mathAbs(barX) < 0.5;
|
15622
|
+
right = mathRound(barX + barW) + xCrisp;
|
15623
|
+
barX = mathRound(barX) + xCrisp;
|
15624
|
+
barW = right - barX;
|
15625
|
+
|
15626
|
+
fromTop = mathAbs(barY) < 0.5;
|
15627
|
+
bottom = mathRound(barY + barH) + yCrisp;
|
15628
|
+
barY = mathRound(barY) + yCrisp;
|
15629
|
+
barH = bottom - barY;
|
15630
|
+
|
15631
|
+
// Top and left edges are exceptions
|
15632
|
+
if (fromLeft) {
|
15633
|
+
barX += 1;
|
15634
|
+
barW -= 1;
|
15635
|
+
}
|
15636
|
+
if (fromTop) {
|
15637
|
+
barY -= 1;
|
15638
|
+
barH += 1;
|
15173
15639
|
}
|
15174
15640
|
|
15641
|
+
// Register shape type and arguments to be used in drawPoints
|
15642
|
+
point.shapeType = 'rect';
|
15643
|
+
point.shapeArgs = {
|
15644
|
+
x: barX,
|
15645
|
+
y: barY,
|
15646
|
+
width: barW,
|
15647
|
+
height: barH
|
15648
|
+
};
|
15175
15649
|
});
|
15176
15650
|
|
15177
15651
|
},
|
@@ -15232,20 +15706,22 @@ var ColumnSeries = extendClass(Series, {
|
|
15232
15706
|
*/
|
15233
15707
|
drawTracker: function () {
|
15234
15708
|
var series = this,
|
15235
|
-
|
15709
|
+
chart = series.chart,
|
15710
|
+
pointer = chart.pointer,
|
15236
15711
|
cursor = series.options.cursor,
|
15237
15712
|
css = cursor && { cursor: cursor },
|
15238
15713
|
onMouseOver = function (e) {
|
15239
15714
|
var target = e.target,
|
15240
15715
|
point;
|
15241
15716
|
|
15242
|
-
series
|
15243
|
-
|
15717
|
+
if (chart.hoverSeries !== series) {
|
15718
|
+
series.onMouseOver();
|
15719
|
+
}
|
15244
15720
|
while (target && !point) {
|
15245
15721
|
point = target.point;
|
15246
15722
|
target = target.parentNode;
|
15247
15723
|
}
|
15248
|
-
if (point !== UNDEFINED) { // undefined on graph in scatterchart
|
15724
|
+
if (point !== UNDEFINED && point !== chart.hoverPoint) { // undefined on graph in scatterchart
|
15249
15725
|
point.onMouseOver(e);
|
15250
15726
|
}
|
15251
15727
|
};
|
@@ -15274,8 +15750,6 @@ var ColumnSeries = extendClass(Series, {
|
|
15274
15750
|
}
|
15275
15751
|
}
|
15276
15752
|
});
|
15277
|
-
|
15278
|
-
} else {
|
15279
15753
|
series._hasTracking = true;
|
15280
15754
|
}
|
15281
15755
|
},
|
@@ -15495,8 +15969,8 @@ var PiePoint = extendClass(Point, {
|
|
15495
15969
|
});
|
15496
15970
|
|
15497
15971
|
// add event listener for select
|
15498
|
-
toggleSlice = function () {
|
15499
|
-
point.slice();
|
15972
|
+
toggleSlice = function (e) {
|
15973
|
+
point.slice(e.type === 'select');
|
15500
15974
|
};
|
15501
15975
|
addEvent(point, 'select', toggleSlice);
|
15502
15976
|
addEvent(point, 'unselect', toggleSlice);
|
@@ -15641,6 +16115,39 @@ var PieSeries = {
|
|
15641
16115
|
this.chart.redraw();
|
15642
16116
|
}
|
15643
16117
|
},
|
16118
|
+
|
16119
|
+
/**
|
16120
|
+
* Extend the generatePoints method by adding total and percentage properties to each point
|
16121
|
+
*/
|
16122
|
+
generatePoints: function () {
|
16123
|
+
var i,
|
16124
|
+
total = 0,
|
16125
|
+
points,
|
16126
|
+
len,
|
16127
|
+
point,
|
16128
|
+
ignoreHiddenPoint = this.options.ignoreHiddenPoint;
|
16129
|
+
|
16130
|
+
Series.prototype.generatePoints.call(this);
|
16131
|
+
|
16132
|
+
// Populate local vars
|
16133
|
+
points = this.points;
|
16134
|
+
len = points.length;
|
16135
|
+
|
16136
|
+
// Get the total sum
|
16137
|
+
for (i = 0; i < len; i++) {
|
16138
|
+
point = points[i];
|
16139
|
+
total += (ignoreHiddenPoint && !point.visible) ? 0 : point.y;
|
16140
|
+
}
|
16141
|
+
this.total = total;
|
16142
|
+
|
16143
|
+
// Set each point's properties
|
16144
|
+
for (i = 0; i < len; i++) {
|
16145
|
+
point = points[i];
|
16146
|
+
point.percentage = total > 0 ? (point.y / total) * 100 : 0;
|
16147
|
+
point.total = total;
|
16148
|
+
}
|
16149
|
+
|
16150
|
+
},
|
15644
16151
|
|
15645
16152
|
/**
|
15646
16153
|
* Get the center of the pie based on the size and center options relative to the
|
@@ -15679,8 +16186,7 @@ var PieSeries = {
|
|
15679
16186
|
translate: function (positions) {
|
15680
16187
|
this.generatePoints();
|
15681
16188
|
|
15682
|
-
var
|
15683
|
-
series = this,
|
16189
|
+
var series = this,
|
15684
16190
|
cumulative = 0,
|
15685
16191
|
precision = 1000, // issue #172
|
15686
16192
|
options = series.options,
|
@@ -15692,7 +16198,6 @@ var PieSeries = {
|
|
15692
16198
|
startAngleRad = series.startAngleRad = mathPI / 180 * ((options.startAngle || 0) % 360 - 90),
|
15693
16199
|
points = series.points,
|
15694
16200
|
circ = 2 * mathPI,
|
15695
|
-
fraction,
|
15696
16201
|
radiusX, // the x component of the radius vector for a given point
|
15697
16202
|
radiusY,
|
15698
16203
|
labelDistance = options.dataLabels.distance,
|
@@ -15718,22 +16223,15 @@ var PieSeries = {
|
|
15718
16223
|
(mathCos(angle) * (positions[2] / 2 + labelDistance));
|
15719
16224
|
};
|
15720
16225
|
|
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
16226
|
// Calculate the geometry for each point
|
15728
16227
|
for (i = 0; i < len; i++) {
|
15729
16228
|
|
15730
16229
|
point = points[i];
|
15731
16230
|
|
15732
16231
|
// set start and end angle
|
15733
|
-
fraction = total ? point.y / total : 0;
|
15734
16232
|
start = mathRound((startAngleRad + (cumulative * circ)) * precision) / precision;
|
15735
16233
|
if (!ignoreHiddenPoint || point.visible) {
|
15736
|
-
cumulative +=
|
16234
|
+
cumulative += point.percentage / 100;
|
15737
16235
|
}
|
15738
16236
|
end = mathRound((startAngleRad + (cumulative * circ)) * precision) / precision;
|
15739
16237
|
|
@@ -15783,10 +16281,6 @@ var PieSeries = {
|
|
15783
16281
|
point.half ? 'right' : 'left', // alignment
|
15784
16282
|
angle // center angle
|
15785
16283
|
];
|
15786
|
-
|
15787
|
-
// API properties
|
15788
|
-
point.percentage = fraction * 100;
|
15789
|
-
point.total = total;
|
15790
16284
|
|
15791
16285
|
}
|
15792
16286
|
|
@@ -15909,7 +16403,7 @@ var PieSeries = {
|
|
15909
16403
|
};
|
15910
16404
|
|
15911
16405
|
// get out if not enabled
|
15912
|
-
if (!options.enabled && !series._hasPointLabels) {
|
16406
|
+
if (!series.visible || (!options.enabled && !series._hasPointLabels)) {
|
15913
16407
|
return;
|
15914
16408
|
}
|
15915
16409
|
|