highcharts-rails 4.2.0 → 4.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +37 -0
- data/app/assets/javascripts/highcharts.js +690 -489
- data/app/assets/javascripts/highcharts/highcharts-3d.js +9 -8
- data/app/assets/javascripts/highcharts/highcharts-more.js +88 -99
- data/app/assets/javascripts/highcharts/modules/boost.js +88 -89
- data/app/assets/javascripts/highcharts/modules/broken-axis.js +3 -3
- data/app/assets/javascripts/highcharts/modules/canvas-tools.js +2 -2
- data/app/assets/javascripts/highcharts/modules/data.js +2 -2
- data/app/assets/javascripts/highcharts/modules/exporting.js +5 -4
- data/app/assets/javascripts/highcharts/modules/funnel.js +17 -11
- data/app/assets/javascripts/highcharts/modules/heatmap.js +2 -2
- data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +2 -2
- data/app/assets/javascripts/highcharts/modules/offline-exporting.js +58 -38
- data/app/assets/javascripts/highcharts/modules/solid-gauge.js +15 -10
- data/app/assets/javascripts/highcharts/modules/treemap.js +1 -1
- data/lib/highcharts/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c72cc1681a1147d68993e02378628c13ea2da7f
|
4
|
+
data.tar.gz: ed6de8e4c3f8c211ea04f901ed0f4c8c1c89c8d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd9e2637e11c8b4fa254e79431c264e14bcb82eec93dadcf855d333be699abbc23d797239751c2bbe1b5dcded9c383678c4e2dfdd2a277b4a46f6ed5e0f9a01d
|
7
|
+
data.tar.gz: f51303cfe27bf5c5f597bc41016c22ae4ea8c5e68892995750e22a62218c297b771a60aad923bf43e1379961f3f94670fcdc2903ab8159349a971bf47fc2ac9b
|
data/CHANGELOG.markdown
CHANGED
@@ -1,3 +1,40 @@
|
|
1
|
+
# 4.2.2 / 2016-04-09
|
2
|
+
|
3
|
+
* Updated Highcharts to 4.2.2 (2016-02-04)
|
4
|
+
* Added new option, linecap, to allow round corners on solid gauge.
|
5
|
+
* Changed chart.load event to wait for external symbol images, so that their size is set correctly in the SVG. This comes in handy for export and server generated images.
|
6
|
+
* Fixed #1977, bubble series shadow was not moved when moving bubbles.
|
7
|
+
* Fixed #4077, panning was not supported on inverted charts.
|
8
|
+
* Fixed #4086, tick marks and labels were not trimmed to axis extremes when tickPositions option was used.
|
9
|
+
* Fixed #4573, wrong number rounding in some cases.
|
10
|
+
* Fixed #4622, updating point didn't change legend's item.
|
11
|
+
* Fixed #4759, a regression which did not update point markers in point.update().
|
12
|
+
* Fixed #4779, data labels were not cropped when rotated.
|
13
|
+
* Fixed #4859, no easy way to catch offline export failed exception.
|
14
|
+
* Fixed #4861, where offline export would fail in some cases with embedded images.
|
15
|
+
* Fixed #4870, column width calculation not correct on logarithmic X axis.
|
16
|
+
* Fixed #4886, pie slicing failed and tooltip disappeared too quickly on Windows phone.
|
17
|
+
* Fixed #4888, fillOpacity of 0 did not take effect on area charts.
|
18
|
+
* Fixed #4889, plotLine and plotBand should be rendered with higher zIndex than frames in 3D view.
|
19
|
+
* Fixed #4890, originalEvent was missing from selection event since 4.2.0.
|
20
|
+
* Fixed #4898, rounding issues with Y axis causing columns to exceed threshold value, and plot lines to be filtered out.
|
21
|
+
* Fixed #4904, async loading of points kept running after chart was destroyed in boost module.
|
22
|
+
* Fixed #4905, pie data labels were not hidden when scaling down.
|
23
|
+
* Fixed #4906, chart did not zoom when drag and drop was dropped on a different chart.
|
24
|
+
* Fixed #4911, false detection of overlapping data labels in multiple panes.
|
25
|
+
* Fixed #4912, specific export data label style didn't take effect for pies.
|
26
|
+
* Fixed #4913, regression in box size detection causing chart to overflow the container in some cases.
|
27
|
+
* Fixed #4914, boost module loadingDiv was destroyed before redraw was finished.
|
28
|
+
* Fixed #4918, spline curved wrongly when plotX or Y had a value of 0.
|
29
|
+
* Fixed #4920, polar X axis labels misaligned after chart redraw.
|
30
|
+
* Fixed #4927, crosshair only worked for one Y axis.
|
31
|
+
* Fixed #4928, HTML label lengths were not reset on resize.
|
32
|
+
* Fixed #4929, halo covered point and disallowed point click in IE8.
|
33
|
+
* Fixed #4938, HTML elements were missing visibility and opacity setters.
|
34
|
+
* Fixed #4951, X axis daily ticks did not render on midnight around a DST crossover when the getTimezoneOffset callback was used.
|
35
|
+
* Fixed #4955, export button was hidden by category crosshair.
|
36
|
+
* Fixed #2069, null points in stacked areas were rendered as zero instead of gaps.
|
37
|
+
|
1
38
|
# 4.2.0 / 2016-04-09
|
2
39
|
|
3
40
|
* Updated Highcharts to 4.2.0 (2015-12-15)
|
@@ -2,9 +2,9 @@
|
|
2
2
|
// @compilation_level SIMPLE_OPTIMIZATIONS
|
3
3
|
|
4
4
|
/**
|
5
|
-
* @license Highcharts JS v4.2.
|
5
|
+
* @license Highcharts JS v4.2.2 (2016-02-04)
|
6
6
|
*
|
7
|
-
* (c) 2009-
|
7
|
+
* (c) 2009-2016 Torstein Honsi
|
8
8
|
*
|
9
9
|
* License: www.highcharts.com/license
|
10
10
|
*/
|
@@ -59,7 +59,7 @@
|
|
59
59
|
charts = [],
|
60
60
|
chartCount = 0,
|
61
61
|
PRODUCT = 'Highcharts',
|
62
|
-
VERSION = '4.2.
|
62
|
+
VERSION = '4.2.2',
|
63
63
|
|
64
64
|
// some constants for frequently used strings
|
65
65
|
DIV = 'div',
|
@@ -312,12 +312,12 @@
|
|
312
312
|
i,
|
313
313
|
start = fromD.split(' '),
|
314
314
|
end = [].concat(toD), // copy
|
315
|
-
|
316
|
-
|
315
|
+
isArea = elem.isArea,
|
316
|
+
positionFactor = isArea ? 2 : 1,
|
317
317
|
sixify = function (arr) { // in splines make move points have six parameters like bezier curves
|
318
318
|
i = arr.length;
|
319
319
|
while (i--) {
|
320
|
-
if (arr[i] === M) {
|
320
|
+
if (arr[i] === M || arr[i] === L) {
|
321
321
|
arr.splice(i + 1, 0, arr[i + 1], arr[i + 2], arr[i + 1], arr[i + 2]);
|
322
322
|
}
|
323
323
|
}
|
@@ -328,39 +328,49 @@
|
|
328
328
|
sixify(end);
|
329
329
|
}
|
330
330
|
|
331
|
-
//
|
332
|
-
|
333
|
-
startBaseLine = start.splice(start.length - 6, 6);
|
334
|
-
endBaseLine = end.splice(end.length - 6, 6);
|
335
|
-
}
|
336
|
-
|
337
|
-
// if shifting points, prepend a dummy point to the end path
|
331
|
+
// If shifting points, prepend a dummy point to the end path. For areas,
|
332
|
+
// prepend both at the beginning and end of the path.
|
338
333
|
if (shift <= end.length / numParams && start.length === end.length) {
|
339
334
|
while (shift--) {
|
340
|
-
end =
|
335
|
+
end = end.slice(0, numParams).concat(end);
|
336
|
+
if (isArea) {
|
337
|
+
end = end.concat(end.slice(end.length - numParams));
|
338
|
+
}
|
341
339
|
}
|
342
340
|
}
|
343
341
|
elem.shift = 0; // reset for following animations
|
344
342
|
|
345
|
-
|
343
|
+
|
344
|
+
// Copy and append last point until the length matches the end length
|
346
345
|
if (start.length) {
|
347
346
|
endLength = end.length;
|
348
347
|
while (start.length < endLength) {
|
349
348
|
|
350
|
-
//
|
351
|
-
|
352
|
-
|
349
|
+
// Pull out the slice that is going to be appended or inserted. In a line graph,
|
350
|
+
// the positionFactor is 1, and the last point is sliced out. In an area graph,
|
351
|
+
// the positionFactor is 2, causing the middle two points to be sliced out, since
|
352
|
+
// an area path starts at left, follows the upper path then turns and follows the
|
353
|
+
// bottom back.
|
354
|
+
slice = start.slice().splice(
|
355
|
+
(start.length / positionFactor) - numParams,
|
356
|
+
numParams * positionFactor
|
357
|
+
);
|
358
|
+
|
359
|
+
// Disable first control point
|
360
|
+
if (bezier) {
|
353
361
|
slice[numParams - 6] = slice[numParams - 2];
|
354
362
|
slice[numParams - 5] = slice[numParams - 1];
|
355
363
|
}
|
356
|
-
|
364
|
+
|
365
|
+
// Now insert the slice, either in the middle (for areas) or at the end (for lines)
|
366
|
+
[].splice.apply(
|
367
|
+
start,
|
368
|
+
[(start.length / positionFactor), 0].concat(slice)
|
369
|
+
);
|
370
|
+
|
357
371
|
}
|
358
372
|
}
|
359
373
|
|
360
|
-
if (startBaseLine) { // append the base lines for areas
|
361
|
-
start = start.concat(startBaseLine);
|
362
|
-
end = end.concat(endBaseLine);
|
363
|
-
}
|
364
374
|
return [start, end];
|
365
375
|
}
|
366
376
|
}; // End of Fx prototype
|
@@ -1001,24 +1011,55 @@
|
|
1001
1011
|
* Format a number and return a string based on input settings
|
1002
1012
|
* @param {Number} number The input number to format
|
1003
1013
|
* @param {Number} decimals The amount of decimals
|
1004
|
-
* @param {String}
|
1014
|
+
* @param {String} decimalPoint The decimal point, defaults to the one given in the lang options
|
1005
1015
|
* @param {String} thousandsSep The thousands separator, defaults to the one given in the lang options
|
1006
1016
|
*/
|
1007
|
-
Highcharts.numberFormat = function (number, decimals,
|
1017
|
+
Highcharts.numberFormat = function (number, decimals, decimalPoint, thousandsSep) {
|
1018
|
+
|
1019
|
+
number = +number || 0;
|
1020
|
+
|
1008
1021
|
var lang = defaultOptions.lang,
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
+
origDec = (number.toString().split('.')[1] || '').length,
|
1023
|
+
decimalComponent,
|
1024
|
+
strinteger,
|
1025
|
+
thousands,
|
1026
|
+
absNumber = Math.abs(number),
|
1027
|
+
ret;
|
1028
|
+
|
1029
|
+
if (decimals === -1) {
|
1030
|
+
decimals = Math.min(origDec, 20); // Preserve decimals. Not huge numbers (#3793).
|
1031
|
+
} else if (isNaN(decimals)) {
|
1032
|
+
decimals = 2;
|
1033
|
+
}
|
1034
|
+
|
1035
|
+
// A string containing the positive integer component of the number
|
1036
|
+
strinteger = String(pInt(absNumber.toFixed(decimals)));
|
1037
|
+
|
1038
|
+
// Leftover after grouping into thousands. Can be 0, 1 or 3.
|
1039
|
+
thousands = strinteger.length > 3 ? strinteger.length % 3 : 0;
|
1040
|
+
|
1041
|
+
// Language
|
1042
|
+
decimalPoint = pick(decimalPoint, lang.decimalPoint);
|
1043
|
+
thousandsSep = pick(thousandsSep, lang.thousandsSep);
|
1044
|
+
|
1045
|
+
// Start building the return
|
1046
|
+
ret = number < 0 ? '-' : '';
|
1047
|
+
|
1048
|
+
// Add the leftover after grouping into thousands. For example, in the number 42 000 000,
|
1049
|
+
// this line adds 42.
|
1050
|
+
ret += thousands ? strinteger.substr(0, thousands) + thousandsSep : '';
|
1051
|
+
|
1052
|
+
// Add the remaining thousands groups, joined by the thousands separator
|
1053
|
+
ret += strinteger.substr(thousands).replace(/(\d{3})(?=\d)/g, '$1' + thousandsSep);
|
1054
|
+
|
1055
|
+
// Add the decimal point and the decimal component
|
1056
|
+
if (+decimals) {
|
1057
|
+
// Get the decimal component, and add power to avoid rounding errors with float numbers (#4573)
|
1058
|
+
decimalComponent = Math.abs(absNumber - strinteger + Math.pow(10, -Math.max(decimals, origDec) - 1));
|
1059
|
+
ret += decimalPoint + decimalComponent.toFixed(decimals).slice(2);
|
1060
|
+
}
|
1061
|
+
|
1062
|
+
return ret;
|
1022
1063
|
};
|
1023
1064
|
|
1024
1065
|
/**
|
@@ -1033,7 +1074,18 @@
|
|
1033
1074
|
* Internal method to return CSS value for given element and property
|
1034
1075
|
*/
|
1035
1076
|
getStyle = function (el, prop) {
|
1036
|
-
|
1077
|
+
|
1078
|
+
var style;
|
1079
|
+
|
1080
|
+
// For width and height, return the actual inner pixel size (#4913)
|
1081
|
+
if (prop === 'width') {
|
1082
|
+
return Math.min(el.offsetWidth, el.scrollWidth) - getStyle(el, 'padding-left') - getStyle(el, 'padding-right');
|
1083
|
+
} else if (prop === 'height') {
|
1084
|
+
return Math.min(el.offsetHeight, el.scrollHeight) - getStyle(el, 'padding-top') - getStyle(el, 'padding-bottom');
|
1085
|
+
}
|
1086
|
+
|
1087
|
+
// Otherwise, get the computed style
|
1088
|
+
style = win.getComputedStyle(el, undefined);
|
1037
1089
|
return style && pInt(style.getPropertyValue(prop));
|
1038
1090
|
};
|
1039
1091
|
|
@@ -1481,7 +1533,7 @@
|
|
1481
1533
|
useUTC: true,
|
1482
1534
|
//timezoneOffset: 0,
|
1483
1535
|
canvasToolsURL: 'http://code.highcharts.com/modules/canvas-tools.js',
|
1484
|
-
VMLRadialGradientURL: 'http://code.highcharts.com/4.2.
|
1536
|
+
VMLRadialGradientURL: 'http://code.highcharts.com/4.2.2/gfx/vml-radial-gradient.png'
|
1485
1537
|
},
|
1486
1538
|
chart: {
|
1487
1539
|
//animation: true,
|
@@ -2181,8 +2233,6 @@
|
|
2181
2233
|
* and apply strokes to the copy.
|
2182
2234
|
*
|
2183
2235
|
* Contrast checks at http://jsfiddle.net/highcharts/43soe9m1/2/
|
2184
|
-
*
|
2185
|
-
* docs: update default, document the polyfill and the limitations on hex colors and pixel values, document contrast pseudo-color
|
2186
2236
|
*/
|
2187
2237
|
applyTextShadow: function (textShadow) {
|
2188
2238
|
var elem = this.element,
|
@@ -2277,7 +2327,8 @@
|
|
2277
2327
|
element = this.element,
|
2278
2328
|
hasSetSymbolSize,
|
2279
2329
|
ret = this,
|
2280
|
-
skipAttr
|
2330
|
+
skipAttr,
|
2331
|
+
setter;
|
2281
2332
|
|
2282
2333
|
// single key-value pair
|
2283
2334
|
if (typeof hash === 'string' && val !== UNDEFINED) {
|
@@ -2312,12 +2363,13 @@
|
|
2312
2363
|
}
|
2313
2364
|
|
2314
2365
|
if (!skipAttr) {
|
2315
|
-
|
2316
|
-
|
2366
|
+
setter = this[key + 'Setter'] || this._defaultSetter;
|
2367
|
+
setter.call(this, value, key, element);
|
2317
2368
|
|
2318
|
-
|
2319
|
-
|
2320
|
-
|
2369
|
+
// Let the shadow follow the main element
|
2370
|
+
if (this.shadows && /^(width|height|visibility|x|y|d|transform|cx|cy|r)$/.test(key)) {
|
2371
|
+
this.updateShadows(key, value, setter);
|
2372
|
+
}
|
2321
2373
|
}
|
2322
2374
|
}
|
2323
2375
|
|
@@ -2338,15 +2390,25 @@
|
|
2338
2390
|
return ret;
|
2339
2391
|
},
|
2340
2392
|
|
2341
|
-
|
2393
|
+
/**
|
2394
|
+
* Update the shadow elements with new attributes
|
2395
|
+
* @param {String} key The attribute name
|
2396
|
+
* @param {String|Number} value The value of the attribute
|
2397
|
+
* @param {Function} setter The setter function, inherited from the parent wrapper
|
2398
|
+
* @returns {undefined}
|
2399
|
+
*/
|
2400
|
+
updateShadows: function (key, value, setter) {
|
2342
2401
|
var shadows = this.shadows,
|
2343
2402
|
i = shadows.length;
|
2403
|
+
|
2344
2404
|
while (i--) {
|
2345
|
-
|
2346
|
-
|
2405
|
+
setter.call(
|
2406
|
+
null,
|
2347
2407
|
key === 'height' ?
|
2348
|
-
|
2349
|
-
|
2408
|
+
Math.max(value - (shadows[i].cutHeight || 0), 0) :
|
2409
|
+
key === 'd' ? this.d : value,
|
2410
|
+
key,
|
2411
|
+
shadows[i]
|
2350
2412
|
);
|
2351
2413
|
}
|
2352
2414
|
},
|
@@ -2717,7 +2779,7 @@
|
|
2717
2779
|
*/
|
2718
2780
|
getBBox: function (reload, rot) {
|
2719
2781
|
var wrapper = this,
|
2720
|
-
bBox
|
2782
|
+
bBox, // = wrapper.bBox,
|
2721
2783
|
renderer = wrapper.renderer,
|
2722
2784
|
width,
|
2723
2785
|
height,
|
@@ -3286,6 +3348,7 @@
|
|
3286
3348
|
renderer.gradients = {}; // Object where gradient SvgElements are stored
|
3287
3349
|
renderer.cache = {}; // Cache for numerical bounding boxes
|
3288
3350
|
renderer.cacheKeys = [];
|
3351
|
+
renderer.imgCount = 0;
|
3289
3352
|
|
3290
3353
|
renderer.setSize(width, height, false);
|
3291
3354
|
|
@@ -3832,12 +3895,11 @@
|
|
3832
3895
|
var attr = isObject(x) ? x : { x: x, y: y, r: r },
|
3833
3896
|
wrapper = this.createElement('circle');
|
3834
3897
|
|
3835
|
-
|
3836
|
-
|
3837
|
-
|
3838
|
-
wrapper.ySetter = function (value) {
|
3839
|
-
this.element.setAttribute('cy', value);
|
3898
|
+
// Setting x or y translates to cx and cy
|
3899
|
+
wrapper.xSetter = wrapper.ySetter = function (value, key, element) {
|
3900
|
+
element.setAttribute('c' + key, value);
|
3840
3901
|
};
|
3902
|
+
|
3841
3903
|
return wrapper.attr(attr);
|
3842
3904
|
},
|
3843
3905
|
|
@@ -3997,7 +4059,8 @@
|
|
3997
4059
|
*/
|
3998
4060
|
symbol: function (symbol, x, y, width, height, options) {
|
3999
4061
|
|
4000
|
-
var
|
4062
|
+
var ren = this,
|
4063
|
+
obj,
|
4001
4064
|
|
4002
4065
|
// get the symbol definition function
|
4003
4066
|
symbolFn = this.symbols[symbol],
|
@@ -4091,10 +4154,17 @@
|
|
4091
4154
|
if (this.parentNode) {
|
4092
4155
|
this.parentNode.removeChild(this);
|
4093
4156
|
}
|
4157
|
+
|
4158
|
+
// Fire the load event when all external images are loaded
|
4159
|
+
ren.imgCount--;
|
4160
|
+
if (!ren.imgCount) {
|
4161
|
+
charts[ren.chartIndex].onload();
|
4162
|
+
}
|
4094
4163
|
},
|
4095
4164
|
src: imageSrc
|
4096
4165
|
});
|
4097
4166
|
}
|
4167
|
+
this.imgCount++;
|
4098
4168
|
}
|
4099
4169
|
|
4100
4170
|
return obj;
|
@@ -4772,10 +4842,10 @@
|
|
4772
4842
|
|
4773
4843
|
if (elem.tagName === 'SPAN') {
|
4774
4844
|
|
4775
|
-
var
|
4776
|
-
rotation = wrapper.rotation,
|
4845
|
+
var rotation = wrapper.rotation,
|
4777
4846
|
baseline,
|
4778
4847
|
textWidth = pInt(wrapper.textWidth),
|
4848
|
+
whiteSpace = styles && styles.whiteSpace,
|
4779
4849
|
currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth, wrapper.textAlign].join(',');
|
4780
4850
|
|
4781
4851
|
if (currentTextTransform !== wrapper.cTT) { // do the calculations and DOM access only if properties changed
|
@@ -4788,19 +4858,24 @@
|
|
4788
4858
|
wrapper.setSpanRotation(rotation, alignCorrection, baseline);
|
4789
4859
|
}
|
4790
4860
|
|
4791
|
-
width = pick(wrapper.elemWidth, elem.offsetWidth);
|
4792
|
-
|
4793
4861
|
// Update textWidth
|
4794
|
-
if (
|
4862
|
+
if (elem.offsetWidth > textWidth && /[ \-]/.test(elem.textContent || elem.innerText)) { // #983, #1254
|
4795
4863
|
css(elem, {
|
4796
4864
|
width: textWidth + PX,
|
4797
4865
|
display: 'block',
|
4798
|
-
whiteSpace:
|
4866
|
+
whiteSpace: whiteSpace || 'normal' // #3331
|
4867
|
+
});
|
4868
|
+
wrapper.hasTextWidth = true;
|
4869
|
+
} else if (wrapper.hasTextWidth) { // #4928
|
4870
|
+
css(elem, {
|
4871
|
+
width: '',
|
4872
|
+
display: '',
|
4873
|
+
whiteSpace: whiteSpace || 'nowrap'
|
4799
4874
|
});
|
4800
|
-
|
4875
|
+
wrapper.hasTextWidth = false;
|
4801
4876
|
}
|
4802
4877
|
|
4803
|
-
wrapper.getSpanCorrection(
|
4878
|
+
wrapper.getSpanCorrection(wrapper.hasTextWidth ? textWidth : elem.offsetWidth, baseline, alignCorrection, rotation, align);
|
4804
4879
|
}
|
4805
4880
|
|
4806
4881
|
// apply position with correction
|
@@ -4853,7 +4928,17 @@
|
|
4853
4928
|
html: function (str, x, y) {
|
4854
4929
|
var wrapper = this.createElement('span'),
|
4855
4930
|
element = wrapper.element,
|
4856
|
-
renderer = wrapper.renderer
|
4931
|
+
renderer = wrapper.renderer,
|
4932
|
+
addSetters = function (element, style) {
|
4933
|
+
// These properties are set as attributes on the SVG group, and as
|
4934
|
+
// identical CSS properties on the div. (#3542)
|
4935
|
+
each(['opacity', 'visibility'], function (prop) {
|
4936
|
+
wrap(element, prop + 'Setter', function (proceed, value, key, elem) {
|
4937
|
+
proceed.call(this, value, key, elem);
|
4938
|
+
style[key] = value;
|
4939
|
+
});
|
4940
|
+
});
|
4941
|
+
};
|
4857
4942
|
|
4858
4943
|
// Text setter
|
4859
4944
|
wrapper.textSetter = function (value) {
|
@@ -4863,6 +4948,7 @@
|
|
4863
4948
|
element.innerHTML = this.textStr = value;
|
4864
4949
|
wrapper.htmlUpdateTransform();
|
4865
4950
|
};
|
4951
|
+
addSetters(wrapper, wrapper.element.style);
|
4866
4952
|
|
4867
4953
|
// Various setters which rely on update transform
|
4868
4954
|
wrapper.xSetter = wrapper.ySetter = wrapper.alignSetter = wrapper.rotationSetter = function (value, key) {
|
@@ -4952,15 +5038,7 @@
|
|
4952
5038
|
parentGroup.doTransform = true;
|
4953
5039
|
}
|
4954
5040
|
});
|
4955
|
-
|
4956
|
-
// These properties are set as attributes on the SVG group, and as
|
4957
|
-
// identical CSS properties on the div. (#3542)
|
4958
|
-
each(['opacity', 'visibility'], function (prop) {
|
4959
|
-
wrap(parentGroup, prop + 'Setter', function (proceed, value, key, elem) {
|
4960
|
-
proceed.call(this, value, key, elem);
|
4961
|
-
htmlGroupStyle[key] = value;
|
4962
|
-
});
|
4963
|
-
});
|
5041
|
+
addSetters(parentGroup, htmlGroupStyle);
|
4964
5042
|
});
|
4965
5043
|
|
4966
5044
|
}
|
@@ -5523,6 +5601,7 @@
|
|
5523
5601
|
renderer.gradients = {};
|
5524
5602
|
renderer.cache = {}; // Cache for numerical bounding boxes
|
5525
5603
|
renderer.cacheKeys = [];
|
5604
|
+
renderer.imgCount = 0;
|
5526
5605
|
|
5527
5606
|
|
5528
5607
|
renderer.setSize(width, height, false);
|
@@ -5973,7 +6052,7 @@
|
|
5973
6052
|
ret.push(
|
5974
6053
|
'e',
|
5975
6054
|
M,
|
5976
|
-
x
|
6055
|
+
x, // - innerRadius,
|
5977
6056
|
y// - innerRadius
|
5978
6057
|
);
|
5979
6058
|
}
|
@@ -6371,13 +6450,13 @@
|
|
6371
6450
|
*/
|
6372
6451
|
getMarkPath: function (x, y, tickLength, tickWidth, horiz, renderer) {
|
6373
6452
|
return renderer.crispLine([
|
6374
|
-
|
6375
|
-
|
6376
|
-
|
6377
|
-
|
6378
|
-
|
6379
|
-
|
6380
|
-
|
6453
|
+
M,
|
6454
|
+
x,
|
6455
|
+
y,
|
6456
|
+
L,
|
6457
|
+
x + (horiz ? 0 : -tickLength),
|
6458
|
+
y + (horiz ? tickLength : 0)
|
6459
|
+
], tickWidth);
|
6381
6460
|
},
|
6382
6461
|
|
6383
6462
|
/**
|
@@ -6561,12 +6640,8 @@
|
|
6561
6640
|
path = [],
|
6562
6641
|
addEvent,
|
6563
6642
|
eventType,
|
6564
|
-
xs,
|
6565
|
-
ys,
|
6566
|
-
x,
|
6567
|
-
y,
|
6568
6643
|
color = options.color,
|
6569
|
-
zIndex = options.zIndex,
|
6644
|
+
zIndex = pick(options.zIndex, 0),
|
6570
6645
|
events = options.events,
|
6571
6646
|
attribs = {},
|
6572
6647
|
renderer = axis.chart.renderer;
|
@@ -6602,9 +6677,7 @@
|
|
6602
6677
|
return;
|
6603
6678
|
}
|
6604
6679
|
// zIndex
|
6605
|
-
|
6606
|
-
attribs.zIndex = zIndex;
|
6607
|
-
}
|
6680
|
+
attribs.zIndex = zIndex;
|
6608
6681
|
|
6609
6682
|
// common for lines and bands
|
6610
6683
|
if (svgElem) {
|
@@ -6646,40 +6719,7 @@
|
|
6646
6719
|
rotation: horiz && !isBand && 90
|
6647
6720
|
}, optionsLabel);
|
6648
6721
|
|
6649
|
-
|
6650
|
-
if (!label) {
|
6651
|
-
attribs = {
|
6652
|
-
align: optionsLabel.textAlign || optionsLabel.align,
|
6653
|
-
rotation: optionsLabel.rotation
|
6654
|
-
};
|
6655
|
-
if (defined(zIndex)) {
|
6656
|
-
attribs.zIndex = zIndex;
|
6657
|
-
}
|
6658
|
-
plotLine.label = label = renderer.text(
|
6659
|
-
optionsLabel.text,
|
6660
|
-
0,
|
6661
|
-
0,
|
6662
|
-
optionsLabel.useHTML
|
6663
|
-
)
|
6664
|
-
.attr(attribs)
|
6665
|
-
.css(optionsLabel.style)
|
6666
|
-
.add();
|
6667
|
-
}
|
6668
|
-
|
6669
|
-
// get the bounding box and align the label
|
6670
|
-
// #3000 changed to better handle choice between plotband or plotline
|
6671
|
-
xs = [path[1], path[4], (isBand ? path[6] : path[1])];
|
6672
|
-
ys = [path[2], path[5], (isBand ? path[7] : path[2])];
|
6673
|
-
x = arrayMin(xs);
|
6674
|
-
y = arrayMin(ys);
|
6675
|
-
|
6676
|
-
label.align(optionsLabel, false, {
|
6677
|
-
x: x,
|
6678
|
-
y: y,
|
6679
|
-
width: arrayMax(xs) - x,
|
6680
|
-
height: arrayMax(ys) - y
|
6681
|
-
});
|
6682
|
-
label.show();
|
6722
|
+
this.renderLabel(optionsLabel, path, isBand, zIndex);
|
6683
6723
|
|
6684
6724
|
} else if (label) { // move out of sight
|
6685
6725
|
label.hide();
|
@@ -6689,6 +6729,55 @@
|
|
6689
6729
|
return plotLine;
|
6690
6730
|
},
|
6691
6731
|
|
6732
|
+
/**
|
6733
|
+
* Render and align label for plot line or band.
|
6734
|
+
*/
|
6735
|
+
renderLabel: function (optionsLabel, path, isBand, zIndex) {
|
6736
|
+
var plotLine = this,
|
6737
|
+
label = plotLine.label,
|
6738
|
+
renderer = plotLine.axis.chart.renderer,
|
6739
|
+
attribs,
|
6740
|
+
xs,
|
6741
|
+
ys,
|
6742
|
+
x,
|
6743
|
+
y;
|
6744
|
+
|
6745
|
+
// add the SVG element
|
6746
|
+
if (!label) {
|
6747
|
+
attribs = {
|
6748
|
+
align: optionsLabel.textAlign || optionsLabel.align,
|
6749
|
+
rotation: optionsLabel.rotation
|
6750
|
+
};
|
6751
|
+
|
6752
|
+
attribs.zIndex = zIndex;
|
6753
|
+
|
6754
|
+
plotLine.label = label = renderer.text(
|
6755
|
+
optionsLabel.text,
|
6756
|
+
0,
|
6757
|
+
0,
|
6758
|
+
optionsLabel.useHTML
|
6759
|
+
)
|
6760
|
+
.attr(attribs)
|
6761
|
+
.css(optionsLabel.style)
|
6762
|
+
.add();
|
6763
|
+
}
|
6764
|
+
|
6765
|
+
// get the bounding box and align the label
|
6766
|
+
// #3000 changed to better handle choice between plotband or plotline
|
6767
|
+
xs = [path[1], path[4], (isBand ? path[6] : path[1])];
|
6768
|
+
ys = [path[2], path[5], (isBand ? path[7] : path[2])];
|
6769
|
+
x = arrayMin(xs);
|
6770
|
+
y = arrayMin(ys);
|
6771
|
+
|
6772
|
+
label.align(optionsLabel, false, {
|
6773
|
+
x: x,
|
6774
|
+
y: y,
|
6775
|
+
width: arrayMax(xs) - x,
|
6776
|
+
height: arrayMax(ys) - y
|
6777
|
+
});
|
6778
|
+
label.show();
|
6779
|
+
},
|
6780
|
+
|
6692
6781
|
/**
|
6693
6782
|
* Remove the plot line or band
|
6694
6783
|
*/
|
@@ -7296,7 +7385,7 @@
|
|
7296
7385
|
localMin = old ? axis.oldMin : axis.min,
|
7297
7386
|
returnValue,
|
7298
7387
|
minPixelPadding = axis.minPixelPadding,
|
7299
|
-
doPostTranslate = (axis.
|
7388
|
+
doPostTranslate = (axis.isOrdinal || axis.isBroken || (axis.isLog && handleLog)) && axis.lin2val;
|
7300
7389
|
|
7301
7390
|
if (!localA) {
|
7302
7391
|
localA = axis.transA;
|
@@ -7961,14 +8050,18 @@
|
|
7961
8050
|
|
7962
8051
|
if (startOnTick) {
|
7963
8052
|
this.min = roundedMin;
|
7964
|
-
} else
|
7965
|
-
tickPositions
|
8053
|
+
} else {
|
8054
|
+
while (this.min - minPointOffset > tickPositions[0]) {
|
8055
|
+
tickPositions.shift();
|
8056
|
+
}
|
7966
8057
|
}
|
7967
8058
|
|
7968
8059
|
if (endOnTick) {
|
7969
8060
|
this.max = roundedMax;
|
7970
|
-
} else
|
7971
|
-
tickPositions.
|
8061
|
+
} else {
|
8062
|
+
while (this.max + minPointOffset < tickPositions[tickPositions.length - 1]) {
|
8063
|
+
tickPositions.pop();
|
8064
|
+
}
|
7972
8065
|
}
|
7973
8066
|
|
7974
8067
|
// If no tick are left, set one tick in the middle (#3195)
|
@@ -8225,12 +8318,13 @@
|
|
8225
8318
|
left = pick(options.left, chart.plotLeft + offsetLeft),
|
8226
8319
|
percentRegex = /%$/;
|
8227
8320
|
|
8228
|
-
// Check for percentage based input values
|
8321
|
+
// Check for percentage based input values. Rounding fixes problems with
|
8322
|
+
// column overflow and plot line filtering (#4898, #4899)
|
8229
8323
|
if (percentRegex.test(height)) {
|
8230
|
-
height = parseFloat(height) / 100 * chart.plotHeight;
|
8324
|
+
height = Math.round(parseFloat(height) / 100 * chart.plotHeight);
|
8231
8325
|
}
|
8232
8326
|
if (percentRegex.test(top)) {
|
8233
|
-
top = parseFloat(top) / 100 * chart.plotHeight + chart.plotTop;
|
8327
|
+
top = Math.round(parseFloat(top) / 100 * chart.plotHeight + chart.plotTop);
|
8234
8328
|
}
|
8235
8329
|
|
8236
8330
|
// Expose basic values to use in Series object and navigator
|
@@ -8454,7 +8548,10 @@
|
|
8454
8548
|
}
|
8455
8549
|
|
8456
8550
|
// Set the explicit or automatic label alignment
|
8457
|
-
this.labelAlign =
|
8551
|
+
this.labelAlign = labelOptions.align || this.autoLabelAlign(this.labelRotation);
|
8552
|
+
if (this.labelAlign) {
|
8553
|
+
attr.align = this.labelAlign;
|
8554
|
+
}
|
8458
8555
|
|
8459
8556
|
// Apply general and specific CSS
|
8460
8557
|
each(tickPositions, function (pos) {
|
@@ -8983,9 +9080,7 @@
|
|
8983
9080
|
// Disabled in options
|
8984
9081
|
!this.crosshair ||
|
8985
9082
|
// Snap
|
8986
|
-
((defined(point) || !pick(options.snap, true)) === false)
|
8987
|
-
// Not on this axis (#4095, #2888)
|
8988
|
-
(point && point.series && point.series[this.coll] !== this)
|
9083
|
+
((defined(point) || !pick(options.snap, true)) === false)
|
8989
9084
|
) {
|
8990
9085
|
this.hideCrosshair();
|
8991
9086
|
|
@@ -9122,6 +9217,7 @@
|
|
9122
9217
|
var time = minDate.getTime(),
|
9123
9218
|
minMonth = minDate[getMonth](),
|
9124
9219
|
minDateDate = minDate[getDate](),
|
9220
|
+
variableDayLength = !useUTC || !!getTimezoneOffset, // #4951
|
9125
9221
|
localTimezoneOffset = (timeUnits.day +
|
9126
9222
|
(useUTC ? getTZOffset(minDate) : minDate.getTimezoneOffset() * 60 * 1000)
|
9127
9223
|
) % timeUnits.day; // #950, #3359
|
@@ -9140,7 +9236,7 @@
|
|
9140
9236
|
|
9141
9237
|
// if we're using global time, the interval is not fixed as it jumps
|
9142
9238
|
// one hour at the DST crossover
|
9143
|
-
} else if (
|
9239
|
+
} else if (variableDayLength && (interval === timeUnits.day || interval === timeUnits.week)) {
|
9144
9240
|
time = makeTime(minYear, minMonth, minDateDate +
|
9145
9241
|
i * count * (interval === timeUnits.day ? 1 : 7));
|
9146
9242
|
|
@@ -9744,11 +9840,11 @@
|
|
9744
9840
|
this.isHidden = false;
|
9745
9841
|
}
|
9746
9842
|
fireEvent(chart, 'tooltipRefresh', {
|
9747
|
-
|
9748
|
-
|
9749
|
-
|
9750
|
-
|
9751
|
-
|
9843
|
+
text: text,
|
9844
|
+
x: x + chart.plotLeft,
|
9845
|
+
y: y + chart.plotTop,
|
9846
|
+
borderColor: borderColor
|
9847
|
+
});
|
9752
9848
|
},
|
9753
9849
|
|
9754
9850
|
/**
|
@@ -9972,9 +10068,9 @@
|
|
9972
10068
|
*/
|
9973
10069
|
getCoordinates: function (e) {
|
9974
10070
|
var coordinates = {
|
9975
|
-
|
9976
|
-
|
9977
|
-
|
10071
|
+
xAxis: [],
|
10072
|
+
yAxis: []
|
10073
|
+
};
|
9978
10074
|
|
9979
10075
|
each(this.chart.axes, function (axis) {
|
9980
10076
|
coordinates[axis.isXAxis ? 'xAxis' : 'yAxis'].push({
|
@@ -10000,14 +10096,13 @@
|
|
10000
10096
|
hoverPoint = chart.hoverPoint,
|
10001
10097
|
hoverSeries = chart.hoverSeries,
|
10002
10098
|
i,
|
10003
|
-
distance = Number.MAX_VALUE, // #4511
|
10099
|
+
distance = [Number.MAX_VALUE, Number.MAX_VALUE], // #4511
|
10004
10100
|
anchor,
|
10005
10101
|
noSharedTooltip,
|
10006
10102
|
stickToHoverSeries,
|
10007
10103
|
directTouch,
|
10008
|
-
pointDistance,
|
10009
10104
|
kdpoints = [],
|
10010
|
-
kdpoint,
|
10105
|
+
kdpoint = [],
|
10011
10106
|
kdpointT;
|
10012
10107
|
|
10013
10108
|
// For hovering over the empty parts of the plot area (hoverSeries is undefined).
|
@@ -10025,7 +10120,7 @@
|
|
10025
10120
|
// search the k-d tree.
|
10026
10121
|
stickToHoverSeries = hoverSeries && (shared ? hoverSeries.noSharedTooltip : hoverSeries.directTouch);
|
10027
10122
|
if (stickToHoverSeries && hoverPoint) {
|
10028
|
-
kdpoint = hoverPoint;
|
10123
|
+
kdpoint = [hoverPoint];
|
10029
10124
|
|
10030
10125
|
// Handle shared tooltip or cases where a series is not yet hovered
|
10031
10126
|
} else {
|
@@ -10043,42 +10138,50 @@
|
|
10043
10138
|
});
|
10044
10139
|
// Find absolute nearest point
|
10045
10140
|
each(kdpoints, function (p) {
|
10046
|
-
|
10047
|
-
|
10048
|
-
|
10049
|
-
|
10050
|
-
|
10141
|
+
if (p) {
|
10142
|
+
// Store both closest points, using point.dist and point.distX comparisons (#4645):
|
10143
|
+
each(['dist', 'distX'], function (dist, k) {
|
10144
|
+
if (typeof p[dist] === 'number' && p[dist] < distance[k]) {
|
10145
|
+
distance[k] = p[dist];
|
10146
|
+
kdpoint[k] = p;
|
10147
|
+
}
|
10148
|
+
});
|
10051
10149
|
}
|
10052
10150
|
});
|
10053
10151
|
}
|
10054
10152
|
|
10153
|
+
// Remove points with different x-positions, required for shared tooltip and crosshairs (#4645):
|
10154
|
+
if (shared) {
|
10155
|
+
i = kdpoints.length;
|
10156
|
+
while (i--) {
|
10157
|
+
if (kdpoints[i].clientX !== kdpoint[1].clientX || kdpoints[i].series.noSharedTooltip) {
|
10158
|
+
kdpoints.splice(i, 1);
|
10159
|
+
}
|
10160
|
+
}
|
10161
|
+
}
|
10162
|
+
|
10055
10163
|
// Refresh tooltip for kdpoint if new hover point or tooltip was hidden // #3926, #4200
|
10056
|
-
if (kdpoint && (kdpoint !== this.prevKDPoint || (tooltip && tooltip.isHidden))) {
|
10164
|
+
if (kdpoint[0] && (kdpoint[0] !== this.prevKDPoint || (tooltip && tooltip.isHidden))) {
|
10057
10165
|
// Draw tooltip if necessary
|
10058
|
-
if (shared && !kdpoint.series.noSharedTooltip) {
|
10059
|
-
i = kdpoints.length;
|
10060
|
-
while (i--) {
|
10061
|
-
if (kdpoints[i].clientX !== kdpoint.clientX || kdpoints[i].series.noSharedTooltip) {
|
10062
|
-
kdpoints.splice(i, 1);
|
10063
|
-
}
|
10064
|
-
}
|
10166
|
+
if (shared && !kdpoint[0].series.noSharedTooltip) {
|
10065
10167
|
if (kdpoints.length && tooltip) {
|
10066
10168
|
tooltip.refresh(kdpoints, e);
|
10067
10169
|
}
|
10068
10170
|
|
10069
10171
|
// Do mouseover on all points (#3919, #3985, #4410)
|
10070
10172
|
each(kdpoints, function (point) {
|
10071
|
-
point.onMouseOver(e, point !== ((hoverSeries && hoverSeries.directTouch && hoverPoint) || kdpoint));
|
10173
|
+
point.onMouseOver(e, point !== ((hoverSeries && hoverSeries.directTouch && hoverPoint) || kdpoint[0]));
|
10072
10174
|
});
|
10175
|
+
this.prevKDPoint = kdpoint[1];
|
10073
10176
|
} else {
|
10074
10177
|
if (tooltip) {
|
10075
|
-
tooltip.refresh(kdpoint, e);
|
10178
|
+
tooltip.refresh(kdpoint[0], e);
|
10076
10179
|
}
|
10077
10180
|
if (!hoverSeries || !hoverSeries.directTouch) { // #4448
|
10078
|
-
kdpoint.onMouseOver(e);
|
10181
|
+
kdpoint[0].onMouseOver(e);
|
10079
10182
|
}
|
10183
|
+
this.prevKDPoint = kdpoint[0];
|
10080
10184
|
}
|
10081
|
-
this.prevKDPoint = kdpoint;
|
10082
10185
|
|
10083
10186
|
// Update positions (regardless of kdpoint or hoverPoint)
|
10084
10187
|
} else {
|
@@ -10100,11 +10203,17 @@
|
|
10100
10203
|
}
|
10101
10204
|
|
10102
10205
|
// Crosshair
|
10103
|
-
each(
|
10104
|
-
|
10206
|
+
each(shared ? kdpoints : [pick(kdpoint[1], hoverPoint)], function (point) {
|
10207
|
+
var series = point && point.series;
|
10208
|
+
if (series) {
|
10209
|
+
each(['xAxis', 'yAxis', 'colorAxis'], function (coll) {
|
10210
|
+
if (series[coll]) {
|
10211
|
+
series[coll].drawCrosshair(e, point);
|
10212
|
+
}
|
10213
|
+
});
|
10214
|
+
}
|
10105
10215
|
});
|
10106
10216
|
|
10107
|
-
|
10108
10217
|
},
|
10109
10218
|
|
10110
10219
|
|
@@ -10329,6 +10438,7 @@
|
|
10329
10438
|
|
10330
10439
|
if (this.selectionMarker) {
|
10331
10440
|
var selectionData = {
|
10441
|
+
originalEvent: e, // #4890
|
10332
10442
|
xAxis: [],
|
10333
10443
|
yAxis: []
|
10334
10444
|
},
|
@@ -10422,9 +10532,9 @@
|
|
10422
10532
|
/**
|
10423
10533
|
* When mouse leaves the container, hide the tooltip.
|
10424
10534
|
*/
|
10425
|
-
onContainerMouseLeave: function () {
|
10535
|
+
onContainerMouseLeave: function (e) {
|
10426
10536
|
var chart = charts[hoverChartIndex];
|
10427
|
-
if (chart) {
|
10537
|
+
if (chart && (e.relatedTarget || e.toElement)) { // #4886, MS Touch end fires mouseleave but with no related target
|
10428
10538
|
chart.pointer.reset();
|
10429
10539
|
chart.pointer.chartPosition = null; // also reset the chart position, used in #149 fix
|
10430
10540
|
}
|
@@ -10435,7 +10545,9 @@
|
|
10435
10545
|
|
10436
10546
|
var chart = this.chart;
|
10437
10547
|
|
10438
|
-
hoverChartIndex
|
10548
|
+
if (!defined(hoverChartIndex) || !charts[hoverChartIndex].mouseIsDown) {
|
10549
|
+
hoverChartIndex = chart.index;
|
10550
|
+
}
|
10439
10551
|
|
10440
10552
|
e = this.normalize(e);
|
10441
10553
|
e.returnValue = false; // #2251, #3224
|
@@ -10476,7 +10588,7 @@
|
|
10476
10588
|
var series = this.chart.hoverSeries,
|
10477
10589
|
relatedTarget = e.relatedTarget || e.toElement;
|
10478
10590
|
|
10479
|
-
if (series && !series.options.stickyTracking &&
|
10591
|
+
if (series && relatedTarget && !series.options.stickyTracking && // #4886
|
10480
10592
|
!this.inClass(relatedTarget, PREFIX + 'tooltip') &&
|
10481
10593
|
!this.inClass(relatedTarget, PREFIX + 'series-' + series.index)) { // #2499, #4465
|
10482
10594
|
series.onMouseOut();
|
@@ -11182,15 +11294,15 @@
|
|
11182
11294
|
legend.setItemEvents(item, li, useHTML, itemStyle, itemHiddenStyle);
|
11183
11295
|
}
|
11184
11296
|
|
11185
|
-
// Colorize the items
|
11186
|
-
legend.colorizeItem(item, item.visible);
|
11187
|
-
|
11188
11297
|
// add the HTML checkbox on top
|
11189
11298
|
if (showCheckbox) {
|
11190
11299
|
legend.createCheckboxForItem(item);
|
11191
11300
|
}
|
11192
11301
|
}
|
11193
11302
|
|
11303
|
+
// Colorize the items
|
11304
|
+
legend.colorizeItem(item, item.visible);
|
11305
|
+
|
11194
11306
|
// Always update the text
|
11195
11307
|
legend.setText(item);
|
11196
11308
|
|
@@ -13068,8 +13180,7 @@
|
|
13068
13180
|
*/
|
13069
13181
|
firstRender: function () {
|
13070
13182
|
var chart = this,
|
13071
|
-
options = chart.options
|
13072
|
-
callback = chart.callback;
|
13183
|
+
options = chart.options;
|
13073
13184
|
|
13074
13185
|
// Check whether the chart is ready to render
|
13075
13186
|
if (!chart.isReadyToRender()) {
|
@@ -13113,24 +13224,36 @@
|
|
13113
13224
|
|
13114
13225
|
// add canvas
|
13115
13226
|
chart.renderer.draw();
|
13116
|
-
|
13117
|
-
if
|
13118
|
-
|
13227
|
+
|
13228
|
+
// Fire the load event if there are no external images
|
13229
|
+
if (!chart.renderer.imgCount) {
|
13230
|
+
chart.onload();
|
13119
13231
|
}
|
13120
|
-
each(chart.callbacks, function (fn) {
|
13121
|
-
if (chart.index !== UNDEFINED) { // Chart destroyed in its own callback (#3600)
|
13122
|
-
fn.apply(chart, [chart]);
|
13123
|
-
}
|
13124
|
-
});
|
13125
|
-
|
13126
|
-
// Fire the load event
|
13127
|
-
fireEvent(chart, 'load');
|
13128
13232
|
|
13129
13233
|
// If the chart was rendered outside the top container, put it back in (#3679)
|
13130
13234
|
chart.cloneRenderTo(true);
|
13131
13235
|
|
13132
13236
|
},
|
13133
13237
|
|
13238
|
+
/**
|
13239
|
+
* On chart load
|
13240
|
+
*/
|
13241
|
+
onload: function () {
|
13242
|
+
var chart = this;
|
13243
|
+
|
13244
|
+
// Run callbacks
|
13245
|
+
each([this.callback].concat(this.callbacks), function (fn) {
|
13246
|
+
if (fn && chart.index !== undefined) { // Chart destroyed in its own callback (#3600)
|
13247
|
+
fn.apply(chart, [chart]);
|
13248
|
+
}
|
13249
|
+
});
|
13250
|
+
|
13251
|
+
// Fire the load event if there are no external images
|
13252
|
+
if (!chart.renderer.imgCount) {
|
13253
|
+
fireEvent(chart, 'load');
|
13254
|
+
}
|
13255
|
+
},
|
13256
|
+
|
13134
13257
|
/**
|
13135
13258
|
* Creates arrays for spacing and margin from given options.
|
13136
13259
|
*/
|
@@ -13237,6 +13360,7 @@
|
|
13237
13360
|
if (pointValKey) {
|
13238
13361
|
point.y = point[pointValKey];
|
13239
13362
|
}
|
13363
|
+
point.isNull = point.y === null;
|
13240
13364
|
|
13241
13365
|
// If no x is set by now, get auto incremented value. All points must have an
|
13242
13366
|
// x value, however the y value can be null to create a gap in the series
|
@@ -13632,51 +13756,7 @@
|
|
13632
13756
|
this.xIncrement = xIncrement + pointInterval;
|
13633
13757
|
return xIncrement;
|
13634
13758
|
},
|
13635
|
-
|
13636
|
-
/**
|
13637
|
-
* Divide the series data into segments divided by null values.
|
13638
|
-
*/
|
13639
|
-
getSegments: function () {
|
13640
|
-
var series = this,
|
13641
|
-
lastNull = -1,
|
13642
|
-
segments = [],
|
13643
|
-
i,
|
13644
|
-
points = series.points,
|
13645
|
-
pointsLength = points.length;
|
13646
|
-
|
13647
|
-
if (pointsLength) { // no action required for []
|
13648
|
-
|
13649
|
-
// if connect nulls, just remove null points
|
13650
|
-
if (series.options.connectNulls) {
|
13651
|
-
i = pointsLength;
|
13652
|
-
while (i--) {
|
13653
|
-
if (points[i].y === null) {
|
13654
|
-
points.splice(i, 1);
|
13655
|
-
}
|
13656
|
-
}
|
13657
|
-
if (points.length) {
|
13658
|
-
segments = [points];
|
13659
|
-
}
|
13660
|
-
|
13661
|
-
// else, split on null points
|
13662
|
-
} else {
|
13663
|
-
each(points, function (point, i) {
|
13664
|
-
if (point.y === null) {
|
13665
|
-
if (i > lastNull + 1) {
|
13666
|
-
segments.push(points.slice(lastNull + 1, i));
|
13667
|
-
}
|
13668
|
-
lastNull = i;
|
13669
|
-
} else if (i === pointsLength - 1) { // last value
|
13670
|
-
segments.push(points.slice(lastNull + 1, i + 1));
|
13671
|
-
}
|
13672
|
-
});
|
13673
|
-
}
|
13674
|
-
}
|
13675
|
-
|
13676
|
-
// register it
|
13677
|
-
series.segments = segments;
|
13678
|
-
},
|
13679
|
-
|
13759
|
+
|
13680
13760
|
/**
|
13681
13761
|
* Set the series options by merging from the options tree
|
13682
13762
|
* @param {Object} itemOptions
|
@@ -13892,8 +13972,7 @@
|
|
13892
13972
|
}
|
13893
13973
|
|
13894
13974
|
series.data = [];
|
13895
|
-
series.options.data = data;
|
13896
|
-
//series.zData = zData;
|
13975
|
+
series.options.data = series.userOptions.data = data;
|
13897
13976
|
|
13898
13977
|
// destroy old points
|
13899
13978
|
i = oldDataLength;
|
@@ -13915,7 +13994,7 @@
|
|
13915
13994
|
|
13916
13995
|
// Typically for pie series, points need to be processed and generated
|
13917
13996
|
// prior to rendering the legend
|
13918
|
-
if (options.legendType === 'point') {
|
13997
|
+
if (options.legendType === 'point') {
|
13919
13998
|
this.processData();
|
13920
13999
|
this.generatePoints();
|
13921
14000
|
}
|
@@ -13946,6 +14025,8 @@
|
|
13946
14025
|
getExtremesFromAll = series.getExtremesFromAll || options.getExtremesFromAll, // #4599
|
13947
14026
|
isCartesian = series.isCartesian,
|
13948
14027
|
xExtremes,
|
14028
|
+
val2lin = xAxis && xAxis.val2lin,
|
14029
|
+
isLog = xAxis && xAxis.isLog,
|
13949
14030
|
min,
|
13950
14031
|
max;
|
13951
14032
|
|
@@ -13981,8 +14062,11 @@
|
|
13981
14062
|
|
13982
14063
|
|
13983
14064
|
// Find the closest distance between processed points
|
13984
|
-
|
13985
|
-
|
14065
|
+
i = processedXData.length || 1;
|
14066
|
+
while (--i) {
|
14067
|
+
distance = isLog ?
|
14068
|
+
val2lin(processedXData[i]) - val2lin(processedXData[i - 1]) :
|
14069
|
+
processedXData[i] - processedXData[i - 1];
|
13986
14070
|
|
13987
14071
|
if (distance > 0 && (closestPointRange === UNDEFINED || distance < closestPointRange)) {
|
13988
14072
|
closestPointRange = distance;
|
@@ -14204,7 +14288,7 @@
|
|
14204
14288
|
|
14205
14289
|
|
14206
14290
|
// Calculate the bottom y value for stacked series
|
14207
|
-
if (stacking && series.visible && stack && stack[xValue]) {
|
14291
|
+
if (stacking && series.visible && !point.isNull && stack && stack[xValue]) {
|
14208
14292
|
stackIndicator = series.getStackIndicator(stackIndicator, xValue, series.index);
|
14209
14293
|
pointStack = stack[xValue];
|
14210
14294
|
stackValues = pointStack.points[stackIndicator.key];
|
@@ -14261,11 +14345,16 @@
|
|
14261
14345
|
lastPlotX = plotX;
|
14262
14346
|
|
14263
14347
|
}
|
14264
|
-
|
14265
14348
|
series.closestPointRangePx = closestPointRangePx;
|
14349
|
+
},
|
14266
14350
|
|
14267
|
-
|
14268
|
-
|
14351
|
+
/**
|
14352
|
+
* Return the series points with null points filtered out
|
14353
|
+
*/
|
14354
|
+
getValidPoints: function () {
|
14355
|
+
return grep(this.points, function (point) {
|
14356
|
+
return !point.isNull;
|
14357
|
+
});
|
14269
14358
|
},
|
14270
14359
|
|
14271
14360
|
/**
|
@@ -14428,6 +14517,7 @@
|
|
14428
14517
|
|
14429
14518
|
if (graphic) { // update
|
14430
14519
|
graphic[isInside ? 'show' : 'hide'](true) // Since the marker group isn't clipped, each individual marker must be toggled
|
14520
|
+
.attr(pointAttr) // #4759
|
14431
14521
|
.animate(extend({
|
14432
14522
|
x: plotX - radius,
|
14433
14523
|
y: plotY - radius
|
@@ -14715,92 +14805,89 @@
|
|
14715
14805
|
},
|
14716
14806
|
|
14717
14807
|
/**
|
14718
|
-
*
|
14808
|
+
* Get the graph path
|
14719
14809
|
*/
|
14720
|
-
|
14810
|
+
getGraphPath: function (points, nullsAsZeroes, connectCliffs) {
|
14721
14811
|
var series = this,
|
14722
|
-
|
14723
|
-
step =
|
14812
|
+
options = series.options,
|
14813
|
+
step = options.step,
|
14814
|
+
graphPath = [],
|
14815
|
+
gap;
|
14724
14816
|
|
14725
|
-
|
14726
|
-
|
14817
|
+
points = points || series.points;
|
14818
|
+
|
14819
|
+
// Build the line
|
14820
|
+
each(points, function (point, i) {
|
14727
14821
|
|
14728
14822
|
var plotX = point.plotX,
|
14729
14823
|
plotY = point.plotY,
|
14730
|
-
lastPoint
|
14824
|
+
lastPoint = points[i - 1],
|
14825
|
+
pathToPoint; // the path to this point from the previous
|
14826
|
+
|
14827
|
+
if ((point.leftCliff || (lastPoint && lastPoint.rightCliff)) && !connectCliffs) {
|
14828
|
+
gap = true; // ... and continue
|
14829
|
+
}
|
14731
14830
|
|
14732
|
-
|
14733
|
-
|
14831
|
+
// Line series, nullsAsZeroes is not handled
|
14832
|
+
if (point.isNull && !defined(nullsAsZeroes) && i > 0) {
|
14833
|
+
gap = !options.connectNulls;
|
14834
|
+
|
14835
|
+
// Area series, nullsAsZeroes is set
|
14836
|
+
} else if (point.isNull && !nullsAsZeroes) {
|
14837
|
+
gap = true;
|
14734
14838
|
|
14735
14839
|
} else {
|
14736
14840
|
|
14737
|
-
|
14738
|
-
|
14841
|
+
if (i === 0 || gap) {
|
14842
|
+
pathToPoint = [M, point.plotX, point.plotY];
|
14843
|
+
|
14844
|
+
} else if (series.getPointSpline) { // generate the spline as defined in the SplineSeries object
|
14845
|
+
|
14846
|
+
pathToPoint = series.getPointSpline(points, point, i);
|
14847
|
+
|
14848
|
+
} else if (step) {
|
14739
14849
|
|
14740
|
-
// step line?
|
14741
|
-
if (step && i) {
|
14742
|
-
lastPoint = segment[i - 1];
|
14743
14850
|
if (step === 'right') {
|
14744
|
-
|
14851
|
+
pathToPoint = [
|
14852
|
+
L,
|
14745
14853
|
lastPoint.plotX,
|
14746
|
-
plotY
|
14747
|
-
|
14748
|
-
|
14749
|
-
|
14854
|
+
plotY
|
14855
|
+
];
|
14856
|
+
|
14750
14857
|
} else if (step === 'center') {
|
14751
|
-
|
14858
|
+
pathToPoint = [
|
14859
|
+
L,
|
14752
14860
|
(lastPoint.plotX + plotX) / 2,
|
14753
14861
|
lastPoint.plotY,
|
14754
14862
|
L,
|
14755
14863
|
(lastPoint.plotX + plotX) / 2,
|
14756
|
-
plotY
|
14757
|
-
|
14758
|
-
|
14759
|
-
|
14864
|
+
plotY
|
14865
|
+
];
|
14866
|
+
|
14760
14867
|
} else {
|
14761
|
-
|
14868
|
+
pathToPoint = [
|
14869
|
+
L,
|
14762
14870
|
plotX,
|
14763
|
-
lastPoint.plotY
|
14764
|
-
|
14765
|
-
);
|
14871
|
+
lastPoint.plotY
|
14872
|
+
];
|
14766
14873
|
}
|
14767
|
-
|
14874
|
+
pathToPoint.push(L, plotX, plotY);
|
14768
14875
|
|
14769
|
-
|
14770
|
-
|
14771
|
-
|
14772
|
-
|
14773
|
-
|
14774
|
-
|
14775
|
-
|
14776
|
-
|
14777
|
-
return segmentPath;
|
14778
|
-
},
|
14779
|
-
|
14780
|
-
/**
|
14781
|
-
* Get the graph path
|
14782
|
-
*/
|
14783
|
-
getGraphPath: function () {
|
14784
|
-
var series = this,
|
14785
|
-
graphPath = [],
|
14786
|
-
segmentPath,
|
14787
|
-
singlePoints = []; // used in drawTracker
|
14788
|
-
|
14789
|
-
// Divide into segments and build graph and area paths
|
14790
|
-
each(series.segments, function (segment) {
|
14876
|
+
} else {
|
14877
|
+
// normal line to next point
|
14878
|
+
pathToPoint = [
|
14879
|
+
L,
|
14880
|
+
plotX,
|
14881
|
+
plotY
|
14882
|
+
];
|
14883
|
+
}
|
14791
14884
|
|
14792
|
-
segmentPath = series.getSegmentPath(segment);
|
14793
14885
|
|
14794
|
-
|
14795
|
-
|
14796
|
-
graphPath = graphPath.concat(segmentPath);
|
14797
|
-
} else {
|
14798
|
-
singlePoints.push(segment[0]);
|
14886
|
+
graphPath.push.apply(graphPath, pathToPoint);
|
14887
|
+
gap = false;
|
14799
14888
|
}
|
14800
14889
|
});
|
14801
14890
|
|
14802
|
-
// Record it for use in drawGraph and drawTracker, and return graphPath
|
14803
|
-
series.singlePoints = singlePoints;
|
14804
14891
|
series.graphPath = graphPath;
|
14805
14892
|
|
14806
14893
|
return graphPath;
|
@@ -14816,7 +14903,7 @@
|
|
14816
14903
|
props = [['graph', options.lineColor || this.color, options.dashStyle]],
|
14817
14904
|
lineWidth = options.lineWidth,
|
14818
14905
|
roundCap = options.linecap !== 'square',
|
14819
|
-
graphPath = this.getGraphPath(),
|
14906
|
+
graphPath = (this.gappedPath || this.getGraphPath).call(this),
|
14820
14907
|
fillColor = (this.fillGraph && this.color) || NONE, // polygon series use filled graph
|
14821
14908
|
zones = this.zones;
|
14822
14909
|
|
@@ -15339,6 +15426,8 @@
|
|
15339
15426
|
|
15340
15427
|
// Save the stack option on the series configuration object, and whether to treat it as percent
|
15341
15428
|
this.stack = stackOption;
|
15429
|
+
this.leftCliff = 0;
|
15430
|
+
this.rightCliff = 0;
|
15342
15431
|
|
15343
15432
|
// The align options and text align varies on whether the stack is negative and
|
15344
15433
|
// if the chart is inverted or not.
|
@@ -15446,18 +15535,29 @@
|
|
15446
15535
|
* Build the stacks from top down
|
15447
15536
|
*/
|
15448
15537
|
Axis.prototype.buildStacks = function () {
|
15449
|
-
var
|
15538
|
+
var axisSeries = this.series,
|
15539
|
+
series,
|
15450
15540
|
reversedStacks = pick(this.options.reversedStacks, true),
|
15451
|
-
|
15541
|
+
len = axisSeries.length,
|
15542
|
+
i;
|
15452
15543
|
if (!this.isXAxis) {
|
15453
15544
|
this.usePercentage = false;
|
15545
|
+
i = len;
|
15454
15546
|
while (i--) {
|
15455
|
-
|
15547
|
+
axisSeries[reversedStacks ? i : len - i - 1].setStackedPoints();
|
15548
|
+
}
|
15549
|
+
|
15550
|
+
i = len;
|
15551
|
+
while (i--) {
|
15552
|
+
series = axisSeries[reversedStacks ? i : len - i - 1];
|
15553
|
+
if (series.setStackCliffs) {
|
15554
|
+
series.setStackCliffs();
|
15555
|
+
}
|
15456
15556
|
}
|
15457
15557
|
// Loop up again to compute percent stack
|
15458
15558
|
if (this.usePercentage) {
|
15459
|
-
for (i = 0; i <
|
15460
|
-
|
15559
|
+
for (i = 0; i < len; i++) {
|
15560
|
+
axisSeries[i].setPercentStacks();
|
15461
15561
|
}
|
15462
15562
|
}
|
15463
15563
|
}
|
@@ -15608,13 +15708,16 @@
|
|
15608
15708
|
|
15609
15709
|
// If the StackItem doesn't exist, create it first
|
15610
15710
|
stack = stacks[key][x];
|
15611
|
-
|
15612
|
-
|
15711
|
+
if (y !== null) {
|
15712
|
+
stack.points[pointKey] = stack.points[series.index] = [pick(stack.cum, stackThreshold)];
|
15713
|
+
stack.touched = yAxis.stacksTouched;
|
15714
|
+
|
15613
15715
|
|
15614
|
-
|
15615
|
-
|
15616
|
-
|
15617
|
-
|
15716
|
+
// In area charts, if there are multiple points on the same X value, let the
|
15717
|
+
// area fill the full span of those points
|
15718
|
+
if (stackIndicator.index > 0 && series.singleStacks === false) {
|
15719
|
+
stack.points[pointKey][0] = stack.points[series.index + ',' + x + ',0'][0];
|
15720
|
+
}
|
15618
15721
|
}
|
15619
15722
|
|
15620
15723
|
// Add value to the stack total
|
@@ -15636,7 +15739,9 @@
|
|
15636
15739
|
|
15637
15740
|
stack.cum = pick(stack.cum, stackThreshold) + (y || 0);
|
15638
15741
|
|
15639
|
-
|
15742
|
+
if (y !== null) {
|
15743
|
+
stack.points[pointKey].push(stack.cum);
|
15744
|
+
}
|
15640
15745
|
stackedYData[i] = stack.cum;
|
15641
15746
|
|
15642
15747
|
}
|
@@ -16040,7 +16145,7 @@
|
|
16040
16145
|
chart = series.chart,
|
16041
16146
|
remove = function () {
|
16042
16147
|
|
16043
|
-
if (
|
16148
|
+
if (points && points.length === data.length) { // #4935
|
16044
16149
|
points.splice(i, 1);
|
16045
16150
|
}
|
16046
16151
|
data.splice(i, 1);
|
@@ -16246,29 +16351,28 @@
|
|
16246
16351
|
var AreaSeries = extendClass(Series, {
|
16247
16352
|
type: 'area',
|
16248
16353
|
singleStacks: false,
|
16249
|
-
/**
|
16250
|
-
*
|
16251
|
-
*
|
16252
|
-
* in the stack.
|
16354
|
+
/**
|
16355
|
+
* Return an array of stacked points, where null and missing points are replaced by
|
16356
|
+
* dummy points in order for gaps to be drawn correctly in stacks.
|
16253
16357
|
*/
|
16254
|
-
|
16358
|
+
getStackPoints: function () {
|
16255
16359
|
var series = this,
|
16256
|
-
segments = [],
|
16257
16360
|
segment = [],
|
16258
16361
|
keys = [],
|
16259
16362
|
xAxis = this.xAxis,
|
16260
16363
|
yAxis = this.yAxis,
|
16261
16364
|
stack = yAxis.stacks[this.stackKey],
|
16262
16365
|
pointMap = {},
|
16263
|
-
plotX,
|
16264
|
-
plotY,
|
16265
16366
|
points = this.points,
|
16266
|
-
|
16267
|
-
|
16367
|
+
seriesIndex = series.index,
|
16368
|
+
yAxisSeries = yAxis.series,
|
16369
|
+
seriesLength = yAxisSeries.length,
|
16370
|
+
visibleSeries,
|
16371
|
+
upOrDown = pick(yAxis.options.reversedStacks, true) ? 1 : -1,
|
16268
16372
|
i,
|
16269
16373
|
x;
|
16270
16374
|
|
16271
|
-
if (this.options.stacking
|
16375
|
+
if (this.options.stacking) {
|
16272
16376
|
// Create a map where we can quickly look up the points by their X value.
|
16273
16377
|
for (i = 0; i < points.length; i++) {
|
16274
16378
|
pointMap[points[i].x] = points[i];
|
@@ -16284,113 +16388,192 @@
|
|
16284
16388
|
return a - b;
|
16285
16389
|
});
|
16286
16390
|
|
16287
|
-
|
16288
|
-
|
16289
|
-
|
16290
|
-
skip = connectNulls && (!pointMap[x] || pointMap[x].y === null); // #1836
|
16391
|
+
visibleSeries = map(yAxisSeries, function () {
|
16392
|
+
return this.visible;
|
16393
|
+
});
|
16291
16394
|
|
16292
|
-
|
16395
|
+
each(keys, function (x, idx) {
|
16396
|
+
var y = 0,
|
16397
|
+
stackPoint,
|
16398
|
+
stackedValues;
|
16399
|
+
|
16400
|
+
if (pointMap[x] && !pointMap[x].isNull) {
|
16401
|
+
segment.push(pointMap[x]);
|
16402
|
+
|
16403
|
+
// Find left and right cliff. -1 goes left, 1 goes right.
|
16404
|
+
each([-1, 1], function (direction) {
|
16405
|
+
var nullName = direction === 1 ? 'rightNull' : 'leftNull',
|
16406
|
+
cliffName = direction === 1 ? 'rightCliff' : 'leftCliff',
|
16407
|
+
cliff = 0,
|
16408
|
+
otherStack = stack[keys[idx + direction]];
|
16409
|
+
|
16410
|
+
// If there is a stack next to this one, to the left or to the right...
|
16411
|
+
if (otherStack) {
|
16412
|
+
i = seriesIndex;
|
16413
|
+
while (i >= 0 && i < seriesLength) { // Can go either up or down, depending on reversedStacks
|
16414
|
+
stackPoint = otherStack.points[i];
|
16415
|
+
if (!stackPoint) {
|
16416
|
+
// If the next point in this series is missing, mark the point
|
16417
|
+
// with point.leftNull or point.rightNull = true.
|
16418
|
+
if (i === seriesIndex) {
|
16419
|
+
pointMap[x][nullName] = true;
|
16420
|
+
|
16421
|
+
// If there are missing points in the next stack in any of the
|
16422
|
+
// series below this one, we need to substract the missing values
|
16423
|
+
// and add a hiatus to the left or right.
|
16424
|
+
} else if (visibleSeries[i]) {
|
16425
|
+
stackedValues = stack[x].points[i];
|
16426
|
+
if (stackedValues) {
|
16427
|
+
cliff -= stackedValues[1] - stackedValues[0];
|
16428
|
+
}
|
16429
|
+
}
|
16430
|
+
}
|
16431
|
+
// When reversedStacks is true, loop up, else loop down
|
16432
|
+
i += upOrDown;
|
16433
|
+
}
|
16434
|
+
}
|
16435
|
+
pointMap[x][cliffName] = cliff;
|
16436
|
+
});
|
16293
16437
|
|
16294
|
-
// The point exists, push it to the segment
|
16295
|
-
if (pointMap[x]) {
|
16296
|
-
segment.push(pointMap[x]);
|
16297
16438
|
|
16298
|
-
|
16299
|
-
|
16300
|
-
|
16301
|
-
|
16439
|
+
// There is no point for this X value in this series, so we
|
16440
|
+
// insert a dummy point in order for the areas to be drawn
|
16441
|
+
// correctly.
|
16442
|
+
} else {
|
16302
16443
|
|
16303
|
-
|
16304
|
-
|
16305
|
-
|
16306
|
-
|
16307
|
-
|
16308
|
-
|
16309
|
-
|
16310
|
-
|
16311
|
-
}
|
16444
|
+
// Loop down the stack to find the series below this one that has
|
16445
|
+
// a value (#1991)
|
16446
|
+
i = seriesIndex;
|
16447
|
+
while (i >= 0 && i < seriesLength) {
|
16448
|
+
stackPoint = stack[x].points[i];
|
16449
|
+
if (stackPoint) {
|
16450
|
+
y = stackPoint[1];
|
16451
|
+
break;
|
16312
16452
|
}
|
16313
|
-
|
16314
|
-
|
16315
|
-
plotY = yAxis.getThreshold(threshold);
|
16316
|
-
segment.push({
|
16317
|
-
y: null,
|
16318
|
-
plotX: plotX,
|
16319
|
-
clientX: plotX,
|
16320
|
-
plotY: plotY,
|
16321
|
-
yBottom: plotY,
|
16322
|
-
onMouseOver: noop
|
16323
|
-
});
|
16453
|
+
// When reversedStacks is true, loop up, else loop down
|
16454
|
+
i += upOrDown;
|
16324
16455
|
}
|
16456
|
+
|
16457
|
+
y = yAxis.toPixels(y, true);
|
16458
|
+
segment.push({
|
16459
|
+
isNull: true,
|
16460
|
+
plotX: xAxis.toPixels(x, true),
|
16461
|
+
plotY: y,
|
16462
|
+
yBottom: y
|
16463
|
+
});
|
16325
16464
|
}
|
16326
16465
|
});
|
16327
16466
|
|
16328
|
-
|
16329
|
-
segments.push(segment);
|
16330
|
-
}
|
16331
|
-
|
16332
|
-
} else {
|
16333
|
-
Series.prototype.getSegments.call(this);
|
16334
|
-
segments = this.segments;
|
16335
|
-
}
|
16467
|
+
}
|
16336
16468
|
|
16337
|
-
|
16469
|
+
return segment;
|
16338
16470
|
},
|
16339
16471
|
|
16340
|
-
|
16341
|
-
|
16342
|
-
|
16343
|
-
*/
|
16344
|
-
getSegmentPath: function (segment) {
|
16345
|
-
|
16346
|
-
var segmentPath = Series.prototype.getSegmentPath.call(this, segment), // call base method
|
16347
|
-
areaSegmentPath = [].concat(segmentPath), // work on a copy for the area path
|
16348
|
-
i,
|
16472
|
+
getGraphPath: function (points) {
|
16473
|
+
var getGraphPath = Series.prototype.getGraphPath,
|
16474
|
+
graphPath,
|
16349
16475
|
options = this.options,
|
16350
|
-
|
16351
|
-
|
16352
|
-
|
16476
|
+
stacking = options.stacking,
|
16477
|
+
yAxis = this.yAxis,
|
16478
|
+
topPath,
|
16479
|
+
//topPoints = [],
|
16480
|
+
bottomPath,
|
16481
|
+
bottomPoints = [],
|
16482
|
+
graphPoints = [],
|
16483
|
+
seriesIndex = this.index,
|
16484
|
+
i,
|
16485
|
+
areaPath,
|
16486
|
+
plotX,
|
16487
|
+
stacks = yAxis.stacks[this.stackKey],
|
16488
|
+
threshold = options.threshold,
|
16489
|
+
translatedThreshold = yAxis.getThreshold(options.threshold),
|
16490
|
+
isNull,
|
16491
|
+
yBottom,
|
16492
|
+
connectNulls = options.connectNulls || stacking === 'percent',
|
16493
|
+
/**
|
16494
|
+
* To display null points in underlying stacked series, this series graph must be
|
16495
|
+
* broken, and the area also fall down to fill the gap left by the null point. #2069
|
16496
|
+
*/
|
16497
|
+
addDummyPoints = function (i, otherI, side) {
|
16498
|
+
var point = points[i],
|
16499
|
+
stackedValues = stacking && stacks[point.x].points[seriesIndex],
|
16500
|
+
nullVal = point[side + 'Null'] || 0,
|
16501
|
+
cliffVal = point[side + 'Cliff'] || 0,
|
16502
|
+
top,
|
16503
|
+
bottom,
|
16504
|
+
isNull = true;
|
16505
|
+
|
16506
|
+
if (cliffVal || nullVal) {
|
16507
|
+
|
16508
|
+
top = (nullVal ? stackedValues[0] : stackedValues[1]) + cliffVal;
|
16509
|
+
bottom = stackedValues[0] + cliffVal;
|
16510
|
+
isNull = !!nullVal;
|
16511
|
+
|
16512
|
+
} else if (!stacking && points[otherI] && points[otherI].isNull) {
|
16513
|
+
top = bottom = threshold;
|
16514
|
+
}
|
16515
|
+
|
16516
|
+
// Add to the top and bottom line of the area
|
16517
|
+
if (top !== undefined) {
|
16518
|
+
graphPoints.push({
|
16519
|
+
plotX: plotX,
|
16520
|
+
plotY: top === null ? translatedThreshold : yAxis.toPixels(top, true),
|
16521
|
+
isNull: isNull
|
16522
|
+
});
|
16523
|
+
bottomPoints.push({
|
16524
|
+
plotX: plotX,
|
16525
|
+
plotY: bottom === null ? translatedThreshold : yAxis.toPixels(bottom, true)
|
16526
|
+
});
|
16527
|
+
}
|
16528
|
+
};
|
16353
16529
|
|
16354
|
-
|
16355
|
-
|
16530
|
+
// Find what points to use
|
16531
|
+
points = points || this.points;
|
16532
|
+
|
16533
|
+
|
16534
|
+
// Fill in missing points
|
16535
|
+
if (stacking) {
|
16536
|
+
points = this.getStackPoints();
|
16356
16537
|
}
|
16357
|
-
if (options.stacking && !this.closedStacks) {
|
16358
16538
|
|
16359
|
-
|
16360
|
-
|
16361
|
-
|
16362
|
-
|
16539
|
+
for (i = 0; i < points.length; i++) {
|
16540
|
+
isNull = points[i].isNull;
|
16541
|
+
plotX = pick(points[i].rectPlotX, points[i].plotX);
|
16542
|
+
yBottom = pick(points[i].yBottom, translatedThreshold);
|
16363
16543
|
|
16364
|
-
|
16544
|
+
if (!isNull || connectNulls) {
|
16365
16545
|
|
16366
|
-
|
16367
|
-
|
16368
|
-
areaSegmentPath.push(segment[i + 1].plotX, yBottom);
|
16546
|
+
if (!connectNulls) {
|
16547
|
+
addDummyPoints(i, i - 1, 'left');
|
16369
16548
|
}
|
16370
16549
|
|
16371
|
-
|
16550
|
+
if (!(isNull && !stacking && connectNulls)) { // Skip null point when stacking is false and connectNulls true
|
16551
|
+
graphPoints.push(points[i]);
|
16552
|
+
bottomPoints.push({
|
16553
|
+
x: i,
|
16554
|
+
plotX: plotX,
|
16555
|
+
plotY: yBottom
|
16556
|
+
});
|
16557
|
+
}
|
16558
|
+
|
16559
|
+
if (!connectNulls) {
|
16560
|
+
addDummyPoints(i, i + 1, 'right');
|
16561
|
+
}
|
16372
16562
|
}
|
16563
|
+
}
|
16373
16564
|
|
16374
|
-
|
16375
|
-
|
16565
|
+
topPath = getGraphPath.call(this, graphPoints, true, true);
|
16566
|
+
|
16567
|
+
bottomPath = getGraphPath.call(this, bottomPoints.reverse(), true, true);
|
16568
|
+
if (bottomPath.length) {
|
16569
|
+
bottomPath[0] = L;
|
16376
16570
|
}
|
16377
|
-
this.areaPath = this.areaPath.concat(areaSegmentPath);
|
16378
|
-
return segmentPath;
|
16379
|
-
},
|
16380
16571
|
|
16381
|
-
|
16382
|
-
|
16383
|
-
|
16384
|
-
|
16385
|
-
|
16386
|
-
path.push(
|
16387
|
-
L,
|
16388
|
-
segment[segment.length - 1].plotX,
|
16389
|
-
translatedThreshold,
|
16390
|
-
L,
|
16391
|
-
segment[0].plotX,
|
16392
|
-
translatedThreshold
|
16393
|
-
);
|
16572
|
+
areaPath = topPath.concat(bottomPath);
|
16573
|
+
graphPath = getGraphPath.call(this, graphPoints, false, connectNulls); // TODO: don't set leftCliff and rightCliff when connectNulls?
|
16574
|
+
|
16575
|
+
this.areaPath = areaPath;
|
16576
|
+
return graphPath;
|
16394
16577
|
},
|
16395
16578
|
|
16396
16579
|
/**
|
@@ -16431,7 +16614,7 @@
|
|
16431
16614
|
zIndex: 0 // #1069
|
16432
16615
|
};
|
16433
16616
|
if (!prop[2]) {
|
16434
|
-
attr['fill-opacity'] = options.fillOpacity
|
16617
|
+
attr['fill-opacity'] = pick(options.fillOpacity, 0.75);
|
16435
16618
|
}
|
16436
16619
|
series[areaKey] = series.chart.renderer.path(areaPath)
|
16437
16620
|
.attr(attr)
|
@@ -16458,22 +16641,21 @@
|
|
16458
16641
|
/**
|
16459
16642
|
* Get the spline segment from a given point's previous neighbour to the given point
|
16460
16643
|
*/
|
16461
|
-
getPointSpline: function (
|
16644
|
+
getPointSpline: function (points, point, i) {
|
16462
16645
|
var smoothing = 1.5, // 1 means control points midway between points, 2 means 1/3 from the point, 3 is 1/4 etc
|
16463
16646
|
denom = smoothing + 1,
|
16464
16647
|
plotX = point.plotX,
|
16465
16648
|
plotY = point.plotY,
|
16466
|
-
lastPoint =
|
16467
|
-
nextPoint =
|
16649
|
+
lastPoint = points[i - 1],
|
16650
|
+
nextPoint = points[i + 1],
|
16468
16651
|
leftContX,
|
16469
16652
|
leftContY,
|
16470
16653
|
rightContX,
|
16471
16654
|
rightContY,
|
16472
16655
|
ret;
|
16473
16656
|
|
16474
|
-
//
|
16475
|
-
if (lastPoint && nextPoint) {
|
16476
|
-
|
16657
|
+
// Find control points
|
16658
|
+
if (lastPoint && !lastPoint.isNull && nextPoint && !nextPoint.isNull) {
|
16477
16659
|
var lastX = lastPoint.plotX,
|
16478
16660
|
lastY = lastPoint.plotY,
|
16479
16661
|
nextX = nextPoint.plotX,
|
@@ -16513,6 +16695,7 @@
|
|
16513
16695
|
point.rightContX = rightContX;
|
16514
16696
|
point.rightContY = rightContY;
|
16515
16697
|
|
16698
|
+
|
16516
16699
|
}
|
16517
16700
|
|
16518
16701
|
// Visualize control points for debugging
|
@@ -16547,23 +16730,17 @@
|
|
16547
16730
|
})
|
16548
16731
|
.add();
|
16549
16732
|
}
|
16550
|
-
*/
|
16551
|
-
|
16552
|
-
|
16553
|
-
|
16554
|
-
|
16555
|
-
|
16556
|
-
|
16557
|
-
|
16558
|
-
|
16559
|
-
|
16560
|
-
|
16561
|
-
leftContY || plotY,
|
16562
|
-
plotX,
|
16563
|
-
plotY
|
16564
|
-
];
|
16565
|
-
lastPoint.rightContX = lastPoint.rightContY = null; // reset for updating series later
|
16566
|
-
}
|
16733
|
+
// */
|
16734
|
+
ret = [
|
16735
|
+
'C',
|
16736
|
+
pick(lastPoint.rightContX, lastPoint.plotX),
|
16737
|
+
pick(lastPoint.rightContY, lastPoint.plotY),
|
16738
|
+
pick(leftContX, plotX),
|
16739
|
+
pick(leftContY, plotY),
|
16740
|
+
plotX,
|
16741
|
+
plotY
|
16742
|
+
];
|
16743
|
+
lastPoint.rightContX = lastPoint.rightContY = null; // reset for updating series later
|
16567
16744
|
return ret;
|
16568
16745
|
}
|
16569
16746
|
});
|
@@ -16580,11 +16757,9 @@
|
|
16580
16757
|
var areaProto = AreaSeries.prototype,
|
16581
16758
|
AreaSplineSeries = extendClass(SplineSeries, {
|
16582
16759
|
type: 'areaspline',
|
16583
|
-
|
16584
|
-
|
16585
|
-
|
16586
|
-
getSegmentPath: areaProto.getSegmentPath,
|
16587
|
-
closeSegment: areaProto.closeSegment,
|
16760
|
+
getStackPoints: areaProto.getStackPoints,
|
16761
|
+
getGraphPath: areaProto.getGraphPath,
|
16762
|
+
setStackCliffs: areaProto.setStackCliffs,
|
16588
16763
|
drawGraph: areaProto.drawGraph,
|
16589
16764
|
drawLegendSymbol: LegendSymbolMixin.drawRectangle
|
16590
16765
|
});
|
@@ -17650,11 +17825,16 @@
|
|
17650
17825
|
plotY = pick(point.plotY, -9999),
|
17651
17826
|
bBox = dataLabel.getBBox(),
|
17652
17827
|
baseline = chart.renderer.fontMetrics(options.style.fontSize).b,
|
17828
|
+
rotation = options.rotation,
|
17829
|
+
normRotation,
|
17830
|
+
negRotation,
|
17831
|
+
align = options.align,
|
17653
17832
|
rotCorr, // rotation correction
|
17654
17833
|
// Math.round for rounding errors (#2683), alignTo to allow column labels (#2700)
|
17655
17834
|
visible = this.visible && (point.series.forceDL || chart.isInsidePlot(plotX, mathRound(plotY), inverted) ||
|
17656
17835
|
(alignTo && chart.isInsidePlot(plotX, inverted ? alignTo.x + 1 : alignTo.y + alignTo.height - 1, inverted))),
|
17657
|
-
alignAttr
|
17836
|
+
alignAttr, // the final position;
|
17837
|
+
justify = pick(options.overflow, 'justify') === 'justify';
|
17658
17838
|
|
17659
17839
|
if (visible) {
|
17660
17840
|
|
@@ -17673,37 +17853,54 @@
|
|
17673
17853
|
});
|
17674
17854
|
|
17675
17855
|
// Allow a hook for changing alignment in the last moment, then do the alignment
|
17676
|
-
if (
|
17677
|
-
|
17678
|
-
|
17679
|
-
|
17680
|
-
|
17681
|
-
|
17856
|
+
if (rotation) {
|
17857
|
+
justify = false; // Not supported for rotated text
|
17858
|
+
rotCorr = chart.renderer.rotCorr(baseline, rotation); // #3723
|
17859
|
+
alignAttr = {
|
17860
|
+
x: alignTo.x + options.x + alignTo.width / 2 + rotCorr.x,
|
17861
|
+
y: alignTo.y + options.y + alignTo.height / 2
|
17862
|
+
};
|
17863
|
+
dataLabel
|
17864
|
+
[isNew ? 'attr' : 'animate'](alignAttr)
|
17682
17865
|
.attr({ // #3003
|
17683
17866
|
align: options.align
|
17684
17867
|
});
|
17685
|
-
} else {
|
17686
|
-
dataLabel.align(options, null, alignTo);
|
17687
|
-
alignAttr = dataLabel.alignAttr;
|
17688
|
-
|
17689
|
-
// Handle justify or crop
|
17690
|
-
if (pick(options.overflow, 'justify') === 'justify') {
|
17691
|
-
this.justifyDataLabel(dataLabel, options, alignAttr, bBox, alignTo, isNew);
|
17692
17868
|
|
17693
|
-
|
17694
|
-
|
17695
|
-
|
17869
|
+
// Compensate for the rotated label sticking out on the sides
|
17870
|
+
normRotation = (rotation + 720) % 360;
|
17871
|
+
negRotation = normRotation > 180 && normRotation < 360;
|
17696
17872
|
|
17873
|
+
if (align === 'left') {
|
17874
|
+
alignAttr.y -= negRotation ? bBox.height : 0;
|
17875
|
+
} else if (align === 'center') {
|
17876
|
+
alignAttr.x -= bBox.width / 2;
|
17877
|
+
alignAttr.y -= bBox.height / 2;
|
17878
|
+
} else if (align === 'right') {
|
17879
|
+
alignAttr.x -= bBox.width;
|
17880
|
+
alignAttr.y -= negRotation ? 0 : bBox.height;
|
17697
17881
|
}
|
17882
|
+
|
17698
17883
|
|
17699
|
-
|
17700
|
-
|
17701
|
-
|
17702
|
-
|
17703
|
-
anchorY: point.plotY
|
17704
|
-
});
|
17705
|
-
}
|
17884
|
+
} else {
|
17885
|
+
dataLabel.align(options, null, alignTo);
|
17886
|
+
alignAttr = dataLabel.alignAttr;
|
17887
|
+
}
|
17706
17888
|
|
17889
|
+
// Handle justify or crop
|
17890
|
+
if (justify) {
|
17891
|
+
this.justifyDataLabel(dataLabel, options, alignAttr, bBox, alignTo, isNew);
|
17892
|
+
|
17893
|
+
// Now check that the data label is within the plot area
|
17894
|
+
} else if (pick(options.crop, true)) {
|
17895
|
+
visible = chart.isInsidePlot(alignAttr.x, alignAttr.y) && chart.isInsidePlot(alignAttr.x + bBox.width, alignAttr.y + bBox.height);
|
17896
|
+
}
|
17897
|
+
|
17898
|
+
// When we're using a shape, make it possible with a connector or an arrow pointing to thie point
|
17899
|
+
if (options.shape && !rotation) {
|
17900
|
+
dataLabel.attr({
|
17901
|
+
anchorX: point.plotX,
|
17902
|
+
anchorY: point.plotY
|
17903
|
+
});
|
17707
17904
|
}
|
17708
17905
|
}
|
17709
17906
|
|
@@ -17827,10 +18024,14 @@
|
|
17827
18024
|
// run parent method
|
17828
18025
|
Series.prototype.drawDataLabels.apply(series);
|
17829
18026
|
|
17830
|
-
// arrange points for detection collision
|
17831
18027
|
each(data, function (point) {
|
17832
18028
|
if (point.dataLabel && point.visible) { // #407, #2510
|
18029
|
+
|
18030
|
+
// Arrange points for detection collision
|
17833
18031
|
halves[point.half].push(point);
|
18032
|
+
|
18033
|
+
// Reset positions (#4905)
|
18034
|
+
point.dataLabel._pos = null;
|
17834
18035
|
}
|
17835
18036
|
});
|
17836
18037
|
|
@@ -18165,12 +18366,7 @@
|
|
18165
18366
|
center[2] = newSize;
|
18166
18367
|
center[3] = Math.min(relativeLength(options.innerSize || 0, newSize), newSize); // #3632
|
18167
18368
|
this.translate(center);
|
18168
|
-
|
18169
|
-
if (point.dataLabel) {
|
18170
|
-
point.dataLabel._pos = null; // reset
|
18171
|
-
}
|
18172
|
-
});
|
18173
|
-
|
18369
|
+
|
18174
18370
|
if (this.drawDataLabels) {
|
18175
18371
|
this.drawDataLabels();
|
18176
18372
|
}
|
@@ -18303,6 +18499,8 @@
|
|
18303
18499
|
isIntersecting,
|
18304
18500
|
pos1,
|
18305
18501
|
pos2,
|
18502
|
+
parent1,
|
18503
|
+
parent2,
|
18306
18504
|
padding,
|
18307
18505
|
intersectRect = function (x1, y1, w1, h1, x2, y2, w2, h2) {
|
18308
18506
|
return !(
|
@@ -18338,14 +18536,16 @@
|
|
18338
18536
|
if (label1 && label2 && label1.placed && label2.placed && label1.newOpacity !== 0 && label2.newOpacity !== 0) {
|
18339
18537
|
pos1 = label1.alignAttr;
|
18340
18538
|
pos2 = label2.alignAttr;
|
18539
|
+
parent1 = label1.parentGroup; // Different panes have different positions
|
18540
|
+
parent2 = label2.parentGroup;
|
18341
18541
|
padding = 2 * (label1.box ? 0 : label1.padding); // Substract the padding if no background or border (#4333)
|
18342
18542
|
isIntersecting = intersectRect(
|
18343
|
-
pos1.x,
|
18344
|
-
pos1.y,
|
18543
|
+
pos1.x + parent1.translateX,
|
18544
|
+
pos1.y + parent1.translateY,
|
18345
18545
|
label1.width - padding,
|
18346
18546
|
label1.height - padding,
|
18347
|
-
pos2.x,
|
18348
|
-
pos2.y,
|
18547
|
+
pos2.x + parent2.translateX,
|
18548
|
+
pos2.y + parent2.translateY,
|
18349
18549
|
label2.width - padding,
|
18350
18550
|
label2.height - padding
|
18351
18551
|
);
|
@@ -18461,8 +18661,6 @@
|
|
18461
18661
|
tracker = series.tracker,
|
18462
18662
|
cursor = options.cursor,
|
18463
18663
|
css = cursor && { cursor: cursor },
|
18464
|
-
singlePoints = series.singlePoints,
|
18465
|
-
singlePoint,
|
18466
18664
|
i,
|
18467
18665
|
onMouseOver = function () {
|
18468
18666
|
if (chart.hoverSeries !== series) {
|
@@ -18498,11 +18696,11 @@
|
|
18498
18696
|
}
|
18499
18697
|
|
18500
18698
|
// handle single points
|
18501
|
-
for (i = 0; i < singlePoints.length; i++) {
|
18699
|
+
/*for (i = 0; i < singlePoints.length; i++) {
|
18502
18700
|
singlePoint = singlePoints[i];
|
18503
18701
|
trackerPath.push(M, singlePoint.plotX - snap, singlePoint.plotY,
|
18504
18702
|
L, singlePoint.plotX + snap, singlePoint.plotY);
|
18505
|
-
}
|
18703
|
+
}*/
|
18506
18704
|
|
18507
18705
|
// draw the tracker
|
18508
18706
|
if (tracker) {
|
@@ -18734,13 +18932,15 @@
|
|
18734
18932
|
}
|
18735
18933
|
|
18736
18934
|
each(panning === 'xy' ? [1, 0] : [1], function (isX) { // xy is used in maps
|
18737
|
-
var
|
18738
|
-
|
18739
|
-
|
18935
|
+
var axis = chart[isX ? 'xAxis' : 'yAxis'][0],
|
18936
|
+
horiz = axis.horiz,
|
18937
|
+
mousePos = e[horiz ? 'chartX' : 'chartY'],
|
18938
|
+
mouseDown = horiz ? 'mouseDownX' : 'mouseDownY',
|
18939
|
+
startPos = chart[mouseDown],
|
18740
18940
|
halfPointRange = (axis.pointRange || 0) / 2,
|
18741
18941
|
extremes = axis.getExtremes(),
|
18742
18942
|
newMin = axis.toValue(startPos - mousePos, true) + halfPointRange,
|
18743
|
-
newMax = axis.toValue(startPos +
|
18943
|
+
newMax = axis.toValue(startPos + axis.len - mousePos, true) - halfPointRange,
|
18744
18944
|
goingLeft = startPos > mousePos; // #3613
|
18745
18945
|
|
18746
18946
|
if (axis.series.length &&
|
@@ -18750,7 +18950,7 @@
|
|
18750
18950
|
doRedraw = true;
|
18751
18951
|
}
|
18752
18952
|
|
18753
|
-
chart[
|
18953
|
+
chart[mouseDown] = mousePos; // set new reference for next run
|
18754
18954
|
});
|
18755
18955
|
|
18756
18956
|
if (doRedraw) {
|
@@ -18985,8 +19185,9 @@
|
|
18985
19185
|
.add(chart.seriesGroup);
|
18986
19186
|
}
|
18987
19187
|
halo.attr(extend({
|
18988
|
-
fill: point.color || series.color,
|
18989
|
-
'fill-opacity': haloOptions.opacity
|
19188
|
+
'fill': point.color || series.color,
|
19189
|
+
'fill-opacity': haloOptions.opacity,
|
19190
|
+
'zIndex': -1 // #4929, IE8 added halo above everything
|
18990
19191
|
},
|
18991
19192
|
haloOptions.attributes))[move ? 'animate' : 'attr']({
|
18992
19193
|
d: point.haloPath(haloOptions.size)
|