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