highcharts-rails 3.0.10 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.asc +13 -13
- data.tar.gz.asc +13 -13
- data/CHANGELOG.markdown +5 -0
- data/Rakefile +4 -5
- data/app/assets/images/highcharts/meteogram-symbols-30px.png +0 -0
- data/app/assets/javascripts/highcharts.js +1221 -1126
- data/app/assets/javascripts/highcharts/adapters/standalone-framework.js +3 -2
- data/app/assets/javascripts/highcharts/highcharts-3d.js +1245 -0
- data/app/assets/javascripts/highcharts/highcharts-more.js +48 -28
- data/app/assets/javascripts/highcharts/modules/canvas-tools.js +1 -1
- data/app/assets/javascripts/highcharts/modules/data.js +8 -4
- data/app/assets/javascripts/highcharts/modules/drilldown.js +52 -26
- data/app/assets/javascripts/highcharts/modules/exporting.js +1 -1
- data/app/assets/javascripts/highcharts/modules/funnel.js +1 -0
- data/app/assets/javascripts/highcharts/modules/heatmap.js +596 -50
- data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +1 -1
- data/app/assets/javascripts/highcharts/modules/solid-gauge.js +224 -0
- data/app/assets/javascripts/highcharts/themes/dark-blue.js +1 -1
- data/app/assets/javascripts/highcharts/themes/dark-green.js +1 -1
- data/app/assets/javascripts/highcharts/themes/dark-unica.js +213 -0
- data/app/assets/javascripts/highcharts/themes/gray.js +1 -1
- data/app/assets/javascripts/highcharts/themes/grid-light.js +74 -0
- data/app/assets/javascripts/highcharts/themes/sand-signika.js +101 -0
- data/lib/highcharts/version.rb +1 -1
- metadata +8 -2
- metadata.gz.asc +13 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 34ea2717f56c979675fe905a6f18999c7a8d5e0c
|
4
|
+
data.tar.gz: ffc12189cbda0a9ec80f4fe7c6e7fe1615086e8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d80310a434ae483f3913e9d00a28b461a8a36818393978251a141397af804bf2db5f2dfca76c269a9f9ba5e6b0346ad885c6d8d6150a0b697b33e74dd98d5c41
|
7
|
+
data.tar.gz: a65952e25bfc4f2d877774f12a7511ca6590283d8c91b64a2fa578887b90f5893bb3a46a770b18f77b7470dad48c679223b18a1d138c30058ff57a4fd06743cd
|
checksums.yaml.gz.asc
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
Version: GnuPG/MacGPG2 v2.0.22 (Darwin)
|
3
3
|
Comment: GPGTools - http://gpgtools.org
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
=
|
5
|
+
iQIcBAABAgAGBQJTVobYAAoJEH1ncb0Txu7X4NIP/jW/2XkfaZMGcCTRNTjw0cE0
|
6
|
+
iNpqs6LkmKgJ1whBFq3CochGBevML+4JTcdxvotB+EyIqYLhZgJNFXg3HEEopADZ
|
7
|
+
Wi9nf2E4V4HCwN4gRd/WUisRc5h8DMxNQFl6N2FImumpsyQ1Xy9DrOoOgfGEkCKZ
|
8
|
+
nPB2bhRieFgBPFe3IgvZXGtHaacavk3YjtIxZPofjAt7cn4tjCk0K3HSNGiZqsfS
|
9
|
+
Cq+H7tVJJPaNmUkeBs8S5K/s65+biaItbqGvQbmglToMtMMY72ngkVoTyegjNEqb
|
10
|
+
gObY8iutWj8rs2tpqaM/XF9618vclD4gVFLzvI6G5Gl3ZM4EOmNnLoXDIs1BTqhs
|
11
|
+
9LiamP1kazyYWkA5MJfhihtO/Apijm6Iydrg+hyC7NDQ+POsT80q5rUGvqglsbIW
|
12
|
+
kUb7QwActx744jrxIoTmVcG+CefvuV0mO5vRsgKO6wti1r5O4PVBrAqYktQYp9sK
|
13
|
+
No5j+616QC6uyQP/TnIJdZnaLRn80Iv9eqVvZEviN8dEuFKIC+215zbu/L2a1Kk0
|
14
|
+
k02K3J/1WGsb6nC4inXw0pB2gH98FAPo1QT9lIg5rS05bTLsDNvCgOfSpeJ0IXwQ
|
15
|
+
fkru8TyOA4z5NWMIr5F1fHnpJy0q+ZYtcc/h+iYDyuiLOy5PlVDF8ZPWb0OsFK1d
|
16
|
+
NeG7+J7OCRidntAeE89M
|
17
|
+
=YkrH
|
18
18
|
-----END PGP SIGNATURE-----
|
data.tar.gz.asc
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
Version: GnuPG/MacGPG2 v2.0.22 (Darwin)
|
3
3
|
Comment: GPGTools - http://gpgtools.org
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
=
|
5
|
+
iQIcBAABAgAGBQJTVobYAAoJEH1ncb0Txu7X49EP/AqBvgdlbe9Av1BtXRov6rly
|
6
|
+
1STFk5806XANJUaoCML8z76/Jzc2Kxqhhy6ylRhI3G+NcI6fGTLdKjQPXo95KVvS
|
7
|
+
6CHoR5Jjff8zTToiVn7Vmr8Nfj28sz7DBAIOtcfbwbCniisPfsTbzljbEX0ekh58
|
8
|
+
F7msBBJKNED05l9mmTzfiCUwKamx8lc/eKrqmx3/AOXB9ojqQ+uTeaMqTpGjif9u
|
9
|
+
A0xJ+CK3ORbZ5vJihhaVwHwE7H/ERPwptAFqSFcIdJy+3BbHzse+Xi1VMkbwk+AP
|
10
|
+
+ooJgF+WZtWUtJ4SkQ0/vLtxG+W1nr+Q4P3+TJYRaVXVQfkwXPTe/mnqmvDeamP0
|
11
|
+
MYBF9kJKWThcTxJaZCLJW+C3CTP0SFk+ohd6735y0TfMoh6Gt5xvmS4CqEEy5Z+q
|
12
|
+
/0EmmUwnq4A4skvgEnUbyPPZBAUjzSZSuuMQmgKgl56P/Cxi9+eMTU5bhFtC1OSI
|
13
|
+
zGejoMelgeB7GvKhdMNBl9bunt6bOJRDmRD0wTx5X0qvTmn1n7Z0JK3Uo5rWVoFP
|
14
|
+
tBmi5ylhntdgESNpaWPdzswMxzH0cGyoXtMlmXojhqq4mAADUNLcaIp4Wzi4Q5Mv
|
15
|
+
c30732TVOCq9H8Lhh5/XWrJ82oqu6wVtCcqoTGV6AEaO8X9wqVGFwtVofpTsEmwp
|
16
|
+
zu6UA9W5DyJxK3Z+Nv6l
|
17
|
+
=DWva
|
18
18
|
-----END PGP SIGNATURE-----
|
data/CHANGELOG.markdown
CHANGED
data/Rakefile
CHANGED
@@ -11,18 +11,17 @@ task :update, :version do |t, args|
|
|
11
11
|
mappings = {
|
12
12
|
"highcharts.src.js" => "highcharts.js",
|
13
13
|
"highcharts-more.src.js" => "highcharts/highcharts-more.js",
|
14
|
-
"
|
15
|
-
"prototype-adapter.src.js" => "highcharts/adapters/prototype-adapter.js",
|
14
|
+
"highcharts-3d.src.js" => "highcharts/highcharts-3d.js",
|
16
15
|
"standalone-framework.src.js" => "highcharts/adapters/standalone-framework.js",
|
17
16
|
"annotations.src.js" => "highcharts/modules/annotations.js",
|
18
17
|
"canvas-tools.src.js" => "highcharts/modules/canvas-tools.js",
|
19
18
|
"data.src.js" => "highcharts/modules/data.js",
|
20
|
-
"
|
19
|
+
"drilldown.src.js" => "highcharts/modules/drilldown.js",
|
21
20
|
"exporting.src.js" => "highcharts/modules/exporting.js",
|
22
21
|
"funnel.src.js" => "highcharts/modules/funnel.js",
|
23
22
|
"heatmap.src.js" => "highcharts/modules/heatmap.js",
|
24
|
-
"
|
25
|
-
"
|
23
|
+
"no-data-to-display.src.js" => "highcharts/modules/no-data-to-display.js",
|
24
|
+
"solid-gauge.src.js" => "highcharts/modules/solid-gauge.js",
|
26
25
|
}
|
27
26
|
dest = "app/assets/javascripts/"
|
28
27
|
Dir.glob("tmp/#{version}/js/**/*.src.js").each do |file|
|
Binary file
|
@@ -2,7 +2,7 @@
|
|
2
2
|
// @compilation_level SIMPLE_OPTIMIZATIONS
|
3
3
|
|
4
4
|
/**
|
5
|
-
* @license Highcharts JS
|
5
|
+
* @license Highcharts JS v4.0.0 (2014-04-22)
|
6
6
|
*
|
7
7
|
* (c) 2009-2014 Torstein Honsi
|
8
8
|
*
|
@@ -54,8 +54,9 @@ var UNDEFINED,
|
|
54
54
|
timeUnits,
|
55
55
|
noop = function () {},
|
56
56
|
charts = [],
|
57
|
+
chartCount = 0,
|
57
58
|
PRODUCT = 'Highcharts',
|
58
|
-
VERSION = '
|
59
|
+
VERSION = '4.0.0',
|
59
60
|
|
60
61
|
// some constants for frequently used strings
|
61
62
|
DIV = 'div',
|
@@ -276,15 +277,13 @@ function defined(obj) {
|
|
276
277
|
*/
|
277
278
|
function attr(elem, prop, value) {
|
278
279
|
var key,
|
279
|
-
setAttribute = 'setAttribute',
|
280
280
|
ret;
|
281
281
|
|
282
282
|
// if the prop is a string
|
283
283
|
if (isString(prop)) {
|
284
284
|
// set the value
|
285
285
|
if (defined(value)) {
|
286
|
-
|
287
|
-
elem[setAttribute](prop, value);
|
286
|
+
elem.setAttribute(prop, value);
|
288
287
|
|
289
288
|
// get the value
|
290
289
|
} else if (elem && elem.getAttribute) { // elem not defined when printing pie demo...
|
@@ -294,7 +293,7 @@ function attr(elem, prop, value) {
|
|
294
293
|
// else if prop is defined, it is a hash of key/value pairs
|
295
294
|
} else if (defined(prop) && isObject(prop)) {
|
296
295
|
for (key in prop) {
|
297
|
-
elem
|
296
|
+
elem.setAttribute(key, prop[key]);
|
298
297
|
}
|
299
298
|
}
|
300
299
|
return ret;
|
@@ -505,12 +504,14 @@ function formatSingle(format, val) {
|
|
505
504
|
if (floatRegex.test(format)) { // float
|
506
505
|
decimals = format.match(decRegex);
|
507
506
|
decimals = decimals ? decimals[1] : -1;
|
508
|
-
val
|
509
|
-
val
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
507
|
+
if (val !== null) {
|
508
|
+
val = numberFormat(
|
509
|
+
val,
|
510
|
+
decimals,
|
511
|
+
lang.decimalPoint,
|
512
|
+
format.indexOf(',') > -1 ? lang.thousandsSep : ''
|
513
|
+
);
|
514
|
+
}
|
514
515
|
} else {
|
515
516
|
val = dateFormat(format, val);
|
516
517
|
}
|
@@ -1024,27 +1025,30 @@ pathAnim = {
|
|
1024
1025
|
ret,
|
1025
1026
|
chart;
|
1026
1027
|
|
1027
|
-
if (
|
1028
|
-
constr = args[0];
|
1029
|
-
args = Array.prototype.slice.call(args, 1);
|
1030
|
-
}
|
1031
|
-
options = args[0];
|
1032
|
-
|
1033
|
-
// Create the chart
|
1034
|
-
if (options !== UNDEFINED) {
|
1035
|
-
/*jslint unused:false*/
|
1036
|
-
options.chart = options.chart || {};
|
1037
|
-
options.chart.renderTo = this[0];
|
1038
|
-
chart = new Highcharts[constr](options, args[1]);
|
1039
|
-
ret = this;
|
1040
|
-
/*jslint unused:true*/
|
1041
|
-
}
|
1028
|
+
if (this[0]) {
|
1042
1029
|
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1030
|
+
if (isString(args[0])) {
|
1031
|
+
constr = args[0];
|
1032
|
+
args = Array.prototype.slice.call(args, 1);
|
1033
|
+
}
|
1034
|
+
options = args[0];
|
1035
|
+
|
1036
|
+
// Create the chart
|
1037
|
+
if (options !== UNDEFINED) {
|
1038
|
+
/*jslint unused:false*/
|
1039
|
+
options.chart = options.chart || {};
|
1040
|
+
options.chart.renderTo = this[0];
|
1041
|
+
chart = new Highcharts[constr](options, args[1]);
|
1042
|
+
ret = this;
|
1043
|
+
/*jslint unused:true*/
|
1044
|
+
}
|
1047
1045
|
|
1046
|
+
// When called without parameters or with the return argument, get a predefined chart
|
1047
|
+
if (options === UNDEFINED) {
|
1048
|
+
ret = charts[attr(this[0], 'data-highcharts-chart')];
|
1049
|
+
}
|
1050
|
+
}
|
1051
|
+
|
1048
1052
|
return ret;
|
1049
1053
|
};
|
1050
1054
|
|
@@ -1140,7 +1144,7 @@ pathAnim = {
|
|
1140
1144
|
detachedType = 'detached' + type,
|
1141
1145
|
defaultPrevented;
|
1142
1146
|
|
1143
|
-
// Remove warnings in Chrome when accessing layerX and layerY. Although Highcharts
|
1147
|
+
// Remove warnings in Chrome when accessing returnValue (#2790), layerX and layerY. Although Highcharts
|
1144
1148
|
// never uses these properties, Chrome includes them in the default click event and
|
1145
1149
|
// raises the warning when they are copied over in the extend statement below.
|
1146
1150
|
//
|
@@ -1149,6 +1153,7 @@ pathAnim = {
|
|
1149
1153
|
if (!isIE && eventArguments) {
|
1150
1154
|
delete eventArguments.layerX;
|
1151
1155
|
delete eventArguments.layerY;
|
1156
|
+
delete eventArguments.returnValue;
|
1152
1157
|
}
|
1153
1158
|
|
1154
1159
|
extend(event, eventArguments);
|
@@ -1285,16 +1290,15 @@ defaultLabelOptions = {
|
|
1285
1290
|
return this.value;
|
1286
1291
|
},*/
|
1287
1292
|
style: {
|
1288
|
-
color: '#
|
1293
|
+
color: '#606060',
|
1289
1294
|
cursor: 'default',
|
1290
1295
|
fontSize: '11px'
|
1291
1296
|
}
|
1292
1297
|
};
|
1293
1298
|
|
1294
1299
|
defaultOptions = {
|
1295
|
-
colors: ['#
|
1296
|
-
|
1297
|
-
//colors: ['#8085e8', '#252530', '#90ee7e', '#8d4654', '#2b908f', '#76758e', '#f6a45c', '#7eb5ee', '#f45b5b', '#9ff0cf'],
|
1300
|
+
colors: ['#7cb5ec', '#434348', '#90ed7d', '#f7a35c',
|
1301
|
+
'#8085e9', '#f15c80', '#e4d354', '#8085e8', '#8d4653', '#91e8e1'], // docs
|
1298
1302
|
symbols: ['circle', 'diamond', 'square', 'triangle', 'triangle-down'],
|
1299
1303
|
lang: {
|
1300
1304
|
loading: 'Loading...',
|
@@ -1311,8 +1315,8 @@ defaultOptions = {
|
|
1311
1315
|
global: {
|
1312
1316
|
useUTC: true,
|
1313
1317
|
//timezoneOffset: 0,
|
1314
|
-
canvasToolsURL: 'http://code.highcharts.com/
|
1315
|
-
VMLRadialGradientURL: 'http://code.highcharts.com/
|
1318
|
+
canvasToolsURL: 'http://code.highcharts.com/4.0.0/modules/canvas-tools.js',
|
1319
|
+
VMLRadialGradientURL: 'http://code.highcharts.com/4.0.0/gfx/vml-radial-gradient.png'
|
1316
1320
|
},
|
1317
1321
|
chart: {
|
1318
1322
|
//animation: true,
|
@@ -1327,7 +1331,7 @@ defaultOptions = {
|
|
1327
1331
|
//marginLeft: null,
|
1328
1332
|
borderColor: '#4572A7',
|
1329
1333
|
//borderWidth: 0,
|
1330
|
-
borderRadius:
|
1334
|
+
borderRadius: 0,
|
1331
1335
|
defaultSeriesType: 'line',
|
1332
1336
|
ignoreHiddenSeries: true,
|
1333
1337
|
//inverted: false,
|
@@ -1369,8 +1373,8 @@ defaultOptions = {
|
|
1369
1373
|
// verticalAlign: 'top',
|
1370
1374
|
// y: null,
|
1371
1375
|
style: {
|
1372
|
-
color: '#
|
1373
|
-
fontSize: '
|
1376
|
+
color: '#333333', // docs
|
1377
|
+
fontSize: '18px'
|
1374
1378
|
}
|
1375
1379
|
|
1376
1380
|
},
|
@@ -1382,7 +1386,7 @@ defaultOptions = {
|
|
1382
1386
|
// verticalAlign: 'top',
|
1383
1387
|
// y: null,
|
1384
1388
|
style: {
|
1385
|
-
color: '#
|
1389
|
+
color: '#555555' // docs
|
1386
1390
|
}
|
1387
1391
|
},
|
1388
1392
|
|
@@ -1405,7 +1409,7 @@ defaultOptions = {
|
|
1405
1409
|
//shadow: false,
|
1406
1410
|
// stacking: null,
|
1407
1411
|
marker: {
|
1408
|
-
enabled: true,
|
1412
|
+
//enabled: true,
|
1409
1413
|
//symbol: null,
|
1410
1414
|
lineWidth: 0,
|
1411
1415
|
radius: 4,
|
@@ -1428,6 +1432,7 @@ defaultOptions = {
|
|
1428
1432
|
},
|
1429
1433
|
dataLabels: merge(defaultLabelOptions, {
|
1430
1434
|
align: 'center',
|
1435
|
+
//defer: true,
|
1431
1436
|
enabled: false,
|
1432
1437
|
formatter: function () {
|
1433
1438
|
return this.y === null ? '' : numberFormat(this.y, -1);
|
@@ -1453,6 +1458,10 @@ defaultOptions = {
|
|
1453
1458
|
marker: {
|
1454
1459
|
// lineWidth: base + 1,
|
1455
1460
|
// radius: base + 1
|
1461
|
+
},
|
1462
|
+
halo: {
|
1463
|
+
size: 10,
|
1464
|
+
opacity: 0.25
|
1456
1465
|
}
|
1457
1466
|
},
|
1458
1467
|
select: {
|
@@ -1461,7 +1470,7 @@ defaultOptions = {
|
|
1461
1470
|
},
|
1462
1471
|
stickyTracking: true,
|
1463
1472
|
//tooltip: {
|
1464
|
-
//pointFormat: '<span style="color:{series.color}">{series.name}
|
1473
|
+
//pointFormat: '<span style="color:{series.color}">\u25CF</span> {series.name}: <b>{point.y}</b>'
|
1465
1474
|
//valueDecimals: null,
|
1466
1475
|
//xDateFormat: '%A, %b %e, %Y',
|
1467
1476
|
//valuePrefix: '',
|
@@ -1487,9 +1496,9 @@ defaultOptions = {
|
|
1487
1496
|
labelFormatter: function () {
|
1488
1497
|
return this.name;
|
1489
1498
|
},
|
1490
|
-
borderWidth:
|
1499
|
+
//borderWidth: 0,
|
1491
1500
|
borderColor: '#909090',
|
1492
|
-
borderRadius:
|
1501
|
+
borderRadius: 0, // docs
|
1493
1502
|
navigation: {
|
1494
1503
|
// animation: true,
|
1495
1504
|
activeColor: '#274b6d',
|
@@ -1497,7 +1506,7 @@ defaultOptions = {
|
|
1497
1506
|
inactiveColor: '#CCC'
|
1498
1507
|
// style: {} // text styles
|
1499
1508
|
},
|
1500
|
-
// margin:
|
1509
|
+
// margin: 20,
|
1501
1510
|
// reversed: false,
|
1502
1511
|
shadow: false,
|
1503
1512
|
// backgroundColor: null,
|
@@ -1505,8 +1514,9 @@ defaultOptions = {
|
|
1505
1514
|
padding: '5px'
|
1506
1515
|
},*/
|
1507
1516
|
itemStyle: {
|
1508
|
-
color: '#
|
1509
|
-
fontSize: '12px'
|
1517
|
+
color: '#333333', // docs
|
1518
|
+
fontSize: '12px',
|
1519
|
+
fontWeight: 'bold' // docs
|
1510
1520
|
},
|
1511
1521
|
itemHoverStyle: {
|
1512
1522
|
//cursor: 'pointer', removed as of #601
|
@@ -1521,6 +1531,7 @@ defaultOptions = {
|
|
1521
1531
|
height: '13px'
|
1522
1532
|
},
|
1523
1533
|
// itemWidth: undefined,
|
1534
|
+
// symbolRadius: 0,
|
1524
1535
|
// symbolWidth: 16,
|
1525
1536
|
symbolPadding: 5,
|
1526
1537
|
verticalAlign: 'bottom',
|
@@ -1555,7 +1566,7 @@ defaultOptions = {
|
|
1555
1566
|
enabled: true,
|
1556
1567
|
animation: hasSVG,
|
1557
1568
|
//crosshairs: null,
|
1558
|
-
backgroundColor: 'rgba(
|
1569
|
+
backgroundColor: 'rgba(249, 249, 249, .85)',
|
1559
1570
|
borderWidth: 1,
|
1560
1571
|
borderRadius: 3,
|
1561
1572
|
dateTimeLabelFormats: {
|
@@ -1570,8 +1581,9 @@ defaultOptions = {
|
|
1570
1581
|
},
|
1571
1582
|
//formatter: defaultFormatter,
|
1572
1583
|
headerFormat: '<span style="font-size: 10px">{point.key}</span><br/>',
|
1573
|
-
pointFormat: '<span style="color:{series.color}">{series.name}
|
1584
|
+
pointFormat: '<span style="color:{series.color}">\u25CF</span> {series.name}: <b>{point.y}</b><br/>', // docs
|
1574
1585
|
shadow: true,
|
1586
|
+
//shape: 'calout',
|
1575
1587
|
//shared: false,
|
1576
1588
|
snap: isTouchDevice ? 25 : 10,
|
1577
1589
|
style: {
|
@@ -1815,13 +1827,6 @@ SVGElement.prototype = {
|
|
1815
1827
|
createElement(nodeName) :
|
1816
1828
|
doc.createElementNS(SVG_NS, nodeName);
|
1817
1829
|
wrapper.renderer = renderer;
|
1818
|
-
/**
|
1819
|
-
* A collection of attribute setters. These methods, if defined, are called right before a certain
|
1820
|
-
* attribute is set on an element wrapper. Returning false prevents the default attribute
|
1821
|
-
* setter to run. Returning a value causes the default setter to set that value. Used in
|
1822
|
-
* Renderer.label.
|
1823
|
-
*/
|
1824
|
-
wrapper.attrSetters = {};
|
1825
1830
|
},
|
1826
1831
|
/**
|
1827
1832
|
* Default base for animation
|
@@ -1849,241 +1854,171 @@ SVGElement.prototype = {
|
|
1849
1854
|
}
|
1850
1855
|
}
|
1851
1856
|
},
|
1857
|
+
|
1858
|
+
/**
|
1859
|
+
* Build an SVG gradient out of a common JavaScript configuration object
|
1860
|
+
*/
|
1861
|
+
colorGradient: function (color, prop, elem) {
|
1862
|
+
var renderer = this.renderer,
|
1863
|
+
colorObject,
|
1864
|
+
gradName,
|
1865
|
+
gradAttr,
|
1866
|
+
gradients,
|
1867
|
+
gradientObject,
|
1868
|
+
stops,
|
1869
|
+
stopColor,
|
1870
|
+
stopOpacity,
|
1871
|
+
radialReference,
|
1872
|
+
n,
|
1873
|
+
id,
|
1874
|
+
key = [];
|
1875
|
+
|
1876
|
+
// Apply linear or radial gradients
|
1877
|
+
if (color.linearGradient) {
|
1878
|
+
gradName = 'linearGradient';
|
1879
|
+
} else if (color.radialGradient) {
|
1880
|
+
gradName = 'radialGradient';
|
1881
|
+
}
|
1882
|
+
|
1883
|
+
if (gradName) {
|
1884
|
+
gradAttr = color[gradName];
|
1885
|
+
gradients = renderer.gradients;
|
1886
|
+
stops = color.stops;
|
1887
|
+
radialReference = elem.radialReference;
|
1888
|
+
|
1889
|
+
// Keep < 2.2 kompatibility
|
1890
|
+
if (isArray(gradAttr)) {
|
1891
|
+
color[gradName] = gradAttr = {
|
1892
|
+
x1: gradAttr[0],
|
1893
|
+
y1: gradAttr[1],
|
1894
|
+
x2: gradAttr[2],
|
1895
|
+
y2: gradAttr[3],
|
1896
|
+
gradientUnits: 'userSpaceOnUse'
|
1897
|
+
};
|
1898
|
+
}
|
1899
|
+
|
1900
|
+
// Correct the radial gradient for the radial reference system
|
1901
|
+
if (gradName === 'radialGradient' && radialReference && !defined(gradAttr.gradientUnits)) {
|
1902
|
+
gradAttr = merge(gradAttr, {
|
1903
|
+
cx: (radialReference[0] - radialReference[2] / 2) + gradAttr.cx * radialReference[2],
|
1904
|
+
cy: (radialReference[1] - radialReference[2] / 2) + gradAttr.cy * radialReference[2],
|
1905
|
+
r: gradAttr.r * radialReference[2],
|
1906
|
+
gradientUnits: 'userSpaceOnUse'
|
1907
|
+
});
|
1908
|
+
}
|
1909
|
+
|
1910
|
+
// Build the unique key to detect whether we need to create a new element (#1282)
|
1911
|
+
for (n in gradAttr) {
|
1912
|
+
if (n !== 'id') {
|
1913
|
+
key.push(n, gradAttr[n]);
|
1914
|
+
}
|
1915
|
+
}
|
1916
|
+
for (n in stops) {
|
1917
|
+
key.push(stops[n]);
|
1918
|
+
}
|
1919
|
+
key = key.join(',');
|
1920
|
+
|
1921
|
+
// Check if a gradient object with the same config object is created within this renderer
|
1922
|
+
if (gradients[key]) {
|
1923
|
+
id = gradients[key].attr('id');
|
1924
|
+
|
1925
|
+
} else {
|
1926
|
+
|
1927
|
+
// Set the id and create the element
|
1928
|
+
gradAttr.id = id = PREFIX + idCounter++;
|
1929
|
+
gradients[key] = gradientObject = renderer.createElement(gradName)
|
1930
|
+
.attr(gradAttr)
|
1931
|
+
.add(renderer.defs);
|
1932
|
+
|
1933
|
+
|
1934
|
+
// The gradient needs to keep a list of stops to be able to destroy them
|
1935
|
+
gradientObject.stops = [];
|
1936
|
+
each(stops, function (stop) {
|
1937
|
+
var stopObject;
|
1938
|
+
if (stop[1].indexOf('rgba') === 0) {
|
1939
|
+
colorObject = Color(stop[1]);
|
1940
|
+
stopColor = colorObject.get('rgb');
|
1941
|
+
stopOpacity = colorObject.get('a');
|
1942
|
+
} else {
|
1943
|
+
stopColor = stop[1];
|
1944
|
+
stopOpacity = 1;
|
1945
|
+
}
|
1946
|
+
stopObject = renderer.createElement('stop').attr({
|
1947
|
+
offset: stop[0],
|
1948
|
+
'stop-color': stopColor,
|
1949
|
+
'stop-opacity': stopOpacity
|
1950
|
+
}).add(gradientObject);
|
1951
|
+
|
1952
|
+
// Add the stop element to the gradient
|
1953
|
+
gradientObject.stops.push(stopObject);
|
1954
|
+
});
|
1955
|
+
}
|
1956
|
+
|
1957
|
+
// Set the reference to the gradient object
|
1958
|
+
elem.setAttribute(prop, 'url(' + renderer.url + '#' + id + ')');
|
1959
|
+
}
|
1960
|
+
},
|
1961
|
+
|
1852
1962
|
/**
|
1853
1963
|
* Set or get a given attribute
|
1854
1964
|
* @param {Object|String} hash
|
1855
1965
|
* @param {Mixed|Undefined} val
|
1856
1966
|
*/
|
1857
1967
|
attr: function (hash, val) {
|
1858
|
-
var
|
1859
|
-
key,
|
1968
|
+
var key,
|
1860
1969
|
value,
|
1861
|
-
|
1862
|
-
i,
|
1863
|
-
child,
|
1864
|
-
element = wrapper.element,
|
1865
|
-
nodeName = element.nodeName.toLowerCase(), // Android2 requires lower for "text"
|
1866
|
-
renderer = wrapper.renderer,
|
1867
|
-
skipAttr,
|
1868
|
-
titleNode,
|
1869
|
-
attrSetters = wrapper.attrSetters,
|
1870
|
-
shadows = wrapper.shadows,
|
1970
|
+
element = this.element,
|
1871
1971
|
hasSetSymbolSize,
|
1872
|
-
|
1873
|
-
|
1972
|
+
ret = this,
|
1973
|
+
skipAttr;
|
1874
1974
|
|
1875
1975
|
// single key-value pair
|
1876
|
-
if (
|
1976
|
+
if (typeof hash === 'string' && val !== UNDEFINED) {
|
1877
1977
|
key = hash;
|
1878
1978
|
hash = {};
|
1879
1979
|
hash[key] = val;
|
1880
1980
|
}
|
1881
1981
|
|
1882
1982
|
// used as a getter: first argument is a string, second is undefined
|
1883
|
-
if (
|
1884
|
-
|
1885
|
-
|
1886
|
-
key = { x: 'cx', y: 'cy' }[key] || key;
|
1887
|
-
} else if (key === 'strokeWidth') {
|
1888
|
-
key = 'stroke-width';
|
1889
|
-
}
|
1890
|
-
ret = attr(element, key) || wrapper[key] || 0;
|
1891
|
-
if (key !== 'd' && key !== 'visibility' && key !== 'fill') { // 'd' is string in animation step
|
1892
|
-
ret = parseFloat(ret);
|
1893
|
-
}
|
1894
|
-
|
1983
|
+
if (typeof hash === 'string') {
|
1984
|
+
ret = (this[hash + 'Getter'] || this._defaultGetter).call(this, hash, element);
|
1985
|
+
|
1895
1986
|
// setter
|
1896
1987
|
} else {
|
1897
1988
|
|
1898
1989
|
for (key in hash) {
|
1899
|
-
skipAttr = false; // reset
|
1900
1990
|
value = hash[key];
|
1991
|
+
skipAttr = false;
|
1901
1992
|
|
1902
|
-
// check for a specific attribute setter
|
1903
|
-
result = attrSetters[key] && attrSetters[key].call(wrapper, value, key);
|
1904
|
-
|
1905
|
-
if (result !== false) {
|
1906
|
-
if (result !== UNDEFINED) {
|
1907
|
-
value = result; // the attribute setter has returned a new value to set
|
1908
|
-
}
|
1909
|
-
|
1910
|
-
|
1911
|
-
// paths
|
1912
|
-
if (key === 'd') {
|
1913
|
-
if (value && value.join) { // join path
|
1914
|
-
value = value.join(' ');
|
1915
|
-
}
|
1916
|
-
if (/(NaN| {2}|^$)/.test(value)) {
|
1917
|
-
value = 'M 0 0';
|
1918
|
-
}
|
1919
|
-
//wrapper.d = value; // shortcut for animations
|
1920
|
-
|
1921
|
-
// update child tspans x values
|
1922
|
-
} else if (key === 'x' && nodeName === 'text') {
|
1923
|
-
for (i = 0; i < element.childNodes.length; i++) {
|
1924
|
-
child = element.childNodes[i];
|
1925
|
-
// if the x values are equal, the tspan represents a linebreak
|
1926
|
-
if (attr(child, 'x') === attr(element, 'x')) {
|
1927
|
-
//child.setAttribute('x', value);
|
1928
|
-
attr(child, 'x', value);
|
1929
|
-
}
|
1930
|
-
}
|
1931
|
-
|
1932
|
-
} else if (wrapper.rotation && (key === 'x' || key === 'y')) {
|
1933
|
-
doTransform = true;
|
1934
|
-
|
1935
|
-
// apply gradients
|
1936
|
-
} else if (key === 'fill') {
|
1937
|
-
value = renderer.color(value, element, key);
|
1938
|
-
|
1939
|
-
// circle x and y
|
1940
|
-
} else if (nodeName === 'circle' && (key === 'x' || key === 'y')) {
|
1941
|
-
key = { x: 'cx', y: 'cy' }[key] || key;
|
1942
|
-
|
1943
|
-
// rectangle border radius
|
1944
|
-
} else if (nodeName === 'rect' && key === 'r') {
|
1945
|
-
attr(element, {
|
1946
|
-
rx: value,
|
1947
|
-
ry: value
|
1948
|
-
});
|
1949
|
-
skipAttr = true;
|
1950
|
-
|
1951
|
-
// translation and text rotation
|
1952
|
-
} else if (key === 'translateX' || key === 'translateY' || key === 'rotation' ||
|
1953
|
-
key === 'verticalAlign' || key === 'scaleX' || key === 'scaleY') {
|
1954
|
-
doTransform = true;
|
1955
|
-
skipAttr = true;
|
1956
|
-
|
1957
|
-
// apply opacity as subnode (required by legacy WebKit and Batik)
|
1958
|
-
} else if (key === 'stroke') {
|
1959
|
-
value = renderer.color(value, element, key);
|
1960
|
-
|
1961
|
-
// emulate VML's dashstyle implementation
|
1962
|
-
} else if (key === 'dashstyle') {
|
1963
|
-
key = 'stroke-dasharray';
|
1964
|
-
value = value && value.toLowerCase();
|
1965
|
-
if (value === 'solid') {
|
1966
|
-
value = NONE;
|
1967
|
-
} else if (value) {
|
1968
|
-
value = value
|
1969
|
-
.replace('shortdashdotdot', '3,1,1,1,1,1,')
|
1970
|
-
.replace('shortdashdot', '3,1,1,1')
|
1971
|
-
.replace('shortdot', '1,1,')
|
1972
|
-
.replace('shortdash', '3,1,')
|
1973
|
-
.replace('longdash', '8,3,')
|
1974
|
-
.replace(/dot/g, '1,3,')
|
1975
|
-
.replace('dash', '4,3,')
|
1976
|
-
.replace(/,$/, '')
|
1977
|
-
.split(','); // ending comma
|
1978
|
-
|
1979
|
-
i = value.length;
|
1980
|
-
while (i--) {
|
1981
|
-
value[i] = pInt(value[i]) * pick(hash['stroke-width'], wrapper['stroke-width']);
|
1982
|
-
}
|
1983
|
-
value = value.join(',');
|
1984
|
-
}
|
1985
|
-
|
1986
|
-
// IE9/MooTools combo: MooTools returns objects instead of numbers and IE9 Beta 2
|
1987
|
-
// is unable to cast them. Test again with final IE9.
|
1988
|
-
} else if (key === 'width') {
|
1989
|
-
value = pInt(value);
|
1990
|
-
|
1991
|
-
// Text alignment
|
1992
|
-
} else if (key === 'align') {
|
1993
|
-
key = 'text-anchor';
|
1994
|
-
value = { left: 'start', center: 'middle', right: 'end' }[value];
|
1995
|
-
|
1996
|
-
// Title requires a subnode, #431
|
1997
|
-
} else if (key === 'title') {
|
1998
|
-
titleNode = element.getElementsByTagName('title')[0];
|
1999
|
-
if (!titleNode) {
|
2000
|
-
titleNode = doc.createElementNS(SVG_NS, 'title');
|
2001
|
-
element.appendChild(titleNode);
|
2002
|
-
}
|
2003
|
-
titleNode.textContent = value;
|
2004
|
-
}
|
2005
|
-
|
2006
|
-
// jQuery animate changes case
|
2007
|
-
if (key === 'strokeWidth') {
|
2008
|
-
key = 'stroke-width';
|
2009
|
-
}
|
2010
|
-
|
2011
|
-
// In Chrome/Win < 6 as well as Batik, the stroke attribute can't be set when the stroke-
|
2012
|
-
// width is 0. #1369
|
2013
|
-
if (key === 'stroke-width' || key === 'stroke') {
|
2014
|
-
wrapper[key] = value;
|
2015
|
-
// Only apply the stroke attribute if the stroke width is defined and larger than 0
|
2016
|
-
if (wrapper.stroke && wrapper['stroke-width']) {
|
2017
|
-
attr(element, 'stroke', wrapper.stroke);
|
2018
|
-
attr(element, 'stroke-width', wrapper['stroke-width']);
|
2019
|
-
wrapper.hasStroke = true;
|
2020
|
-
} else if (key === 'stroke-width' && value === 0 && wrapper.hasStroke) {
|
2021
|
-
element.removeAttribute('stroke');
|
2022
|
-
wrapper.hasStroke = false;
|
2023
|
-
}
|
2024
|
-
skipAttr = true;
|
2025
|
-
}
|
2026
|
-
|
2027
|
-
// symbols
|
2028
|
-
if (wrapper.symbolName && /^(x|y|width|height|r|start|end|innerR|anchorX|anchorY)/.test(key)) {
|
2029
|
-
|
2030
|
-
|
2031
|
-
if (!hasSetSymbolSize) {
|
2032
|
-
wrapper.symbolAttr(hash);
|
2033
|
-
hasSetSymbolSize = true;
|
2034
|
-
}
|
2035
|
-
skipAttr = true;
|
2036
|
-
}
|
2037
|
-
|
2038
|
-
// let the shadow follow the main element
|
2039
|
-
if (shadows && /^(width|height|visibility|x|y|d|transform|cx|cy|r)$/.test(key)) {
|
2040
|
-
i = shadows.length;
|
2041
|
-
while (i--) {
|
2042
|
-
attr(
|
2043
|
-
shadows[i],
|
2044
|
-
key,
|
2045
|
-
key === 'height' ?
|
2046
|
-
mathMax(value - (shadows[i].cutHeight || 0), 0) :
|
2047
|
-
value
|
2048
|
-
);
|
2049
|
-
}
|
2050
|
-
}
|
2051
|
-
|
2052
|
-
// validate heights
|
2053
|
-
if ((key === 'width' || key === 'height') && nodeName === 'rect' && value < 0) {
|
2054
|
-
value = 0;
|
2055
|
-
}
|
2056
|
-
|
2057
|
-
// Record for animation and quick access without polling the DOM
|
2058
|
-
wrapper[key] = value;
|
2059
1993
|
|
2060
1994
|
|
2061
|
-
|
2062
|
-
|
2063
|
-
|
2064
|
-
|
2065
|
-
delete wrapper.bBox;
|
2066
|
-
|
2067
|
-
wrapper.textStr = value;
|
2068
|
-
if (wrapper.added) {
|
2069
|
-
renderer.buildText(wrapper);
|
2070
|
-
}
|
2071
|
-
}
|
2072
|
-
} else if (!skipAttr) {
|
2073
|
-
//attr(element, key, value);
|
2074
|
-
if (value !== undefined) {
|
2075
|
-
element.setAttribute(key, value);
|
2076
|
-
}
|
1995
|
+
if (this.symbolName && /^(x|y|width|height|r|start|end|innerR|anchorX|anchorY)/.test(key)) {
|
1996
|
+
if (!hasSetSymbolSize) {
|
1997
|
+
this.symbolAttr(hash);
|
1998
|
+
hasSetSymbolSize = true;
|
2077
1999
|
}
|
2000
|
+
skipAttr = true;
|
2001
|
+
}
|
2078
2002
|
|
2003
|
+
if (this.rotation && (key === 'x' || key === 'y')) {
|
2004
|
+
this.doTransform = true;
|
2005
|
+
}
|
2006
|
+
|
2007
|
+
if (!skipAttr) {
|
2008
|
+
(this[key + 'Setter'] || this._defaultSetter).call(this, value, key, element);
|
2079
2009
|
}
|
2080
2010
|
|
2011
|
+
// Let the shadow follow the main element
|
2012
|
+
if (this.shadows && /^(width|height|visibility|x|y|d|transform|cx|cy|r)$/.test(key)) {
|
2013
|
+
this.updateShadows(key, value);
|
2014
|
+
}
|
2081
2015
|
}
|
2082
2016
|
|
2083
2017
|
// Update transform. Do this outside the loop to prevent redundant updating for batch setting
|
2084
2018
|
// of attributes.
|
2085
|
-
if (doTransform) {
|
2086
|
-
|
2019
|
+
if (this.doTransform) {
|
2020
|
+
this.updateTransform();
|
2021
|
+
this.doTransform = false;
|
2087
2022
|
}
|
2088
2023
|
|
2089
2024
|
}
|
@@ -2091,6 +2026,18 @@ SVGElement.prototype = {
|
|
2091
2026
|
return ret;
|
2092
2027
|
},
|
2093
2028
|
|
2029
|
+
updateShadows: function (key, value) {
|
2030
|
+
var shadows = this.shadows,
|
2031
|
+
i = shadows.length;
|
2032
|
+
while (i--) {
|
2033
|
+
shadows[i].setAttribute(
|
2034
|
+
key,
|
2035
|
+
key === 'height' ?
|
2036
|
+
mathMax(value - (shadows[i].cutHeight || 0), 0) :
|
2037
|
+
key === 'd' ? this.d : value
|
2038
|
+
);
|
2039
|
+
}
|
2040
|
+
},
|
2094
2041
|
|
2095
2042
|
/**
|
2096
2043
|
* Add a class name to an element
|
@@ -2323,6 +2270,7 @@ SVGElement.prototype = {
|
|
2323
2270
|
scaleY = wrapper.scaleY,
|
2324
2271
|
inverted = wrapper.inverted,
|
2325
2272
|
rotation = wrapper.rotation,
|
2273
|
+
element = wrapper.element,
|
2326
2274
|
transform;
|
2327
2275
|
|
2328
2276
|
// flipping affects translate as adjustment for flipping around the group's axis
|
@@ -2339,7 +2287,7 @@ SVGElement.prototype = {
|
|
2339
2287
|
if (inverted) {
|
2340
2288
|
transform.push('rotate(90) scale(-1,1)');
|
2341
2289
|
} else if (rotation) { // text rotation
|
2342
|
-
transform.push('rotate(' + rotation + ' ' + (
|
2290
|
+
transform.push('rotate(' + rotation + ' ' + (element.getAttribute('x') || 0) + ' ' + (element.getAttribute('y') || 0) + ')');
|
2343
2291
|
}
|
2344
2292
|
|
2345
2293
|
// apply scale
|
@@ -2348,7 +2296,7 @@ SVGElement.prototype = {
|
|
2348
2296
|
}
|
2349
2297
|
|
2350
2298
|
if (transform.length) {
|
2351
|
-
|
2299
|
+
element.setAttribute('transform', transform.join(' '));
|
2352
2300
|
}
|
2353
2301
|
},
|
2354
2302
|
/**
|
@@ -2447,14 +2395,21 @@ SVGElement.prototype = {
|
|
2447
2395
|
styles = wrapper.styles,
|
2448
2396
|
rad = rotation * deg2rad,
|
2449
2397
|
textStr = wrapper.textStr,
|
2450
|
-
|
2398
|
+
cacheKey;
|
2451
2399
|
|
2452
2400
|
// Since numbers are monospaced, and numerical labels appear a lot in a chart,
|
2453
2401
|
// we assume that a label of n characters has the same bounding box as others
|
2454
2402
|
// of the same length.
|
2455
2403
|
if (textStr === '' || numRegex.test(textStr)) {
|
2456
|
-
|
2457
|
-
|
2404
|
+
cacheKey = 'num.' + textStr.toString().length + (styles ? ('|' + styles.fontSize + '|' + styles.fontFamily) : '');
|
2405
|
+
|
2406
|
+
} //else { // This code block made demo/waterfall fail, related to buildText
|
2407
|
+
// Caching all strings reduces rendering time by 4-5%.
|
2408
|
+
// TODO: Check how this affects places where bBox is found on the element
|
2409
|
+
//cacheKey = textStr + (styles ? ('|' + styles.fontSize + '|' + styles.fontFamily) : '');
|
2410
|
+
//}
|
2411
|
+
if (cacheKey) {
|
2412
|
+
bBox = renderer.cache[cacheKey];
|
2458
2413
|
}
|
2459
2414
|
|
2460
2415
|
// No cache found
|
@@ -2509,8 +2464,8 @@ SVGElement.prototype = {
|
|
2509
2464
|
|
2510
2465
|
// Cache it
|
2511
2466
|
wrapper.bBox = bBox;
|
2512
|
-
if (
|
2513
|
-
renderer.cache[
|
2467
|
+
if (cacheKey) {
|
2468
|
+
renderer.cache[cacheKey] = bBox;
|
2514
2469
|
}
|
2515
2470
|
}
|
2516
2471
|
return bBox;
|
@@ -2520,7 +2475,13 @@ SVGElement.prototype = {
|
|
2520
2475
|
* Show the element
|
2521
2476
|
*/
|
2522
2477
|
show: function (inherit) {
|
2523
|
-
|
2478
|
+
// IE9-11 doesn't handle visibilty:inherit well, so we remove the attribute instead (#2881)
|
2479
|
+
if (inherit && this.element.namespaceURI === SVG_NS) {
|
2480
|
+
this.element.removeAttribute('visibility');
|
2481
|
+
return this;
|
2482
|
+
} else {
|
2483
|
+
return this.attr({ visibility: inherit ? 'inherit' : VISIBLE });
|
2484
|
+
}
|
2524
2485
|
},
|
2525
2486
|
|
2526
2487
|
/**
|
@@ -2735,9 +2696,141 @@ SVGElement.prototype = {
|
|
2735
2696
|
}
|
2736
2697
|
return this;
|
2737
2698
|
|
2699
|
+
},
|
2700
|
+
|
2701
|
+
xGetter: function (key) {
|
2702
|
+
if (this.element.nodeName === 'circle') {
|
2703
|
+
key = { x: 'cx', y: 'cy' }[key] || key;
|
2704
|
+
}
|
2705
|
+
return this._defaultGetter(key);
|
2706
|
+
},
|
2707
|
+
|
2708
|
+
/**
|
2709
|
+
* Get the current value of an attribute or pseudo attribute, used mainly
|
2710
|
+
* for animation.
|
2711
|
+
*/
|
2712
|
+
_defaultGetter: function (key) {
|
2713
|
+
var ret = pick(this[key], this.element ? this.element.getAttribute(key) : null, 0);
|
2714
|
+
|
2715
|
+
if (/^[0-9\.]+$/.test(ret)) { // is numerical
|
2716
|
+
ret = parseFloat(ret);
|
2717
|
+
}
|
2718
|
+
return ret;
|
2719
|
+
},
|
2720
|
+
|
2721
|
+
|
2722
|
+
dSetter: function (value, key, element) {
|
2723
|
+
if (value && value.join) { // join path
|
2724
|
+
value = value.join(' ');
|
2725
|
+
}
|
2726
|
+
if (/(NaN| {2}|^$)/.test(value)) {
|
2727
|
+
value = 'M 0 0';
|
2728
|
+
}
|
2729
|
+
element.setAttribute(key, value);
|
2730
|
+
|
2731
|
+
this[key] = value;
|
2732
|
+
},
|
2733
|
+
dashstyleSetter: function (value) {
|
2734
|
+
var i;
|
2735
|
+
value = value && value.toLowerCase();
|
2736
|
+
if (value) {
|
2737
|
+
value = value
|
2738
|
+
.replace('shortdashdotdot', '3,1,1,1,1,1,')
|
2739
|
+
.replace('shortdashdot', '3,1,1,1')
|
2740
|
+
.replace('shortdot', '1,1,')
|
2741
|
+
.replace('shortdash', '3,1,')
|
2742
|
+
.replace('longdash', '8,3,')
|
2743
|
+
.replace(/dot/g, '1,3,')
|
2744
|
+
.replace('dash', '4,3,')
|
2745
|
+
.replace(/,$/, '')
|
2746
|
+
.split(','); // ending comma
|
2747
|
+
|
2748
|
+
i = value.length;
|
2749
|
+
while (i--) {
|
2750
|
+
value[i] = pInt(value[i]) * this.element.getAttribute('stroke-width');
|
2751
|
+
}
|
2752
|
+
value = value.join(',');
|
2753
|
+
this.element.setAttribute('stroke-dasharray', value);
|
2754
|
+
}
|
2755
|
+
},
|
2756
|
+
alignSetter: function (value) {
|
2757
|
+
this.element.setAttribute('text-anchor', { left: 'start', center: 'middle', right: 'end' }[value]);
|
2758
|
+
},
|
2759
|
+
opacitySetter: function (value, key, element) {
|
2760
|
+
this[key] = value;
|
2761
|
+
element.setAttribute(key, value);
|
2762
|
+
},
|
2763
|
+
// In Chrome/Win < 6 as well as Batik and PhantomJS as of 1.9.7, the stroke attribute can't be set when the stroke-
|
2764
|
+
// width is 0. #1369
|
2765
|
+
'stroke-widthSetter': function (value, key, element) {
|
2766
|
+
if (value === 0) {
|
2767
|
+
value = 0.00001;
|
2768
|
+
}
|
2769
|
+
this.strokeWidth = value; // read in symbol paths like 'callout'
|
2770
|
+
element.setAttribute(key, value);
|
2771
|
+
},
|
2772
|
+
titleSetter: function (value) {
|
2773
|
+
var titleNode = this.element.getElementsByTagName('title')[0];
|
2774
|
+
if (!titleNode) {
|
2775
|
+
titleNode = doc.createElementNS(SVG_NS, 'title');
|
2776
|
+
this.element.appendChild(titleNode);
|
2777
|
+
}
|
2778
|
+
titleNode.textContent = value;
|
2779
|
+
},
|
2780
|
+
textSetter: function (value) {
|
2781
|
+
if (value !== this.textStr) {
|
2782
|
+
// Delete bBox memo when the text changes
|
2783
|
+
delete this.bBox;
|
2784
|
+
|
2785
|
+
this.textStr = value;
|
2786
|
+
if (this.added) {
|
2787
|
+
this.renderer.buildText(this);
|
2788
|
+
}
|
2789
|
+
}
|
2790
|
+
},
|
2791
|
+
fillSetter: function (value, key, element) {
|
2792
|
+
|
2793
|
+
if (typeof value === 'string') {
|
2794
|
+
element.setAttribute(key, value);
|
2795
|
+
} else if (value) {
|
2796
|
+
this.colorGradient(value, key, element);
|
2797
|
+
}
|
2798
|
+
},
|
2799
|
+
zIndexSetter: function (value, key, element) {
|
2800
|
+
element.setAttribute(key, value);
|
2801
|
+
this[key] = value;
|
2802
|
+
},
|
2803
|
+
_defaultSetter: function (value, key, element) {
|
2804
|
+
element.setAttribute(key, value);
|
2738
2805
|
}
|
2739
2806
|
};
|
2740
2807
|
|
2808
|
+
// Some shared setters and getters
|
2809
|
+
SVGElement.prototype.yGetter = SVGElement.prototype.xGetter;
|
2810
|
+
SVGElement.prototype.translateXSetter = SVGElement.prototype.translateYSetter =
|
2811
|
+
SVGElement.prototype.rotationSetter = SVGElement.prototype.verticalAlignSetter =
|
2812
|
+
SVGElement.prototype.scaleXSetter = SVGElement.prototype.scaleYSetter = function (value, key) {
|
2813
|
+
this[key] = value;
|
2814
|
+
this.doTransform = true;
|
2815
|
+
};
|
2816
|
+
|
2817
|
+
|
2818
|
+
|
2819
|
+
// In Chrome/Win < 6 as well as Batik, the stroke attribute can't be set when the stroke-
|
2820
|
+
// width is 0. #1369
|
2821
|
+
/*SVGElement.prototype['stroke-widthSetter'] = SVGElement.prototype.strokeSetter = function (value, key) {
|
2822
|
+
this[key] = value;
|
2823
|
+
// Only apply the stroke attribute if the stroke width is defined and larger than 0
|
2824
|
+
if (this.stroke && this['stroke-width']) {
|
2825
|
+
this.element.setAttribute('stroke', this.stroke);
|
2826
|
+
this.element.setAttribute('stroke-width', this['stroke-width']);
|
2827
|
+
this.hasStroke = true;
|
2828
|
+
} else if (key === 'stroke-width' && value === 0 && this.hasStroke) {
|
2829
|
+
this.element.removeAttribute('stroke');
|
2830
|
+
this.hasStroke = false;
|
2831
|
+
}
|
2832
|
+
};*/
|
2833
|
+
|
2741
2834
|
|
2742
2835
|
/**
|
2743
2836
|
* The default SVG renderer
|
@@ -2830,7 +2923,7 @@ SVGRenderer.prototype = {
|
|
2830
2923
|
|
2831
2924
|
getStyle: function (style) {
|
2832
2925
|
return (this.style = extend({
|
2833
|
-
fontFamily: '"Lucida Grande", "Lucida Sans Unicode",
|
2926
|
+
fontFamily: '"Lucida Grande", "Lucida Sans Unicode", Arial, Helvetica, sans-serif', // default font
|
2834
2927
|
fontSize: '12px'
|
2835
2928
|
}, style));
|
2836
2929
|
},
|
@@ -2898,15 +2991,12 @@ SVGRenderer.prototype = {
|
|
2898
2991
|
var textNode = wrapper.element,
|
2899
2992
|
renderer = this,
|
2900
2993
|
forExport = renderer.forExport,
|
2901
|
-
|
2902
|
-
|
2903
|
-
|
2904
|
-
.replace(/<a/g, '<span')
|
2905
|
-
.replace(/<\/(b|strong|i|em|a)>/g, '</span>')
|
2906
|
-
.split(/<br.*?>/g),
|
2994
|
+
textStr = pick(wrapper.textStr, '').toString(),
|
2995
|
+
hasMarkup = textStr.indexOf('<') !== -1,
|
2996
|
+
lines,
|
2907
2997
|
childNodes = textNode.childNodes,
|
2908
|
-
styleRegex
|
2909
|
-
hrefRegex
|
2998
|
+
styleRegex,
|
2999
|
+
hrefRegex,
|
2910
3000
|
parentX = attr(textNode, 'x'),
|
2911
3001
|
textStyles = wrapper.styles,
|
2912
3002
|
width = wrapper.textWidth,
|
@@ -2918,7 +3008,7 @@ SVGRenderer.prototype = {
|
|
2918
3008
|
renderer.fontMetrics(
|
2919
3009
|
/(px|em)$/.test(tspan && tspan.style.fontSize) ?
|
2920
3010
|
tspan.style.fontSize :
|
2921
|
-
(textStyles.fontSize ||
|
3011
|
+
((textStyles && textStyles.fontSize) || renderer.style.fontSize || 12)
|
2922
3012
|
).h;
|
2923
3013
|
};
|
2924
3014
|
|
@@ -2927,142 +3017,170 @@ SVGRenderer.prototype = {
|
|
2927
3017
|
textNode.removeChild(childNodes[i]);
|
2928
3018
|
}
|
2929
3019
|
|
2930
|
-
|
2931
|
-
|
2932
|
-
|
3020
|
+
// Skip tspans, add text directly to text node
|
3021
|
+
if (!hasMarkup && textStr.indexOf(' ') === -1) {
|
3022
|
+
textNode.appendChild(doc.createTextNode(textStr));
|
3023
|
+
return;
|
2933
3024
|
|
2934
|
-
//
|
2935
|
-
|
2936
|
-
lines.pop();
|
2937
|
-
}
|
3025
|
+
// Complex strings, add more logic
|
3026
|
+
} else {
|
2938
3027
|
|
2939
|
-
|
2940
|
-
|
2941
|
-
var spans, spanNo = 0;
|
3028
|
+
styleRegex = /<.*style="([^"]+)".*>/;
|
3029
|
+
hrefRegex = /<.*href="(http[^"]+)".*>/;
|
2942
3030
|
|
2943
|
-
|
2944
|
-
|
3031
|
+
if (width && !wrapper.added) {
|
3032
|
+
this.box.appendChild(textNode); // attach it to the DOM to read offset width
|
3033
|
+
}
|
2945
3034
|
|
2946
|
-
|
2947
|
-
|
2948
|
-
|
2949
|
-
|
2950
|
-
|
2951
|
-
|
2952
|
-
|
2953
|
-
attr(tspan, 'style', spanStyle);
|
2954
|
-
}
|
2955
|
-
if (hrefRegex.test(span) && !forExport) { // Not for export - #1529
|
2956
|
-
attr(tspan, 'onclick', 'location.href=\"' + span.match(hrefRegex)[1] + '\"');
|
2957
|
-
css(tspan, { cursor: 'pointer' });
|
2958
|
-
}
|
3035
|
+
if (hasMarkup) {
|
3036
|
+
lines = textStr
|
3037
|
+
.replace(/<(b|strong)>/g, '<span style="font-weight:bold">')
|
3038
|
+
.replace(/<(i|em)>/g, '<span style="font-style:italic">')
|
3039
|
+
.replace(/<a/g, '<span')
|
3040
|
+
.replace(/<\/(b|strong|i|em|a)>/g, '</span>')
|
3041
|
+
.split(/<br.*?>/g);
|
2959
3042
|
|
2960
|
-
|
2961
|
-
|
2962
|
-
|
3043
|
+
} else {
|
3044
|
+
lines = [textStr];
|
3045
|
+
}
|
2963
3046
|
|
2964
|
-
// Nested tags aren't supported, and cause crash in Safari (#1596)
|
2965
|
-
if (span !== ' ') {
|
2966
3047
|
|
2967
|
-
|
2968
|
-
|
3048
|
+
// remove empty line at end
|
3049
|
+
if (lines[lines.length - 1] === '') {
|
3050
|
+
lines.pop();
|
3051
|
+
}
|
2969
3052
|
|
2970
|
-
|
2971
|
-
|
2972
|
-
|
2973
|
-
|
3053
|
+
|
3054
|
+
// build the lines
|
3055
|
+
each(lines, function (line, lineNo) {
|
3056
|
+
var spans, spanNo = 0;
|
3057
|
+
|
3058
|
+
line = line.replace(/<span/g, '|||<span').replace(/<\/span>/g, '</span>|||');
|
3059
|
+
spans = line.split('|||');
|
3060
|
+
|
3061
|
+
each(spans, function (span) {
|
3062
|
+
if (span !== '' || spans.length === 1) {
|
3063
|
+
var attributes = {},
|
3064
|
+
tspan = doc.createElementNS(SVG_NS, 'tspan'),
|
3065
|
+
spanStyle; // #390
|
3066
|
+
if (styleRegex.test(span)) {
|
3067
|
+
spanStyle = span.match(styleRegex)[1].replace(/(;| |^)color([ :])/, '$1fill$2');
|
3068
|
+
attr(tspan, 'style', spanStyle);
|
3069
|
+
}
|
3070
|
+
if (hrefRegex.test(span) && !forExport) { // Not for export - #1529
|
3071
|
+
attr(tspan, 'onclick', 'location.href=\"' + span.match(hrefRegex)[1] + '\"');
|
3072
|
+
css(tspan, { cursor: 'pointer' });
|
2974
3073
|
}
|
2975
3074
|
|
2976
|
-
|
2977
|
-
|
3075
|
+
span = (span.replace(/<(.|\n)*?>/g, '') || ' ')
|
3076
|
+
.replace(/</g, '<')
|
3077
|
+
.replace(/>/g, '>');
|
2978
3078
|
|
2979
|
-
//
|
2980
|
-
if (
|
3079
|
+
// Nested tags aren't supported, and cause crash in Safari (#1596)
|
3080
|
+
if (span !== ' ') {
|
2981
3081
|
|
2982
|
-
//
|
2983
|
-
|
2984
|
-
|
3082
|
+
// add the text node
|
3083
|
+
tspan.appendChild(doc.createTextNode(span));
|
3084
|
+
|
3085
|
+
if (!spanNo) { // first span in a line, align it to the left
|
3086
|
+
if (lineNo && parentX !== null) {
|
3087
|
+
attributes.x = parentX;
|
3088
|
+
}
|
3089
|
+
} else {
|
3090
|
+
attributes.dx = 0; // #16
|
2985
3091
|
}
|
2986
3092
|
|
2987
|
-
//
|
2988
|
-
|
2989
|
-
attr(
|
2990
|
-
tspan,
|
2991
|
-
'dy',
|
2992
|
-
getLineHeight(tspan),
|
2993
|
-
// Safari 6.0.2 - too optimized for its own good (#1539)
|
2994
|
-
// TODO: revisit this with future versions of Safari
|
2995
|
-
isWebKit && tspan.offsetHeight
|
2996
|
-
);
|
2997
|
-
}
|
3093
|
+
// add attributes
|
3094
|
+
attr(tspan, attributes);
|
2998
3095
|
|
2999
|
-
|
3000
|
-
|
3001
|
-
|
3002
|
-
spanNo++;
|
3003
|
-
|
3004
|
-
// check width and apply soft breaks
|
3005
|
-
if (width) {
|
3006
|
-
var words = span.replace(/([^\^])-/g, '$1- ').split(' '), // #1273
|
3007
|
-
hasWhiteSpace = words.length > 1 && textStyles.whiteSpace !== 'nowrap',
|
3008
|
-
tooLong,
|
3009
|
-
actualWidth,
|
3010
|
-
clipHeight = wrapper._clipHeight,
|
3011
|
-
rest = [],
|
3012
|
-
dy = getLineHeight(),
|
3013
|
-
softLineNo = 1,
|
3014
|
-
bBox;
|
3015
|
-
|
3016
|
-
while (hasWhiteSpace && (words.length || rest.length)) {
|
3017
|
-
delete wrapper.bBox; // delete cache
|
3018
|
-
bBox = wrapper.getBBox();
|
3019
|
-
actualWidth = bBox.width;
|
3096
|
+
// first span on subsequent line, add the line height
|
3097
|
+
if (!spanNo && lineNo) {
|
3020
3098
|
|
3021
|
-
//
|
3022
|
-
if (!hasSVG &&
|
3023
|
-
|
3099
|
+
// allow getting the right offset height in exporting in IE
|
3100
|
+
if (!hasSVG && forExport) {
|
3101
|
+
css(tspan, { display: 'block' });
|
3024
3102
|
}
|
3025
3103
|
|
3026
|
-
|
3027
|
-
|
3028
|
-
|
3029
|
-
|
3030
|
-
|
3031
|
-
|
3032
|
-
|
3033
|
-
|
3034
|
-
|
3035
|
-
|
3036
|
-
|
3037
|
-
|
3038
|
-
|
3039
|
-
|
3040
|
-
|
3041
|
-
|
3042
|
-
|
3043
|
-
|
3044
|
-
|
3045
|
-
|
3046
|
-
|
3104
|
+
// Set the line height based on the font size of either
|
3105
|
+
// the text element or the tspan element
|
3106
|
+
attr(
|
3107
|
+
tspan,
|
3108
|
+
'dy',
|
3109
|
+
getLineHeight(tspan),
|
3110
|
+
// Safari 6.0.2 - too optimized for its own good (#1539)
|
3111
|
+
// TODO: revisit this with future versions of Safari
|
3112
|
+
isWebKit && tspan.offsetHeight
|
3113
|
+
);
|
3114
|
+
}
|
3115
|
+
|
3116
|
+
// Append it
|
3117
|
+
textNode.appendChild(tspan);
|
3118
|
+
|
3119
|
+
spanNo++;
|
3120
|
+
|
3121
|
+
// check width and apply soft breaks
|
3122
|
+
if (width) {
|
3123
|
+
var words = span.replace(/([^\^])-/g, '$1- ').split(' '), // #1273
|
3124
|
+
hasWhiteSpace = words.length > 1 && textStyles.whiteSpace !== 'nowrap',
|
3125
|
+
tooLong,
|
3126
|
+
actualWidth,
|
3127
|
+
clipHeight = wrapper._clipHeight,
|
3128
|
+
rest = [],
|
3129
|
+
dy = getLineHeight(),
|
3130
|
+
softLineNo = 1,
|
3131
|
+
bBox;
|
3132
|
+
|
3133
|
+
while (hasWhiteSpace && (words.length || rest.length)) {
|
3134
|
+
delete wrapper.bBox; // delete cache
|
3135
|
+
bBox = wrapper.getBBox();
|
3136
|
+
actualWidth = bBox.width;
|
3137
|
+
|
3138
|
+
// Old IE cannot measure the actualWidth for SVG elements (#2314)
|
3139
|
+
if (!hasSVG && renderer.forExport) {
|
3140
|
+
actualWidth = renderer.measureSpanWidth(tspan.firstChild.data, wrapper.styles);
|
3141
|
+
}
|
3047
3142
|
|
3048
|
-
|
3049
|
-
|
3143
|
+
tooLong = actualWidth > width;
|
3144
|
+
if (!tooLong || words.length === 1) { // new line needed
|
3145
|
+
words = rest;
|
3146
|
+
rest = [];
|
3147
|
+
if (words.length) {
|
3148
|
+
softLineNo++;
|
3149
|
+
|
3150
|
+
if (clipHeight && softLineNo * dy > clipHeight) {
|
3151
|
+
words = ['...'];
|
3152
|
+
wrapper.attr('title', wrapper.textStr);
|
3153
|
+
} else {
|
3154
|
+
|
3155
|
+
tspan = doc.createElementNS(SVG_NS, 'tspan');
|
3156
|
+
attr(tspan, {
|
3157
|
+
dy: dy,
|
3158
|
+
x: parentX
|
3159
|
+
});
|
3160
|
+
if (spanStyle) { // #390
|
3161
|
+
attr(tspan, 'style', spanStyle);
|
3162
|
+
}
|
3163
|
+
textNode.appendChild(tspan);
|
3164
|
+
|
3165
|
+
if (actualWidth > width) { // a single word is pressing it out
|
3166
|
+
width = actualWidth;
|
3167
|
+
}
|
3050
3168
|
}
|
3051
3169
|
}
|
3170
|
+
} else { // append to existing line tspan
|
3171
|
+
tspan.removeChild(tspan.firstChild);
|
3172
|
+
rest.unshift(words.pop());
|
3173
|
+
}
|
3174
|
+
if (words.length) {
|
3175
|
+
tspan.appendChild(doc.createTextNode(words.join(' ').replace(/- /g, '-')));
|
3052
3176
|
}
|
3053
|
-
} else { // append to existing line tspan
|
3054
|
-
tspan.removeChild(tspan.firstChild);
|
3055
|
-
rest.unshift(words.pop());
|
3056
|
-
}
|
3057
|
-
if (words.length) {
|
3058
|
-
tspan.appendChild(doc.createTextNode(words.join(' ').replace(/- /g, '-')));
|
3059
3177
|
}
|
3060
3178
|
}
|
3061
3179
|
}
|
3062
3180
|
}
|
3063
|
-
}
|
3181
|
+
});
|
3064
3182
|
});
|
3065
|
-
}
|
3183
|
+
}
|
3066
3184
|
},
|
3067
3185
|
|
3068
3186
|
/**
|
@@ -3084,7 +3202,6 @@ SVGRenderer.prototype = {
|
|
3084
3202
|
hoverStyle,
|
3085
3203
|
pressedStyle,
|
3086
3204
|
disabledStyle,
|
3087
|
-
STYLE = 'style',
|
3088
3205
|
verticalGradient = { x1: 0, y1: 0, x2: 0, y2: 1 };
|
3089
3206
|
|
3090
3207
|
// Normal state - prepare the attributes
|
@@ -3104,8 +3221,8 @@ SVGRenderer.prototype = {
|
|
3104
3221
|
color: 'black'
|
3105
3222
|
}
|
3106
3223
|
}, normalState);
|
3107
|
-
normalStyle = normalState
|
3108
|
-
delete normalState
|
3224
|
+
normalStyle = normalState.style;
|
3225
|
+
delete normalState.style;
|
3109
3226
|
|
3110
3227
|
// Hover state
|
3111
3228
|
hoverState = merge(normalState, {
|
@@ -3118,8 +3235,8 @@ SVGRenderer.prototype = {
|
|
3118
3235
|
]
|
3119
3236
|
}
|
3120
3237
|
}, hoverState);
|
3121
|
-
hoverStyle = hoverState
|
3122
|
-
delete hoverState
|
3238
|
+
hoverStyle = hoverState.style;
|
3239
|
+
delete hoverState.style;
|
3123
3240
|
|
3124
3241
|
// Pressed state
|
3125
3242
|
pressedState = merge(normalState, {
|
@@ -3132,8 +3249,8 @@ SVGRenderer.prototype = {
|
|
3132
3249
|
]
|
3133
3250
|
}
|
3134
3251
|
}, pressedState);
|
3135
|
-
pressedStyle = pressedState
|
3136
|
-
delete pressedState
|
3252
|
+
pressedStyle = pressedState.style;
|
3253
|
+
delete pressedState.style;
|
3137
3254
|
|
3138
3255
|
// Disabled state
|
3139
3256
|
disabledState = merge(normalState, {
|
@@ -3141,8 +3258,8 @@ SVGRenderer.prototype = {
|
|
3141
3258
|
color: '#CCC'
|
3142
3259
|
}
|
3143
3260
|
}, disabledState);
|
3144
|
-
disabledStyle = disabledState
|
3145
|
-
delete disabledState
|
3261
|
+
disabledStyle = disabledState.style;
|
3262
|
+
delete disabledState.style;
|
3146
3263
|
|
3147
3264
|
// Add the events. IE9 and IE10 need mouseover and mouseout to funciton (#667).
|
3148
3265
|
addEvent(label.element, isIE ? 'mouseover' : 'mouseenter', function () {
|
@@ -3232,9 +3349,16 @@ SVGRenderer.prototype = {
|
|
3232
3349
|
x: x,
|
3233
3350
|
y: y,
|
3234
3351
|
r: r
|
3235
|
-
}
|
3352
|
+
},
|
3353
|
+
wrapper = this.createElement('circle');
|
3236
3354
|
|
3237
|
-
|
3355
|
+
wrapper.xSetter = function (value) {
|
3356
|
+
this.element.setAttribute('cx', value);
|
3357
|
+
};
|
3358
|
+
wrapper.ySetter = function (value) {
|
3359
|
+
this.element.setAttribute('cy', value);
|
3360
|
+
};
|
3361
|
+
return wrapper.attr(attr);
|
3238
3362
|
},
|
3239
3363
|
|
3240
3364
|
/**
|
@@ -3283,7 +3407,7 @@ SVGRenderer.prototype = {
|
|
3283
3407
|
r = isObject(x) ? x.r : r;
|
3284
3408
|
|
3285
3409
|
var wrapper = this.createElement('rect'),
|
3286
|
-
|
3410
|
+
attribs = isObject(x) ? x : x === UNDEFINED ? {} : {
|
3287
3411
|
x: x,
|
3288
3412
|
y: y,
|
3289
3413
|
width: mathMax(width, 0),
|
@@ -3291,15 +3415,22 @@ SVGRenderer.prototype = {
|
|
3291
3415
|
};
|
3292
3416
|
|
3293
3417
|
if (strokeWidth !== UNDEFINED) {
|
3294
|
-
|
3295
|
-
|
3418
|
+
attribs.strokeWidth = strokeWidth;
|
3419
|
+
attribs = wrapper.crisp(attribs);
|
3296
3420
|
}
|
3297
3421
|
|
3298
3422
|
if (r) {
|
3299
|
-
|
3300
|
-
}
|
3423
|
+
attribs.r = r;
|
3424
|
+
}
|
3425
|
+
|
3426
|
+
wrapper.rSetter = function (value) {
|
3427
|
+
attr(this.element, {
|
3428
|
+
rx: value,
|
3429
|
+
ry: value
|
3430
|
+
});
|
3431
|
+
};
|
3301
3432
|
|
3302
|
-
return wrapper.attr(
|
3433
|
+
return wrapper.attr(attribs);
|
3303
3434
|
},
|
3304
3435
|
|
3305
3436
|
/**
|
@@ -3563,6 +3694,65 @@ SVGRenderer.prototype = {
|
|
3563
3694
|
|
3564
3695
|
open ? '' : 'Z' // close
|
3565
3696
|
];
|
3697
|
+
},
|
3698
|
+
|
3699
|
+
/**
|
3700
|
+
* Callout shape used for default tooltips, also used for rounded rectangles in VML
|
3701
|
+
*/
|
3702
|
+
callout: function (x, y, w, h, options) {
|
3703
|
+
var arrowLength = 6,
|
3704
|
+
halfDistance = 6,
|
3705
|
+
r = mathMin((options && options.r) || 0, w, h),
|
3706
|
+
safeDistance = r + halfDistance,
|
3707
|
+
anchorX = options && options.anchorX,
|
3708
|
+
anchorY = options && options.anchorY,
|
3709
|
+
path,
|
3710
|
+
normalizer = mathRound(options.strokeWidth || 0) % 2 / 2; // mathRound because strokeWidth can sometimes have roundoff errors;
|
3711
|
+
|
3712
|
+
x += normalizer;
|
3713
|
+
y += normalizer;
|
3714
|
+
path = [
|
3715
|
+
'M', x + r, y,
|
3716
|
+
'L', x + w - r, y, // top side
|
3717
|
+
'C', x + w, y, x + w, y, x + w, y + r, // top-right corner
|
3718
|
+
'L', x + w, y + h - r, // right side
|
3719
|
+
'C', x + w, y + h, x + w, y + h, x + w - r, y + h, // bottom-right corner
|
3720
|
+
'L', x + r, y + h, // bottom side
|
3721
|
+
'C', x, y + h, x, y + h, x, y + h - r, // bottom-left corner
|
3722
|
+
'L', x, y + r, // left side
|
3723
|
+
'C', x, y, x, y, x + r, y // top-right corner
|
3724
|
+
];
|
3725
|
+
|
3726
|
+
if (anchorX && anchorX > w && anchorY > y + safeDistance && anchorY < y + h - safeDistance) { // replace right side
|
3727
|
+
path.splice(13, 3,
|
3728
|
+
'L', x + w, anchorY - halfDistance,
|
3729
|
+
x + w + arrowLength, anchorY,
|
3730
|
+
x + w, anchorY + halfDistance,
|
3731
|
+
x + w, y + h - r
|
3732
|
+
);
|
3733
|
+
} else if (anchorX && anchorX < 0 && anchorY > y + safeDistance && anchorY < y + h - safeDistance) { // replace left side
|
3734
|
+
path.splice(33, 3,
|
3735
|
+
'L', x, anchorY + halfDistance,
|
3736
|
+
x - arrowLength, anchorY,
|
3737
|
+
x, anchorY - halfDistance,
|
3738
|
+
x, y + r
|
3739
|
+
);
|
3740
|
+
} else if (anchorY && anchorY > h && anchorX > x + safeDistance && anchorX < x + w - safeDistance) { // replace bottom
|
3741
|
+
path.splice(23, 3,
|
3742
|
+
'L', anchorX + halfDistance, y + h,
|
3743
|
+
anchorX, y + h + arrowLength,
|
3744
|
+
anchorX - halfDistance, y + h,
|
3745
|
+
x + r, y + h
|
3746
|
+
);
|
3747
|
+
} else if (anchorY && anchorY < 0 && anchorX > x + safeDistance && anchorX < x + w - safeDistance) { // replace top
|
3748
|
+
path.splice(3, 3,
|
3749
|
+
'L', anchorX - halfDistance, y,
|
3750
|
+
anchorX, y - arrowLength,
|
3751
|
+
anchorX + halfDistance, y,
|
3752
|
+
w - r, y
|
3753
|
+
);
|
3754
|
+
}
|
3755
|
+
return path;
|
3566
3756
|
}
|
3567
3757
|
},
|
3568
3758
|
|
@@ -3590,132 +3780,7 @@ SVGRenderer.prototype = {
|
|
3590
3780
|
},
|
3591
3781
|
|
3592
3782
|
|
3593
|
-
|
3594
|
-
* Take a color and return it if it's a string, make it a gradient if it's a
|
3595
|
-
* gradient configuration object. Prior to Highstock, an array was used to define
|
3596
|
-
* a linear gradient with pixel positions relative to the SVG. In newer versions
|
3597
|
-
* we change the coordinates to apply relative to the shape, using coordinates
|
3598
|
-
* 0-1 within the shape. To preserve backwards compatibility, linearGradient
|
3599
|
-
* in this definition is an object of x1, y1, x2 and y2.
|
3600
|
-
*
|
3601
|
-
* @param {Object} color The color or config object
|
3602
|
-
*/
|
3603
|
-
color: function (color, elem, prop) {
|
3604
|
-
var renderer = this,
|
3605
|
-
colorObject,
|
3606
|
-
regexRgba = /^rgba/,
|
3607
|
-
gradName,
|
3608
|
-
gradAttr,
|
3609
|
-
gradients,
|
3610
|
-
gradientObject,
|
3611
|
-
stops,
|
3612
|
-
stopColor,
|
3613
|
-
stopOpacity,
|
3614
|
-
radialReference,
|
3615
|
-
n,
|
3616
|
-
id,
|
3617
|
-
key = [];
|
3618
|
-
|
3619
|
-
// Apply linear or radial gradients
|
3620
|
-
if (color && color.linearGradient) {
|
3621
|
-
gradName = 'linearGradient';
|
3622
|
-
} else if (color && color.radialGradient) {
|
3623
|
-
gradName = 'radialGradient';
|
3624
|
-
}
|
3625
|
-
|
3626
|
-
if (gradName) {
|
3627
|
-
gradAttr = color[gradName];
|
3628
|
-
gradients = renderer.gradients;
|
3629
|
-
stops = color.stops;
|
3630
|
-
radialReference = elem.radialReference;
|
3631
|
-
|
3632
|
-
// Keep < 2.2 kompatibility
|
3633
|
-
if (isArray(gradAttr)) {
|
3634
|
-
color[gradName] = gradAttr = {
|
3635
|
-
x1: gradAttr[0],
|
3636
|
-
y1: gradAttr[1],
|
3637
|
-
x2: gradAttr[2],
|
3638
|
-
y2: gradAttr[3],
|
3639
|
-
gradientUnits: 'userSpaceOnUse'
|
3640
|
-
};
|
3641
|
-
}
|
3642
|
-
|
3643
|
-
// Correct the radial gradient for the radial reference system
|
3644
|
-
if (gradName === 'radialGradient' && radialReference && !defined(gradAttr.gradientUnits)) {
|
3645
|
-
gradAttr = merge(gradAttr, {
|
3646
|
-
cx: (radialReference[0] - radialReference[2] / 2) + gradAttr.cx * radialReference[2],
|
3647
|
-
cy: (radialReference[1] - radialReference[2] / 2) + gradAttr.cy * radialReference[2],
|
3648
|
-
r: gradAttr.r * radialReference[2],
|
3649
|
-
gradientUnits: 'userSpaceOnUse'
|
3650
|
-
});
|
3651
|
-
}
|
3652
|
-
|
3653
|
-
// Build the unique key to detect whether we need to create a new element (#1282)
|
3654
|
-
for (n in gradAttr) {
|
3655
|
-
if (n !== 'id') {
|
3656
|
-
key.push(n, gradAttr[n]);
|
3657
|
-
}
|
3658
|
-
}
|
3659
|
-
for (n in stops) {
|
3660
|
-
key.push(stops[n]);
|
3661
|
-
}
|
3662
|
-
key = key.join(',');
|
3663
|
-
|
3664
|
-
// Check if a gradient object with the same config object is created within this renderer
|
3665
|
-
if (gradients[key]) {
|
3666
|
-
id = gradients[key].id;
|
3667
|
-
|
3668
|
-
} else {
|
3669
|
-
|
3670
|
-
// Set the id and create the element
|
3671
|
-
gradAttr.id = id = PREFIX + idCounter++;
|
3672
|
-
gradients[key] = gradientObject = renderer.createElement(gradName)
|
3673
|
-
.attr(gradAttr)
|
3674
|
-
.add(renderer.defs);
|
3675
|
-
|
3676
|
-
|
3677
|
-
// The gradient needs to keep a list of stops to be able to destroy them
|
3678
|
-
gradientObject.stops = [];
|
3679
|
-
each(stops, function (stop) {
|
3680
|
-
var stopObject;
|
3681
|
-
if (regexRgba.test(stop[1])) {
|
3682
|
-
colorObject = Color(stop[1]);
|
3683
|
-
stopColor = colorObject.get('rgb');
|
3684
|
-
stopOpacity = colorObject.get('a');
|
3685
|
-
} else {
|
3686
|
-
stopColor = stop[1];
|
3687
|
-
stopOpacity = 1;
|
3688
|
-
}
|
3689
|
-
stopObject = renderer.createElement('stop').attr({
|
3690
|
-
offset: stop[0],
|
3691
|
-
'stop-color': stopColor,
|
3692
|
-
'stop-opacity': stopOpacity
|
3693
|
-
}).add(gradientObject);
|
3694
|
-
|
3695
|
-
// Add the stop element to the gradient
|
3696
|
-
gradientObject.stops.push(stopObject);
|
3697
|
-
});
|
3698
|
-
}
|
3699
|
-
|
3700
|
-
// Return the reference to the gradient object
|
3701
|
-
return 'url(' + renderer.url + '#' + id + ')';
|
3702
|
-
|
3703
|
-
// Webkit and Batik can't show rgba.
|
3704
|
-
} else if (regexRgba.test(color)) {
|
3705
|
-
colorObject = Color(color);
|
3706
|
-
attr(elem, prop + '-opacity', colorObject.get('a'));
|
3707
|
-
|
3708
|
-
return colorObject.get('rgb');
|
3709
|
-
|
3710
|
-
|
3711
|
-
} else {
|
3712
|
-
// Remove the opacity attribute added above. Does not throw if the attribute is not there.
|
3713
|
-
elem.removeAttribute(prop + '-opacity');
|
3714
|
-
|
3715
|
-
return color;
|
3716
|
-
}
|
3717
|
-
|
3718
|
-
},
|
3783
|
+
|
3719
3784
|
|
3720
3785
|
|
3721
3786
|
/**
|
@@ -3730,21 +3795,23 @@ SVGRenderer.prototype = {
|
|
3730
3795
|
// declare variables
|
3731
3796
|
var renderer = this,
|
3732
3797
|
fakeSVG = useCanVG || (!hasSVG && renderer.forExport),
|
3733
|
-
wrapper
|
3798
|
+
wrapper,
|
3799
|
+
attr = {};
|
3734
3800
|
|
3735
3801
|
if (useHTML && !renderer.forExport) {
|
3736
3802
|
return renderer.html(str, x, y);
|
3737
3803
|
}
|
3738
3804
|
|
3739
|
-
x =
|
3740
|
-
|
3805
|
+
attr.x = Math.round(x || 0); // X is always needed for line-wrap logic
|
3806
|
+
if (y) {
|
3807
|
+
attr.y = Math.round(y);
|
3808
|
+
}
|
3809
|
+
if (str || str === 0) {
|
3810
|
+
attr.text = str;
|
3811
|
+
}
|
3741
3812
|
|
3742
3813
|
wrapper = renderer.createElement('text')
|
3743
|
-
.attr(
|
3744
|
-
x: x,
|
3745
|
-
y: y,
|
3746
|
-
text: str
|
3747
|
-
});
|
3814
|
+
.attr(attr);
|
3748
3815
|
|
3749
3816
|
// Prevent wrapping from creating false offsetWidths in export in legacy IE (#1079, #1063)
|
3750
3817
|
if (fakeSVG) {
|
@@ -3753,8 +3820,22 @@ SVGRenderer.prototype = {
|
|
3753
3820
|
});
|
3754
3821
|
}
|
3755
3822
|
|
3756
|
-
|
3757
|
-
|
3823
|
+
if (!useHTML) {
|
3824
|
+
wrapper.xSetter = function (value, key, element) {
|
3825
|
+
var childNodes = element.childNodes,
|
3826
|
+
child,
|
3827
|
+
i;
|
3828
|
+
for (i = 1; i < childNodes.length; i++) {
|
3829
|
+
child = childNodes[i];
|
3830
|
+
// if the x values are equal, the tspan represents a linebreak
|
3831
|
+
if (child.getAttribute('x') === element.getAttribute('x')) {
|
3832
|
+
child.setAttribute('x', value);
|
3833
|
+
}
|
3834
|
+
}
|
3835
|
+
element.setAttribute(key, value);
|
3836
|
+
};
|
3837
|
+
}
|
3838
|
+
|
3758
3839
|
return wrapper;
|
3759
3840
|
},
|
3760
3841
|
|
@@ -3811,7 +3892,6 @@ SVGRenderer.prototype = {
|
|
3811
3892
|
crispAdjust = 0,
|
3812
3893
|
deferredAttr = {},
|
3813
3894
|
baselineOffset,
|
3814
|
-
attrSetters = wrapper.attrSetters,
|
3815
3895
|
needsBox;
|
3816
3896
|
|
3817
3897
|
/**
|
@@ -3832,6 +3912,7 @@ SVGRenderer.prototype = {
|
|
3832
3912
|
// update the label-scoped y offset
|
3833
3913
|
baselineOffset = padding + renderer.fontMetrics(style && style.fontSize).b;
|
3834
3914
|
|
3915
|
+
|
3835
3916
|
if (needsBox) {
|
3836
3917
|
|
3837
3918
|
// create the border box if it is not already present
|
@@ -3847,9 +3928,9 @@ SVGRenderer.prototype = {
|
|
3847
3928
|
|
3848
3929
|
// apply the box attributes
|
3849
3930
|
if (!box.isImg) { // #1630
|
3850
|
-
box.attr(
|
3851
|
-
width: wrapper.width,
|
3852
|
-
height: wrapper.height
|
3931
|
+
box.attr(extend({
|
3932
|
+
width: mathRound(wrapper.width),
|
3933
|
+
height: mathRound(wrapper.height)
|
3853
3934
|
}, deferredAttr));
|
3854
3935
|
}
|
3855
3936
|
deferredAttr = null;
|
@@ -3875,10 +3956,10 @@ SVGRenderer.prototype = {
|
|
3875
3956
|
|
3876
3957
|
// update if anything changed
|
3877
3958
|
if (x !== text.x || y !== text.y) {
|
3878
|
-
text.attr(
|
3879
|
-
|
3880
|
-
y
|
3881
|
-
}
|
3959
|
+
text.attr('x', x);
|
3960
|
+
if (y !== UNDEFINED) {
|
3961
|
+
text.attr('y', y);
|
3962
|
+
}
|
3882
3963
|
}
|
3883
3964
|
|
3884
3965
|
// record current values
|
@@ -3906,7 +3987,7 @@ SVGRenderer.prototype = {
|
|
3906
3987
|
wrapper.onAdd = function () {
|
3907
3988
|
text.add(wrapper);
|
3908
3989
|
wrapper.attr({
|
3909
|
-
text: str, // alignment is available now
|
3990
|
+
text: str || '', // alignment is available now
|
3910
3991
|
x: x,
|
3911
3992
|
y: y
|
3912
3993
|
});
|
@@ -3924,84 +4005,75 @@ SVGRenderer.prototype = {
|
|
3924
4005
|
*/
|
3925
4006
|
|
3926
4007
|
// only change local variables
|
3927
|
-
|
4008
|
+
wrapper.widthSetter = function (value) {
|
3928
4009
|
width = value;
|
3929
|
-
return false;
|
3930
4010
|
};
|
3931
|
-
|
4011
|
+
wrapper.heightSetter = function (value) {
|
3932
4012
|
height = value;
|
3933
|
-
return false;
|
3934
4013
|
};
|
3935
|
-
|
4014
|
+
wrapper.paddingSetter = function (value) {
|
3936
4015
|
if (defined(value) && value !== padding) {
|
3937
4016
|
padding = value;
|
3938
4017
|
updateTextPadding();
|
3939
4018
|
}
|
3940
|
-
return false;
|
3941
4019
|
};
|
3942
|
-
|
4020
|
+
wrapper.paddingLeftSetter = function (value) {
|
3943
4021
|
if (defined(value) && value !== paddingLeft) {
|
3944
4022
|
paddingLeft = value;
|
3945
4023
|
updateTextPadding();
|
3946
4024
|
}
|
3947
|
-
return false;
|
3948
4025
|
};
|
3949
4026
|
|
3950
4027
|
|
3951
|
-
// change local variable and
|
3952
|
-
|
4028
|
+
// change local variable and prevent setting attribute on the group
|
4029
|
+
wrapper.alignSetter = function (value) {
|
3953
4030
|
alignFactor = { left: 0, center: 0.5, right: 1 }[value];
|
3954
|
-
return false; // prevent setting text-anchor on the group
|
3955
4031
|
};
|
3956
4032
|
|
3957
4033
|
// apply these to the box and the text alike
|
3958
|
-
|
3959
|
-
|
4034
|
+
wrapper.textSetter = function (value) {
|
4035
|
+
if (value !== UNDEFINED) {
|
4036
|
+
text.textSetter(value);
|
4037
|
+
}
|
3960
4038
|
updateBoxSize();
|
3961
4039
|
updateTextPadding();
|
3962
|
-
return false;
|
3963
4040
|
};
|
3964
4041
|
|
3965
4042
|
// apply these to the box but not to the text
|
3966
|
-
|
4043
|
+
wrapper['stroke-widthSetter'] = function (value, key) {
|
3967
4044
|
if (value) {
|
3968
4045
|
needsBox = true;
|
3969
4046
|
}
|
3970
4047
|
crispAdjust = value % 2 / 2;
|
3971
4048
|
boxAttr(key, value);
|
3972
|
-
return false;
|
3973
4049
|
};
|
3974
|
-
|
4050
|
+
wrapper.strokeSetter = wrapper.fillSetter = wrapper.rSetter = function (value, key) {
|
3975
4051
|
if (key === 'fill' && value) {
|
3976
4052
|
needsBox = true;
|
3977
4053
|
}
|
3978
4054
|
boxAttr(key, value);
|
3979
|
-
return false;
|
3980
4055
|
};
|
3981
|
-
|
4056
|
+
wrapper.anchorXSetter = function (value, key) {
|
3982
4057
|
anchorX = value;
|
3983
4058
|
boxAttr(key, value + crispAdjust - wrapperX);
|
3984
|
-
return false;
|
3985
4059
|
};
|
3986
|
-
|
4060
|
+
wrapper.anchorYSetter = function (value, key) {
|
3987
4061
|
anchorY = value;
|
3988
4062
|
boxAttr(key, value - wrapperY);
|
3989
|
-
return false;
|
3990
4063
|
};
|
3991
4064
|
|
3992
4065
|
// rename attributes
|
3993
|
-
|
4066
|
+
wrapper.xSetter = function (value) {
|
3994
4067
|
wrapper.x = value; // for animation getter
|
3995
|
-
|
4068
|
+
if (alignFactor) {
|
4069
|
+
value -= alignFactor * ((width || bBox.width) + padding);
|
4070
|
+
}
|
3996
4071
|
wrapperX = mathRound(value);
|
3997
|
-
|
3998
4072
|
wrapper.attr('translateX', wrapperX);
|
3999
|
-
return false;
|
4000
4073
|
};
|
4001
|
-
|
4074
|
+
wrapper.ySetter = function (value) {
|
4002
4075
|
wrapperY = wrapper.y = mathRound(value);
|
4003
4076
|
wrapper.attr('translateY', wrapperY);
|
4004
|
-
return false;
|
4005
4077
|
};
|
4006
4078
|
|
4007
4079
|
// Redirect certain methods to either the box or the text
|
@@ -4251,28 +4323,24 @@ extend(SVGRenderer.prototype, {
|
|
4251
4323
|
*/
|
4252
4324
|
html: function (str, x, y) {
|
4253
4325
|
var wrapper = this.createElement('span'),
|
4254
|
-
attrSetters = wrapper.attrSetters,
|
4255
4326
|
element = wrapper.element,
|
4256
4327
|
renderer = wrapper.renderer;
|
4257
4328
|
|
4258
4329
|
// Text setter
|
4259
|
-
|
4330
|
+
wrapper.textSetter = function (value) {
|
4260
4331
|
if (value !== element.innerHTML) {
|
4261
4332
|
delete this.bBox;
|
4262
4333
|
}
|
4263
4334
|
element.innerHTML = this.textStr = value;
|
4264
|
-
return false;
|
4265
4335
|
};
|
4266
4336
|
|
4267
4337
|
// Various setters which rely on update transform
|
4268
|
-
|
4338
|
+
wrapper.xSetter = wrapper.ySetter = wrapper.alignSetter = wrapper.rotationSetter = function (value, key) {
|
4269
4339
|
if (key === 'align') {
|
4270
4340
|
key = 'textAlign'; // Do not overwrite the SVGElement.align method. Same as VML.
|
4271
4341
|
}
|
4272
4342
|
wrapper[key] = value;
|
4273
4343
|
wrapper.htmlUpdateTransform();
|
4274
|
-
|
4275
|
-
return false;
|
4276
4344
|
};
|
4277
4345
|
|
4278
4346
|
// Set the default attributes
|
@@ -4336,14 +4404,18 @@ extend(SVGRenderer.prototype, {
|
|
4336
4404
|
|
4337
4405
|
// Set listeners to update the HTML div's position whenever the SVG group
|
4338
4406
|
// position is changed
|
4339
|
-
extend(parentGroup
|
4340
|
-
|
4407
|
+
extend(parentGroup, {
|
4408
|
+
translateXSetter: function (value, key) {
|
4341
4409
|
htmlGroupStyle.left = value + PX;
|
4410
|
+
parentGroup[key] = value;
|
4411
|
+
parentGroup.doTransform = true;
|
4342
4412
|
},
|
4343
|
-
|
4413
|
+
translateYSetter: function (value, key) {
|
4344
4414
|
htmlGroupStyle.top = value + PX;
|
4415
|
+
parentGroup[key] = value;
|
4416
|
+
parentGroup.doTransform = true;
|
4345
4417
|
},
|
4346
|
-
|
4418
|
+
visibilitySetter: function (value, key) {
|
4347
4419
|
htmlGroupStyle[key] = value;
|
4348
4420
|
}
|
4349
4421
|
});
|
@@ -4418,7 +4490,6 @@ Highcharts.VMLElement = VMLElement = {
|
|
4418
4490
|
}
|
4419
4491
|
|
4420
4492
|
wrapper.renderer = renderer;
|
4421
|
-
wrapper.attrSetters = {};
|
4422
4493
|
},
|
4423
4494
|
|
4424
4495
|
/**
|
@@ -4560,237 +4631,12 @@ Highcharts.VMLElement = VMLElement = {
|
|
4560
4631
|
if (path[i] === 'H') { // horizontal line to
|
4561
4632
|
path[i] = 'L';
|
4562
4633
|
path.splice(i + 2, 0, path[i - 1]);
|
4563
|
-
} else if (path[i] === 'V') { // vertical line to
|
4564
|
-
path[i] = 'L';
|
4565
|
-
path.splice(i + 1, 0, path[i - 2]);
|
4566
|
-
}
|
4567
|
-
}*/
|
4568
|
-
return path.join(' ') || 'x';
|
4569
|
-
},
|
4570
|
-
|
4571
|
-
/**
|
4572
|
-
* Get or set attributes
|
4573
|
-
*/
|
4574
|
-
attr: function (hash, val) {
|
4575
|
-
var wrapper = this,
|
4576
|
-
key,
|
4577
|
-
value,
|
4578
|
-
i,
|
4579
|
-
result,
|
4580
|
-
element = wrapper.element || {},
|
4581
|
-
elemStyle = element.style,
|
4582
|
-
nodeName = element.nodeName,
|
4583
|
-
renderer = wrapper.renderer,
|
4584
|
-
symbolName = wrapper.symbolName,
|
4585
|
-
hasSetSymbolSize,
|
4586
|
-
shadows = wrapper.shadows,
|
4587
|
-
skipAttr,
|
4588
|
-
attrSetters = wrapper.attrSetters,
|
4589
|
-
ret = wrapper;
|
4590
|
-
|
4591
|
-
// single key-value pair
|
4592
|
-
if (isString(hash) && defined(val)) {
|
4593
|
-
key = hash;
|
4594
|
-
hash = {};
|
4595
|
-
hash[key] = val;
|
4596
|
-
}
|
4597
|
-
|
4598
|
-
// used as a getter, val is undefined
|
4599
|
-
if (isString(hash)) {
|
4600
|
-
key = hash;
|
4601
|
-
if (key === 'strokeWidth' || key === 'stroke-width') {
|
4602
|
-
ret = wrapper.strokeweight;
|
4603
|
-
} else {
|
4604
|
-
ret = wrapper[key];
|
4605
|
-
}
|
4606
|
-
|
4607
|
-
// setter
|
4608
|
-
} else {
|
4609
|
-
for (key in hash) {
|
4610
|
-
value = hash[key];
|
4611
|
-
skipAttr = false;
|
4612
|
-
|
4613
|
-
// check for a specific attribute setter
|
4614
|
-
result = attrSetters[key] && attrSetters[key].call(wrapper, value, key);
|
4615
|
-
|
4616
|
-
if (result !== false && value !== null) { // #620
|
4617
|
-
|
4618
|
-
if (result !== UNDEFINED) {
|
4619
|
-
value = result; // the attribute setter has returned a new value to set
|
4620
|
-
}
|
4621
|
-
|
4622
|
-
|
4623
|
-
// prepare paths
|
4624
|
-
// symbols
|
4625
|
-
if (symbolName && /^(x|y|r|start|end|width|height|innerR|anchorX|anchorY)/.test(key)) {
|
4626
|
-
// if one of the symbol size affecting parameters are changed,
|
4627
|
-
// check all the others only once for each call to an element's
|
4628
|
-
// .attr() method
|
4629
|
-
if (!hasSetSymbolSize) {
|
4630
|
-
wrapper.symbolAttr(hash);
|
4631
|
-
|
4632
|
-
hasSetSymbolSize = true;
|
4633
|
-
}
|
4634
|
-
skipAttr = true;
|
4635
|
-
|
4636
|
-
} else if (key === 'd') {
|
4637
|
-
value = value || [];
|
4638
|
-
wrapper.d = value.join(' '); // used in getter for animation
|
4639
|
-
|
4640
|
-
element.path = value = wrapper.pathToVML(value);
|
4641
|
-
|
4642
|
-
// update shadows
|
4643
|
-
if (shadows) {
|
4644
|
-
i = shadows.length;
|
4645
|
-
while (i--) {
|
4646
|
-
shadows[i].path = shadows[i].cutOff ? this.cutOffPath(value, shadows[i].cutOff) : value;
|
4647
|
-
}
|
4648
|
-
}
|
4649
|
-
skipAttr = true;
|
4650
|
-
|
4651
|
-
// handle visibility
|
4652
|
-
} else if (key === 'visibility') {
|
4653
|
-
|
4654
|
-
// Handle inherited visibility
|
4655
|
-
if (value === 'inherit') {
|
4656
|
-
value = VISIBLE;
|
4657
|
-
}
|
4658
|
-
|
4659
|
-
// Let the shadow follow the main element
|
4660
|
-
if (shadows) {
|
4661
|
-
i = shadows.length;
|
4662
|
-
while (i--) {
|
4663
|
-
shadows[i].style[key] = value;
|
4664
|
-
}
|
4665
|
-
}
|
4666
|
-
|
4667
|
-
// Instead of toggling the visibility CSS property, move the div out of the viewport.
|
4668
|
-
// This works around #61 and #586
|
4669
|
-
if (nodeName === 'DIV') {
|
4670
|
-
value = value === HIDDEN ? '-999em' : 0;
|
4671
|
-
|
4672
|
-
// In order to redraw, IE7 needs the div to be visible when tucked away
|
4673
|
-
// outside the viewport. So the visibility is actually opposite of
|
4674
|
-
// the expected value. This applies to the tooltip only.
|
4675
|
-
if (!docMode8) {
|
4676
|
-
elemStyle[key] = value ? VISIBLE : HIDDEN;
|
4677
|
-
}
|
4678
|
-
key = 'top';
|
4679
|
-
}
|
4680
|
-
elemStyle[key] = value;
|
4681
|
-
skipAttr = true;
|
4682
|
-
|
4683
|
-
// directly mapped to css
|
4684
|
-
} else if (key === 'zIndex') {
|
4685
|
-
|
4686
|
-
if (value) {
|
4687
|
-
elemStyle[key] = value;
|
4688
|
-
}
|
4689
|
-
skipAttr = true;
|
4690
|
-
|
4691
|
-
// x, y, width, height
|
4692
|
-
} else if (inArray(key, ['x', 'y', 'width', 'height']) !== -1) {
|
4693
|
-
|
4694
|
-
wrapper[key] = value; // used in getter
|
4695
|
-
|
4696
|
-
if (key === 'x' || key === 'y') {
|
4697
|
-
key = { x: 'left', y: 'top' }[key];
|
4698
|
-
} else {
|
4699
|
-
value = mathMax(0, value); // don't set width or height below zero (#311)
|
4700
|
-
}
|
4701
|
-
|
4702
|
-
// clipping rectangle special
|
4703
|
-
if (wrapper.updateClipping) {
|
4704
|
-
wrapper[key] = value; // the key is now 'left' or 'top' for 'x' and 'y'
|
4705
|
-
wrapper.updateClipping();
|
4706
|
-
} else {
|
4707
|
-
// normal
|
4708
|
-
elemStyle[key] = value;
|
4709
|
-
}
|
4710
|
-
|
4711
|
-
skipAttr = true;
|
4712
|
-
|
4713
|
-
// class name
|
4714
|
-
} else if (key === 'class' && nodeName === 'DIV') {
|
4715
|
-
// IE8 Standards mode has problems retrieving the className
|
4716
|
-
element.className = value;
|
4717
|
-
|
4718
|
-
// stroke
|
4719
|
-
} else if (key === 'stroke') {
|
4720
|
-
|
4721
|
-
value = renderer.color(value, element, key);
|
4722
|
-
|
4723
|
-
key = 'strokecolor';
|
4724
|
-
|
4725
|
-
// stroke width
|
4726
|
-
} else if (key === 'stroke-width' || key === 'strokeWidth') {
|
4727
|
-
element.stroked = value ? true : false;
|
4728
|
-
key = 'strokeweight';
|
4729
|
-
wrapper[key] = value; // used in getter, issue #113
|
4730
|
-
if (isNumber(value)) {
|
4731
|
-
value += PX;
|
4732
|
-
}
|
4733
|
-
|
4734
|
-
// dashStyle
|
4735
|
-
} else if (key === 'dashstyle') {
|
4736
|
-
var strokeElem = element.getElementsByTagName('stroke')[0] ||
|
4737
|
-
createElement(renderer.prepVML(['<stroke/>']), null, null, element);
|
4738
|
-
strokeElem[key] = value || 'solid';
|
4739
|
-
wrapper.dashstyle = value; /* because changing stroke-width will change the dash length
|
4740
|
-
and cause an epileptic effect */
|
4741
|
-
skipAttr = true;
|
4742
|
-
|
4743
|
-
// fill
|
4744
|
-
} else if (key === 'fill') {
|
4745
|
-
|
4746
|
-
if (nodeName === 'SPAN') { // text color
|
4747
|
-
elemStyle.color = value;
|
4748
|
-
} else if (nodeName !== 'IMG') { // #1336
|
4749
|
-
element.filled = value !== NONE ? true : false;
|
4750
|
-
|
4751
|
-
value = renderer.color(value, element, key, wrapper);
|
4752
|
-
|
4753
|
-
key = 'fillcolor';
|
4754
|
-
}
|
4755
|
-
|
4756
|
-
// opacity: don't bother - animation is too slow and filters introduce artifacts
|
4757
|
-
} else if (key === 'opacity') {
|
4758
|
-
/*css(element, {
|
4759
|
-
opacity: value
|
4760
|
-
});*/
|
4761
|
-
skipAttr = true;
|
4762
|
-
|
4763
|
-
// rotation on VML elements
|
4764
|
-
} else if (nodeName === 'shape' && key === 'rotation') {
|
4765
|
-
|
4766
|
-
wrapper[key] = element.style[key] = value; // style is for #1873
|
4767
|
-
|
4768
|
-
// Correction for the 1x1 size of the shape container. Used in gauge needles.
|
4769
|
-
element.style.left = -mathRound(mathSin(value * deg2rad) + 1) + PX;
|
4770
|
-
element.style.top = mathRound(mathCos(value * deg2rad)) + PX;
|
4771
|
-
|
4772
|
-
// translation for animation
|
4773
|
-
} else if (key === 'translateX' || key === 'translateY' || key === 'rotation') {
|
4774
|
-
wrapper[key] = value;
|
4775
|
-
wrapper.updateTransform();
|
4776
|
-
|
4777
|
-
skipAttr = true;
|
4778
|
-
|
4779
|
-
}
|
4780
|
-
|
4781
|
-
|
4782
|
-
if (!skipAttr) {
|
4783
|
-
if (docMode8) { // IE8 setAttribute bug
|
4784
|
-
element[key] = value;
|
4785
|
-
} else {
|
4786
|
-
attr(element, key, value);
|
4787
|
-
}
|
4788
|
-
}
|
4789
|
-
|
4790
|
-
}
|
4634
|
+
} else if (path[i] === 'V') { // vertical line to
|
4635
|
+
path[i] = 'L';
|
4636
|
+
path.splice(i + 1, 0, path[i - 2]);
|
4791
4637
|
}
|
4792
|
-
}
|
4793
|
-
return
|
4638
|
+
}*/
|
4639
|
+
return path.join(' ') || 'x';
|
4794
4640
|
},
|
4795
4641
|
|
4796
4642
|
/**
|
@@ -4953,11 +4799,138 @@ Highcharts.VMLElement = VMLElement = {
|
|
4953
4799
|
this.shadows = shadows;
|
4954
4800
|
}
|
4955
4801
|
return this;
|
4802
|
+
},
|
4803
|
+
updateShadows: noop, // Used in SVG only
|
4804
|
+
|
4805
|
+
setAttr: function (key, value) {
|
4806
|
+
if (docMode8) { // IE8 setAttribute bug
|
4807
|
+
this.element[key] = value;
|
4808
|
+
} else {
|
4809
|
+
this.element.setAttribute(key, value);
|
4810
|
+
}
|
4811
|
+
},
|
4812
|
+
classSetter: function (value) {
|
4813
|
+
// IE8 Standards mode has problems retrieving the className unless set like this
|
4814
|
+
this.element.className = value;
|
4815
|
+
},
|
4816
|
+
dashstyleSetter: function (value, key, element) {
|
4817
|
+
var strokeElem = element.getElementsByTagName('stroke')[0] ||
|
4818
|
+
createElement(this.renderer.prepVML(['<stroke/>']), null, null, element);
|
4819
|
+
strokeElem[key] = value || 'solid';
|
4820
|
+
this[key] = value; /* because changing stroke-width will change the dash length
|
4821
|
+
and cause an epileptic effect */
|
4822
|
+
},
|
4823
|
+
dSetter: function (value, key, element) {
|
4824
|
+
var i,
|
4825
|
+
shadows = this.shadows;
|
4826
|
+
value = value || [];
|
4827
|
+
this.d = value.join(' '); // used in getter for animation
|
4828
|
+
|
4829
|
+
element.path = value = this.pathToVML(value);
|
4830
|
+
|
4831
|
+
// update shadows
|
4832
|
+
if (shadows) {
|
4833
|
+
i = shadows.length;
|
4834
|
+
while (i--) {
|
4835
|
+
shadows[i].path = shadows[i].cutOff ? this.cutOffPath(value, shadows[i].cutOff) : value;
|
4836
|
+
}
|
4837
|
+
}
|
4838
|
+
this.setAttr(key, value);
|
4839
|
+
},
|
4840
|
+
fillSetter: function (value, key, element) {
|
4841
|
+
var nodeName = element.nodeName;
|
4842
|
+
if (nodeName === 'SPAN') { // text color
|
4843
|
+
element.style.color = value;
|
4844
|
+
} else if (nodeName !== 'IMG') { // #1336
|
4845
|
+
element.filled = value !== NONE;
|
4846
|
+
this.setAttr('fillcolor', this.renderer.color(value, element, key, this));
|
4847
|
+
}
|
4848
|
+
},
|
4849
|
+
opacitySetter: noop, // Don't bother - animation is too slow and filters introduce artifacts
|
4850
|
+
rotationSetter: function (value, key, element) {
|
4851
|
+
var style = element.style;
|
4852
|
+
this[key] = style[key] = value; // style is for #1873
|
4853
|
+
|
4854
|
+
// Correction for the 1x1 size of the shape container. Used in gauge needles.
|
4855
|
+
style.left = -mathRound(mathSin(value * deg2rad) + 1) + PX;
|
4856
|
+
style.top = mathRound(mathCos(value * deg2rad)) + PX;
|
4857
|
+
},
|
4858
|
+
strokeSetter: function (value, key, element) {
|
4859
|
+
this.setAttr('strokecolor', this.renderer.color(value, element, key));
|
4860
|
+
},
|
4861
|
+
'stroke-widthSetter': function (value, key, element) {
|
4862
|
+
element.stroked = !!value; // VML "stroked" attribute
|
4863
|
+
this[key] = value; // used in getter, issue #113
|
4864
|
+
if (isNumber(value)) {
|
4865
|
+
value += PX;
|
4866
|
+
}
|
4867
|
+
this.setAttr('strokeweight', value);
|
4868
|
+
},
|
4869
|
+
titleSetter: function (value, key) {
|
4870
|
+
this.setAttr(key, value);
|
4871
|
+
},
|
4872
|
+
visibilitySetter: function (value, key, element) {
|
4873
|
+
|
4874
|
+
// Handle inherited visibility
|
4875
|
+
if (value === 'inherit') {
|
4876
|
+
value = VISIBLE;
|
4877
|
+
}
|
4878
|
+
|
4879
|
+
// Let the shadow follow the main element
|
4880
|
+
if (this.shadows) {
|
4881
|
+
each(this.shadows, function (shadow) {
|
4882
|
+
shadow.style[key] = value;
|
4883
|
+
});
|
4884
|
+
}
|
4885
|
+
|
4886
|
+
// Instead of toggling the visibility CSS property, move the div out of the viewport.
|
4887
|
+
// This works around #61 and #586
|
4888
|
+
if (element.nodeName === 'DIV') {
|
4889
|
+
value = value === HIDDEN ? '-999em' : 0;
|
4890
|
+
|
4891
|
+
// In order to redraw, IE7 needs the div to be visible when tucked away
|
4892
|
+
// outside the viewport. So the visibility is actually opposite of
|
4893
|
+
// the expected value. This applies to the tooltip only.
|
4894
|
+
if (!docMode8) {
|
4895
|
+
element.style[key] = value ? VISIBLE : HIDDEN;
|
4896
|
+
}
|
4897
|
+
key = 'top';
|
4898
|
+
}
|
4899
|
+
element.style[key] = value;
|
4900
|
+
},
|
4901
|
+
xSetter: function (value, key, element) {
|
4902
|
+
this[key] = value; // used in getter
|
4956
4903
|
|
4904
|
+
if (key === 'x') {
|
4905
|
+
key = 'left';
|
4906
|
+
} else if (key === 'y') {
|
4907
|
+
key = 'top';
|
4908
|
+
}/* else {
|
4909
|
+
value = mathMax(0, value); // don't set width or height below zero (#311)
|
4910
|
+
}*/
|
4911
|
+
|
4912
|
+
// clipping rectangle special
|
4913
|
+
if (this.updateClipping) {
|
4914
|
+
this[key] = value; // the key is now 'left' or 'top' for 'x' and 'y'
|
4915
|
+
this.updateClipping();
|
4916
|
+
} else {
|
4917
|
+
// normal
|
4918
|
+
element.style[key] = value;
|
4919
|
+
}
|
4920
|
+
},
|
4921
|
+
zIndexSetter: function (value, key, element) {
|
4922
|
+
element.style[key] = value;
|
4957
4923
|
}
|
4958
4924
|
};
|
4959
4925
|
VMLElement = extendClass(SVGElement, VMLElement);
|
4960
4926
|
|
4927
|
+
// Some shared setters
|
4928
|
+
VMLElement.prototype.ySetter =
|
4929
|
+
VMLElement.prototype.widthSetter =
|
4930
|
+
VMLElement.prototype.heightSetter =
|
4931
|
+
VMLElement.prototype.xSetter;
|
4932
|
+
|
4933
|
+
|
4961
4934
|
/**
|
4962
4935
|
* The VML renderer
|
4963
4936
|
*/
|
@@ -5077,7 +5050,9 @@ var VMLRendererExtension = { // inherit SVGRenderer
|
|
5077
5050
|
// used in attr and animation to update the clipping of all members
|
5078
5051
|
updateClipping: function () {
|
5079
5052
|
each(clipRect.members, function (member) {
|
5080
|
-
member.
|
5053
|
+
if (member.element) { // Deleted series, like in stock/members/series-remove demo. Should be removed from members, but this will do.
|
5054
|
+
member.css(clipRect.getCSS(member));
|
5055
|
+
}
|
5081
5056
|
});
|
5082
5057
|
}
|
5083
5058
|
});
|
@@ -5493,71 +5468,13 @@ var VMLRendererExtension = { // inherit SVGRenderer
|
|
5493
5468
|
},
|
5494
5469
|
/**
|
5495
5470
|
* Add rectangle symbol path which eases rotation and omits arcsize problems
|
5496
|
-
* compared to the built-in VML roundrect shape
|
5497
|
-
*
|
5498
|
-
* @param {Number} left Left position
|
5499
|
-
* @param {Number} top Top position
|
5500
|
-
* @param {Number} r Border radius
|
5501
|
-
* @param {Object} options Width and height
|
5471
|
+
* compared to the built-in VML roundrect shape. When borders are not rounded,
|
5472
|
+
* use the simpler square path, else use the callout path without the arrow.
|
5502
5473
|
*/
|
5503
|
-
|
5504
|
-
|
5505
|
-
|
5506
|
-
|
5507
|
-
bottom = top + height,
|
5508
|
-
ret,
|
5509
|
-
r;
|
5510
|
-
|
5511
|
-
// No radius, return the more lightweight square
|
5512
|
-
if (!defined(options) || !options.r) {
|
5513
|
-
ret = SVGRenderer.prototype.symbols.square.apply(0, arguments);
|
5514
|
-
|
5515
|
-
// Has radius add arcs for the corners
|
5516
|
-
} else {
|
5517
|
-
|
5518
|
-
r = mathMin(options.r, width, height);
|
5519
|
-
ret = [
|
5520
|
-
M,
|
5521
|
-
left + r, top,
|
5522
|
-
|
5523
|
-
L,
|
5524
|
-
right - r, top,
|
5525
|
-
'wa',
|
5526
|
-
right - 2 * r, top,
|
5527
|
-
right, top + 2 * r,
|
5528
|
-
right - r, top,
|
5529
|
-
right, top + r,
|
5530
|
-
|
5531
|
-
L,
|
5532
|
-
right, bottom - r,
|
5533
|
-
'wa',
|
5534
|
-
right - 2 * r, bottom - 2 * r,
|
5535
|
-
right, bottom,
|
5536
|
-
right, bottom - r,
|
5537
|
-
right - r, bottom,
|
5538
|
-
|
5539
|
-
L,
|
5540
|
-
left + r, bottom,
|
5541
|
-
'wa',
|
5542
|
-
left, bottom - 2 * r,
|
5543
|
-
left + 2 * r, bottom,
|
5544
|
-
left + r, bottom,
|
5545
|
-
left, bottom - r,
|
5546
|
-
|
5547
|
-
L,
|
5548
|
-
left, top + r,
|
5549
|
-
'wa',
|
5550
|
-
left, top,
|
5551
|
-
left + 2 * r, top + 2 * r,
|
5552
|
-
left, top + r,
|
5553
|
-
left + r, top,
|
5554
|
-
|
5555
|
-
|
5556
|
-
'x',
|
5557
|
-
'e'
|
5558
|
-
];
|
5559
|
-
}
|
5560
|
-
return ret;
|
5474
|
+
rect: function (x, y, w, h, options) {
|
5475
|
+
return SVGRenderer.prototype.symbols[
|
5476
|
+
!defined(options) || !options.r ? 'square' : 'callout'
|
5477
|
+
].call(0, x, y, w, h, options);
|
5561
5478
|
}
|
5562
5479
|
}
|
5563
5480
|
};
|
@@ -6135,7 +6052,7 @@ Highcharts.PlotLineOrBand.prototype = {
|
|
6135
6052
|
color = options.color,
|
6136
6053
|
zIndex = options.zIndex,
|
6137
6054
|
events = options.events,
|
6138
|
-
attribs,
|
6055
|
+
attribs = {},
|
6139
6056
|
renderer = axis.chart.renderer;
|
6140
6057
|
|
6141
6058
|
// logarithmic conversion
|
@@ -6162,9 +6079,9 @@ Highcharts.PlotLineOrBand.prototype = {
|
|
6162
6079
|
to = mathMin(to, axis.max + halfPointRange);
|
6163
6080
|
|
6164
6081
|
path = axis.getPlotBandPath(from, to, options);
|
6165
|
-
|
6166
|
-
fill
|
6167
|
-
}
|
6082
|
+
if (color) {
|
6083
|
+
attribs.fill = color;
|
6084
|
+
}
|
6168
6085
|
if (options.borderWidth) {
|
6169
6086
|
attribs.stroke = options.borderColor;
|
6170
6087
|
attribs['stroke-width'] = options.borderWidth;
|
@@ -6222,17 +6139,20 @@ Highcharts.PlotLineOrBand.prototype = {
|
|
6222
6139
|
|
6223
6140
|
// add the SVG element
|
6224
6141
|
if (!label) {
|
6142
|
+
attribs = {
|
6143
|
+
align: optionsLabel.textAlign || optionsLabel.align,
|
6144
|
+
rotation: optionsLabel.rotation
|
6145
|
+
};
|
6146
|
+
if (defined(zIndex)) {
|
6147
|
+
attribs.zIndex = zIndex;
|
6148
|
+
}
|
6225
6149
|
plotLine.label = label = renderer.text(
|
6226
6150
|
optionsLabel.text,
|
6227
6151
|
0,
|
6228
6152
|
0,
|
6229
6153
|
optionsLabel.useHTML
|
6230
6154
|
)
|
6231
|
-
.attr(
|
6232
|
-
align: optionsLabel.textAlign || optionsLabel.align,
|
6233
|
-
rotation: optionsLabel.rotation,
|
6234
|
-
zIndex: zIndex
|
6235
|
-
})
|
6155
|
+
.attr(attribs)
|
6236
6156
|
.css(optionsLabel.style)
|
6237
6157
|
.add();
|
6238
6158
|
}
|
@@ -6424,7 +6344,7 @@ Axis.prototype = {
|
|
6424
6344
|
startOnTick: false,
|
6425
6345
|
tickColor: '#C0D0E0',
|
6426
6346
|
//tickInterval: null,
|
6427
|
-
tickLength:
|
6347
|
+
tickLength: 10,
|
6428
6348
|
tickmarkPlacement: 'between', // on or between
|
6429
6349
|
tickPixelInterval: 100,
|
6430
6350
|
tickPosition: 'outside',
|
@@ -6436,9 +6356,7 @@ Axis.prototype = {
|
|
6436
6356
|
//rotation: 0,
|
6437
6357
|
//side: 'outside',
|
6438
6358
|
style: {
|
6439
|
-
color: '#
|
6440
|
-
//font: defaultFont.replace('normal', 'bold')
|
6441
|
-
fontWeight: 'bold'
|
6359
|
+
color: '#707070' // docs
|
6442
6360
|
}
|
6443
6361
|
//x: 0,
|
6444
6362
|
//y: 0
|
@@ -6487,7 +6405,7 @@ Axis.prototype = {
|
|
6487
6405
|
*/
|
6488
6406
|
defaultLeftAxisOptions: {
|
6489
6407
|
labels: {
|
6490
|
-
x: -
|
6408
|
+
x: -15,
|
6491
6409
|
y: null
|
6492
6410
|
},
|
6493
6411
|
title: {
|
@@ -6500,7 +6418,7 @@ Axis.prototype = {
|
|
6500
6418
|
*/
|
6501
6419
|
defaultRightAxisOptions: {
|
6502
6420
|
labels: {
|
6503
|
-
x:
|
6421
|
+
x: 15,
|
6504
6422
|
y: null
|
6505
6423
|
},
|
6506
6424
|
title: {
|
@@ -6514,7 +6432,7 @@ Axis.prototype = {
|
|
6514
6432
|
defaultBottomAxisOptions: {
|
6515
6433
|
labels: {
|
6516
6434
|
x: 0,
|
6517
|
-
y:
|
6435
|
+
y: 20
|
6518
6436
|
// overflow: undefined,
|
6519
6437
|
// staggerLines: null
|
6520
6438
|
},
|
@@ -6528,7 +6446,7 @@ Axis.prototype = {
|
|
6528
6446
|
defaultTopAxisOptions: {
|
6529
6447
|
labels: {
|
6530
6448
|
x: 0,
|
6531
|
-
y: -
|
6449
|
+
y: -15
|
6532
6450
|
// overflow: undefined
|
6533
6451
|
// staggerLines: null
|
6534
6452
|
},
|
@@ -6970,6 +6888,11 @@ Axis.prototype = {
|
|
6970
6888
|
roundedMax = correctFloat(mathCeil(max / tickInterval) * tickInterval),
|
6971
6889
|
tickPositions = [];
|
6972
6890
|
|
6891
|
+
// For single points, add a tick regardless of the relative position (#2662)
|
6892
|
+
if (min === max && isNumber(min)) {
|
6893
|
+
return [min];
|
6894
|
+
}
|
6895
|
+
|
6973
6896
|
// Populate the intermediate values
|
6974
6897
|
pos = roundedMin;
|
6975
6898
|
while (pos <= roundedMax) {
|
@@ -7133,7 +7056,7 @@ Axis.prototype = {
|
|
7133
7056
|
|
7134
7057
|
} else {
|
7135
7058
|
each(axis.series, function (series) {
|
7136
|
-
var seriesPointRange =
|
7059
|
+
var seriesPointRange = hasCategories ? 1 : (axis.isXAxis ? series.pointRange : (axis.axisPointRange || 0)), // #2806
|
7137
7060
|
pointPlacement = series.options.pointPlacement,
|
7138
7061
|
seriesClosestPointRange = series.closestPointRange;
|
7139
7062
|
|
@@ -7265,6 +7188,14 @@ Axis.prototype = {
|
|
7265
7188
|
}
|
7266
7189
|
}
|
7267
7190
|
|
7191
|
+
// Stay within floor and ceiling
|
7192
|
+
if (isNumber(options.floor)) {
|
7193
|
+
axis.min = mathMax(axis.min, options.floor);
|
7194
|
+
}
|
7195
|
+
if (isNumber(options.ceiling)) {
|
7196
|
+
axis.max = mathMin(axis.max, options.ceiling);
|
7197
|
+
}
|
7198
|
+
|
7268
7199
|
// get tickInterval
|
7269
7200
|
if (axis.min === axis.max || axis.min === undefined || axis.max === undefined) {
|
7270
7201
|
axis.tickInterval = 1;
|
@@ -7384,10 +7315,10 @@ Axis.prototype = {
|
|
7384
7315
|
}
|
7385
7316
|
|
7386
7317
|
// When there is only one point, or all points have the same value on this axis, then min
|
7387
|
-
// and max are equal and tickPositions.length is 1. In this case, add some padding
|
7318
|
+
// and max are equal and tickPositions.length is 0 or 1. In this case, add some padding
|
7388
7319
|
// in order to center the point, but leave it with one tick. #1337.
|
7389
7320
|
if (tickPositions.length === 1) {
|
7390
|
-
singlePad = mathAbs(axis.max
|
7321
|
+
singlePad = mathAbs(axis.max) > 10e12 ? 1 : 0.001; // The lowest possible number to avoid extra padding on columns (#2619, #2846)
|
7391
7322
|
axis.min -= singlePad;
|
7392
7323
|
axis.max += singlePad;
|
7393
7324
|
}
|
@@ -7603,16 +7534,25 @@ Axis.prototype = {
|
|
7603
7534
|
offsetLeft = options.offsetLeft || 0,
|
7604
7535
|
offsetRight = options.offsetRight || 0,
|
7605
7536
|
horiz = this.horiz,
|
7606
|
-
width,
|
7607
|
-
height,
|
7608
|
-
top,
|
7609
|
-
left
|
7537
|
+
width = pick(options.width, chart.plotWidth - offsetLeft + offsetRight),
|
7538
|
+
height = pick(options.height, chart.plotHeight),
|
7539
|
+
top = pick(options.top, chart.plotTop),
|
7540
|
+
left = pick(options.left, chart.plotLeft + offsetLeft),
|
7541
|
+
percentRegex = /%$/; // docs
|
7542
|
+
|
7543
|
+
// Check for percentage based input values
|
7544
|
+
if (percentRegex.test(height)) {
|
7545
|
+
height = parseInt(height, 10) / 100 * chart.plotHeight;
|
7546
|
+
}
|
7547
|
+
if (percentRegex.test(top)) {
|
7548
|
+
top = parseInt(top, 10) / 100 * chart.plotHeight + chart.plotTop;
|
7549
|
+
}
|
7610
7550
|
|
7611
7551
|
// Expose basic values to use in Series object and navigator
|
7612
|
-
this.left = left
|
7613
|
-
this.top = top
|
7614
|
-
this.width = width
|
7615
|
-
this.height = height
|
7552
|
+
this.left = left;
|
7553
|
+
this.top = top;
|
7554
|
+
this.width = width;
|
7555
|
+
this.height = height;
|
7616
7556
|
this.bottom = chart.chartHeight - height - top;
|
7617
7557
|
this.right = chart.chartWidth - width - left;
|
7618
7558
|
|
@@ -7711,7 +7651,8 @@ Axis.prototype = {
|
|
7711
7651
|
bBox,
|
7712
7652
|
x,
|
7713
7653
|
w,
|
7714
|
-
lineNo
|
7654
|
+
lineNo,
|
7655
|
+
lineHeightCorrection = side === 2 ? renderer.fontMetrics(labelOptions.style.fontSize).b : 0;
|
7715
7656
|
|
7716
7657
|
// For reuse in Axis.render
|
7717
7658
|
axis.hasData = hasData = (axis.hasVisibleSeries || (defined(axis.min) && defined(axis.max) && !!tickPositions));
|
@@ -7844,7 +7785,7 @@ Axis.prototype = {
|
|
7844
7785
|
axis.axisTitleMargin =
|
7845
7786
|
pick(titleOffsetOption,
|
7846
7787
|
labelOffset + titleMargin +
|
7847
|
-
(
|
7788
|
+
(labelOffset && (directionFactor * options.labels[horiz ? 'y' : 'x'] - lineHeightCorrection))
|
7848
7789
|
);
|
7849
7790
|
|
7850
7791
|
axisOffset[side] = mathMax(
|
@@ -8610,7 +8551,7 @@ Tooltip.prototype = {
|
|
8610
8551
|
|
8611
8552
|
|
8612
8553
|
// create the label
|
8613
|
-
this.label = chart.renderer.label('', 0, 0, options.shape, null, null, options.useHTML, null, 'tooltip')
|
8554
|
+
this.label = chart.renderer.label('', 0, 0, options.shape || 'callout', null, null, options.useHTML, null, 'tooltip')
|
8614
8555
|
.attr({
|
8615
8556
|
padding: padding,
|
8616
8557
|
fill: options.backgroundColor,
|
@@ -8655,14 +8596,15 @@ Tooltip.prototype = {
|
|
8655
8596
|
move: function (x, y, anchorX, anchorY) {
|
8656
8597
|
var tooltip = this,
|
8657
8598
|
now = tooltip.now,
|
8658
|
-
animate = tooltip.options.animation !== false && !tooltip.isHidden
|
8599
|
+
animate = tooltip.options.animation !== false && !tooltip.isHidden,
|
8600
|
+
skipAnchor = tooltip.followPointer || tooltip.len > 1;
|
8659
8601
|
|
8660
8602
|
// get intermediate values for animation
|
8661
8603
|
extend(now, {
|
8662
8604
|
x: animate ? (2 * now.x + x) / 3 : x,
|
8663
8605
|
y: animate ? (now.y + y) / 2 : y,
|
8664
|
-
anchorX: animate ? (2 * now.anchorX + anchorX) / 3 : anchorX,
|
8665
|
-
anchorY: animate ? (now.anchorY + anchorY) / 2 : anchorY
|
8606
|
+
anchorX: skipAnchor ? UNDEFINED : animate ? (2 * now.anchorX + anchorX) / 3 : anchorX,
|
8607
|
+
anchorY: skipAnchor ? UNDEFINED : animate ? (now.anchorY + anchorY) / 2 : anchorY
|
8666
8608
|
});
|
8667
8609
|
|
8668
8610
|
// move to the intermediate value
|
@@ -8770,49 +8712,89 @@ Tooltip.prototype = {
|
|
8770
8712
|
*/
|
8771
8713
|
getPosition: function (boxWidth, boxHeight, point) {
|
8772
8714
|
|
8773
|
-
// Set up the variables
|
8774
8715
|
var chart = this.chart,
|
8775
|
-
|
8776
|
-
|
8777
|
-
|
8778
|
-
|
8779
|
-
|
8780
|
-
|
8781
|
-
|
8782
|
-
|
8783
|
-
|
8784
|
-
|
8716
|
+
distance = this.distance,
|
8717
|
+
ret = {},
|
8718
|
+
swapped,
|
8719
|
+
first = ['y', chart.chartHeight, boxHeight, point.plotY + chart.plotTop],
|
8720
|
+
second = ['x', chart.chartWidth, boxWidth, point.plotX + chart.plotLeft],
|
8721
|
+
// The far side is right or bottom
|
8722
|
+
preferFarSide = point.ttBelow || (chart.inverted && !point.negative) || (!chart.inverted && point.negative),
|
8723
|
+
/**
|
8724
|
+
* Handle the preferred dimension. When the preferred dimension is tooltip
|
8725
|
+
* on top or bottom of the point, it will look for space there.
|
8726
|
+
*/
|
8727
|
+
firstDimension = function (dim, outerSize, innerSize, point) {
|
8728
|
+
var roomLeft = innerSize < point - distance,
|
8729
|
+
roomRight = point + distance + innerSize < outerSize,
|
8730
|
+
alignedLeft = point - distance - innerSize,
|
8731
|
+
alignedRight = point + distance;
|
8732
|
+
|
8733
|
+
if (preferFarSide && roomRight) {
|
8734
|
+
ret[dim] = alignedRight;
|
8735
|
+
} else if (!preferFarSide && roomLeft) {
|
8736
|
+
ret[dim] = alignedLeft;
|
8737
|
+
} else if (roomLeft) {
|
8738
|
+
ret[dim] = alignedLeft;
|
8739
|
+
} else if (roomRight) {
|
8740
|
+
ret[dim] = alignedRight;
|
8741
|
+
} else {
|
8742
|
+
return false;
|
8743
|
+
}
|
8744
|
+
},
|
8745
|
+
/**
|
8746
|
+
* Handle the secondary dimension. If the preferred dimension is tooltip
|
8747
|
+
* on top or bottom of the point, the second dimension is to align the tooltip
|
8748
|
+
* above the point, trying to align center but allowing left or right
|
8749
|
+
* align within the chart box.
|
8750
|
+
*/
|
8751
|
+
secondDimension = function (dim, outerSize, innerSize, point) {
|
8752
|
+
// Too close to the edge, return false and swap dimensions
|
8753
|
+
if (point < distance || point > outerSize - distance) {
|
8754
|
+
return false;
|
8755
|
+
|
8756
|
+
// Align left/top
|
8757
|
+
} else if (point < innerSize / 2) {
|
8758
|
+
ret[dim] = 1;
|
8759
|
+
// Align right/bottom
|
8760
|
+
} else if (point > outerSize - innerSize / 2) {
|
8761
|
+
ret[dim] = outerSize - innerSize - 2;
|
8762
|
+
// Align center
|
8763
|
+
} else {
|
8764
|
+
ret[dim] = point - innerSize / 2;
|
8765
|
+
}
|
8766
|
+
},
|
8767
|
+
/**
|
8768
|
+
* Swap the dimensions
|
8769
|
+
*/
|
8770
|
+
swap = function (count) {
|
8771
|
+
var temp = first;
|
8772
|
+
first = second;
|
8773
|
+
second = temp;
|
8774
|
+
swapped = count;
|
8775
|
+
},
|
8776
|
+
run = function () {
|
8777
|
+
if (firstDimension.apply(0, first) !== false) {
|
8778
|
+
if (secondDimension.apply(0, second) === false && !swapped) {
|
8779
|
+
swap(true);
|
8780
|
+
run();
|
8781
|
+
}
|
8782
|
+
} else if (!swapped) {
|
8783
|
+
swap(true);
|
8784
|
+
run();
|
8785
|
+
} else {
|
8786
|
+
ret.x = ret.y = 0;
|
8787
|
+
}
|
8788
|
+
};
|
8785
8789
|
|
8786
|
-
//
|
8787
|
-
if (
|
8788
|
-
|
8789
|
-
}
|
8790
|
-
|
8791
|
-
// Test to see if the tooltip is too far to the right,
|
8792
|
-
// if it is, move it back to be inside and then up to not cover the point.
|
8793
|
-
if ((x + boxWidth) > (plotLeft + plotWidth)) {
|
8794
|
-
x -= (x + boxWidth) - (plotLeft + plotWidth);
|
8795
|
-
y = pointY - boxHeight + plotTop - distance;
|
8796
|
-
alignedRight = true;
|
8797
|
-
}
|
8798
|
-
|
8799
|
-
// If it is now above the plot area, align it to the top of the plot area
|
8800
|
-
if (y < plotTop + 5) {
|
8801
|
-
y = plotTop + 5;
|
8802
|
-
|
8803
|
-
// If the tooltip is still covering the point, move it below instead
|
8804
|
-
if (alignedRight && pointY >= y && pointY <= (y + boxHeight)) {
|
8805
|
-
y = pointY + plotTop + distance; // below
|
8806
|
-
}
|
8807
|
-
}
|
8808
|
-
|
8809
|
-
// Now if the tooltip is below the chart, move it up. It's better to cover the
|
8810
|
-
// point than to disappear outside the chart. #834.
|
8811
|
-
if (y + boxHeight > plotTop + plotHeight) {
|
8812
|
-
y = mathMax(plotTop, plotTop + plotHeight - boxHeight - distance); // below
|
8790
|
+
// Under these conditions, prefer the tooltip on the side of the point
|
8791
|
+
if (chart.inverted || this.len > 1) {
|
8792
|
+
swap();
|
8813
8793
|
}
|
8794
|
+
run();
|
8795
|
+
|
8796
|
+
return ret;
|
8814
8797
|
|
8815
|
-
return {x: x, y: y};
|
8816
8798
|
},
|
8817
8799
|
|
8818
8800
|
/**
|
@@ -8892,6 +8874,7 @@ Tooltip.prototype = {
|
|
8892
8874
|
y: point[0].y
|
8893
8875
|
};
|
8894
8876
|
textConfig.points = pointConfig;
|
8877
|
+
this.len = pointConfig.length;
|
8895
8878
|
point = point[0];
|
8896
8879
|
|
8897
8880
|
// single point tooltip
|
@@ -8902,6 +8885,7 @@ Tooltip.prototype = {
|
|
8902
8885
|
|
8903
8886
|
// register the current series
|
8904
8887
|
currentSeries = point.series;
|
8888
|
+
this.distance = pick(currentSeries.tooltipOptions.distance, 16);
|
8905
8889
|
|
8906
8890
|
// update the inner HTML
|
8907
8891
|
if (text === false) {
|
@@ -8925,7 +8909,7 @@ Tooltip.prototype = {
|
|
8925
8909
|
stroke: borderColor
|
8926
8910
|
});
|
8927
8911
|
|
8928
|
-
tooltip.updatePosition({ plotX: x, plotY: y });
|
8912
|
+
tooltip.updatePosition({ plotX: x, plotY: y, negative: point.negative, ttBelow: point.ttBelow });
|
8929
8913
|
|
8930
8914
|
this.isHidden = false;
|
8931
8915
|
}
|
@@ -9044,6 +9028,7 @@ Pointer.prototype = {
|
|
9044
9028
|
this.zoomY = zoomY = /y/.test(zoomType);
|
9045
9029
|
this.zoomHor = (zoomX && !inverted) || (zoomY && inverted);
|
9046
9030
|
this.zoomVert = (zoomY && !inverted) || (zoomX && inverted);
|
9031
|
+
this.hasZoom = zoomX || zoomY;
|
9047
9032
|
|
9048
9033
|
// Do we need to handle click on a touch device?
|
9049
9034
|
this.runChartClick = chartEvents && !!chartEvents.click;
|
@@ -9053,6 +9038,7 @@ Pointer.prototype = {
|
|
9053
9038
|
|
9054
9039
|
if (Highcharts.Tooltip && options.tooltip.enabled) {
|
9055
9040
|
chart.tooltip = new Tooltip(chart, options.tooltip);
|
9041
|
+
this.followTouchMove = options.tooltip.followTouchMove;
|
9056
9042
|
}
|
9057
9043
|
|
9058
9044
|
this.setDOMEvents();
|
@@ -9068,7 +9054,7 @@ Pointer.prototype = {
|
|
9068
9054
|
ePos;
|
9069
9055
|
|
9070
9056
|
// common IE normalizing
|
9071
|
-
e = e ||
|
9057
|
+
e = e || window.event;
|
9072
9058
|
|
9073
9059
|
// Framework specific normalizing (#1165)
|
9074
9060
|
e = washMouseEvent(e);
|
@@ -9078,8 +9064,8 @@ Pointer.prototype = {
|
|
9078
9064
|
e.target = e.srcElement;
|
9079
9065
|
}
|
9080
9066
|
|
9081
|
-
// iOS
|
9082
|
-
ePos = e.touches ? e.touches.item(0) : e;
|
9067
|
+
// iOS (#2757)
|
9068
|
+
ePos = e.touches ? (e.touches.length ? e.touches.item(0) : e.changedTouches[0]) : e;
|
9083
9069
|
|
9084
9070
|
// Get mouse position
|
9085
9071
|
if (!chartPosition) {
|
@@ -9142,6 +9128,7 @@ Pointer.prototype = {
|
|
9142
9128
|
chart = pointer.chart,
|
9143
9129
|
series = chart.series,
|
9144
9130
|
tooltip = chart.tooltip,
|
9131
|
+
followPointer,
|
9145
9132
|
point,
|
9146
9133
|
points,
|
9147
9134
|
hoverPoint = chart.hoverPoint,
|
@@ -9184,8 +9171,9 @@ Pointer.prototype = {
|
|
9184
9171
|
}
|
9185
9172
|
}
|
9186
9173
|
|
9187
|
-
//
|
9188
|
-
|
9174
|
+
// Separate tooltip and general mouse events
|
9175
|
+
followPointer = hoverSeries && hoverSeries.tooltipOptions.followPointer;
|
9176
|
+
if (hoverSeries && hoverSeries.tracker && !followPointer) { // #2584, #2830
|
9189
9177
|
|
9190
9178
|
// get the point
|
9191
9179
|
point = hoverSeries.tooltipPoints[index];
|
@@ -9198,7 +9186,7 @@ Pointer.prototype = {
|
|
9198
9186
|
|
9199
9187
|
}
|
9200
9188
|
|
9201
|
-
} else if (tooltip &&
|
9189
|
+
} else if (tooltip && followPointer && !tooltip.isHidden) {
|
9202
9190
|
anchor = tooltip.getAnchor([{}], e);
|
9203
9191
|
tooltip.updatePosition({ plotX: anchor[0], plotY: anchor[1] });
|
9204
9192
|
}
|
@@ -9206,7 +9194,7 @@ Pointer.prototype = {
|
|
9206
9194
|
// Start the event listener to pick up the tooltip
|
9207
9195
|
if (tooltip && !pointer._onDocumentMouseMove) {
|
9208
9196
|
pointer._onDocumentMouseMove = function (e) {
|
9209
|
-
if (
|
9197
|
+
if (charts[hoverChartIndex]) {
|
9210
9198
|
charts[hoverChartIndex].pointer.onDocumentMouseMove(e);
|
9211
9199
|
}
|
9212
9200
|
};
|
@@ -9418,9 +9406,12 @@ Pointer.prototype = {
|
|
9418
9406
|
originalEvent: e.originalEvent || e
|
9419
9407
|
},
|
9420
9408
|
selectionBox = this.selectionMarker,
|
9421
|
-
selectionLeft = selectionBox.x,
|
9422
|
-
selectionTop = selectionBox.y,
|
9409
|
+
selectionLeft = selectionBox.attr ? selectionBox.attr('x') : selectionBox.x,
|
9410
|
+
selectionTop = selectionBox.attr ? selectionBox.attr('y') : selectionBox.y,
|
9411
|
+
selectionWidth = selectionBox.attr ? selectionBox.attr('width') : selectionBox.width,
|
9412
|
+
selectionHeight = selectionBox.attr ? selectionBox.attr('height') : selectionBox.height,
|
9423
9413
|
runZoom;
|
9414
|
+
|
9424
9415
|
// a selection has been made
|
9425
9416
|
if (this.hasDragged || hasPinched) {
|
9426
9417
|
|
@@ -9429,7 +9420,7 @@ Pointer.prototype = {
|
|
9429
9420
|
if (axis.zoomEnabled) {
|
9430
9421
|
var horiz = axis.horiz,
|
9431
9422
|
selectionMin = axis.toValue((horiz ? selectionLeft : selectionTop)),
|
9432
|
-
selectionMax = axis.toValue((horiz ? selectionLeft +
|
9423
|
+
selectionMax = axis.toValue((horiz ? selectionLeft + selectionWidth : selectionTop + selectionHeight));
|
9433
9424
|
|
9434
9425
|
if (!isNaN(selectionMin) && !isNaN(selectionMax)) { // #859
|
9435
9426
|
selectionData[axis.coll].push({
|
@@ -9480,7 +9471,7 @@ Pointer.prototype = {
|
|
9480
9471
|
|
9481
9472
|
|
9482
9473
|
onDocumentMouseUp: function (e) {
|
9483
|
-
if (
|
9474
|
+
if (charts[hoverChartIndex]) {
|
9484
9475
|
charts[hoverChartIndex].pointer.drop(e);
|
9485
9476
|
}
|
9486
9477
|
},
|
@@ -9512,7 +9503,6 @@ Pointer.prototype = {
|
|
9512
9503
|
chart.pointer.reset();
|
9513
9504
|
chart.pointer.chartPosition = null; // also reset the chart position, used in #149 fix
|
9514
9505
|
}
|
9515
|
-
hoverChartIndex = null;
|
9516
9506
|
},
|
9517
9507
|
|
9518
9508
|
// The mousemove, touchmove and touchstart event handler
|
@@ -9640,8 +9630,9 @@ Pointer.prototype = {
|
|
9640
9630
|
pointer.onContainerClick(e);
|
9641
9631
|
};
|
9642
9632
|
addEvent(container, 'mouseleave', pointer.onContainerMouseLeave);
|
9643
|
-
|
9644
|
-
|
9633
|
+
if (chartCount === 1) {
|
9634
|
+
addEvent(doc, 'mouseup', pointer.onDocumentMouseUp);
|
9635
|
+
}
|
9645
9636
|
if (hasTouch) {
|
9646
9637
|
container.ontouchstart = function (e) {
|
9647
9638
|
pointer.onContainerTouchStart(e);
|
@@ -9649,7 +9640,9 @@ Pointer.prototype = {
|
|
9649
9640
|
container.ontouchmove = function (e) {
|
9650
9641
|
pointer.onContainerTouchMove(e);
|
9651
9642
|
};
|
9652
|
-
|
9643
|
+
if (chartCount === 1) {
|
9644
|
+
addEvent(doc, 'touchend', pointer.onDocumentTouchEnd);
|
9645
|
+
}
|
9653
9646
|
}
|
9654
9647
|
|
9655
9648
|
},
|
@@ -9661,9 +9654,11 @@ Pointer.prototype = {
|
|
9661
9654
|
var prop;
|
9662
9655
|
|
9663
9656
|
removeEvent(this.chart.container, 'mouseleave', this.onContainerMouseLeave);
|
9664
|
-
|
9665
|
-
|
9666
|
-
|
9657
|
+
if (!chartCount) {
|
9658
|
+
removeEvent(doc, 'mouseup', this.onDocumentMouseUp);
|
9659
|
+
removeEvent(doc, 'touchend', this.onDocumentTouchEnd);
|
9660
|
+
}
|
9661
|
+
|
9667
9662
|
// memory and CPU leak
|
9668
9663
|
clearInterval(this.tooltipTimeout);
|
9669
9664
|
|
@@ -9680,11 +9675,11 @@ extend(Highcharts.Pointer.prototype, {
|
|
9680
9675
|
/**
|
9681
9676
|
* Run translation operations
|
9682
9677
|
*/
|
9683
|
-
pinchTranslate: function (
|
9684
|
-
if (zoomHor) {
|
9678
|
+
pinchTranslate: function (pinchDown, touches, transform, selectionMarker, clip, lastValidTouch) {
|
9679
|
+
if (this.zoomHor || this.pinchHor) {
|
9685
9680
|
this.pinchTranslateDirection(true, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
|
9686
9681
|
}
|
9687
|
-
if (zoomVert) {
|
9682
|
+
if (this.zoomVert || this.pinchVert) {
|
9688
9683
|
this.pinchTranslateDirection(false, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
|
9689
9684
|
}
|
9690
9685
|
},
|
@@ -9775,13 +9770,11 @@ extend(Highcharts.Pointer.prototype, {
|
|
9775
9770
|
var self = this,
|
9776
9771
|
chart = self.chart,
|
9777
9772
|
pinchDown = self.pinchDown,
|
9778
|
-
followTouchMove =
|
9773
|
+
followTouchMove = self.followTouchMove,
|
9779
9774
|
touches = e.touches,
|
9780
9775
|
touchesLength = touches.length,
|
9781
9776
|
lastValidTouch = self.lastValidTouch,
|
9782
|
-
|
9783
|
-
zoomVert = self.zoomVert || self.pinchVert,
|
9784
|
-
hasZoom = zoomHor || zoomVert,
|
9777
|
+
hasZoom = self.hasZoom,
|
9785
9778
|
selectionMarker = self.selectionMarker,
|
9786
9779
|
transform = {},
|
9787
9780
|
fireClickEvent = touchesLength === 1 && ((self.inClass(e.target, PREFIX + 'tracker') &&
|
@@ -9833,7 +9826,7 @@ extend(Highcharts.Pointer.prototype, {
|
|
9833
9826
|
}, chart.plotBox);
|
9834
9827
|
}
|
9835
9828
|
|
9836
|
-
self.pinchTranslate(
|
9829
|
+
self.pinchTranslate(pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
|
9837
9830
|
|
9838
9831
|
self.hasPinched = hasZoom;
|
9839
9832
|
|
@@ -9858,11 +9851,6 @@ extend(Highcharts.Pointer.prototype, {
|
|
9858
9851
|
|
9859
9852
|
if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
|
9860
9853
|
|
9861
|
-
// Prevent the click pseudo event from firing unless it is set in the options
|
9862
|
-
/*if (!chart.runChartClick) {
|
9863
|
-
e.preventDefault();
|
9864
|
-
}*/
|
9865
|
-
|
9866
9854
|
// Run mouse events and display tooltip etc
|
9867
9855
|
this.runPointActions(e);
|
9868
9856
|
|
@@ -9885,7 +9873,7 @@ extend(Highcharts.Pointer.prototype, {
|
|
9885
9873
|
},
|
9886
9874
|
|
9887
9875
|
onDocumentTouchEnd: function (e) {
|
9888
|
-
if (
|
9876
|
+
if (charts[hoverChartIndex]) {
|
9889
9877
|
charts[hoverChartIndex].pointer.drop(e);
|
9890
9878
|
}
|
9891
9879
|
}
|
@@ -9960,17 +9948,21 @@ if (win.PointerEvent || win.MSPointerEvent) {
|
|
9960
9948
|
|
9961
9949
|
// Disable default IE actions for pinch and such on chart element
|
9962
9950
|
wrap(Pointer.prototype, 'init', function (proceed, chart, options) {
|
9963
|
-
css(chart.container, {
|
9964
|
-
'-ms-touch-action': NONE,
|
9965
|
-
'touch-action': NONE
|
9966
|
-
});
|
9967
9951
|
proceed.call(this, chart, options);
|
9952
|
+
if (this.hasZoom || this.followTouchMove) {
|
9953
|
+
css(chart.container, {
|
9954
|
+
'-ms-touch-action': NONE,
|
9955
|
+
'touch-action': NONE
|
9956
|
+
});
|
9957
|
+
}
|
9968
9958
|
});
|
9969
9959
|
|
9970
9960
|
// Add IE specific touch events to chart
|
9971
9961
|
wrap(Pointer.prototype, 'setDOMEvents', function (proceed) {
|
9972
9962
|
proceed.apply(this);
|
9973
|
-
this.
|
9963
|
+
if (this.hasZoom || this.followTouchMove) {
|
9964
|
+
this.batchMSEvents(addEvent);
|
9965
|
+
}
|
9974
9966
|
});
|
9975
9967
|
// Destroy MS events also
|
9976
9968
|
wrap(Pointer.prototype, 'destroy', function (proceed) {
|
@@ -10043,10 +10035,7 @@ Legend.prototype = {
|
|
10043
10035
|
textColor = visible ? options.itemStyle.color : hiddenColor,
|
10044
10036
|
symbolColor = visible ? (item.legendColor || item.color || '#CCC') : hiddenColor,
|
10045
10037
|
markerOptions = item.options && item.options.marker,
|
10046
|
-
symbolAttr = {
|
10047
|
-
stroke: symbolColor,
|
10048
|
-
fill: symbolColor
|
10049
|
-
},
|
10038
|
+
symbolAttr = { fill: symbolColor },
|
10050
10039
|
key,
|
10051
10040
|
val;
|
10052
10041
|
|
@@ -10061,6 +10050,7 @@ Legend.prototype = {
|
|
10061
10050
|
|
10062
10051
|
// Apply marker options
|
10063
10052
|
if (markerOptions && legendSymbol.isMarker) { // #585
|
10053
|
+
symbolAttr.stroke = symbolColor;
|
10064
10054
|
markerOptions = item.convertAttribs(markerOptions);
|
10065
10055
|
for (key in markerOptions) {
|
10066
10056
|
val = markerOptions[key];
|
@@ -10203,7 +10193,7 @@ Legend.prototype = {
|
|
10203
10193
|
itemStyle = legend.itemStyle,
|
10204
10194
|
itemHiddenStyle = legend.itemHiddenStyle,
|
10205
10195
|
padding = legend.padding,
|
10206
|
-
itemDistance = horizontal ? pick(options.itemDistance,
|
10196
|
+
itemDistance = horizontal ? pick(options.itemDistance, 20) : 0, // docs
|
10207
10197
|
ltr = !options.rtl,
|
10208
10198
|
itemHeight,
|
10209
10199
|
widthOption = options.width,
|
@@ -10648,7 +10638,7 @@ var LegendSymbolMixin = Highcharts.LegendSymbolMixin = {
|
|
10648
10638
|
legend.baseline - 5 - (symbolHeight / 2),
|
10649
10639
|
legend.symbolWidth,
|
10650
10640
|
symbolHeight,
|
10651
|
-
|
10641
|
+
legend.options.symbolRadius || 0
|
10652
10642
|
).attr({
|
10653
10643
|
zIndex: 3
|
10654
10644
|
}).add(item.legendGroup);
|
@@ -10695,7 +10685,7 @@ var LegendSymbolMixin = Highcharts.LegendSymbolMixin = {
|
|
10695
10685
|
}
|
10696
10686
|
|
10697
10687
|
// Draw the marker
|
10698
|
-
if (markerOptions && markerOptions.enabled) {
|
10688
|
+
if (markerOptions && markerOptions.enabled !== false) {
|
10699
10689
|
radius = markerOptions.radius;
|
10700
10690
|
this.legendSymbol = legendSymbol = renderer.symbol(
|
10701
10691
|
this.symbol,
|
@@ -10723,11 +10713,11 @@ if (/Trident\/7\.0/.test(userAgent) || isFirefox) {
|
|
10723
10713
|
}
|
10724
10714
|
};
|
10725
10715
|
|
10726
|
-
|
10727
|
-
|
10728
|
-
|
10729
|
-
|
10730
|
-
|
10716
|
+
// Do it now, for export and to get checkbox placement
|
10717
|
+
runPositionItem();
|
10718
|
+
|
10719
|
+
// Do it after to work around the core issue
|
10720
|
+
setTimeout(runPositionItem);
|
10731
10721
|
});
|
10732
10722
|
}
|
10733
10723
|
/**
|
@@ -10810,6 +10800,7 @@ Chart.prototype = {
|
|
10810
10800
|
// Add the chart to the global lookup
|
10811
10801
|
chart.index = charts.length;
|
10812
10802
|
charts.push(chart);
|
10803
|
+
chartCount++;
|
10813
10804
|
|
10814
10805
|
// Set up auto resize
|
10815
10806
|
if (optionsChart.reflow !== false) {
|
@@ -11221,11 +11212,6 @@ Chart.prototype = {
|
|
11221
11212
|
|
11222
11213
|
if (!titleOptions.floating && !titleOptions.verticalAlign) {
|
11223
11214
|
titleOffset = title.getBBox().height;
|
11224
|
-
|
11225
|
-
// Adjust for browser consistency + backwards compat after #776 fix
|
11226
|
-
if (titleOffset >= 18 && titleOffset <= 25) {
|
11227
|
-
titleOffset = 15;
|
11228
|
-
}
|
11229
11215
|
}
|
11230
11216
|
}
|
11231
11217
|
if (subtitle) {
|
@@ -11414,7 +11400,7 @@ Chart.prototype = {
|
|
11414
11400
|
legend = chart.legend,
|
11415
11401
|
margin = chart.margin,
|
11416
11402
|
legendOptions = chart.options.legend,
|
11417
|
-
legendMargin = pick(legendOptions.margin,
|
11403
|
+
legendMargin = pick(legendOptions.margin, 20),
|
11418
11404
|
legendX = legendOptions.x,
|
11419
11405
|
legendY = legendOptions.y,
|
11420
11406
|
align = legendOptions.align,
|
@@ -11604,6 +11590,7 @@ Chart.prototype = {
|
|
11604
11590
|
chart.isDirtyLegend = true; // force legend redraw
|
11605
11591
|
chart.isDirtyBox = true; // force redraw of plot and chart border
|
11606
11592
|
|
11593
|
+
chart.layOutTitles(); // #2857
|
11607
11594
|
chart.getMargins();
|
11608
11595
|
|
11609
11596
|
chart.redraw(animation);
|
@@ -12018,6 +12005,7 @@ Chart.prototype = {
|
|
12018
12005
|
|
12019
12006
|
// Delete the chart from charts lookup array
|
12020
12007
|
charts[chart.index] = UNDEFINED;
|
12008
|
+
chartCount--;
|
12021
12009
|
chart.renderTo.removeAttribute('data-highcharts-chart');
|
12022
12010
|
|
12023
12011
|
// remove events
|
@@ -12416,6 +12404,34 @@ Point.prototype = {
|
|
12416
12404
|
point: this,
|
12417
12405
|
series: this.series
|
12418
12406
|
});
|
12407
|
+
},
|
12408
|
+
|
12409
|
+
/**
|
12410
|
+
* Fire an event on the Point object. Must not be renamed to fireEvent, as this
|
12411
|
+
* causes a name clash in MooTools
|
12412
|
+
* @param {String} eventType
|
12413
|
+
* @param {Object} eventArgs Additional event arguments
|
12414
|
+
* @param {Function} defaultFunction Default event handler
|
12415
|
+
*/
|
12416
|
+
firePointEvent: function (eventType, eventArgs, defaultFunction) {
|
12417
|
+
var point = this,
|
12418
|
+
series = this.series,
|
12419
|
+
seriesOptions = series.options;
|
12420
|
+
|
12421
|
+
// load event handlers on demand to save time on mouseover/out
|
12422
|
+
if (seriesOptions.point.events[eventType] || (point.options && point.options.events && point.options.events[eventType])) {
|
12423
|
+
this.importEvents();
|
12424
|
+
}
|
12425
|
+
|
12426
|
+
// add default handler if in selection mode
|
12427
|
+
if (eventType === 'click' && seriesOptions.allowPointSelect) {
|
12428
|
+
defaultFunction = function (event) {
|
12429
|
+
// Control key is for Windows, meta (= Cmd key) for Mac, Shift for Opera
|
12430
|
+
point.select(null, event.ctrlKey || event.metaKey || event.shiftKey);
|
12431
|
+
};
|
12432
|
+
}
|
12433
|
+
|
12434
|
+
fireEvent(this, eventType, eventArgs, defaultFunction);
|
12419
12435
|
}
|
12420
12436
|
};/**
|
12421
12437
|
* @classDescription The base function which all other series types inherit from. The data in the series is stored
|
@@ -12904,7 +12920,10 @@ Series.prototype = {
|
|
12904
12920
|
i, // loop variable
|
12905
12921
|
options = series.options,
|
12906
12922
|
cropThreshold = options.cropThreshold,
|
12907
|
-
|
12923
|
+
activePointCount = 0,
|
12924
|
+
isCartesian = series.isCartesian,
|
12925
|
+
min,
|
12926
|
+
max;
|
12908
12927
|
|
12909
12928
|
// If the series data or axes haven't changed, don't go through this. Return false to pass
|
12910
12929
|
// the message on to override methods like in data grouping.
|
@@ -12915,8 +12934,9 @@ Series.prototype = {
|
|
12915
12934
|
|
12916
12935
|
// optionally filter out points outside the plot area
|
12917
12936
|
if (isCartesian && series.sorted && (!cropThreshold || dataLength > cropThreshold || series.forceCrop)) {
|
12918
|
-
|
12919
|
-
|
12937
|
+
|
12938
|
+
min = xAxis.min;
|
12939
|
+
max = xAxis.max;
|
12920
12940
|
|
12921
12941
|
// it's outside current extremes
|
12922
12942
|
if (processedXData[dataLength - 1] < min || processedXData[0] > max) {
|
@@ -12930,6 +12950,7 @@ Series.prototype = {
|
|
12930
12950
|
processedYData = croppedData.yData;
|
12931
12951
|
cropStart = croppedData.start;
|
12932
12952
|
cropped = true;
|
12953
|
+
activePointCount = processedXData.length;
|
12933
12954
|
}
|
12934
12955
|
}
|
12935
12956
|
|
@@ -12937,6 +12958,10 @@ Series.prototype = {
|
|
12937
12958
|
// Find the closest distance between processed points
|
12938
12959
|
for (i = processedXData.length - 1; i >= 0; i--) {
|
12939
12960
|
distance = processedXData[i] - processedXData[i - 1];
|
12961
|
+
|
12962
|
+
if (!cropped && processedXData[i] > min && processedXData[i] < max) {
|
12963
|
+
activePointCount++;
|
12964
|
+
}
|
12940
12965
|
if (distance > 0 && (closestPointRange === UNDEFINED || distance < closestPointRange)) {
|
12941
12966
|
closestPointRange = distance;
|
12942
12967
|
|
@@ -12952,6 +12977,7 @@ Series.prototype = {
|
|
12952
12977
|
series.cropStart = cropStart;
|
12953
12978
|
series.processedXData = processedXData;
|
12954
12979
|
series.processedYData = processedYData;
|
12980
|
+
series.activePointCount = activePointCount;
|
12955
12981
|
|
12956
12982
|
if (options.pointRange === null) { // null means auto, as for columns, candlesticks and OHLC
|
12957
12983
|
series.pointRange = closestPointRange || 1;
|
@@ -13156,7 +13182,7 @@ Series.prototype = {
|
|
13156
13182
|
if (stacking && series.visible && stack && stack[xValue]) {
|
13157
13183
|
|
13158
13184
|
pointStack = stack[xValue];
|
13159
|
-
stackValues = pointStack.points[series.index];
|
13185
|
+
stackValues = pointStack.points[series.index + ',' + i];
|
13160
13186
|
yBottom = stackValues[0];
|
13161
13187
|
yValue = stackValues[1];
|
13162
13188
|
|
@@ -13218,7 +13244,7 @@ Series.prototype = {
|
|
13218
13244
|
clipRect,
|
13219
13245
|
markerClipRect,
|
13220
13246
|
animation = series.options.animation,
|
13221
|
-
clipBox = chart.clipBox,
|
13247
|
+
clipBox = series.clipBox || chart.clipBox,
|
13222
13248
|
inverted = chart.inverted,
|
13223
13249
|
sharedClipKey;
|
13224
13250
|
|
@@ -13226,7 +13252,7 @@ Series.prototype = {
|
|
13226
13252
|
if (animation && !isObject(animation)) {
|
13227
13253
|
animation = defaultPlotOptions[series.type].animation;
|
13228
13254
|
}
|
13229
|
-
sharedClipKey = '_sharedClip'
|
13255
|
+
sharedClipKey = ['_sharedClip', animation.duration, animation.easing, clipBox.height].join(',');
|
13230
13256
|
|
13231
13257
|
// Initialize the animation. Set up the clipping rectangle.
|
13232
13258
|
if (init) {
|
@@ -13257,6 +13283,8 @@ Series.prototype = {
|
|
13257
13283
|
clipRect.animate({
|
13258
13284
|
width: chart.plotSizeX
|
13259
13285
|
}, animation);
|
13286
|
+
}
|
13287
|
+
if (chart[sharedClipKey + 'm']) {
|
13260
13288
|
chart[sharedClipKey + 'm'].animate({
|
13261
13289
|
width: chart.plotSizeX + 99
|
13262
13290
|
}, animation);
|
@@ -13264,12 +13292,7 @@ Series.prototype = {
|
|
13264
13292
|
|
13265
13293
|
// Delete this function to allow it only once
|
13266
13294
|
series.animate = null;
|
13267
|
-
|
13268
|
-
// Call the afterAnimate function on animation complete (but don't overwrite the animation.complete option
|
13269
|
-
// which should be available to the user).
|
13270
|
-
series.animationTimeout = setTimeout(function () {
|
13271
|
-
series.afterAnimate();
|
13272
|
-
}, animation.duration);
|
13295
|
+
|
13273
13296
|
}
|
13274
13297
|
},
|
13275
13298
|
|
@@ -13279,18 +13302,27 @@ Series.prototype = {
|
|
13279
13302
|
afterAnimate: function () {
|
13280
13303
|
var chart = this.chart,
|
13281
13304
|
sharedClipKey = this.sharedClipKey,
|
13282
|
-
group = this.group
|
13305
|
+
group = this.group,
|
13306
|
+
clipBox = this.clipBox;
|
13283
13307
|
|
13284
13308
|
if (group && this.options.clip !== false) {
|
13285
|
-
|
13309
|
+
if (!sharedClipKey || !clipBox) {
|
13310
|
+
group.clip(clipBox ? chart.renderer.clipRect(clipBox) : chart.clipRect);
|
13311
|
+
}
|
13286
13312
|
this.markerGroup.clip(); // no clip
|
13287
13313
|
}
|
13288
13314
|
|
13315
|
+
fireEvent(this, 'afterAnimate');
|
13316
|
+
|
13289
13317
|
// Remove the shared clipping rectancgle when all series are shown
|
13290
13318
|
setTimeout(function () {
|
13291
13319
|
if (sharedClipKey && chart[sharedClipKey]) {
|
13292
|
-
|
13293
|
-
|
13320
|
+
if (!clipBox) {
|
13321
|
+
chart[sharedClipKey] = chart[sharedClipKey].destroy();
|
13322
|
+
}
|
13323
|
+
if (chart[sharedClipKey + 'm']) {
|
13324
|
+
chart[sharedClipKey + 'm'] = chart[sharedClipKey + 'm'].destroy();
|
13325
|
+
}
|
13294
13326
|
}
|
13295
13327
|
}, 100);
|
13296
13328
|
},
|
@@ -13317,9 +13349,13 @@ Series.prototype = {
|
|
13317
13349
|
pointMarkerOptions,
|
13318
13350
|
enabled,
|
13319
13351
|
isInside,
|
13320
|
-
markerGroup = series.markerGroup
|
13352
|
+
markerGroup = series.markerGroup,
|
13353
|
+
globallyEnabled = pick(
|
13354
|
+
seriesMarkerOptions.enabled,
|
13355
|
+
series.activePointCount < (0.5 * series.xAxis.len / seriesMarkerOptions.radius)
|
13356
|
+
);
|
13321
13357
|
|
13322
|
-
if (seriesMarkerOptions.enabled || series._hasPointMarkers) {
|
13358
|
+
if (seriesMarkerOptions.enabled !== false || series._hasPointMarkers) {
|
13323
13359
|
|
13324
13360
|
i = points.length;
|
13325
13361
|
while (i--) {
|
@@ -13328,7 +13364,7 @@ Series.prototype = {
|
|
13328
13364
|
plotY = point.plotY;
|
13329
13365
|
graphic = point.graphic;
|
13330
13366
|
pointMarkerOptions = point.marker || {};
|
13331
|
-
enabled = (
|
13367
|
+
enabled = (globallyEnabled && pointMarkerOptions.enabled === UNDEFINED) || pointMarkerOptions.enabled;
|
13332
13368
|
isInside = chart.isInsidePlot(mathRound(plotX), plotY, chart.inverted); // #1858
|
13333
13369
|
|
13334
13370
|
// only draw the point if y is defined
|
@@ -13341,10 +13377,7 @@ Series.prototype = {
|
|
13341
13377
|
isImage = symbol.indexOf('url') === 0;
|
13342
13378
|
|
13343
13379
|
if (graphic) { // update
|
13344
|
-
graphic
|
13345
|
-
.attr({ // Since the marker group isn't clipped, each individual marker must be toggled
|
13346
|
-
visibility: isInside ? 'inherit' : HIDDEN
|
13347
|
-
})
|
13380
|
+
graphic[isInside ? 'show' : 'hide'](true) // Since the marker group isn't clipped, each individual marker must be toggled
|
13348
13381
|
.animate(extend({
|
13349
13382
|
x: plotX - radius,
|
13350
13383
|
y: plotY - radius
|
@@ -13900,9 +13933,18 @@ Series.prototype = {
|
|
13900
13933
|
* Get the translation and scale for the plot area of this series
|
13901
13934
|
*/
|
13902
13935
|
getPlotBox: function () {
|
13936
|
+
var chart = this.chart,
|
13937
|
+
xAxis = this.xAxis,
|
13938
|
+
yAxis = this.yAxis;
|
13939
|
+
|
13940
|
+
// Swap axes for inverted (#2339)
|
13941
|
+
if (chart.inverted) {
|
13942
|
+
xAxis = yAxis;
|
13943
|
+
yAxis = this.xAxis;
|
13944
|
+
}
|
13903
13945
|
return {
|
13904
|
-
translateX:
|
13905
|
-
translateY:
|
13946
|
+
translateX: xAxis ? xAxis.left : chart.plotLeft,
|
13947
|
+
translateY: yAxis ? yAxis.top : chart.plotTop,
|
13906
13948
|
scaleX: 1, // #1623
|
13907
13949
|
scaleY: 1
|
13908
13950
|
};
|
@@ -13917,9 +13959,9 @@ Series.prototype = {
|
|
13917
13959
|
group,
|
13918
13960
|
options = series.options,
|
13919
13961
|
animation = options.animation,
|
13920
|
-
|
13921
|
-
|
13922
|
-
|
13962
|
+
// Animation doesn't work in IE8 quirks when the group div is hidden,
|
13963
|
+
// and looks bad in other oldIE
|
13964
|
+
animDuration = (animation && !!series.animate && chart.renderer.isSVG && pick(animation.duration, 500)) || 0,
|
13923
13965
|
visibility = series.visible ? VISIBLE : HIDDEN,
|
13924
13966
|
zIndex = options.zIndex,
|
13925
13967
|
hasRendered = series.hasRendered,
|
@@ -13943,7 +13985,7 @@ Series.prototype = {
|
|
13943
13985
|
);
|
13944
13986
|
|
13945
13987
|
// initiate the animation
|
13946
|
-
if (
|
13988
|
+
if (animDuration) {
|
13947
13989
|
series.animate(true);
|
13948
13990
|
}
|
13949
13991
|
|
@@ -13986,10 +14028,20 @@ Series.prototype = {
|
|
13986
14028
|
}
|
13987
14029
|
|
13988
14030
|
// Run the animation
|
13989
|
-
if (
|
14031
|
+
if (animDuration) {
|
13990
14032
|
series.animate();
|
13991
|
-
}
|
13992
|
-
|
14033
|
+
}
|
14034
|
+
|
14035
|
+
// Call the afterAnimate function on animation complete (but don't overwrite the animation.complete option
|
14036
|
+
// which should be available to the user).
|
14037
|
+
if (!hasRendered) {
|
14038
|
+
if (animDuration) {
|
14039
|
+
series.animationTimeout = setTimeout(function () {
|
14040
|
+
series.afterAnimate();
|
14041
|
+
}, animDuration);
|
14042
|
+
} else {
|
14043
|
+
series.afterAnimate();
|
14044
|
+
}
|
13993
14045
|
}
|
13994
14046
|
|
13995
14047
|
series.isDirty = series.isDirtyData = false; // means data is in accordance with what you see
|
@@ -14024,7 +14076,9 @@ Series.prototype = {
|
|
14024
14076
|
}
|
14025
14077
|
|
14026
14078
|
series.translate();
|
14027
|
-
series.setTooltipPoints
|
14079
|
+
if (series.setTooltipPoints) {
|
14080
|
+
series.setTooltipPoints(true);
|
14081
|
+
}
|
14028
14082
|
series.render();
|
14029
14083
|
|
14030
14084
|
if (wasDirtyData) {
|
@@ -14036,7 +14090,7 @@ Series.prototype = {
|
|
14036
14090
|
/**
|
14037
14091
|
* The class for stack items
|
14038
14092
|
*/
|
14039
|
-
function StackItem(axis, options, isNegative, x, stackOption
|
14093
|
+
function StackItem(axis, options, isNegative, x, stackOption) {
|
14040
14094
|
|
14041
14095
|
var inverted = axis.chart.inverted;
|
14042
14096
|
|
@@ -14054,12 +14108,11 @@ function StackItem(axis, options, isNegative, x, stackOption, stacking) {
|
|
14054
14108
|
// Initialize total value
|
14055
14109
|
this.total = null;
|
14056
14110
|
|
14057
|
-
// This will keep each points' extremes stored by series.index
|
14111
|
+
// This will keep each points' extremes stored by series.index and point index
|
14058
14112
|
this.points = {};
|
14059
14113
|
|
14060
14114
|
// Save the stack option on the series configuration object, and whether to treat it as percent
|
14061
14115
|
this.stack = stackOption;
|
14062
|
-
this.percent = stacking === 'percent';
|
14063
14116
|
|
14064
14117
|
// The align options and text align varies on whether the stack is negative and
|
14065
14118
|
// if the chart is inverted or not.
|
@@ -14095,7 +14148,7 @@ StackItem.prototype = {
|
|
14095
14148
|
// Create new label
|
14096
14149
|
} else {
|
14097
14150
|
this.label =
|
14098
|
-
this.axis.chart.renderer.text(str,
|
14151
|
+
this.axis.chart.renderer.text(str, null, null, options.useHTML) // dummy positions, actual position updated with setOffset method in columnseries
|
14099
14152
|
.css(options.style) // apply style
|
14100
14153
|
.attr({
|
14101
14154
|
align: this.textAlign, // fix the text-anchor
|
@@ -14115,7 +14168,7 @@ StackItem.prototype = {
|
|
14115
14168
|
chart = axis.chart,
|
14116
14169
|
inverted = chart.inverted,
|
14117
14170
|
neg = this.isNegative, // special treatment is needed for negative stacks
|
14118
|
-
y = axis.translate(
|
14171
|
+
y = axis.translate(axis.usePercentage ? 100 : this.total, 0, 0, 0, 1), // stack value translated mapped to chart coordinates
|
14119
14172
|
yZero = axis.translate(0), // stack origin
|
14120
14173
|
h = mathAbs(y - yZero), // stack height
|
14121
14174
|
x = chart.xAxis[0].translate(this.x) + xOffset, // stack x position
|
@@ -14227,6 +14280,7 @@ Series.prototype.setStackedPoints = function () {
|
|
14227
14280
|
stack,
|
14228
14281
|
other,
|
14229
14282
|
key,
|
14283
|
+
pointKey,
|
14230
14284
|
i,
|
14231
14285
|
x,
|
14232
14286
|
y;
|
@@ -14235,6 +14289,7 @@ Series.prototype.setStackedPoints = function () {
|
|
14235
14289
|
for (i = 0; i < yDataLength; i++) {
|
14236
14290
|
x = xData[i];
|
14237
14291
|
y = yData[i];
|
14292
|
+
pointKey = series.index + ',' + i;
|
14238
14293
|
|
14239
14294
|
// Read stacked values into a stack based on the x value,
|
14240
14295
|
// the sign of y and the stack key. Stacking is also handled for null values (#739)
|
@@ -14252,13 +14307,13 @@ Series.prototype.setStackedPoints = function () {
|
|
14252
14307
|
stacks[key][x] = oldStacks[key][x];
|
14253
14308
|
stacks[key][x].total = null;
|
14254
14309
|
} else {
|
14255
|
-
stacks[key][x] = new StackItem(yAxis, yAxis.options.stackLabels, isNegative, x, stackOption
|
14310
|
+
stacks[key][x] = new StackItem(yAxis, yAxis.options.stackLabels, isNegative, x, stackOption);
|
14256
14311
|
}
|
14257
14312
|
}
|
14258
14313
|
|
14259
14314
|
// If the StackItem doesn't exist, create it first
|
14260
14315
|
stack = stacks[key][x];
|
14261
|
-
stack.points[
|
14316
|
+
stack.points[pointKey] = [stack.cum || 0];
|
14262
14317
|
|
14263
14318
|
// Add value to the stack total
|
14264
14319
|
if (stacking === 'percent') {
|
@@ -14279,7 +14334,7 @@ Series.prototype.setStackedPoints = function () {
|
|
14279
14334
|
|
14280
14335
|
stack.cum = (stack.cum || 0) + (y || 0);
|
14281
14336
|
|
14282
|
-
stack.points[
|
14337
|
+
stack.points[pointKey].push(stack.cum);
|
14283
14338
|
stackedYData[i] = stack.cum;
|
14284
14339
|
|
14285
14340
|
}
|
@@ -14313,7 +14368,7 @@ Series.prototype.setPercentStacks = function () {
|
|
14313
14368
|
while (i--) {
|
14314
14369
|
x = processedXData[i];
|
14315
14370
|
stack = stacks[key] && stacks[key][x];
|
14316
|
-
pointExtremes = stack && stack.points[series.index];
|
14371
|
+
pointExtremes = stack && stack.points[series.index + ',' + i];
|
14317
14372
|
if (pointExtremes) {
|
14318
14373
|
totalFactor = stack.total ? 100 / stack.total : 0;
|
14319
14374
|
pointExtremes[0] = correctFloat(pointExtremes[0] * totalFactor); // Y bottom value
|
@@ -14745,7 +14800,7 @@ extend(Axis.prototype, {
|
|
14745
14800
|
newOptions = chart.options[this.coll][this.options.index] = merge(this.userOptions, newOptions);
|
14746
14801
|
|
14747
14802
|
this.destroy(true);
|
14748
|
-
this._addedPlotLB =
|
14803
|
+
this._addedPlotLB = UNDEFINED; // #1611, #2887
|
14749
14804
|
|
14750
14805
|
this.init(chart, extend(newOptions, { events: UNDEFINED }));
|
14751
14806
|
|
@@ -15160,7 +15215,7 @@ seriesTypes.areaspline = AreaSplineSeries;
|
|
15160
15215
|
*/
|
15161
15216
|
defaultPlotOptions.column = merge(defaultSeriesOptions, {
|
15162
15217
|
borderColor: '#FFFFFF',
|
15163
|
-
borderWidth: 1,
|
15218
|
+
//borderWidth: 1,
|
15164
15219
|
borderRadius: 0,
|
15165
15220
|
//colorByPoint: undefined,
|
15166
15221
|
groupPadding: 0.2,
|
@@ -15174,7 +15229,8 @@ defaultPlotOptions.column = merge(defaultSeriesOptions, {
|
|
15174
15229
|
states: {
|
15175
15230
|
hover: {
|
15176
15231
|
brightness: 0.1,
|
15177
|
-
shadow: false
|
15232
|
+
shadow: false,
|
15233
|
+
halo: false
|
15178
15234
|
},
|
15179
15235
|
select: {
|
15180
15236
|
color: '#C0C0C0',
|
@@ -15188,6 +15244,9 @@ defaultPlotOptions.column = merge(defaultSeriesOptions, {
|
|
15188
15244
|
y: null
|
15189
15245
|
},
|
15190
15246
|
stickyTracking: false,
|
15247
|
+
tooltip: {
|
15248
|
+
distance: 6
|
15249
|
+
},
|
15191
15250
|
threshold: 0
|
15192
15251
|
});
|
15193
15252
|
|
@@ -15198,7 +15257,6 @@ var ColumnSeries = extendClass(Series, {
|
|
15198
15257
|
type: 'column',
|
15199
15258
|
pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
|
15200
15259
|
stroke: 'borderColor',
|
15201
|
-
'stroke-width': 'borderWidth',
|
15202
15260
|
fill: 'color',
|
15203
15261
|
r: 'borderRadius'
|
15204
15262
|
},
|
@@ -15301,7 +15359,10 @@ var ColumnSeries = extendClass(Series, {
|
|
15301
15359
|
var series = this,
|
15302
15360
|
chart = series.chart,
|
15303
15361
|
options = series.options,
|
15304
|
-
borderWidth =
|
15362
|
+
borderWidth = series.borderWidth = pick(
|
15363
|
+
options.borderWidth,
|
15364
|
+
series.activePointCount > 0.5 * series.xAxis.len ? 0 : 1
|
15365
|
+
),
|
15305
15366
|
yAxis = series.yAxis,
|
15306
15367
|
threshold = options.threshold,
|
15307
15368
|
translatedThreshold = series.translatedThreshold = yAxis.getThreshold(threshold),
|
@@ -15347,6 +15408,9 @@ var ColumnSeries = extendClass(Series, {
|
|
15347
15408
|
point.barX = barX;
|
15348
15409
|
point.pointWidth = pointWidth;
|
15349
15410
|
|
15411
|
+
// Fix the tooltip on center of grouped columns (#1216)
|
15412
|
+
point.tooltipPos = chart.inverted ? [yAxis.len - plotY, series.xAxis.len - barX - barW / 2] : [barX + barW / 2, plotY];
|
15413
|
+
|
15350
15414
|
// Round off to obtain crisp edges
|
15351
15415
|
fromLeft = mathAbs(barX) < 0.5;
|
15352
15416
|
right = mathRound(barX + barW) + xCrisp;
|
@@ -15404,7 +15468,9 @@ var ColumnSeries = extendClass(Series, {
|
|
15404
15468
|
options = series.options,
|
15405
15469
|
renderer = chart.renderer,
|
15406
15470
|
animationLimit = options.animationLimit || 250,
|
15407
|
-
shapeArgs
|
15471
|
+
shapeArgs,
|
15472
|
+
pointAttr,
|
15473
|
+
borderAttr;
|
15408
15474
|
|
15409
15475
|
// draw the columns
|
15410
15476
|
each(series.points, function (point) {
|
@@ -15413,14 +15479,18 @@ var ColumnSeries = extendClass(Series, {
|
|
15413
15479
|
|
15414
15480
|
if (plotY !== UNDEFINED && !isNaN(plotY) && point.y !== null) {
|
15415
15481
|
shapeArgs = point.shapeArgs;
|
15416
|
-
|
15482
|
+
borderAttr = defined(series.borderWidth) ? {
|
15483
|
+
'stroke-width': series.borderWidth
|
15484
|
+
} : {};
|
15485
|
+
pointAttr = point.pointAttr[point.selected ? SELECT_STATE : NORMAL_STATE] || series.pointAttr[NORMAL_STATE];
|
15417
15486
|
if (graphic) { // update
|
15418
15487
|
stop(graphic);
|
15419
|
-
graphic[
|
15488
|
+
graphic.attr(borderAttr)[chart.pointCount < animationLimit ? 'animate' : 'attr'](merge(shapeArgs));
|
15420
15489
|
|
15421
15490
|
} else {
|
15422
15491
|
point.graphic = graphic = renderer[point.shapeType](shapeArgs)
|
15423
|
-
.attr(
|
15492
|
+
.attr(pointAttr)
|
15493
|
+
.attr(borderAttr)
|
15424
15494
|
.add(series.group)
|
15425
15495
|
.shadow(options.shadow, null, options.stacking && !options.borderRadius);
|
15426
15496
|
}
|
@@ -15506,9 +15576,8 @@ seriesTypes.bar = BarSeries;
|
|
15506
15576
|
defaultPlotOptions.scatter = merge(defaultSeriesOptions, {
|
15507
15577
|
lineWidth: 0,
|
15508
15578
|
tooltip: {
|
15509
|
-
headerFormat: '<span style="
|
15510
|
-
pointFormat: 'x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>'
|
15511
|
-
followPointer: true
|
15579
|
+
headerFormat: '<span style="color:{series.color}">\u25CF</span> <span style="font-size: 10px;"> {series.name}</span><br/>', // docs
|
15580
|
+
pointFormat: 'x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>'
|
15512
15581
|
},
|
15513
15582
|
stickyTracking: false
|
15514
15583
|
});
|
@@ -15549,9 +15618,7 @@ defaultPlotOptions.pie = merge(defaultSeriesOptions, {
|
|
15549
15618
|
// connectorPadding: 5,
|
15550
15619
|
distance: 30,
|
15551
15620
|
enabled: true,
|
15552
|
-
|
15553
|
-
return this.point.name;
|
15554
|
-
}
|
15621
|
+
format: '{point.name}'
|
15555
15622
|
// softConnector: true,
|
15556
15623
|
//y: 0
|
15557
15624
|
},
|
@@ -15672,6 +15739,17 @@ var PiePoint = extendClass(Point, {
|
|
15672
15739
|
point.shadowGroup.animate(translation);
|
15673
15740
|
}
|
15674
15741
|
|
15742
|
+
},
|
15743
|
+
|
15744
|
+
haloPath: function (size) {
|
15745
|
+
var shapeArgs = this.shapeArgs,
|
15746
|
+
chart = this.series.chart;
|
15747
|
+
|
15748
|
+
return this.series.chart.renderer.symbols.arc(chart.plotLeft + shapeArgs.x, chart.plotTop + shapeArgs.y, shapeArgs.r + size, shapeArgs.r + size, {
|
15749
|
+
innerR: this.shapeArgs.r,
|
15750
|
+
start: shapeArgs.start,
|
15751
|
+
end: shapeArgs.end
|
15752
|
+
});
|
15675
15753
|
}
|
15676
15754
|
});
|
15677
15755
|
|
@@ -16016,10 +16094,17 @@ Series.prototype.drawDataLabels = function () {
|
|
16016
16094
|
dataLabelsGroup = series.plotGroup(
|
16017
16095
|
'dataLabelsGroup',
|
16018
16096
|
'data-labels',
|
16019
|
-
|
16097
|
+
HIDDEN,
|
16020
16098
|
options.zIndex || 6
|
16021
16099
|
);
|
16022
16100
|
|
16101
|
+
if (!series.hasRendered && pick(options.defer, true)) {
|
16102
|
+
dataLabelsGroup.attr({ opacity: 0 });
|
16103
|
+
addEvent(series, 'afterAnimate', function () {
|
16104
|
+
series.dataLabelsGroup.show()[seriesOptions.animation ? 'animate' : 'attr']({ opacity: 1 }, { duration: 200 });
|
16105
|
+
});
|
16106
|
+
}
|
16107
|
+
|
16023
16108
|
// Make the labels for each point
|
16024
16109
|
generalOptions = options;
|
16025
16110
|
each(points, function (point) {
|
@@ -16534,7 +16619,7 @@ if (seriesTypes.pie) {
|
|
16534
16619
|
visibility: visibility
|
16535
16620
|
//zIndex: 0 // #2722 (reversed)
|
16536
16621
|
})
|
16537
|
-
.add(series.
|
16622
|
+
.add(series.dataLabelsGroup);
|
16538
16623
|
}
|
16539
16624
|
} else if (connector) {
|
16540
16625
|
point.connector = connector.destroy();
|
@@ -16718,26 +16803,26 @@ var TrackerMixin = Highcharts.TrackerMixin = {
|
|
16718
16803
|
// Add reference to the point
|
16719
16804
|
each(series.points, function (point) {
|
16720
16805
|
if (point.graphic) {
|
16721
|
-
|
16806
|
+
point.graphic.element.point = point;
|
16722
16807
|
}
|
16723
16808
|
if (point.dataLabel) {
|
16724
|
-
|
16809
|
+
point.dataLabel.element.point = point;
|
16725
16810
|
}
|
16726
16811
|
});
|
16727
16812
|
|
16728
16813
|
// Add the event listeners, we need to do this only once
|
16729
16814
|
if (!series._hasTracking) {
|
16730
16815
|
each(series.trackerGroups, function (key) {
|
16731
|
-
|
16732
|
-
|
16733
|
-
|
16734
|
-
|
16735
|
-
|
16736
|
-
|
16737
|
-
|
16738
|
-
|
16816
|
+
if (series[key]) { // we don't always have dataLabelsGroup
|
16817
|
+
series[key]
|
16818
|
+
.addClass(PREFIX + 'tracker')
|
16819
|
+
.on('mouseover', onMouseOver)
|
16820
|
+
.on('mouseout', function (e) { pointer.onTrackerMouseOut(e); })
|
16821
|
+
.css(css);
|
16822
|
+
if (hasTouch) {
|
16823
|
+
series[key].on('touchstart', onMouseOver);
|
16824
|
+
}
|
16739
16825
|
}
|
16740
|
-
}
|
16741
16826
|
});
|
16742
16827
|
series._hasTracking = true;
|
16743
16828
|
}
|
@@ -16856,6 +16941,10 @@ if (seriesTypes.scatter) {
|
|
16856
16941
|
ScatterSeries.prototype.drawTracker = TrackerMixin.drawTrackerPoint;
|
16857
16942
|
}
|
16858
16943
|
|
16944
|
+
if (seriesTypes.gauge) {
|
16945
|
+
seriesTypes.gauge.prototype.drawTracker = TrackerMixin.drawTrackerPoint;
|
16946
|
+
}
|
16947
|
+
|
16859
16948
|
/*
|
16860
16949
|
* Extend Legend for item events
|
16861
16950
|
*/
|
@@ -17127,33 +17216,6 @@ extend(Point.prototype, {
|
|
17127
17216
|
}
|
17128
17217
|
},
|
17129
17218
|
|
17130
|
-
/**
|
17131
|
-
* Fire an event on the Point object. Must not be renamed to fireEvent, as this
|
17132
|
-
* causes a name clash in MooTools
|
17133
|
-
* @param {String} eventType
|
17134
|
-
* @param {Object} eventArgs Additional event arguments
|
17135
|
-
* @param {Function} defaultFunction Default event handler
|
17136
|
-
*/
|
17137
|
-
firePointEvent: function (eventType, eventArgs, defaultFunction) {
|
17138
|
-
var point = this,
|
17139
|
-
series = this.series,
|
17140
|
-
seriesOptions = series.options;
|
17141
|
-
|
17142
|
-
// load event handlers on demand to save time on mouseover/out
|
17143
|
-
if (seriesOptions.point.events[eventType] || (point.options && point.options.events && point.options.events[eventType])) {
|
17144
|
-
this.importEvents();
|
17145
|
-
}
|
17146
|
-
|
17147
|
-
// add default handler if in selection mode
|
17148
|
-
if (eventType === 'click' && seriesOptions.allowPointSelect) {
|
17149
|
-
defaultFunction = function (event) {
|
17150
|
-
// Control key is for Windows, meta (= Cmd key) for Mac, Shift for Opera
|
17151
|
-
point.select(null, event.ctrlKey || event.metaKey || event.shiftKey);
|
17152
|
-
};
|
17153
|
-
}
|
17154
|
-
|
17155
|
-
fireEvent(this, eventType, eventArgs, defaultFunction);
|
17156
|
-
},
|
17157
17219
|
/**
|
17158
17220
|
* Import events from the series' and point's options. Only do it on
|
17159
17221
|
* demand, to save processing time on hovering.
|
@@ -17193,11 +17255,13 @@ extend(Point.prototype, {
|
|
17193
17255
|
pointMarker = point.marker || {},
|
17194
17256
|
chart = series.chart,
|
17195
17257
|
radius,
|
17258
|
+
halo = series.halo,
|
17259
|
+
haloOptions,
|
17196
17260
|
newSymbol,
|
17197
|
-
pointAttr
|
17261
|
+
pointAttr;
|
17198
17262
|
|
17199
17263
|
state = state || NORMAL_STATE; // empty string
|
17200
|
-
|
17264
|
+
pointAttr = point.pointAttr[state] || series.pointAttr[state];
|
17201
17265
|
|
17202
17266
|
if (
|
17203
17267
|
// already has this state
|
@@ -17207,7 +17271,7 @@ extend(Point.prototype, {
|
|
17207
17271
|
// series' state options is disabled
|
17208
17272
|
(stateOptions[state] && stateOptions[state].enabled === false) ||
|
17209
17273
|
// general point marker's state options is disabled
|
17210
|
-
(state && (stateDisabled || (normalDisabled &&
|
17274
|
+
(state && (stateDisabled || (normalDisabled && markerStateOptions.enabled === false))) ||
|
17211
17275
|
// individual point marker's state options is disabled
|
17212
17276
|
(state && pointMarker.states && pointMarker.states[state] && pointMarker.states[state].enabled === false) // #1610
|
17213
17277
|
|
@@ -17215,12 +17279,11 @@ extend(Point.prototype, {
|
|
17215
17279
|
return;
|
17216
17280
|
}
|
17217
17281
|
|
17218
|
-
|
17219
17282
|
// apply hover styles to the existing point
|
17220
17283
|
if (point.graphic) {
|
17221
|
-
radius = markerOptions && point.graphic.symbolName && pointAttr
|
17284
|
+
radius = markerOptions && point.graphic.symbolName && pointAttr.r;
|
17222
17285
|
point.graphic.attr(merge(
|
17223
|
-
pointAttr
|
17286
|
+
pointAttr,
|
17224
17287
|
radius ? { // new symbol attributes (#507, #612)
|
17225
17288
|
x: plotX - radius,
|
17226
17289
|
y: plotY - radius,
|
@@ -17228,6 +17291,11 @@ extend(Point.prototype, {
|
|
17228
17291
|
height: 2 * radius
|
17229
17292
|
} : {}
|
17230
17293
|
));
|
17294
|
+
|
17295
|
+
// Zooming in from a range with no markers to a range with markers
|
17296
|
+
if (stateMarkerGraphic) {
|
17297
|
+
stateMarkerGraphic.hide();
|
17298
|
+
}
|
17231
17299
|
} else {
|
17232
17300
|
// if a graphic is not applied to each point in the normal state, create a shared
|
17233
17301
|
// graphic for the hover state
|
@@ -17243,16 +17311,18 @@ extend(Point.prototype, {
|
|
17243
17311
|
|
17244
17312
|
// Add a new state marker graphic
|
17245
17313
|
if (!stateMarkerGraphic) {
|
17246
|
-
|
17247
|
-
|
17248
|
-
|
17249
|
-
|
17250
|
-
|
17251
|
-
|
17252
|
-
|
17253
|
-
|
17254
|
-
|
17255
|
-
|
17314
|
+
if (newSymbol) {
|
17315
|
+
series.stateMarkerGraphic = stateMarkerGraphic = chart.renderer.symbol(
|
17316
|
+
newSymbol,
|
17317
|
+
plotX - radius,
|
17318
|
+
plotY - radius,
|
17319
|
+
2 * radius,
|
17320
|
+
2 * radius
|
17321
|
+
)
|
17322
|
+
.attr(pointAttr)
|
17323
|
+
.add(series.markerGroup);
|
17324
|
+
stateMarkerGraphic.currentSymbol = newSymbol;
|
17325
|
+
}
|
17256
17326
|
|
17257
17327
|
// Move the existing graphic
|
17258
17328
|
} else {
|
@@ -17268,7 +17338,32 @@ extend(Point.prototype, {
|
|
17268
17338
|
}
|
17269
17339
|
}
|
17270
17340
|
|
17341
|
+
// Show me your halo
|
17342
|
+
haloOptions = stateOptions[state] && stateOptions[state].halo;
|
17343
|
+
if (haloOptions && haloOptions.size) {
|
17344
|
+
if (!halo) {
|
17345
|
+
series.halo = halo = chart.renderer.path()
|
17346
|
+
.add(series.seriesGroup);
|
17347
|
+
}
|
17348
|
+
halo.attr(extend({
|
17349
|
+
fill: Color(point.color || series.color).setOpacity(haloOptions.opacity).get()
|
17350
|
+
}, haloOptions.attributes))[move ? 'animate' : 'attr']({
|
17351
|
+
d: point.haloPath(haloOptions.size)
|
17352
|
+
});
|
17353
|
+
} else if (halo) {
|
17354
|
+
halo.attr({ d: [] });
|
17355
|
+
}
|
17356
|
+
|
17271
17357
|
point.state = state;
|
17358
|
+
},
|
17359
|
+
haloPath: function (size) {
|
17360
|
+
var chart = this.series.chart;
|
17361
|
+
return chart.renderer.symbols.circle(
|
17362
|
+
chart.plotLeft + this.plotX - size,
|
17363
|
+
chart.plotTop + this.plotY - size,
|
17364
|
+
size * 2,
|
17365
|
+
size * 2
|
17366
|
+
);
|
17272
17367
|
}
|
17273
17368
|
});
|
17274
17369
|
|