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