highcharts-rails 4.2.0 → 4.2.2
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.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)
|