highcharts-rails 4.0.4 → 4.0.4.1
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 +18 -0
- data.tar.gz.asc +18 -0
- data/CHANGELOG.markdown +4 -0
- data/README.markdown +1 -1
- data/app/assets/javascripts/highcharts/modules/map.js +1872 -1411
- data/lib/highcharts/version.rb +1 -1
- metadata +12 -12
- metadata.gz.asc +18 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3644773cb5374bcf7a9164ed6463d6d6e636e7c4
|
|
4
|
+
data.tar.gz: b9094ef3a1009bad92aceffa198bd63c01b56ddb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d378850d7953c9f74e06bfed2f060f85303326267cc5e55a8f6476b74c772c0b4703e99a289976d67c90307cec90b44d627092ae609045466ffd0905a0a46b5d
|
|
7
|
+
data.tar.gz: 98a59a0861fefd2b25312e3061182200348cd1eae4bd18d6c7354522d2b67d1d1aefbff3d1a7189b32f103f45b70990763fa1e019c0cf402ed75f3eaf3d487e4
|
checksums.yaml.gz.asc
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-----BEGIN PGP SIGNATURE-----
|
|
2
|
+
Version: GnuPG/MacGPG2 v2.0.22 (Darwin)
|
|
3
|
+
Comment: GPGTools - http://gpgtools.org
|
|
4
|
+
|
|
5
|
+
iQIcBAABAgAGBQJUa2yWAAoJEH1ncb0Txu7Xn/QP/3Qz092gifbewAAbI0aCLdx2
|
|
6
|
+
fZ+w0wDfQfpB9MNusZ3sc9sFxZ1GVb/q8MIpoxjdDgHB50ZlCCs6/DdV2o7EkgW7
|
|
7
|
+
zc+Cy099rso5FXwlCz7S2Y4aD3LvHwoj7jHEMe1M+1aQv78tJebYqAHTm02QurI+
|
|
8
|
+
HMw0hXp1//uJwb6BzH6BvVYzv2M9uChmlxcfS9lvNFT3z+YTYeRX5uJAfS4Cn3oA
|
|
9
|
+
OqeAzUBSHivcKxeqRQFIBa3nFQWyHmYwHkROJcy/XEQcjDvIVDT7BUsXAwIUJ5A5
|
|
10
|
+
1MoAttjaEfyUjiIwe/yrKyaTBoawgsMxBr+8+mfw+fMuHQC51LUpXCAr5lciVeJS
|
|
11
|
+
vf6C/IWSEaBt0oiOJSfnK68jySAlECwE0KvgkfWsMJ+TSSQyaHqPoiv32BqZg8qU
|
|
12
|
+
HrrDgKn3Gl8Hc2jI0sZduds+MoZIWcl4iGl0teitkVJrk0ySEvxbJZ1Oe+j6AHmR
|
|
13
|
+
Gsj4mI7JgxCDlzYVydMengYl1OpjFuHAn4ZxQEyatEhRbkCLCclWkSsZLo4Cu9Zp
|
|
14
|
+
FWX+tnyO5XvqGn4CcDy3+QDG816hDpEYzbJE8EPQqlbAOaAJkeJoEXgCMgivbQcq
|
|
15
|
+
GHNOn9ZjgH45wOIkq3r0WkSUuRjhwgbbg5WLCZK5CP0PHFUflXvPbJIU6wqrA06t
|
|
16
|
+
EcSRzTBVW9L/3UbGt3e6
|
|
17
|
+
=+6PL
|
|
18
|
+
-----END PGP SIGNATURE-----
|
data.tar.gz.asc
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-----BEGIN PGP SIGNATURE-----
|
|
2
|
+
Version: GnuPG/MacGPG2 v2.0.22 (Darwin)
|
|
3
|
+
Comment: GPGTools - http://gpgtools.org
|
|
4
|
+
|
|
5
|
+
iQIcBAABAgAGBQJUa2yWAAoJEH1ncb0Txu7XtPEP/jP5/3oJJtC+xZfnrt5mMvvL
|
|
6
|
+
20Pfz/OkZlr3SXFYb4RYuMMNyHBLNynOkejFy61Wynx8WYpAhqXPUWp0gSmTXAsd
|
|
7
|
+
UEi2N+u/4XQYBN+CqxnfVoaB6k/SOaMtwOgnN+IIeDfc1cEzMR5t+ZSEFo7Wiac4
|
|
8
|
+
AyKuCdk/WD1coZR4/3xdrpG59D9jIl1Qcee99eptpn/Qm8+Qkb0WP5lOQ92j+TwE
|
|
9
|
+
31UMJhx6pCS09i5jLw2tv+mEafBxYGO/qbRgAcjvLpP/PKAdYqfTWSVi/gMdrC0z
|
|
10
|
+
DM9hUeIZyAnXrW+I5DrTF+GbGHs3kwwhhuKDKgOZ9CQWgNvUILQwSd9f6kYzZ2aK
|
|
11
|
+
aeVTNbCkImPLiIdqe0m/ynkgL6EZvof5RFKMNTlRyyNcgCNuWX0EC2kBCJ3FVY3Y
|
|
12
|
+
akUSIaxQF0krRe49P6qRy21FLiKiMb0l25UxvPFPyKpVyZ0jAWVaV9ESFzqFQKek
|
|
13
|
+
cqaJqPQ+6WuDFEMCskmZF8ZLvyBbhNx+v1RrXw/0zjTQSNZi22VDONe908LJ2T1k
|
|
14
|
+
jJmCMCuU0MTCl9DixCOo2On2rajClMyAG/lcVAIh9/pJAyw+iKdWB96jlRK9M3xt
|
|
15
|
+
l4p/hCNfj9nXnqhVg6XVbPPS6W4p4OoJSjs0eV7f8e6zpzrJqNBEd6ikX3k6Nit4
|
|
16
|
+
ZKIM3coZuzUTppFMnURu
|
|
17
|
+
=7VNA
|
|
18
|
+
-----END PGP SIGNATURE-----
|
data/CHANGELOG.markdown
CHANGED
data/README.markdown
CHANGED
|
@@ -50,7 +50,7 @@ Or one of the themes
|
|
|
50
50
|
//= require highcharts/themes/grid
|
|
51
51
|
//= require highcharts/themes/skies
|
|
52
52
|
|
|
53
|
-
Other than that, refer to the [Highcharts documentation](http://
|
|
53
|
+
Other than that, refer to the [Highcharts documentation](http://www.highcharts.com/docs)
|
|
54
54
|
|
|
55
55
|
## Licensing
|
|
56
56
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license
|
|
2
|
+
* @license Highmaps JS v1.0.4 (2014-09-02)
|
|
3
|
+
* Highmaps as a plugin for Highcharts 4.0.1 or Highstock 2.0.1
|
|
3
4
|
*
|
|
4
5
|
* (c) 2011-2014 Torstein Honsi
|
|
5
6
|
*
|
|
@@ -7,617 +8,490 @@
|
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
/*global HighchartsAdapter*/
|
|
10
|
-
(function (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
extendClass = H.extendClass,
|
|
26
|
-
merge = H.merge,
|
|
27
|
-
pick = H.pick,
|
|
28
|
-
numberFormat = H.numberFormat,
|
|
29
|
-
defaultOptions = H.getOptions(),
|
|
30
|
-
seriesTypes = H.seriesTypes,
|
|
31
|
-
plotOptions = defaultOptions.plotOptions,
|
|
32
|
-
wrap = H.wrap,
|
|
33
|
-
noop = function () {};
|
|
34
|
-
|
|
35
|
-
// Add language
|
|
36
|
-
extend(defaultOptions.lang, {
|
|
37
|
-
zoomIn: 'Zoom in',
|
|
38
|
-
zoomOut: 'Zoom out'
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
/*
|
|
42
|
-
* Return an intermediate color between two colors, according to pos where 0
|
|
43
|
-
* is the from color and 1 is the to color
|
|
44
|
-
*/
|
|
45
|
-
function tweenColors(from, to, pos) {
|
|
46
|
-
var i = 4,
|
|
47
|
-
val,
|
|
48
|
-
rgba = [];
|
|
49
|
-
|
|
50
|
-
while (i--) {
|
|
51
|
-
val = to.rgba[i] + (from.rgba[i] - to.rgba[i]) * (1 - pos);
|
|
52
|
-
rgba[i] = i === 3 ? val : Math.round(val); // Do not round opacity
|
|
53
|
-
}
|
|
54
|
-
return 'rgba(' + rgba.join(',') + ')';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Set the default map navigation options
|
|
58
|
-
defaultOptions.mapNavigation = {
|
|
59
|
-
buttonOptions: {
|
|
60
|
-
alignTo: 'plotBox',
|
|
61
|
-
align: 'left',
|
|
62
|
-
verticalAlign: 'top',
|
|
63
|
-
x: 0,
|
|
64
|
-
width: 18,
|
|
65
|
-
height: 18,
|
|
66
|
-
style: {
|
|
67
|
-
fontSize: '15px',
|
|
68
|
-
fontWeight: 'bold',
|
|
69
|
-
textAlign: 'center'
|
|
70
|
-
},
|
|
71
|
-
theme: {
|
|
72
|
-
'stroke-width': 1
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
buttons: {
|
|
76
|
-
zoomIn: {
|
|
77
|
-
onclick: function () {
|
|
78
|
-
this.mapZoom(0.5);
|
|
79
|
-
},
|
|
80
|
-
text: '+',
|
|
81
|
-
y: 0
|
|
82
|
-
},
|
|
83
|
-
zoomOut: {
|
|
84
|
-
onclick: function () {
|
|
85
|
-
this.mapZoom(2);
|
|
86
|
-
},
|
|
87
|
-
text: '-',
|
|
88
|
-
y: 28
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
// enabled: false,
|
|
92
|
-
// enableButtons: null, // inherit from enabled
|
|
93
|
-
// enableTouchZoom: null, // inherit from enabled
|
|
94
|
-
// enableDoubleClickZoom: null, // inherit from enabled
|
|
95
|
-
// enableDoubleClickZoomTo: false
|
|
96
|
-
// enableMouseWheelZoom: null, // inherit from enabled
|
|
97
|
-
};
|
|
11
|
+
(function (Highcharts) {
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
var UNDEFINED,
|
|
15
|
+
Axis = Highcharts.Axis,
|
|
16
|
+
Chart = Highcharts.Chart,
|
|
17
|
+
Color = Highcharts.Color,
|
|
18
|
+
Point = Highcharts.Point,
|
|
19
|
+
Pointer = Highcharts.Pointer,
|
|
20
|
+
Legend = Highcharts.Legend,
|
|
21
|
+
LegendSymbolMixin = Highcharts.LegendSymbolMixin,
|
|
22
|
+
Renderer = Highcharts.Renderer,
|
|
23
|
+
Series = Highcharts.Series,
|
|
24
|
+
SVGRenderer = Highcharts.SVGRenderer,
|
|
25
|
+
VMLRenderer = Highcharts.VMLRenderer,
|
|
98
26
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
path = path.split(/[ ,]+/);
|
|
112
|
-
|
|
113
|
-
// Parse numbers
|
|
114
|
-
for (i = 0; i < path.length; i++) {
|
|
115
|
-
if (!/[a-zA-Z]/.test(path[i])) {
|
|
116
|
-
path[i] = parseFloat(path[i]);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return path;
|
|
120
|
-
};
|
|
27
|
+
addEvent = Highcharts.addEvent,
|
|
28
|
+
each = Highcharts.each,
|
|
29
|
+
extend = Highcharts.extend,
|
|
30
|
+
extendClass = Highcharts.extendClass,
|
|
31
|
+
merge = Highcharts.merge,
|
|
32
|
+
pick = Highcharts.pick,
|
|
33
|
+
numberFormat = Highcharts.numberFormat,
|
|
34
|
+
defaultOptions = Highcharts.getOptions(),
|
|
35
|
+
seriesTypes = Highcharts.seriesTypes,
|
|
36
|
+
defaultPlotOptions = defaultOptions.plotOptions,
|
|
37
|
+
wrap = Highcharts.wrap,
|
|
38
|
+
noop = function () {};
|
|
121
39
|
|
|
122
|
-
// A placeholder for map definitions
|
|
123
|
-
H.maps = {};
|
|
124
|
-
|
|
125
40
|
/**
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
}
|
|
41
|
+
* Override to use the extreme coordinates from the SVG shape, not the
|
|
42
|
+
* data values
|
|
43
|
+
*/
|
|
44
|
+
wrap(Axis.prototype, 'getSeriesExtremes', function (proceed) {
|
|
45
|
+
var isXAxis = this.isXAxis,
|
|
46
|
+
dataMin,
|
|
47
|
+
dataMax,
|
|
48
|
+
xData = [],
|
|
49
|
+
useMapGeometry;
|
|
50
|
+
|
|
51
|
+
// Remove the xData array and cache it locally so that the proceed method doesn't use it
|
|
52
|
+
if (isXAxis) {
|
|
53
|
+
each(this.series, function (series, i) {
|
|
54
|
+
if (series.useMapGeometry) {
|
|
55
|
+
xData[i] = series.xData;
|
|
56
|
+
series.xData = [];
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
144
60
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
61
|
+
// Call base to reach normal cartesian series (like mappoint)
|
|
62
|
+
proceed.call(this);
|
|
63
|
+
|
|
64
|
+
// Run extremes logic for map and mapline
|
|
65
|
+
if (isXAxis) {
|
|
66
|
+
dataMin = pick(this.dataMin, Number.MAX_VALUE);
|
|
67
|
+
dataMax = pick(this.dataMax, Number.MIN_VALUE);
|
|
68
|
+
each(this.series, function (series, i) {
|
|
69
|
+
if (series.useMapGeometry) {
|
|
70
|
+
dataMin = Math.min(dataMin, pick(series.minX, dataMin));
|
|
71
|
+
dataMax = Math.max(dataMax, pick(series.maxX, dataMin));
|
|
72
|
+
series.xData = xData[i]; // Reset xData array
|
|
73
|
+
useMapGeometry = true;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
if (useMapGeometry) {
|
|
160
77
|
this.dataMin = dataMin;
|
|
161
78
|
this.dataMax = dataMax;
|
|
162
79
|
}
|
|
163
|
-
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
164
82
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Override axis translation to make sure the aspect ratio is always kept
|
|
85
|
+
*/
|
|
86
|
+
wrap(Axis.prototype, 'setAxisTranslation', function (proceed) {
|
|
87
|
+
var chart = this.chart,
|
|
88
|
+
mapRatio,
|
|
89
|
+
plotRatio = chart.plotWidth / chart.plotHeight,
|
|
90
|
+
adjustedAxisLength,
|
|
91
|
+
xAxis = chart.xAxis[0],
|
|
92
|
+
padAxis,
|
|
93
|
+
fixTo,
|
|
94
|
+
fixDiff;
|
|
177
95
|
|
|
96
|
+
|
|
97
|
+
// Run the parent method
|
|
98
|
+
proceed.call(this);
|
|
99
|
+
|
|
100
|
+
// On Y axis, handle both
|
|
101
|
+
if (chart.options.chart.preserveAspectRatio && this.coll === 'yAxis' && xAxis.transA !== UNDEFINED) {
|
|
178
102
|
|
|
179
|
-
//
|
|
180
|
-
|
|
103
|
+
// Use the same translation for both axes
|
|
104
|
+
this.transA = xAxis.transA = Math.min(this.transA, xAxis.transA);
|
|
181
105
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
padAxis.minPixelPadding
|
|
197
|
-
|
|
198
|
-
fixTo = padAxis.fixTo;
|
|
199
|
-
if (fixTo) {
|
|
200
|
-
fixDiff = fixTo[1] - padAxis.toValue(fixTo[0], true);
|
|
201
|
-
fixDiff *= padAxis.transA;
|
|
202
|
-
if (Math.abs(fixDiff) > padAxis.minPixelPadding) { // zooming out again, keep within restricted area
|
|
203
|
-
fixDiff = 0;
|
|
204
|
-
}
|
|
205
|
-
padAxis.minPixelPadding -= fixDiff;
|
|
206
|
-
|
|
106
|
+
mapRatio = plotRatio / ((xAxis.max - xAxis.min) / (this.max - this.min));
|
|
107
|
+
|
|
108
|
+
// What axis to pad to put the map in the middle
|
|
109
|
+
padAxis = mapRatio < 1 ? this : xAxis;
|
|
110
|
+
|
|
111
|
+
// Pad it
|
|
112
|
+
adjustedAxisLength = (padAxis.max - padAxis.min) * padAxis.transA;
|
|
113
|
+
padAxis.pixelPadding = padAxis.len - adjustedAxisLength;
|
|
114
|
+
padAxis.minPixelPadding = padAxis.pixelPadding / 2;
|
|
115
|
+
|
|
116
|
+
fixTo = padAxis.fixTo;
|
|
117
|
+
if (fixTo) {
|
|
118
|
+
fixDiff = fixTo[1] - padAxis.toValue(fixTo[0], true);
|
|
119
|
+
fixDiff *= padAxis.transA;
|
|
120
|
+
if (Math.abs(fixDiff) > padAxis.minPixelPadding || (padAxis.min === padAxis.dataMin && padAxis.max === padAxis.dataMax)) { // zooming out again, keep within restricted area
|
|
121
|
+
fixDiff = 0;
|
|
207
122
|
}
|
|
123
|
+
padAxis.minPixelPadding -= fixDiff;
|
|
208
124
|
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Override Axis.render in order to delete the fixTo prop
|
|
213
|
-
*/
|
|
214
|
-
wrap(Axis.prototype, 'render', function (proceed) {
|
|
215
|
-
proceed.call(this);
|
|
216
|
-
this.fixTo = null;
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
// Extend the Pointer
|
|
220
|
-
extend(Pointer.prototype, {
|
|
125
|
+
}
|
|
126
|
+
});
|
|
221
127
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Override Axis.render in order to delete the fixTo prop
|
|
130
|
+
*/
|
|
131
|
+
wrap(Axis.prototype, 'render', function (proceed) {
|
|
132
|
+
proceed.call(this);
|
|
133
|
+
this.fixTo = null;
|
|
134
|
+
});
|
|
227
135
|
|
|
228
|
-
e = this.normalize(e);
|
|
229
136
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
137
|
+
/**
|
|
138
|
+
* The ColorAxis object for inclusion in gradient legends
|
|
139
|
+
*/
|
|
140
|
+
var ColorAxis = Highcharts.ColorAxis = function () {
|
|
141
|
+
this.isColorAxis = true;
|
|
142
|
+
this.init.apply(this, arguments);
|
|
143
|
+
};
|
|
144
|
+
extend(ColorAxis.prototype, Axis.prototype);
|
|
145
|
+
extend(ColorAxis.prototype, {
|
|
146
|
+
defaultColorAxisOptions: {
|
|
147
|
+
lineWidth: 0,
|
|
148
|
+
gridLineWidth: 1,
|
|
149
|
+
tickPixelInterval: 72,
|
|
150
|
+
startOnTick: true,
|
|
151
|
+
endOnTick: true,
|
|
152
|
+
offset: 0,
|
|
153
|
+
marker: {
|
|
154
|
+
animation: {
|
|
155
|
+
duration: 50
|
|
156
|
+
},
|
|
157
|
+
color: 'gray',
|
|
158
|
+
width: 0.01
|
|
243
159
|
},
|
|
160
|
+
labels: {
|
|
161
|
+
overflow: 'justify'
|
|
162
|
+
},
|
|
163
|
+
minColor: '#EFEFFF',
|
|
164
|
+
maxColor: '#003875',
|
|
165
|
+
tickLength: 5
|
|
166
|
+
},
|
|
167
|
+
init: function (chart, userOptions) {
|
|
168
|
+
var horiz = chart.options.legend.layout !== 'vertical',
|
|
169
|
+
options;
|
|
170
|
+
|
|
171
|
+
// Build the options
|
|
172
|
+
options = merge(this.defaultColorAxisOptions, {
|
|
173
|
+
side: horiz ? 2 : 1,
|
|
174
|
+
reversed: !horiz
|
|
175
|
+
}, userOptions, {
|
|
176
|
+
isX: horiz,
|
|
177
|
+
opposite: !horiz,
|
|
178
|
+
showEmpty: false,
|
|
179
|
+
title: null,
|
|
180
|
+
isColor: true
|
|
181
|
+
});
|
|
244
182
|
|
|
245
|
-
|
|
246
|
-
* The event handler for the mouse scroll event
|
|
247
|
-
*/
|
|
248
|
-
onContainerMouseWheel: function (e) {
|
|
249
|
-
var chart = this.chart,
|
|
250
|
-
delta;
|
|
251
|
-
|
|
252
|
-
e = this.normalize(e);
|
|
253
|
-
|
|
254
|
-
// Firefox uses e.detail, WebKit and IE uses wheelDelta
|
|
255
|
-
delta = e.detail || -(e.wheelDelta / 120);
|
|
256
|
-
if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
|
|
257
|
-
chart.mapZoom(
|
|
258
|
-
delta > 0 ? 2 : 1 / 2,
|
|
259
|
-
chart.xAxis[0].toValue(e.chartX),
|
|
260
|
-
chart.yAxis[0].toValue(e.chartY),
|
|
261
|
-
delta > 0 ? undefined : e.chartX,
|
|
262
|
-
delta > 0 ? undefined : e.chartY
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
// Implement the pinchType option
|
|
269
|
-
wrap(Pointer.prototype, 'init', function (proceed, chart, options) {
|
|
270
|
-
|
|
271
|
-
proceed.call(this, chart, options);
|
|
183
|
+
Axis.prototype.init.call(this, chart, options);
|
|
272
184
|
|
|
273
|
-
//
|
|
274
|
-
|
|
275
|
-
this.pinchX = this.pinchHor =
|
|
276
|
-
this.pinchY = this.pinchVert = true;
|
|
277
|
-
}
|
|
278
|
-
});
|
|
185
|
+
// Base init() pushes it to the xAxis array, now pop it again
|
|
186
|
+
//chart[this.isXAxis ? 'xAxis' : 'yAxis'].pop();
|
|
279
187
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
proceed.call(this, zoomHor, zoomVert, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
|
|
285
|
-
|
|
286
|
-
// Keep ratio
|
|
287
|
-
if (this.chart.options.chart.type === 'map') {
|
|
288
|
-
xBigger = transform.scaleX > transform.scaleY;
|
|
289
|
-
this.pinchTranslateDirection(
|
|
290
|
-
!xBigger,
|
|
291
|
-
pinchDown,
|
|
292
|
-
touches,
|
|
293
|
-
transform,
|
|
294
|
-
selectionMarker,
|
|
295
|
-
clip,
|
|
296
|
-
lastValidTouch,
|
|
297
|
-
xBigger ? transform.scaleX : transform.scaleY
|
|
298
|
-
);
|
|
188
|
+
// Prepare data classes
|
|
189
|
+
if (userOptions.dataClasses) {
|
|
190
|
+
this.initDataClasses(userOptions);
|
|
299
191
|
}
|
|
300
|
-
|
|
192
|
+
this.initStops(userOptions);
|
|
301
193
|
|
|
194
|
+
// Override original axis properties
|
|
195
|
+
this.isXAxis = true;
|
|
196
|
+
this.horiz = horiz;
|
|
197
|
+
this.zoomEnabled = false;
|
|
198
|
+
},
|
|
302
199
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
* The ColorAxis object for inclusion in gradient legends
|
|
200
|
+
/*
|
|
201
|
+
* Return an intermediate color between two colors, according to pos where 0
|
|
202
|
+
* is the from color and 1 is the to color
|
|
307
203
|
*/
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
options
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}, userOptions, {
|
|
342
|
-
isX: horiz,
|
|
343
|
-
opposite: !horiz,
|
|
344
|
-
showEmpty: false,
|
|
345
|
-
title: null
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
Axis.prototype.init.call(this, chart, options);
|
|
349
|
-
|
|
350
|
-
// Base init() pushes it to the xAxis array, now pop it again
|
|
351
|
-
//chart[this.isXAxis ? 'xAxis' : 'yAxis'].pop();
|
|
352
|
-
|
|
353
|
-
// Prepare data classes
|
|
354
|
-
if (userOptions.dataClasses) {
|
|
355
|
-
this.initDataClasses(userOptions);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// Override original axis properties
|
|
359
|
-
this.isXAxis = true;
|
|
360
|
-
this.horiz = horiz;
|
|
361
|
-
},
|
|
362
|
-
|
|
363
|
-
initDataClasses: function (userOptions) {
|
|
364
|
-
var chart = this.chart,
|
|
365
|
-
dataClasses,
|
|
366
|
-
colorCounter = 0,
|
|
367
|
-
options = this.options;
|
|
368
|
-
this.dataClasses = dataClasses = [];
|
|
369
|
-
|
|
370
|
-
each(userOptions.dataClasses, function (dataClass, i) {
|
|
371
|
-
var colors;
|
|
372
|
-
|
|
373
|
-
dataClass = merge(dataClass);
|
|
374
|
-
dataClasses.push(dataClass);
|
|
375
|
-
if (!dataClass.color) {
|
|
376
|
-
if (options.dataClassColor === 'category') {
|
|
377
|
-
colors = chart.options.colors;
|
|
378
|
-
dataClass.color = colors[colorCounter++];
|
|
379
|
-
// loop back to zero
|
|
380
|
-
if (colorCounter === colors.length) {
|
|
381
|
-
colorCounter = 0;
|
|
382
|
-
}
|
|
383
|
-
} else {
|
|
384
|
-
dataClass.color = tweenColors(Color(options.minColor), Color(options.maxColor), i / (userOptions.dataClasses.length - 1));
|
|
204
|
+
tweenColors: function (from, to, pos) {
|
|
205
|
+
// Check for has alpha, because rgba colors perform worse due to lack of
|
|
206
|
+
// support in WebKit.
|
|
207
|
+
var hasAlpha = (to.rgba[3] !== 1 || from.rgba[3] !== 1);
|
|
208
|
+
return (hasAlpha ? 'rgba(' : 'rgb(') +
|
|
209
|
+
Math.round(to.rgba[0] + (from.rgba[0] - to.rgba[0]) * (1 - pos)) + ',' +
|
|
210
|
+
Math.round(to.rgba[1] + (from.rgba[1] - to.rgba[1]) * (1 - pos)) + ',' +
|
|
211
|
+
Math.round(to.rgba[2] + (from.rgba[2] - to.rgba[2]) * (1 - pos)) +
|
|
212
|
+
(hasAlpha ? (',' + (to.rgba[3] + (from.rgba[3] - to.rgba[3]) * (1 - pos))) : '') + ')';
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
initDataClasses: function (userOptions) {
|
|
216
|
+
var axis = this,
|
|
217
|
+
chart = this.chart,
|
|
218
|
+
dataClasses,
|
|
219
|
+
colorCounter = 0,
|
|
220
|
+
options = this.options,
|
|
221
|
+
len = userOptions.dataClasses.length;
|
|
222
|
+
this.dataClasses = dataClasses = [];
|
|
223
|
+
this.legendItems = [];
|
|
224
|
+
|
|
225
|
+
each(userOptions.dataClasses, function (dataClass, i) {
|
|
226
|
+
var colors;
|
|
227
|
+
|
|
228
|
+
dataClass = merge(dataClass);
|
|
229
|
+
dataClasses.push(dataClass);
|
|
230
|
+
if (!dataClass.color) {
|
|
231
|
+
if (options.dataClassColor === 'category') {
|
|
232
|
+
colors = chart.options.colors;
|
|
233
|
+
dataClass.color = colors[colorCounter++];
|
|
234
|
+
// loop back to zero
|
|
235
|
+
if (colorCounter === colors.length) {
|
|
236
|
+
colorCounter = 0;
|
|
385
237
|
}
|
|
238
|
+
} else {
|
|
239
|
+
dataClass.color = axis.tweenColors(
|
|
240
|
+
Color(options.minColor),
|
|
241
|
+
Color(options.maxColor),
|
|
242
|
+
len < 2 ? 0.5 : i / (len - 1) // #3219
|
|
243
|
+
);
|
|
386
244
|
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
[0, this.options.minColor],
|
|
401
|
-
[1, this.options.maxColor]
|
|
402
|
-
];
|
|
403
|
-
each(this.stops, function (stop) {
|
|
404
|
-
stop.color = Color(stop[1]);
|
|
405
|
-
});
|
|
406
|
-
this.coll = 'colorAxis';
|
|
407
|
-
},
|
|
408
|
-
|
|
409
|
-
setAxisSize: function () {
|
|
410
|
-
var symbol = this.legendSymbol,
|
|
411
|
-
chart = this.chart;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
initStops: function (userOptions) {
|
|
250
|
+
this.stops = userOptions.stops || [
|
|
251
|
+
[0, this.options.minColor],
|
|
252
|
+
[1, this.options.maxColor]
|
|
253
|
+
];
|
|
254
|
+
each(this.stops, function (stop) {
|
|
255
|
+
stop.color = Color(stop[1]);
|
|
256
|
+
});
|
|
257
|
+
},
|
|
412
258
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
259
|
+
/**
|
|
260
|
+
* Extend the setOptions method to process extreme colors and color
|
|
261
|
+
* stops.
|
|
262
|
+
*/
|
|
263
|
+
setOptions: function (userOptions) {
|
|
264
|
+
Axis.prototype.setOptions.call(this, userOptions);
|
|
265
|
+
|
|
266
|
+
this.options.crosshair = this.options.marker;
|
|
267
|
+
this.coll = 'colorAxis';
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
setAxisSize: function () {
|
|
271
|
+
var symbol = this.legendSymbol,
|
|
272
|
+
chart = this.chart,
|
|
273
|
+
x,
|
|
274
|
+
y,
|
|
275
|
+
width,
|
|
276
|
+
height;
|
|
277
|
+
|
|
278
|
+
if (symbol) {
|
|
279
|
+
this.left = x = symbol.attr('x');
|
|
280
|
+
this.top = y = symbol.attr('y');
|
|
281
|
+
this.width = width = symbol.attr('width');
|
|
282
|
+
this.height = height = symbol.attr('height');
|
|
283
|
+
this.right = chart.chartWidth - x - width;
|
|
284
|
+
this.bottom = chart.chartHeight - y - height;
|
|
285
|
+
|
|
286
|
+
this.len = this.horiz ? width : height;
|
|
287
|
+
this.pos = this.horiz ? x : y;
|
|
288
|
+
}
|
|
289
|
+
},
|
|
420
290
|
|
|
421
|
-
|
|
422
|
-
|
|
291
|
+
/**
|
|
292
|
+
* Translate from a value to a color
|
|
293
|
+
*/
|
|
294
|
+
toColor: function (value, point) {
|
|
295
|
+
var pos,
|
|
296
|
+
stops = this.stops,
|
|
297
|
+
from,
|
|
298
|
+
to,
|
|
299
|
+
color,
|
|
300
|
+
dataClasses = this.dataClasses,
|
|
301
|
+
dataClass,
|
|
302
|
+
i;
|
|
303
|
+
|
|
304
|
+
if (dataClasses) {
|
|
305
|
+
i = dataClasses.length;
|
|
306
|
+
while (i--) {
|
|
307
|
+
dataClass = dataClasses[i];
|
|
308
|
+
from = dataClass.from;
|
|
309
|
+
to = dataClass.to;
|
|
310
|
+
if ((from === UNDEFINED || value >= from) && (to === UNDEFINED || value <= to)) {
|
|
311
|
+
color = dataClass.color;
|
|
312
|
+
if (point) {
|
|
313
|
+
point.dataClass = i;
|
|
314
|
+
}
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
423
317
|
}
|
|
424
|
-
},
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* Translate from a value to a color
|
|
428
|
-
*/
|
|
429
|
-
toColor: function (value, point) {
|
|
430
|
-
var pos,
|
|
431
|
-
stops = this.stops,
|
|
432
|
-
from,
|
|
433
|
-
to,
|
|
434
|
-
color,
|
|
435
|
-
dataClasses = this.dataClasses,
|
|
436
|
-
dataClass,
|
|
437
|
-
i;
|
|
438
|
-
|
|
439
|
-
if (dataClasses) {
|
|
440
|
-
i = dataClasses.length;
|
|
441
|
-
while (i--) {
|
|
442
|
-
dataClass = dataClasses[i];
|
|
443
|
-
from = dataClass.from;
|
|
444
|
-
to = dataClass.to;
|
|
445
|
-
if ((from === UNDEFINED || value >= from) && (to === UNDEFINED || value <= to)) {
|
|
446
|
-
color = dataClass.color;
|
|
447
|
-
if (point) {
|
|
448
|
-
point.dataClass = i;
|
|
449
|
-
}
|
|
450
|
-
break;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
318
|
|
|
454
|
-
|
|
319
|
+
} else {
|
|
455
320
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
}
|
|
321
|
+
if (this.isLog) {
|
|
322
|
+
value = this.val2lin(value);
|
|
323
|
+
}
|
|
324
|
+
pos = 1 - ((this.max - value) / ((this.max - this.min) || 1));
|
|
325
|
+
i = stops.length;
|
|
326
|
+
while (i--) {
|
|
327
|
+
if (pos > stops[i][0]) {
|
|
328
|
+
break;
|
|
465
329
|
}
|
|
466
|
-
from = stops[i] || stops[i + 1];
|
|
467
|
-
to = stops[i + 1] || from;
|
|
468
|
-
|
|
469
|
-
// The position within the gradient
|
|
470
|
-
pos = 1 - (to[0] - pos) / ((to[0] - from[0]) || 1);
|
|
471
|
-
|
|
472
|
-
color = tweenColors(
|
|
473
|
-
from.color,
|
|
474
|
-
to.color,
|
|
475
|
-
pos
|
|
476
|
-
);
|
|
477
330
|
}
|
|
478
|
-
|
|
479
|
-
|
|
331
|
+
from = stops[i] || stops[i + 1];
|
|
332
|
+
to = stops[i + 1] || from;
|
|
480
333
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
if (group) {
|
|
334
|
+
// The position within the gradient
|
|
335
|
+
pos = 1 - (to[0] - pos) / ((to[0] - from[0]) || 1);
|
|
484
336
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
337
|
+
color = this.tweenColors(
|
|
338
|
+
from.color,
|
|
339
|
+
to.color,
|
|
340
|
+
pos
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
return color;
|
|
344
|
+
},
|
|
488
345
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
346
|
+
getOffset: function () {
|
|
347
|
+
var group = this.legendGroup,
|
|
348
|
+
sideOffset = this.chart.axisOffset[this.side];
|
|
349
|
+
|
|
350
|
+
if (group) {
|
|
493
351
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
},
|
|
352
|
+
Axis.prototype.getOffset.call(this);
|
|
353
|
+
|
|
354
|
+
if (!this.axisGroup.parentGroup) {
|
|
498
355
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
var grad,
|
|
504
|
-
horiz = this.horiz,
|
|
505
|
-
options = this.options;
|
|
506
|
-
|
|
507
|
-
grad = horiz ? [0, 0, 1, 0] : [0, 0, 0, 1];
|
|
508
|
-
this.legendColor = {
|
|
509
|
-
linearGradient: { x1: grad[0], y1: grad[1], x2: grad[2], y2: grad[3] },
|
|
510
|
-
stops: options.stops || [
|
|
511
|
-
[0, options.minColor],
|
|
512
|
-
[1, options.maxColor]
|
|
513
|
-
]
|
|
514
|
-
};
|
|
515
|
-
},
|
|
356
|
+
// Move the axis elements inside the legend group
|
|
357
|
+
this.axisGroup.add(group);
|
|
358
|
+
this.gridGroup.add(group);
|
|
359
|
+
this.labelGroup.add(group);
|
|
516
360
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
horiz = this.horiz,
|
|
524
|
-
box,
|
|
525
|
-
width = pick(legendOptions.symbolWidth, horiz ? 200 : 12),
|
|
526
|
-
height = pick(legendOptions.symbolHeight, horiz ? 12 : 200),
|
|
527
|
-
labelPadding = pick(legendOptions.labelPadding, horiz ? 10 : 30);
|
|
361
|
+
this.added = true;
|
|
362
|
+
}
|
|
363
|
+
// Reset it to avoid color axis reserving space
|
|
364
|
+
this.chart.axisOffset[this.side] = sideOffset;
|
|
365
|
+
}
|
|
366
|
+
},
|
|
528
367
|
|
|
529
|
-
|
|
368
|
+
/**
|
|
369
|
+
* Create the color gradient
|
|
370
|
+
*/
|
|
371
|
+
setLegendColor: function () {
|
|
372
|
+
var grad,
|
|
373
|
+
horiz = this.horiz,
|
|
374
|
+
options = this.options;
|
|
375
|
+
|
|
376
|
+
grad = horiz ? [0, 0, 1, 0] : [0, 0, 0, 1];
|
|
377
|
+
this.legendColor = {
|
|
378
|
+
linearGradient: { x1: grad[0], y1: grad[1], x2: grad[2], y2: grad[3] },
|
|
379
|
+
stops: options.stops || [
|
|
380
|
+
[0, options.minColor],
|
|
381
|
+
[1, options.maxColor]
|
|
382
|
+
]
|
|
383
|
+
};
|
|
384
|
+
},
|
|
530
385
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
386
|
+
/**
|
|
387
|
+
* The color axis appears inside the legend and has its own legend symbol
|
|
388
|
+
*/
|
|
389
|
+
drawLegendSymbol: function (legend, item) {
|
|
390
|
+
var padding = legend.padding,
|
|
391
|
+
legendOptions = legend.options,
|
|
392
|
+
horiz = this.horiz,
|
|
393
|
+
box,
|
|
394
|
+
width = pick(legendOptions.symbolWidth, horiz ? 200 : 12),
|
|
395
|
+
height = pick(legendOptions.symbolHeight, horiz ? 12 : 200),
|
|
396
|
+
labelPadding = pick(legendOptions.labelPadding, horiz ? 16 : 30),
|
|
397
|
+
itemDistance = pick(legendOptions.itemDistance, 10);
|
|
398
|
+
|
|
399
|
+
this.setLegendColor();
|
|
400
|
+
|
|
401
|
+
// Create the gradient
|
|
402
|
+
item.legendSymbol = this.chart.renderer.rect(
|
|
403
|
+
0,
|
|
404
|
+
legend.baseline - 11,
|
|
405
|
+
width,
|
|
406
|
+
height
|
|
407
|
+
).attr({
|
|
408
|
+
zIndex: 1
|
|
409
|
+
}).add(item.legendGroup);
|
|
410
|
+
box = item.legendSymbol.getBBox();
|
|
411
|
+
|
|
412
|
+
// Set how much space this legend item takes up
|
|
413
|
+
this.legendItemWidth = width + padding + (horiz ? itemDistance : labelPadding);
|
|
414
|
+
this.legendItemHeight = height + padding + (horiz ? labelPadding : 0);
|
|
415
|
+
},
|
|
416
|
+
/**
|
|
417
|
+
* Fool the legend
|
|
418
|
+
*/
|
|
419
|
+
setState: noop,
|
|
420
|
+
visible: true,
|
|
421
|
+
setVisible: noop,
|
|
422
|
+
getSeriesExtremes: function () {
|
|
423
|
+
var series;
|
|
424
|
+
if (this.series.length) {
|
|
425
|
+
series = this.series[0];
|
|
426
|
+
this.dataMin = series.valueMin;
|
|
427
|
+
this.dataMax = series.valueMax;
|
|
428
|
+
}
|
|
429
|
+
},
|
|
430
|
+
drawCrosshair: function (e, point) {
|
|
431
|
+
var newCross = !this.cross,
|
|
432
|
+
plotX = point && point.plotX,
|
|
433
|
+
plotY = point && point.plotY,
|
|
434
|
+
crossPos,
|
|
435
|
+
axisPos = this.pos,
|
|
436
|
+
axisLen = this.len;
|
|
437
|
+
|
|
438
|
+
if (point) {
|
|
439
|
+
crossPos = this.toPixels(point.value);
|
|
440
|
+
if (crossPos < axisPos) {
|
|
441
|
+
crossPos = axisPos - 2;
|
|
442
|
+
} else if (crossPos > axisPos + axisLen) {
|
|
443
|
+
crossPos = axisPos + axisLen + 2;
|
|
558
444
|
}
|
|
559
|
-
},
|
|
560
|
-
drawCrosshair: function (e, point) {
|
|
561
|
-
var newCross = !this.cross,
|
|
562
|
-
plotX = point && point.plotX,
|
|
563
|
-
plotY = point && point.plotY,
|
|
564
|
-
crossPos,
|
|
565
|
-
axisPos = this.pos,
|
|
566
|
-
axisLen = this.len;
|
|
567
445
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
point.plotY = plotY;
|
|
581
|
-
|
|
582
|
-
if (!newCross && this.cross) {
|
|
583
|
-
this.cross
|
|
584
|
-
.attr({
|
|
585
|
-
fill: this.crosshair.color
|
|
586
|
-
})
|
|
587
|
-
.add(this.labelGroup);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
},
|
|
591
|
-
getPlotLinePath: function (a, b, c, d, pos) {
|
|
592
|
-
if (pos) { // crosshairs only
|
|
593
|
-
return this.horiz ?
|
|
594
|
-
['M', pos - 4, this.top - 6, 'L', pos + 4, this.top - 6, pos, this.top, 'Z'] :
|
|
595
|
-
['M', this.left, pos, 'L', this.left - 6, pos + 6, this.left - 6, pos - 6, 'Z'];
|
|
596
|
-
} else {
|
|
597
|
-
return Axis.prototype.getPlotLinePath.call(this, a, b, c, d);
|
|
598
|
-
}
|
|
599
|
-
},
|
|
600
|
-
|
|
601
|
-
update: function (newOptions, redraw) {
|
|
602
|
-
Axis.prototype.update.call(this, newOptions, redraw);
|
|
603
|
-
if (this.legendItem) {
|
|
604
|
-
this.setLegendColor();
|
|
605
|
-
this.chart.legend.colorizeItem(this, true);
|
|
446
|
+
point.plotX = crossPos;
|
|
447
|
+
point.plotY = this.len - crossPos;
|
|
448
|
+
Axis.prototype.drawCrosshair.call(this, e, point);
|
|
449
|
+
point.plotX = plotX;
|
|
450
|
+
point.plotY = plotY;
|
|
451
|
+
|
|
452
|
+
if (!newCross && this.cross) {
|
|
453
|
+
this.cross
|
|
454
|
+
.attr({
|
|
455
|
+
fill: this.crosshair.color
|
|
456
|
+
})
|
|
457
|
+
.add(this.labelGroup);
|
|
606
458
|
}
|
|
607
|
-
}
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
getPlotLinePath: function (a, b, c, d, pos) {
|
|
462
|
+
if (pos) { // crosshairs only
|
|
463
|
+
return this.horiz ?
|
|
464
|
+
['M', pos - 4, this.top - 6, 'L', pos + 4, this.top - 6, pos, this.top, 'Z'] :
|
|
465
|
+
['M', this.left, pos, 'L', this.left - 6, pos + 6, this.left - 6, pos - 6, 'Z'];
|
|
466
|
+
} else {
|
|
467
|
+
return Axis.prototype.getPlotLinePath.call(this, a, b, c, d);
|
|
468
|
+
}
|
|
469
|
+
},
|
|
608
470
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
name;
|
|
471
|
+
update: function (newOptions, redraw) {
|
|
472
|
+
each(this.series, function (series) {
|
|
473
|
+
series.isDirtyData = true; // Needed for Axis.update when choropleth colors change
|
|
474
|
+
});
|
|
475
|
+
Axis.prototype.update.call(this, newOptions, redraw);
|
|
476
|
+
if (this.legendItem) {
|
|
477
|
+
this.setLegendColor();
|
|
478
|
+
this.chart.legend.colorizeItem(this, true);
|
|
479
|
+
}
|
|
480
|
+
},
|
|
620
481
|
|
|
482
|
+
/**
|
|
483
|
+
* Get the legend item symbols for data classes
|
|
484
|
+
*/
|
|
485
|
+
getDataClassLegendSymbols: function () {
|
|
486
|
+
var axis = this,
|
|
487
|
+
chart = this.chart,
|
|
488
|
+
legendItems = this.legendItems,
|
|
489
|
+
legendOptions = chart.options.legend,
|
|
490
|
+
valueDecimals = legendOptions.valueDecimals,
|
|
491
|
+
valueSuffix = legendOptions.valueSuffix || '',
|
|
492
|
+
name;
|
|
493
|
+
|
|
494
|
+
if (!legendItems.length) {
|
|
621
495
|
each(this.dataClasses, function (dataClass, i) {
|
|
622
496
|
var vis = true,
|
|
623
497
|
from = dataClass.from,
|
|
@@ -641,11 +515,11 @@
|
|
|
641
515
|
}
|
|
642
516
|
|
|
643
517
|
// Add a mock object to the legend items
|
|
644
|
-
legendItems.push(
|
|
518
|
+
legendItems.push(extend({
|
|
645
519
|
chart: chart,
|
|
646
520
|
name: name,
|
|
647
521
|
options: {},
|
|
648
|
-
drawLegendSymbol:
|
|
522
|
+
drawLegendSymbol: LegendSymbolMixin.drawRectangle,
|
|
649
523
|
visible: true,
|
|
650
524
|
setState: noop,
|
|
651
525
|
setVisible: function () {
|
|
@@ -662,995 +536,1582 @@
|
|
|
662
536
|
}
|
|
663
537
|
}, dataClass));
|
|
664
538
|
});
|
|
665
|
-
return legendItems;
|
|
666
539
|
}
|
|
540
|
+
return legendItems;
|
|
541
|
+
},
|
|
542
|
+
name: '' // Prevents 'undefined' in legend in IE8
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Handle animation of the color attributes directly
|
|
547
|
+
*/
|
|
548
|
+
each(['fill', 'stroke'], function (prop) {
|
|
549
|
+
HighchartsAdapter.addAnimSetter(prop, function (fx) {
|
|
550
|
+
fx.elem.attr(prop, ColorAxis.prototype.tweenColors(Color(fx.start), Color(fx.end), fx.pos));
|
|
667
551
|
});
|
|
552
|
+
});
|
|
668
553
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
wrap(Legend.prototype, 'getAllItems', function (proceed) {
|
|
674
|
-
var allItems = [],
|
|
675
|
-
colorAxis = this.chart.colorAxis[0];
|
|
554
|
+
/**
|
|
555
|
+
* Extend the chart getAxes method to also get the color axis
|
|
556
|
+
*/
|
|
557
|
+
wrap(Chart.prototype, 'getAxes', function (proceed) {
|
|
676
558
|
|
|
677
|
-
|
|
559
|
+
var options = this.options,
|
|
560
|
+
colorAxisOptions = options.colorAxis;
|
|
678
561
|
|
|
679
|
-
|
|
680
|
-
if (colorAxis.options.dataClasses) {
|
|
681
|
-
allItems = allItems.concat(colorAxis.getDataClassLegendSymbols());
|
|
682
|
-
// Gradient legend
|
|
683
|
-
} else {
|
|
684
|
-
// Add this axis on top
|
|
685
|
-
allItems.push(colorAxis);
|
|
686
|
-
}
|
|
562
|
+
proceed.call(this);
|
|
687
563
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
564
|
+
this.colorAxis = [];
|
|
565
|
+
if (colorAxisOptions) {
|
|
566
|
+
proceed = new ColorAxis(this, colorAxisOptions); // Fake assignment for jsLint
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Wrap the legend getAllItems method to add the color axis. This also removes the
|
|
573
|
+
* axis' own series to prevent them from showing up individually.
|
|
574
|
+
*/
|
|
575
|
+
wrap(Legend.prototype, 'getAllItems', function (proceed) {
|
|
576
|
+
var allItems = [],
|
|
577
|
+
colorAxis = this.chart.colorAxis[0];
|
|
578
|
+
|
|
579
|
+
if (colorAxis) {
|
|
580
|
+
|
|
581
|
+
// Data classes
|
|
582
|
+
if (colorAxis.options.dataClasses) {
|
|
583
|
+
allItems = allItems.concat(colorAxis.getDataClassLegendSymbols());
|
|
584
|
+
// Gradient legend
|
|
585
|
+
} else {
|
|
586
|
+
// Add this axis on top
|
|
587
|
+
allItems.push(colorAxis);
|
|
692
588
|
}
|
|
693
589
|
|
|
694
|
-
|
|
695
|
-
|
|
590
|
+
// Don't add the color axis' series
|
|
591
|
+
each(colorAxis.series, function (series) {
|
|
592
|
+
series.options.showInLegend = false;
|
|
593
|
+
});
|
|
594
|
+
}
|
|
696
595
|
|
|
596
|
+
return allItems.concat(proceed.call(this));
|
|
597
|
+
});/**
|
|
598
|
+
* Mixin for maps and heatmaps
|
|
599
|
+
*/
|
|
600
|
+
var colorSeriesMixin = {
|
|
601
|
+
|
|
602
|
+
pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
|
|
603
|
+
stroke: 'borderColor',
|
|
604
|
+
'stroke-width': 'borderWidth',
|
|
605
|
+
fill: 'color',
|
|
606
|
+
dashstyle: 'dashStyle'
|
|
607
|
+
},
|
|
608
|
+
pointArrayMap: ['value'],
|
|
609
|
+
axisTypes: ['xAxis', 'yAxis', 'colorAxis'],
|
|
610
|
+
optionalAxis: 'colorAxis',
|
|
611
|
+
trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'],
|
|
612
|
+
getSymbol: noop,
|
|
613
|
+
parallelArrays: ['x', 'y', 'value'],
|
|
614
|
+
colorKey: 'value',
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* In choropleth maps, the color is a result of the value, so this needs translation too
|
|
618
|
+
*/
|
|
619
|
+
translateColors: function () {
|
|
620
|
+
var series = this,
|
|
621
|
+
nullColor = this.options.nullColor,
|
|
622
|
+
colorAxis = this.colorAxis,
|
|
623
|
+
colorKey = this.colorKey;
|
|
697
624
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
var chart = this,
|
|
702
|
-
options = this.options.mapNavigation,
|
|
703
|
-
buttons = options.buttons,
|
|
704
|
-
n,
|
|
705
|
-
button,
|
|
706
|
-
buttonOptions,
|
|
707
|
-
attr,
|
|
708
|
-
states,
|
|
709
|
-
outerHandler = function () {
|
|
710
|
-
this.handler.call(chart);
|
|
711
|
-
};
|
|
625
|
+
each(this.data, function (point) {
|
|
626
|
+
var value = point[colorKey],
|
|
627
|
+
color;
|
|
712
628
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
attr = buttonOptions.theme;
|
|
718
|
-
states = attr.states;
|
|
719
|
-
button = chart.renderer.button(
|
|
720
|
-
buttonOptions.text,
|
|
721
|
-
0,
|
|
722
|
-
0,
|
|
723
|
-
outerHandler,
|
|
724
|
-
attr,
|
|
725
|
-
states && states.hover,
|
|
726
|
-
states && states.select,
|
|
727
|
-
0,
|
|
728
|
-
n === 'zoomIn' ? 'topbutton' : 'bottombutton'
|
|
729
|
-
)
|
|
730
|
-
.attr({
|
|
731
|
-
width: buttonOptions.width,
|
|
732
|
-
height: buttonOptions.height,
|
|
733
|
-
title: chart.options.lang[n],
|
|
734
|
-
zIndex: 5
|
|
735
|
-
})
|
|
736
|
-
.css(buttonOptions.style)
|
|
737
|
-
.add();
|
|
738
|
-
button.handler = buttonOptions.onclick;
|
|
739
|
-
button.align(extend(buttonOptions, { width: button.width, height: 2 * button.height }), null, buttonOptions.alignTo);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
629
|
+
color = value === null ? nullColor : (colorAxis && value !== undefined) ? colorAxis.toColor(value, point) : point.color || series.color;
|
|
630
|
+
|
|
631
|
+
if (color) {
|
|
632
|
+
point.color = color;
|
|
742
633
|
}
|
|
743
|
-
}
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
};
|
|
744
637
|
|
|
745
|
-
/**
|
|
746
|
-
* Fit an inner box to an outer. If the inner box overflows left or right, align it to the sides of the
|
|
747
|
-
* outer. If it overflows both sides, fit it within the outer. This is a pattern that occurs more places
|
|
748
|
-
* in Highcharts, perhaps it should be elevated to a common utility function.
|
|
749
|
-
*/
|
|
750
|
-
fitToBox: function (inner, outer) {
|
|
751
|
-
each([['x', 'width'], ['y', 'height']], function (dim) {
|
|
752
|
-
var pos = dim[0],
|
|
753
|
-
size = dim[1];
|
|
754
|
-
|
|
755
|
-
if (inner[pos] + inner[size] > outer[pos] + outer[size]) { // right overflow
|
|
756
|
-
if (inner[size] > outer[size]) { // the general size is greater, fit fully to outer
|
|
757
|
-
inner[size] = outer[size];
|
|
758
|
-
inner[pos] = outer[pos];
|
|
759
|
-
} else { // align right
|
|
760
|
-
inner[pos] = outer[pos] + outer[size] - inner[size];
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
if (inner[size] > outer[size]) {
|
|
764
|
-
inner[size] = outer[size];
|
|
765
|
-
}
|
|
766
|
-
if (inner[pos] < outer[pos]) {
|
|
767
|
-
inner[pos] = outer[pos];
|
|
768
|
-
}
|
|
769
|
-
});
|
|
770
|
-
|
|
771
638
|
|
|
772
|
-
|
|
773
|
-
|
|
639
|
+
/**
|
|
640
|
+
* Wrap the buildText method and add the hook for add text stroke
|
|
641
|
+
*/
|
|
642
|
+
wrap(SVGRenderer.prototype, 'buildText', function (proceed, wrapper) {
|
|
774
643
|
|
|
775
|
-
|
|
776
|
-
* Zoom the map in or out by a certain amount. Less than 1 zooms in, greater than 1 zooms out.
|
|
777
|
-
*/
|
|
778
|
-
mapZoom: function (howMuch, centerXArg, centerYArg, mouseX, mouseY) {
|
|
779
|
-
/*if (this.isMapZooming) {
|
|
780
|
-
this.mapZoomQueue = arguments;
|
|
781
|
-
return;
|
|
782
|
-
}*/
|
|
783
|
-
|
|
784
|
-
var chart = this,
|
|
785
|
-
xAxis = chart.xAxis[0],
|
|
786
|
-
xRange = xAxis.max - xAxis.min,
|
|
787
|
-
centerX = pick(centerXArg, xAxis.min + xRange / 2),
|
|
788
|
-
newXRange = xRange * howMuch,
|
|
789
|
-
yAxis = chart.yAxis[0],
|
|
790
|
-
yRange = yAxis.max - yAxis.min,
|
|
791
|
-
centerY = pick(centerYArg, yAxis.min + yRange / 2),
|
|
792
|
-
newYRange = yRange * howMuch,
|
|
793
|
-
fixToX = mouseX ? ((mouseX - xAxis.pos) / xAxis.len) : 0.5,
|
|
794
|
-
fixToY = mouseY ? ((mouseY - yAxis.pos) / yAxis.len) : 0.5,
|
|
795
|
-
newXMin = centerX - newXRange * fixToX,
|
|
796
|
-
newYMin = centerY - newYRange * fixToY,
|
|
797
|
-
newExt = chart.fitToBox({
|
|
798
|
-
x: newXMin,
|
|
799
|
-
y: newYMin,
|
|
800
|
-
width: newXRange,
|
|
801
|
-
height: newYRange
|
|
802
|
-
}, {
|
|
803
|
-
x: xAxis.dataMin,
|
|
804
|
-
y: yAxis.dataMin,
|
|
805
|
-
width: xAxis.dataMax - xAxis.dataMin,
|
|
806
|
-
height: yAxis.dataMax - yAxis.dataMin
|
|
807
|
-
});
|
|
644
|
+
var textStroke = wrapper.styles && wrapper.styles.HcTextStroke;
|
|
808
645
|
|
|
809
|
-
|
|
810
|
-
if (mouseX) {
|
|
811
|
-
xAxis.fixTo = [mouseX - xAxis.pos, centerXArg];
|
|
812
|
-
}
|
|
813
|
-
if (mouseY) {
|
|
814
|
-
yAxis.fixTo = [mouseY - yAxis.pos, centerYArg];
|
|
815
|
-
}
|
|
646
|
+
proceed.call(this, wrapper);
|
|
816
647
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
648
|
+
// Apply the text stroke
|
|
649
|
+
if (textStroke && wrapper.applyTextStroke) {
|
|
650
|
+
wrapper.applyTextStroke(textStroke);
|
|
651
|
+
}
|
|
652
|
+
});
|
|
821
653
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
654
|
+
/**
|
|
655
|
+
* Apply an outside text stroke to data labels, based on the custom CSS property, HcTextStroke.
|
|
656
|
+
* Consider moving this to Highcharts core, also makes sense on stacked columns etc.
|
|
657
|
+
*/
|
|
658
|
+
SVGRenderer.prototype.Element.prototype.applyTextStroke = function (textStroke) {
|
|
659
|
+
var elem = this.element,
|
|
660
|
+
tspans,
|
|
661
|
+
firstChild;
|
|
662
|
+
|
|
663
|
+
textStroke = textStroke.split(' ');
|
|
664
|
+
tspans = elem.getElementsByTagName('tspan');
|
|
665
|
+
firstChild = elem.firstChild;
|
|
666
|
+
|
|
667
|
+
// In order to get the right y position of the clones,
|
|
668
|
+
// copy over the y setter
|
|
669
|
+
this.ySetter = this.xSetter;
|
|
670
|
+
|
|
671
|
+
each([].slice.call(tspans), function (tspan, y) {
|
|
672
|
+
var clone;
|
|
673
|
+
if (y === 0) {
|
|
674
|
+
tspan.setAttribute('x', elem.getAttribute('x'));
|
|
675
|
+
if ((y = elem.getAttribute('y')) !== null) {
|
|
676
|
+
tspan.setAttribute('y', y);
|
|
826
677
|
}
|
|
827
|
-
|
|
828
|
-
// Prevent zooming until this one is finished animating
|
|
829
|
-
/*delay = animation ? animation.duration || 500 : 0;
|
|
830
|
-
if (delay) {
|
|
831
|
-
chart.isMapZooming = true;
|
|
832
|
-
setTimeout(function () {
|
|
833
|
-
chart.isMapZooming = false;
|
|
834
|
-
if (chart.mapZoomQueue) {
|
|
835
|
-
chart.mapZoom.apply(chart, chart.mapZoomQueue);
|
|
836
|
-
}
|
|
837
|
-
chart.mapZoomQueue = null;
|
|
838
|
-
}, delay);
|
|
839
|
-
}*/
|
|
840
|
-
|
|
841
|
-
chart.redraw();
|
|
842
678
|
}
|
|
679
|
+
clone = tspan.cloneNode(1);
|
|
680
|
+
clone.setAttribute('stroke', textStroke[1]);
|
|
681
|
+
clone.setAttribute('stroke-width', textStroke[0]);
|
|
682
|
+
clone.setAttribute('stroke-linejoin', 'round');
|
|
683
|
+
elem.insertBefore(clone, firstChild);
|
|
843
684
|
});
|
|
685
|
+
};
|
|
686
|
+
// Add events to the Chart object itself
|
|
687
|
+
extend(Chart.prototype, {
|
|
688
|
+
renderMapNavigation: function () {
|
|
689
|
+
var chart = this,
|
|
690
|
+
options = this.options.mapNavigation,
|
|
691
|
+
buttons = options.buttons,
|
|
692
|
+
n,
|
|
693
|
+
button,
|
|
694
|
+
buttonOptions,
|
|
695
|
+
attr,
|
|
696
|
+
states,
|
|
697
|
+
outerHandler = function () {
|
|
698
|
+
this.handler.call(chart);
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
if (pick(options.enableButtons, options.enabled) && !chart.renderer.forExport) {
|
|
702
|
+
for (n in buttons) {
|
|
703
|
+
if (buttons.hasOwnProperty(n)) {
|
|
704
|
+
buttonOptions = merge(options.buttonOptions, buttons[n]);
|
|
705
|
+
attr = buttonOptions.theme;
|
|
706
|
+
states = attr.states;
|
|
707
|
+
button = chart.renderer.button(
|
|
708
|
+
buttonOptions.text,
|
|
709
|
+
0,
|
|
710
|
+
0,
|
|
711
|
+
outerHandler,
|
|
712
|
+
attr,
|
|
713
|
+
states && states.hover,
|
|
714
|
+
states && states.select,
|
|
715
|
+
0,
|
|
716
|
+
n === 'zoomIn' ? 'topbutton' : 'bottombutton'
|
|
717
|
+
)
|
|
718
|
+
.attr({
|
|
719
|
+
width: buttonOptions.width,
|
|
720
|
+
height: buttonOptions.height,
|
|
721
|
+
title: chart.options.lang[n],
|
|
722
|
+
zIndex: 5
|
|
723
|
+
})
|
|
724
|
+
.css(buttonOptions.style)
|
|
725
|
+
.add();
|
|
726
|
+
button.handler = buttonOptions.onclick;
|
|
727
|
+
button.align(extend(buttonOptions, { width: button.width, height: 2 * button.height }), null, buttonOptions.alignTo);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
},
|
|
844
732
|
|
|
845
733
|
/**
|
|
846
|
-
*
|
|
734
|
+
* Fit an inner box to an outer. If the inner box overflows left or right, align it to the sides of the
|
|
735
|
+
* outer. If it overflows both sides, fit it within the outer. This is a pattern that occurs more places
|
|
736
|
+
* in Highcharts, perhaps it should be elevated to a common utility function.
|
|
847
737
|
*/
|
|
848
|
-
|
|
738
|
+
fitToBox: function (inner, outer) {
|
|
739
|
+
each([['x', 'width'], ['y', 'height']], function (dim) {
|
|
740
|
+
var pos = dim[0],
|
|
741
|
+
size = dim[1];
|
|
849
742
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
743
|
+
if (inner[pos] + inner[size] > outer[pos] + outer[size]) { // right overflow
|
|
744
|
+
if (inner[size] > outer[size]) { // the general size is greater, fit fully to outer
|
|
745
|
+
inner[size] = outer[size];
|
|
746
|
+
inner[pos] = outer[pos];
|
|
747
|
+
} else { // align right
|
|
748
|
+
inner[pos] = outer[pos] + outer[size] - inner[size];
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
if (inner[size] > outer[size]) {
|
|
752
|
+
inner[size] = outer[size];
|
|
753
|
+
}
|
|
754
|
+
if (inner[pos] < outer[pos]) {
|
|
755
|
+
inner[pos] = outer[pos];
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
|
|
854
759
|
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
proceed = new ColorAxis(this, colorAxisOptions); // Fake assignment for jsLint
|
|
858
|
-
}
|
|
859
|
-
});
|
|
760
|
+
return inner;
|
|
761
|
+
},
|
|
860
762
|
|
|
861
763
|
/**
|
|
862
|
-
*
|
|
764
|
+
* Zoom the map in or out by a certain amount. Less than 1 zooms in, greater than 1 zooms out.
|
|
863
765
|
*/
|
|
864
|
-
|
|
766
|
+
mapZoom: function (howMuch, centerXArg, centerYArg, mouseX, mouseY) {
|
|
767
|
+
/*if (this.isMapZooming) {
|
|
768
|
+
this.mapZoomQueue = arguments;
|
|
769
|
+
return;
|
|
770
|
+
}*/
|
|
771
|
+
|
|
865
772
|
var chart = this,
|
|
866
|
-
|
|
773
|
+
xAxis = chart.xAxis[0],
|
|
774
|
+
xRange = xAxis.max - xAxis.min,
|
|
775
|
+
centerX = pick(centerXArg, xAxis.min + xRange / 2),
|
|
776
|
+
newXRange = xRange * howMuch,
|
|
777
|
+
yAxis = chart.yAxis[0],
|
|
778
|
+
yRange = yAxis.max - yAxis.min,
|
|
779
|
+
centerY = pick(centerYArg, yAxis.min + yRange / 2),
|
|
780
|
+
newYRange = yRange * howMuch,
|
|
781
|
+
fixToX = mouseX ? ((mouseX - xAxis.pos) / xAxis.len) : 0.5,
|
|
782
|
+
fixToY = mouseY ? ((mouseY - yAxis.pos) / yAxis.len) : 0.5,
|
|
783
|
+
newXMin = centerX - newXRange * fixToX,
|
|
784
|
+
newYMin = centerY - newYRange * fixToY,
|
|
785
|
+
newExt = chart.fitToBox({
|
|
786
|
+
x: newXMin,
|
|
787
|
+
y: newYMin,
|
|
788
|
+
width: newXRange,
|
|
789
|
+
height: newYRange
|
|
790
|
+
}, {
|
|
791
|
+
x: xAxis.dataMin,
|
|
792
|
+
y: yAxis.dataMin,
|
|
793
|
+
width: xAxis.dataMax - xAxis.dataMin,
|
|
794
|
+
height: yAxis.dataMax - yAxis.dataMin
|
|
795
|
+
});
|
|
867
796
|
|
|
868
|
-
|
|
797
|
+
// When mousewheel zooming, fix the point under the mouse
|
|
798
|
+
if (mouseX) {
|
|
799
|
+
xAxis.fixTo = [mouseX - xAxis.pos, centerXArg];
|
|
800
|
+
}
|
|
801
|
+
if (mouseY) {
|
|
802
|
+
yAxis.fixTo = [mouseY - yAxis.pos, centerYArg];
|
|
803
|
+
}
|
|
869
804
|
|
|
870
|
-
//
|
|
871
|
-
|
|
805
|
+
// Zoom
|
|
806
|
+
if (howMuch !== undefined) {
|
|
807
|
+
xAxis.setExtremes(newExt.x, newExt.x + newExt.width, false);
|
|
808
|
+
yAxis.setExtremes(newExt.y, newExt.y + newExt.height, false);
|
|
872
809
|
|
|
873
|
-
//
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
});
|
|
810
|
+
// Reset zoom
|
|
811
|
+
} else {
|
|
812
|
+
xAxis.setExtremes(undefined, undefined, false);
|
|
813
|
+
yAxis.setExtremes(undefined, undefined, false);
|
|
878
814
|
}
|
|
815
|
+
|
|
816
|
+
// Prevent zooming until this one is finished animating
|
|
817
|
+
/*chart.holdMapZoom = true;
|
|
818
|
+
setTimeout(function () {
|
|
819
|
+
chart.holdMapZoom = false;
|
|
820
|
+
}, 200);*/
|
|
821
|
+
/*delay = animation ? animation.duration || 500 : 0;
|
|
822
|
+
if (delay) {
|
|
823
|
+
chart.isMapZooming = true;
|
|
824
|
+
setTimeout(function () {
|
|
825
|
+
chart.isMapZooming = false;
|
|
826
|
+
if (chart.mapZoomQueue) {
|
|
827
|
+
chart.mapZoom.apply(chart, chart.mapZoomQueue);
|
|
828
|
+
}
|
|
829
|
+
chart.mapZoomQueue = null;
|
|
830
|
+
}, delay);
|
|
831
|
+
}*/
|
|
879
832
|
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
chart.pointer.onContainerMouseWheel(e);
|
|
884
|
-
return false;
|
|
885
|
-
});
|
|
886
|
-
}
|
|
887
|
-
});
|
|
833
|
+
chart.redraw();
|
|
834
|
+
}
|
|
835
|
+
});
|
|
888
836
|
|
|
837
|
+
/**
|
|
838
|
+
* Extend the Chart.render method to add zooming and panning
|
|
839
|
+
*/
|
|
840
|
+
wrap(Chart.prototype, 'render', function (proceed) {
|
|
841
|
+
var chart = this,
|
|
842
|
+
mapNavigation = chart.options.mapNavigation;
|
|
843
|
+
|
|
844
|
+
// Render the plus and minus buttons. Doing this before the shapes makes getBBox much quicker, at least in Chrome.
|
|
845
|
+
chart.renderMapNavigation();
|
|
846
|
+
|
|
847
|
+
proceed.call(chart);
|
|
848
|
+
|
|
849
|
+
// Add the double click event
|
|
850
|
+
if (pick(mapNavigation.enableDoubleClickZoom, mapNavigation.enabled) || mapNavigation.enableDoubleClickZoomTo) {
|
|
851
|
+
addEvent(chart.container, 'dblclick', function (e) {
|
|
852
|
+
chart.pointer.onContainerDblClick(e);
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// Add the mousewheel event
|
|
857
|
+
if (pick(mapNavigation.enableMouseWheelZoom, mapNavigation.enabled)) {
|
|
858
|
+
addEvent(chart.container, document.onmousewheel === undefined ? 'DOMMouseScroll' : 'mousewheel', function (e) {
|
|
859
|
+
chart.pointer.onContainerMouseWheel(e);
|
|
860
|
+
return false;
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
// Extend the Pointer
|
|
866
|
+
extend(Pointer.prototype, {
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* The event handler for the doubleclick event
|
|
870
|
+
*/
|
|
871
|
+
onContainerDblClick: function (e) {
|
|
872
|
+
var chart = this.chart;
|
|
873
|
+
|
|
874
|
+
e = this.normalize(e);
|
|
875
|
+
|
|
876
|
+
if (chart.options.mapNavigation.enableDoubleClickZoomTo) {
|
|
877
|
+
if (chart.pointer.inClass(e.target, 'highcharts-tracker')) {
|
|
878
|
+
chart.hoverPoint.zoomTo();
|
|
879
|
+
}
|
|
880
|
+
} else if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
|
|
881
|
+
chart.mapZoom(
|
|
882
|
+
0.5,
|
|
883
|
+
chart.xAxis[0].toValue(e.chartX),
|
|
884
|
+
chart.yAxis[0].toValue(e.chartY),
|
|
885
|
+
e.chartX,
|
|
886
|
+
e.chartY
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
},
|
|
889
890
|
|
|
890
|
-
|
|
891
891
|
/**
|
|
892
|
-
*
|
|
892
|
+
* The event handler for the mouse scroll event
|
|
893
893
|
*/
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
894
|
+
onContainerMouseWheel: function (e) {
|
|
895
|
+
var chart = this.chart,
|
|
896
|
+
delta;
|
|
897
|
+
|
|
898
|
+
e = this.normalize(e);
|
|
899
|
+
|
|
900
|
+
// Firefox uses e.detail, WebKit and IE uses wheelDelta
|
|
901
|
+
delta = e.detail || -(e.wheelDelta / 120);
|
|
902
|
+
if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
|
|
903
|
+
chart.mapZoom(
|
|
904
|
+
//delta > 0 ? 2 : 0.5,
|
|
905
|
+
Math.pow(2, delta),
|
|
906
|
+
chart.xAxis[0].toValue(e.chartX),
|
|
907
|
+
chart.yAxis[0].toValue(e.chartY),
|
|
908
|
+
e.chartX,
|
|
909
|
+
e.chartY
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
// Implement the pinchType option
|
|
916
|
+
wrap(Pointer.prototype, 'init', function (proceed, chart, options) {
|
|
917
|
+
|
|
918
|
+
proceed.call(this, chart, options);
|
|
919
|
+
|
|
920
|
+
// Pinch status
|
|
921
|
+
if (pick(options.mapNavigation.enableTouchZoom, options.mapNavigation.enabled)) {
|
|
922
|
+
this.pinchX = this.pinchHor = this.pinchY = this.pinchVert = this.hasZoom = true;
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
|
|
926
|
+
// Extend the pinchTranslate method to preserve fixed ratio when zooming
|
|
927
|
+
wrap(Pointer.prototype, 'pinchTranslate', function (proceed, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch) {
|
|
928
|
+
var xBigger;
|
|
929
|
+
proceed.call(this, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
|
|
930
|
+
|
|
931
|
+
// Keep ratio
|
|
932
|
+
if (this.chart.options.chart.type === 'map' && this.hasZoom) {
|
|
933
|
+
xBigger = transform.scaleX > transform.scaleY;
|
|
934
|
+
this.pinchTranslateDirection(
|
|
935
|
+
!xBigger,
|
|
936
|
+
pinchDown,
|
|
937
|
+
touches,
|
|
938
|
+
transform,
|
|
939
|
+
selectionMarker,
|
|
940
|
+
clip,
|
|
941
|
+
lastValidTouch,
|
|
942
|
+
xBigger ? transform.scaleX : transform.scaleY
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
/**
|
|
950
|
+
* Extend the default options with map options
|
|
951
|
+
*/
|
|
952
|
+
defaultPlotOptions.map = merge(defaultPlotOptions.scatter, {
|
|
953
|
+
allAreas: true,
|
|
954
|
+
|
|
955
|
+
animation: false, // makes the complex shapes slow
|
|
956
|
+
nullColor: '#F8F8F8',
|
|
957
|
+
borderColor: 'silver',
|
|
958
|
+
borderWidth: 1,
|
|
959
|
+
marker: null,
|
|
960
|
+
stickyTracking: false,
|
|
961
|
+
dataLabels: {
|
|
962
|
+
formatter: function () { // #2945
|
|
963
|
+
return this.point.value;
|
|
905
964
|
},
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
965
|
+
verticalAlign: 'middle',
|
|
966
|
+
crop: false,
|
|
967
|
+
overflow: false,
|
|
968
|
+
padding: 0,
|
|
969
|
+
style: {
|
|
970
|
+
color: 'white',
|
|
971
|
+
fontWeight: 'bold',
|
|
972
|
+
HcTextStroke: '3px rgba(0,0,0,0.5)'
|
|
973
|
+
}
|
|
974
|
+
},
|
|
975
|
+
turboThreshold: 0,
|
|
976
|
+
tooltip: {
|
|
977
|
+
followPointer: true,
|
|
978
|
+
pointFormat: '{point.name}: {point.value}<br/>'
|
|
979
|
+
},
|
|
980
|
+
states: {
|
|
981
|
+
normal: {
|
|
982
|
+
animation: true
|
|
910
983
|
},
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
},
|
|
915
|
-
hover: {
|
|
916
|
-
brightness: 0.2
|
|
917
|
-
}
|
|
984
|
+
hover: {
|
|
985
|
+
brightness: 0.2,
|
|
986
|
+
halo: null
|
|
918
987
|
}
|
|
919
|
-
}
|
|
988
|
+
}
|
|
989
|
+
});
|
|
920
990
|
|
|
991
|
+
/**
|
|
992
|
+
* The MapAreaPoint object
|
|
993
|
+
*/
|
|
994
|
+
var MapAreaPoint = extendClass(Point, {
|
|
921
995
|
/**
|
|
922
|
-
*
|
|
996
|
+
* Extend the Point object to split paths
|
|
923
997
|
*/
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
series.getMapData(joinBy, point[joinBy]) : // Join by a string
|
|
939
|
-
seriesOptions.mapData[point.x]; // Use array position (faster)
|
|
940
|
-
|
|
941
|
-
if (mapPoint) {
|
|
942
|
-
// This applies only to bubbles
|
|
943
|
-
if (series.xyFromShape) {
|
|
944
|
-
point.x = mapPoint._midX;
|
|
945
|
-
point.y = mapPoint._midY;
|
|
946
|
-
}
|
|
947
|
-
extend(point, mapPoint); // copy over properties
|
|
948
|
-
} else {
|
|
949
|
-
point.value = point.value || null;
|
|
998
|
+
applyOptions: function (options, x) {
|
|
999
|
+
|
|
1000
|
+
var point = Point.prototype.applyOptions.call(this, options, x),
|
|
1001
|
+
series = this.series,
|
|
1002
|
+
joinBy = series.joinBy,
|
|
1003
|
+
mapPoint;
|
|
1004
|
+
|
|
1005
|
+
if (series.mapData) {
|
|
1006
|
+
mapPoint = point[joinBy[1]] !== undefined && series.mapMap[point[joinBy[1]]];
|
|
1007
|
+
if (mapPoint) {
|
|
1008
|
+
// This applies only to bubbles
|
|
1009
|
+
if (series.xyFromShape) {
|
|
1010
|
+
point.x = mapPoint._midX;
|
|
1011
|
+
point.y = mapPoint._midY;
|
|
950
1012
|
}
|
|
1013
|
+
extend(point, mapPoint); // copy over properties
|
|
1014
|
+
} else {
|
|
1015
|
+
point.value = point.value || null;
|
|
951
1016
|
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
return point;
|
|
1020
|
+
},
|
|
955
1021
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1022
|
+
/**
|
|
1023
|
+
* Set the visibility of a single map area
|
|
1024
|
+
*/
|
|
1025
|
+
setVisible: function (vis) {
|
|
1026
|
+
var point = this,
|
|
1027
|
+
method = vis ? 'show' : 'hide';
|
|
1028
|
+
|
|
1029
|
+
// Show and hide associated elements
|
|
1030
|
+
each(['graphic', 'dataLabel'], function (key) {
|
|
1031
|
+
if (point[key]) {
|
|
1032
|
+
point[key][method]();
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
1035
|
+
},
|
|
970
1036
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1037
|
+
/**
|
|
1038
|
+
* Stop the fade-out
|
|
1039
|
+
*/
|
|
1040
|
+
onMouseOver: function (e) {
|
|
1041
|
+
clearTimeout(this.colorInterval);
|
|
1042
|
+
if (this.value !== null) {
|
|
976
1043
|
Point.prototype.onMouseOver.call(this, e);
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1044
|
+
}
|
|
1045
|
+
},
|
|
1046
|
+
/**
|
|
1047
|
+
* Custom animation for tweening out the colors. Animation reduces blinking when hovering
|
|
1048
|
+
* over islands and coast lines. We run a custom implementation of animation becuase we
|
|
1049
|
+
* need to be able to run this independently from other animations like zoom redraw. Also,
|
|
1050
|
+
* adding color animation to the adapters would introduce almost the same amount of code.
|
|
1051
|
+
*/
|
|
1052
|
+
onMouseOut: function () {
|
|
1053
|
+
var point = this,
|
|
1054
|
+
start = +new Date(),
|
|
1055
|
+
normalColor = Color(point.color),
|
|
1056
|
+
hoverColor = Color(point.pointAttr.hover.fill),
|
|
1057
|
+
animation = point.series.options.states.normal.animation,
|
|
1058
|
+
duration = animation && (animation.duration || 500),
|
|
1059
|
+
fill;
|
|
1060
|
+
|
|
1061
|
+
if (duration && normalColor.rgba.length === 4 && hoverColor.rgba.length === 4 && point.state !== 'select') {
|
|
1062
|
+
fill = point.pointAttr[''].fill;
|
|
1063
|
+
delete point.pointAttr[''].fill; // avoid resetting it in Point.setState
|
|
1064
|
+
|
|
1065
|
+
clearTimeout(point.colorInterval);
|
|
1066
|
+
point.colorInterval = setInterval(function () {
|
|
1067
|
+
var pos = (new Date() - start) / duration,
|
|
1068
|
+
graphic = point.graphic;
|
|
1069
|
+
if (pos > 1) {
|
|
1070
|
+
pos = 1;
|
|
1071
|
+
}
|
|
1072
|
+
if (graphic) {
|
|
1073
|
+
graphic.attr('fill', ColorAxis.prototype.tweenColors.call(0, hoverColor, normalColor, pos));
|
|
1074
|
+
}
|
|
1075
|
+
if (pos >= 1) {
|
|
1076
|
+
clearTimeout(point.colorInterval);
|
|
1077
|
+
}
|
|
1078
|
+
}, 13);
|
|
1079
|
+
}
|
|
1080
|
+
Point.prototype.onMouseOut.call(point);
|
|
1012
1081
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
*/
|
|
1016
|
-
zoomTo: function () {
|
|
1017
|
-
var point = this,
|
|
1018
|
-
series = point.series;
|
|
1019
|
-
|
|
1020
|
-
series.xAxis.setExtremes(
|
|
1021
|
-
point._minX,
|
|
1022
|
-
point._maxX,
|
|
1023
|
-
false
|
|
1024
|
-
);
|
|
1025
|
-
series.yAxis.setExtremes(
|
|
1026
|
-
point._minY,
|
|
1027
|
-
point._maxY,
|
|
1028
|
-
false
|
|
1029
|
-
);
|
|
1030
|
-
series.chart.redraw();
|
|
1082
|
+
if (fill) {
|
|
1083
|
+
point.pointAttr[''].fill = fill;
|
|
1031
1084
|
}
|
|
1032
|
-
}
|
|
1085
|
+
},
|
|
1033
1086
|
|
|
1034
1087
|
/**
|
|
1035
|
-
*
|
|
1088
|
+
* Zoom the chart to view a specific area point
|
|
1036
1089
|
*/
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
parallelArrays: ['x', 'y', 'value'],
|
|
1090
|
+
zoomTo: function () {
|
|
1091
|
+
var point = this,
|
|
1092
|
+
series = point.series;
|
|
1093
|
+
|
|
1094
|
+
series.xAxis.setExtremes(
|
|
1095
|
+
point._minX,
|
|
1096
|
+
point._maxX,
|
|
1097
|
+
false
|
|
1098
|
+
);
|
|
1099
|
+
series.yAxis.setExtremes(
|
|
1100
|
+
point._minY,
|
|
1101
|
+
point._maxY,
|
|
1102
|
+
false
|
|
1103
|
+
);
|
|
1104
|
+
series.chart.redraw();
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1055
1107
|
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1108
|
+
/**
|
|
1109
|
+
* Add the series type
|
|
1110
|
+
*/
|
|
1111
|
+
seriesTypes.map = extendClass(seriesTypes.scatter, merge(colorSeriesMixin, {
|
|
1112
|
+
type: 'map',
|
|
1113
|
+
pointClass: MapAreaPoint,
|
|
1114
|
+
supportsDrilldown: true,
|
|
1115
|
+
getExtremesFromAll: true,
|
|
1116
|
+
useMapGeometry: true, // get axis extremes from paths, not values
|
|
1117
|
+
forceDL: true,
|
|
1118
|
+
/**
|
|
1119
|
+
* Get the bounding box of all paths in the map combined.
|
|
1120
|
+
*/
|
|
1121
|
+
getBox: function (paths) {
|
|
1122
|
+
var MAX_VALUE = Number.MAX_VALUE,
|
|
1123
|
+
maxX = -MAX_VALUE,
|
|
1124
|
+
minX = MAX_VALUE,
|
|
1125
|
+
maxY = -MAX_VALUE,
|
|
1126
|
+
minY = MAX_VALUE,
|
|
1127
|
+
minRange = MAX_VALUE,
|
|
1128
|
+
xAxis = this.xAxis,
|
|
1129
|
+
yAxis = this.yAxis,
|
|
1130
|
+
hasBox;
|
|
1131
|
+
|
|
1132
|
+
// Find the bounding box
|
|
1133
|
+
each(paths || [], function (point) {
|
|
1068
1134
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1135
|
+
if (point.path) {
|
|
1136
|
+
if (typeof point.path === 'string') {
|
|
1137
|
+
point.path = Highcharts.splitPath(point.path);
|
|
1138
|
+
}
|
|
1073
1139
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
even = !even;
|
|
1140
|
+
var path = point.path || [],
|
|
1141
|
+
i = path.length,
|
|
1142
|
+
even = false, // while loop reads from the end
|
|
1143
|
+
pointMaxX = -MAX_VALUE,
|
|
1144
|
+
pointMinX = MAX_VALUE,
|
|
1145
|
+
pointMaxY = -MAX_VALUE,
|
|
1146
|
+
pointMinY = MAX_VALUE,
|
|
1147
|
+
properties = point.properties;
|
|
1148
|
+
|
|
1149
|
+
// The first time a map point is used, analyze its box
|
|
1150
|
+
if (!point._foundBox) {
|
|
1151
|
+
while (i--) {
|
|
1152
|
+
if (typeof path[i] === 'number' && !isNaN(path[i])) {
|
|
1153
|
+
if (even) { // even = x
|
|
1154
|
+
pointMaxX = Math.max(pointMaxX, path[i]);
|
|
1155
|
+
pointMinX = Math.min(pointMinX, path[i]);
|
|
1156
|
+
} else { // odd = Y
|
|
1157
|
+
pointMaxY = Math.max(pointMaxY, path[i]);
|
|
1158
|
+
pointMinY = Math.min(pointMinY, path[i]);
|
|
1094
1159
|
}
|
|
1160
|
+
even = !even;
|
|
1095
1161
|
}
|
|
1096
|
-
// Cache point bounding box for use to position data labels, bubbles etc
|
|
1097
|
-
point._midX = pointMinX + (pointMaxX - pointMinX) * (point.middleX || 0.5); // pick is slower and very marginally needed
|
|
1098
|
-
point._midY = pointMinY + (pointMaxY - pointMinY) * (point.middleY || 0.5);
|
|
1099
|
-
point._maxX = pointMaxX;
|
|
1100
|
-
point._minX = pointMinX;
|
|
1101
|
-
point._maxY = pointMaxY;
|
|
1102
|
-
point._minY = pointMinY;
|
|
1103
|
-
point._foundBox = true;
|
|
1104
1162
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1163
|
+
// Cache point bounding box for use to position data labels, bubbles etc
|
|
1164
|
+
point._midX = pointMinX + (pointMaxX - pointMinX) *
|
|
1165
|
+
(point.middleX || (properties && properties['hc-middle-x']) || 0.5); // pick is slower and very marginally needed
|
|
1166
|
+
point._midY = pointMinY + (pointMaxY - pointMinY) *
|
|
1167
|
+
(point.middleY || (properties && properties['hc-middle-y']) || 0.5);
|
|
1168
|
+
point._maxX = pointMaxX;
|
|
1169
|
+
point._minX = pointMinX;
|
|
1170
|
+
point._maxY = pointMaxY;
|
|
1171
|
+
point._minY = pointMinY;
|
|
1172
|
+
point.labelrank = pick(point.labelrank, (pointMaxX - pointMinX) * (pointMaxY - pointMinY));
|
|
1173
|
+
point._foundBox = true;
|
|
1112
1174
|
}
|
|
1113
|
-
});
|
|
1114
1175
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1176
|
+
maxX = Math.max(maxX, point._maxX);
|
|
1177
|
+
minX = Math.min(minX, point._minX);
|
|
1178
|
+
maxY = Math.max(maxY, point._maxY);
|
|
1179
|
+
minY = Math.min(minY, point._minY);
|
|
1180
|
+
minRange = Math.min(point._maxX - point._minX, point._maxY - point._minY, minRange);
|
|
1181
|
+
hasBox = true;
|
|
1121
1182
|
}
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
getExtremes: function () {
|
|
1125
|
-
// Get the actual value extremes for colors
|
|
1126
|
-
Series.prototype.getExtremes.call(this, this.valueData);
|
|
1183
|
+
});
|
|
1127
1184
|
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1185
|
+
// Set the box for the whole series
|
|
1186
|
+
if (hasBox) {
|
|
1187
|
+
this.minY = Math.min(minY, pick(this.minY, MAX_VALUE));
|
|
1188
|
+
this.maxY = Math.max(maxY, pick(this.maxY, -MAX_VALUE));
|
|
1189
|
+
this.minX = Math.min(minX, pick(this.minX, MAX_VALUE));
|
|
1190
|
+
this.maxX = Math.max(maxX, pick(this.maxX, -MAX_VALUE));
|
|
1191
|
+
|
|
1192
|
+
// If no minRange option is set, set the default minimum zooming range to 5 times the
|
|
1193
|
+
// size of the smallest element
|
|
1194
|
+
if (xAxis && xAxis.options.minRange === undefined) {
|
|
1195
|
+
xAxis.minRange = Math.min(5 * minRange, (this.maxX - this.minX) / 5, xAxis.minRange || MAX_VALUE);
|
|
1196
|
+
}
|
|
1197
|
+
if (yAxis && yAxis.options.minRange === undefined) {
|
|
1198
|
+
yAxis.minRange = Math.min(5 * minRange, (this.maxY - this.minY) / 5, yAxis.minRange || MAX_VALUE);
|
|
1131
1199
|
}
|
|
1200
|
+
}
|
|
1201
|
+
},
|
|
1202
|
+
|
|
1203
|
+
getExtremes: function () {
|
|
1204
|
+
// Get the actual value extremes for colors
|
|
1205
|
+
Series.prototype.getExtremes.call(this, this.valueData);
|
|
1206
|
+
|
|
1207
|
+
// Recalculate box on updated data
|
|
1208
|
+
if (this.chart.hasRendered && this.isDirtyData) {
|
|
1209
|
+
this.getBox(this.options.data);
|
|
1210
|
+
}
|
|
1132
1211
|
|
|
1133
|
-
|
|
1134
|
-
|
|
1212
|
+
this.valueMin = this.dataMin;
|
|
1213
|
+
this.valueMax = this.dataMax;
|
|
1135
1214
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1215
|
+
// Extremes for the mock Y axis
|
|
1216
|
+
this.dataMin = this.minY;
|
|
1217
|
+
this.dataMax = this.maxY;
|
|
1218
|
+
},
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* Translate the path so that it automatically fits into the plot area box
|
|
1222
|
+
* @param {Object} path
|
|
1223
|
+
*/
|
|
1224
|
+
translatePath: function (path) {
|
|
1140
1225
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
ret[i] = even ?
|
|
1166
|
-
(path[i] - xMin) * xTransA + xMinPixelPadding :
|
|
1167
|
-
(path[i] - yMin) * yTransA + yMinPixelPadding;
|
|
1168
|
-
even = !even;
|
|
1169
|
-
} else {
|
|
1170
|
-
ret[i] = path[i];
|
|
1171
|
-
}
|
|
1226
|
+
var series = this,
|
|
1227
|
+
even = false, // while loop reads from the end
|
|
1228
|
+
xAxis = series.xAxis,
|
|
1229
|
+
yAxis = series.yAxis,
|
|
1230
|
+
xMin = xAxis.min,
|
|
1231
|
+
xTransA = xAxis.transA,
|
|
1232
|
+
xMinPixelPadding = xAxis.minPixelPadding,
|
|
1233
|
+
yMin = yAxis.min,
|
|
1234
|
+
yTransA = yAxis.transA,
|
|
1235
|
+
yMinPixelPadding = yAxis.minPixelPadding,
|
|
1236
|
+
i,
|
|
1237
|
+
ret = []; // Preserve the original
|
|
1238
|
+
|
|
1239
|
+
// Do the translation
|
|
1240
|
+
if (path) {
|
|
1241
|
+
i = path.length;
|
|
1242
|
+
while (i--) {
|
|
1243
|
+
if (typeof path[i] === 'number') {
|
|
1244
|
+
ret[i] = even ?
|
|
1245
|
+
(path[i] - xMin) * xTransA + xMinPixelPadding :
|
|
1246
|
+
(path[i] - yMin) * yTransA + yMinPixelPadding;
|
|
1247
|
+
even = !even;
|
|
1248
|
+
} else {
|
|
1249
|
+
ret[i] = path[i];
|
|
1172
1250
|
}
|
|
1173
1251
|
}
|
|
1252
|
+
}
|
|
1174
1253
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1254
|
+
return ret;
|
|
1255
|
+
},
|
|
1256
|
+
|
|
1257
|
+
/**
|
|
1258
|
+
* Extend setData to join in mapData. If the allAreas option is true, all areas
|
|
1259
|
+
* from the mapData are used, and those that don't correspond to a data value
|
|
1260
|
+
* are given null values.
|
|
1261
|
+
*/
|
|
1262
|
+
setData: function (data, redraw) {
|
|
1263
|
+
var options = this.options,
|
|
1264
|
+
mapData = options.mapData,
|
|
1265
|
+
joinBy = options.joinBy,
|
|
1266
|
+
joinByNull = joinBy === null,
|
|
1267
|
+
dataUsed = [],
|
|
1268
|
+
mapPoint,
|
|
1269
|
+
props,
|
|
1270
|
+
i;
|
|
1271
|
+
|
|
1272
|
+
if (joinByNull) {
|
|
1273
|
+
joinBy = '_i';
|
|
1274
|
+
}
|
|
1275
|
+
joinBy = this.joinBy = Highcharts.splat(joinBy);
|
|
1276
|
+
if (!joinBy[1]) {
|
|
1277
|
+
joinBy[1] = joinBy[0];
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// Pick up numeric values, add index
|
|
1281
|
+
if (data) {
|
|
1282
|
+
each(data, function (val, i) {
|
|
1283
|
+
if (typeof val === 'number') {
|
|
1284
|
+
data[i] = {
|
|
1285
|
+
value: val
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
if (joinByNull) {
|
|
1289
|
+
data[i]._i = i;
|
|
1290
|
+
}
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
this.getBox(data);
|
|
1295
|
+
if (mapData) {
|
|
1296
|
+
if (mapData.type === 'FeatureCollection') {
|
|
1297
|
+
mapData = Highcharts.geojson(mapData, this.type, this);
|
|
1298
|
+
}
|
|
1189
1299
|
|
|
1190
|
-
this.getBox(data);
|
|
1191
1300
|
this.getBox(mapData);
|
|
1192
|
-
|
|
1301
|
+
this.mapData = mapData;
|
|
1302
|
+
this.mapMap = {};
|
|
1303
|
+
|
|
1304
|
+
for (i = 0; i < mapData.length; i++) {
|
|
1305
|
+
mapPoint = mapData[i];
|
|
1306
|
+
props = mapPoint.properties;
|
|
1307
|
+
|
|
1308
|
+
mapPoint._i = i;
|
|
1309
|
+
// Copy the property over to root for faster access
|
|
1310
|
+
if (joinBy[0] && props && props[joinBy[0]]) {
|
|
1311
|
+
mapPoint[joinBy[0]] = props[joinBy[0]];
|
|
1312
|
+
}
|
|
1313
|
+
this.mapMap[mapPoint[joinBy[0]]] = mapPoint;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
if (options.allAreas) {
|
|
1193
1317
|
|
|
1194
1318
|
data = data || [];
|
|
1195
1319
|
|
|
1196
1320
|
// Registered the point codes that actually hold data
|
|
1197
|
-
if (joinBy) {
|
|
1321
|
+
if (joinBy[1]) {
|
|
1198
1322
|
each(data, function (point) {
|
|
1199
|
-
dataUsed.push(point[joinBy]);
|
|
1323
|
+
dataUsed.push(point[joinBy[1]]);
|
|
1200
1324
|
});
|
|
1201
1325
|
}
|
|
1202
1326
|
|
|
1203
1327
|
// Add those map points that don't correspond to data, which will be drawn as null points
|
|
1204
1328
|
dataUsed = '|' + dataUsed.join('|') + '|'; // String search is faster than array.indexOf
|
|
1329
|
+
|
|
1205
1330
|
each(mapData, function (mapPoint) {
|
|
1206
|
-
if (!joinBy || dataUsed.indexOf('|' + mapPoint[joinBy] + '|') === -1) {
|
|
1331
|
+
if (!joinBy[0] || dataUsed.indexOf('|' + mapPoint[joinBy[0]] + '|') === -1) {
|
|
1207
1332
|
data.push(merge(mapPoint, { value: null }));
|
|
1208
1333
|
}
|
|
1209
1334
|
});
|
|
1210
1335
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
/**
|
|
1215
|
-
* For each point, get the corresponding map data
|
|
1216
|
-
*/
|
|
1217
|
-
getMapData: function (key, value) {
|
|
1218
|
-
var options = this.options,
|
|
1219
|
-
mapData = options.mapData,
|
|
1220
|
-
mapMap = this.mapMap,
|
|
1221
|
-
i = mapData.length;
|
|
1222
|
-
|
|
1223
|
-
// Create a cache for quicker lookup second time
|
|
1224
|
-
if (!mapMap) {
|
|
1225
|
-
mapMap = this.mapMap = {};
|
|
1226
|
-
}
|
|
1227
|
-
if (mapMap[value] !== undefined) {
|
|
1228
|
-
return mapData[mapMap[value]];
|
|
1229
|
-
|
|
1230
|
-
} else if (value !== undefined) {
|
|
1231
|
-
while (i--) {
|
|
1232
|
-
if (mapData[i][key] === value) {
|
|
1233
|
-
mapMap[value] = i; // cache it
|
|
1234
|
-
return mapData[i];
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
},
|
|
1239
|
-
|
|
1240
|
-
/**
|
|
1241
|
-
* In choropleth maps, the color is a result of the value, so this needs translation too
|
|
1242
|
-
*/
|
|
1243
|
-
translateColors: function () {
|
|
1244
|
-
var series = this,
|
|
1245
|
-
nullColor = this.options.nullColor,
|
|
1246
|
-
colorAxis = this.colorAxis;
|
|
1336
|
+
}
|
|
1337
|
+
Series.prototype.setData.call(this, data, redraw);
|
|
1338
|
+
},
|
|
1247
1339
|
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1340
|
+
|
|
1341
|
+
/**
|
|
1342
|
+
* No graph for the map series
|
|
1343
|
+
*/
|
|
1344
|
+
drawGraph: noop,
|
|
1345
|
+
|
|
1346
|
+
/**
|
|
1347
|
+
* We need the points' bounding boxes in order to draw the data labels, so
|
|
1348
|
+
* we skip it now and call it from drawPoints instead.
|
|
1349
|
+
*/
|
|
1350
|
+
drawDataLabels: noop,
|
|
1251
1351
|
|
|
1252
|
-
|
|
1352
|
+
/**
|
|
1353
|
+
* Allow a quick redraw by just translating the area group. Used for zooming and panning
|
|
1354
|
+
* in capable browsers.
|
|
1355
|
+
*/
|
|
1356
|
+
doFullTranslate: function () {
|
|
1357
|
+
return this.isDirtyData || this.chart.renderer.isVML || !this.baseTrans;
|
|
1358
|
+
},
|
|
1359
|
+
|
|
1360
|
+
/**
|
|
1361
|
+
* Add the path option for data points. Find the max value for color calculation.
|
|
1362
|
+
*/
|
|
1363
|
+
translate: function () {
|
|
1364
|
+
var series = this,
|
|
1365
|
+
xAxis = series.xAxis,
|
|
1366
|
+
yAxis = series.yAxis,
|
|
1367
|
+
doFullTranslate = series.doFullTranslate();
|
|
1253
1368
|
|
|
1254
|
-
|
|
1255
|
-
point.color = point.options.color = color;
|
|
1256
|
-
}
|
|
1257
|
-
});
|
|
1258
|
-
},
|
|
1369
|
+
series.generatePoints();
|
|
1259
1370
|
|
|
1260
|
-
|
|
1261
|
-
* No graph for the map series
|
|
1262
|
-
*/
|
|
1263
|
-
drawGraph: noop,
|
|
1371
|
+
each(series.data, function (point) {
|
|
1264
1372
|
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
drawDataLabels: noop,
|
|
1270
|
-
|
|
1271
|
-
/**
|
|
1272
|
-
* Add the path option for data points. Find the max value for color calculation.
|
|
1273
|
-
*/
|
|
1274
|
-
translate: function () {
|
|
1275
|
-
var series = this,
|
|
1276
|
-
xAxis = series.xAxis,
|
|
1277
|
-
yAxis = series.yAxis;
|
|
1278
|
-
|
|
1279
|
-
series.generatePoints();
|
|
1280
|
-
|
|
1281
|
-
each(series.data, function (point) {
|
|
1282
|
-
|
|
1283
|
-
// Record the middle point (loosely based on centroid), determined
|
|
1284
|
-
// by the middleX and middleY options.
|
|
1285
|
-
point.plotX = xAxis.toPixels(point._midX, true);
|
|
1286
|
-
point.plotY = yAxis.toPixels(point._midY, true);
|
|
1373
|
+
// Record the middle point (loosely based on centroid), determined
|
|
1374
|
+
// by the middleX and middleY options.
|
|
1375
|
+
point.plotX = xAxis.toPixels(point._midX, true);
|
|
1376
|
+
point.plotY = yAxis.toPixels(point._midY, true);
|
|
1287
1377
|
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
point.shapeType = 'path';
|
|
1291
|
-
point.shapeArgs = {
|
|
1292
|
-
//d: display ? series.translatePath(point.path) : ''
|
|
1293
|
-
d: series.translatePath(point.path),
|
|
1294
|
-
'vector-effect': 'non-scaling-stroke'
|
|
1295
|
-
};
|
|
1296
|
-
}
|
|
1297
|
-
});
|
|
1298
|
-
|
|
1299
|
-
series.translateColors();
|
|
1300
|
-
},
|
|
1378
|
+
if (doFullTranslate) {
|
|
1301
1379
|
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
var series = this,
|
|
1308
|
-
xAxis = series.xAxis,
|
|
1309
|
-
yAxis = series.yAxis,
|
|
1310
|
-
scale,
|
|
1311
|
-
translateX,
|
|
1312
|
-
group = series.group,
|
|
1313
|
-
chart = series.chart,
|
|
1314
|
-
renderer = chart.renderer,
|
|
1315
|
-
translateY,
|
|
1316
|
-
getTranslate = function (axis, mapRatio) {
|
|
1317
|
-
var dataMin = axis.dataMin,
|
|
1318
|
-
dataMax = axis.dataMax,
|
|
1319
|
-
fullDataMin = dataMin - ((dataMax - dataMin) * (mapRatio - 1) / 2),
|
|
1320
|
-
fullMin = axis.min - axis.minPixelPadding / axis.transA,
|
|
1321
|
-
minOffset = fullMin - fullDataMin,
|
|
1322
|
-
centerOffset = (dataMax - dataMin - axis.max + axis.min) * mapRatio,
|
|
1323
|
-
center = minOffset / centerOffset;
|
|
1324
|
-
return (axis.len * (1 - scale)) * center;
|
|
1380
|
+
point.shapeType = 'path';
|
|
1381
|
+
point.shapeArgs = {
|
|
1382
|
+
//d: display ? series.translatePath(point.path) : ''
|
|
1383
|
+
d: series.translatePath(point.path),
|
|
1384
|
+
'vector-effect': 'non-scaling-stroke'
|
|
1325
1385
|
};
|
|
1326
|
-
|
|
1327
|
-
// Set a group that handles transform during zooming and panning in order to preserve clipping
|
|
1328
|
-
// on series.group
|
|
1329
|
-
if (!series.transformGroup) {
|
|
1330
|
-
series.transformGroup = renderer.g()
|
|
1331
|
-
.attr({
|
|
1332
|
-
scaleX: 1,
|
|
1333
|
-
scaleY: 1
|
|
1334
|
-
})
|
|
1335
|
-
.add(group);
|
|
1336
1386
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1387
|
+
});
|
|
1388
|
+
|
|
1389
|
+
series.translateColors();
|
|
1390
|
+
},
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Use the drawPoints method of column, that is able to handle simple shapeArgs.
|
|
1394
|
+
* Extend it by assigning the tooltip position.
|
|
1395
|
+
*/
|
|
1396
|
+
drawPoints: function () {
|
|
1397
|
+
var series = this,
|
|
1398
|
+
xAxis = series.xAxis,
|
|
1399
|
+
yAxis = series.yAxis,
|
|
1400
|
+
group = series.group,
|
|
1401
|
+
chart = series.chart,
|
|
1402
|
+
renderer = chart.renderer,
|
|
1403
|
+
scaleX,
|
|
1404
|
+
scaleY,
|
|
1405
|
+
translateX,
|
|
1406
|
+
translateY,
|
|
1407
|
+
baseTrans = this.baseTrans;
|
|
1408
|
+
|
|
1409
|
+
// Set a group that handles transform during zooming and panning in order to preserve clipping
|
|
1410
|
+
// on series.group
|
|
1411
|
+
if (!series.transformGroup) {
|
|
1412
|
+
series.transformGroup = renderer.g()
|
|
1413
|
+
.attr({
|
|
1414
|
+
scaleX: 1,
|
|
1415
|
+
scaleY: 1
|
|
1416
|
+
})
|
|
1417
|
+
.add(group);
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
// Draw the shapes again
|
|
1421
|
+
if (series.doFullTranslate()) {
|
|
1345
1422
|
|
|
1346
|
-
|
|
1423
|
+
// Individual point actions
|
|
1424
|
+
if (chart.hasRendered && series.pointAttrToOptions.fill === 'color') {
|
|
1347
1425
|
each(series.points, function (point) {
|
|
1348
1426
|
|
|
1349
1427
|
// Reset color on update/redraw
|
|
1350
|
-
if (
|
|
1351
|
-
point.graphic.attr('fill', point.
|
|
1428
|
+
if (point.graphic) {
|
|
1429
|
+
point.graphic.attr('fill', point.color);
|
|
1352
1430
|
}
|
|
1353
1431
|
|
|
1354
1432
|
});
|
|
1433
|
+
}
|
|
1355
1434
|
|
|
1356
|
-
|
|
1357
|
-
|
|
1435
|
+
// Draw them in transformGroup
|
|
1436
|
+
series.group = series.transformGroup;
|
|
1437
|
+
seriesTypes.column.prototype.drawPoints.apply(series);
|
|
1438
|
+
series.group = group; // Reset
|
|
1358
1439
|
|
|
1359
|
-
//
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
this.transformGroup.animate({
|
|
1373
|
-
translateX: translateX,
|
|
1374
|
-
translateY: translateY,
|
|
1375
|
-
scaleX: scale,
|
|
1376
|
-
scaleY: scale
|
|
1377
|
-
});
|
|
1440
|
+
// Add class names
|
|
1441
|
+
each(series.points, function (point) {
|
|
1442
|
+
if (point.graphic) {
|
|
1443
|
+
if (point.name) {
|
|
1444
|
+
point.graphic.addClass('highcharts-name-' + point.name.replace(' ', '-').toLowerCase());
|
|
1445
|
+
}
|
|
1446
|
+
if (point.properties && point.properties['hc-key']) {
|
|
1447
|
+
point.graphic.addClass('highcharts-key-' + point.properties['hc-key'].toLowerCase());
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
});
|
|
1378
1451
|
|
|
1379
|
-
|
|
1452
|
+
// Set the base for later scale-zooming. The originX and originY properties are the
|
|
1453
|
+
// axis values in the plot area's upper left corner.
|
|
1454
|
+
this.baseTrans = {
|
|
1455
|
+
originX: xAxis.min - xAxis.minPixelPadding / xAxis.transA,
|
|
1456
|
+
originY: yAxis.min - yAxis.minPixelPadding / yAxis.transA + (yAxis.reversed ? 0 : yAxis.len / yAxis.transA),
|
|
1457
|
+
transAX: xAxis.transA,
|
|
1458
|
+
transAY: yAxis.transA
|
|
1459
|
+
};
|
|
1380
1460
|
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1461
|
+
// Just update the scale and transform for better performance
|
|
1462
|
+
} else {
|
|
1463
|
+
scaleX = xAxis.transA / baseTrans.transAX;
|
|
1464
|
+
scaleY = yAxis.transA / baseTrans.transAY;
|
|
1465
|
+
if (scaleX > 0.99 && scaleX < 1.01 && scaleY > 0.99 && scaleY < 1.01) { // rounding errors
|
|
1466
|
+
translateX = 0;
|
|
1467
|
+
translateY = 0;
|
|
1468
|
+
scaleX = 1;
|
|
1469
|
+
scaleY = 1;
|
|
1470
|
+
|
|
1471
|
+
} else {
|
|
1472
|
+
translateX = xAxis.toPixels(baseTrans.originX, true);
|
|
1473
|
+
translateY = yAxis.toPixels(baseTrans.originY, true);
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
this.transformGroup.animate({
|
|
1477
|
+
translateX: translateX,
|
|
1478
|
+
translateY: translateY,
|
|
1479
|
+
scaleX: scaleX,
|
|
1480
|
+
scaleY: scaleY
|
|
1481
|
+
});
|
|
1386
1482
|
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
this.drawMapDataLabels();
|
|
1486
|
+
|
|
1487
|
+
|
|
1488
|
+
},
|
|
1489
|
+
|
|
1490
|
+
/**
|
|
1491
|
+
* Draw the data labels. Special for maps is the time that the data labels are drawn (after points),
|
|
1492
|
+
* and the clipping of the dataLabelsGroup.
|
|
1493
|
+
*/
|
|
1494
|
+
drawMapDataLabels: function () {
|
|
1495
|
+
|
|
1496
|
+
Series.prototype.drawDataLabels.call(this);
|
|
1497
|
+
if (this.dataLabelsGroup) {
|
|
1498
|
+
this.dataLabelsGroup.clip(this.chart.clipRect);
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
this.hideOverlappingDataLabels();
|
|
1502
|
+
},
|
|
1503
|
+
|
|
1504
|
+
/**
|
|
1505
|
+
* Hide overlapping labels. Labels are moved and faded in and out on zoom to provide a smooth
|
|
1506
|
+
* visual imression.
|
|
1507
|
+
*/
|
|
1508
|
+
hideOverlappingDataLabels: function () {
|
|
1509
|
+
|
|
1510
|
+
var points = this.points,
|
|
1511
|
+
len = points.length,
|
|
1512
|
+
i,
|
|
1513
|
+
j,
|
|
1514
|
+
label1,
|
|
1515
|
+
label2,
|
|
1516
|
+
intersectRect = function (pos1, pos2, size1, size2) {
|
|
1517
|
+
return !(
|
|
1518
|
+
pos2.x > pos1.x + size1.width ||
|
|
1519
|
+
pos2.x + size2.width < pos1.x ||
|
|
1520
|
+
pos2.y > pos1.y + size1.height ||
|
|
1521
|
+
pos2.y + size2.height < pos1.y
|
|
1522
|
+
);
|
|
1523
|
+
};
|
|
1524
|
+
|
|
1525
|
+
// Mark with initial opacity
|
|
1526
|
+
each(points, function (point, label) {
|
|
1527
|
+
label = point.dataLabel;
|
|
1528
|
+
if (label) {
|
|
1529
|
+
label.oldOpacity = label.opacity;
|
|
1530
|
+
label.newOpacity = 1;
|
|
1401
1531
|
}
|
|
1402
|
-
}
|
|
1532
|
+
});
|
|
1403
1533
|
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
yAxis = this.yAxis,
|
|
1414
|
-
left = xAxis.pos,
|
|
1415
|
-
top = yAxis.pos;
|
|
1416
|
-
|
|
1417
|
-
if (chart.renderer.isSVG) {
|
|
1418
|
-
|
|
1419
|
-
if (animation === true) {
|
|
1420
|
-
animation = {
|
|
1421
|
-
duration: 1000
|
|
1422
|
-
};
|
|
1534
|
+
// Detect overlapping labels
|
|
1535
|
+
for (i = 0; i < len - 1; ++i) {
|
|
1536
|
+
label1 = points[i].dataLabel;
|
|
1537
|
+
|
|
1538
|
+
for (j = i + 1; j < len; ++j) {
|
|
1539
|
+
label2 = points[j].dataLabel;
|
|
1540
|
+
if (label1 && label2 && label1.newOpacity !== 0 && label2.newOpacity !== 0 &&
|
|
1541
|
+
intersectRect(label1.alignAttr, label2.alignAttr, label1, label2)) {
|
|
1542
|
+
(points[i].labelrank < points[j].labelrank ? label1 : label2).newOpacity = 0;
|
|
1423
1543
|
}
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
scaleY: 0.001
|
|
1434
|
-
});
|
|
1435
|
-
|
|
1436
|
-
// Run the animation
|
|
1437
|
-
} else {
|
|
1438
|
-
group.animate({
|
|
1439
|
-
translateX: left,
|
|
1440
|
-
translateY: top,
|
|
1441
|
-
scaleX: 1,
|
|
1442
|
-
scaleY: 1
|
|
1443
|
-
}, animation);
|
|
1444
|
-
|
|
1445
|
-
// Delete this function to allow it only once
|
|
1446
|
-
this.animate = null;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
// Hide or show
|
|
1548
|
+
each(points, function (point, label) {
|
|
1549
|
+
label = point.dataLabel;
|
|
1550
|
+
if (label) {
|
|
1551
|
+
if (label.oldOpacity !== label.newOpacity) {
|
|
1552
|
+
label[label.isOld ? 'animate' : 'attr'](extend({ opacity: label.newOpacity }, label.alignAttr));
|
|
1447
1553
|
}
|
|
1554
|
+
label.isOld = true;
|
|
1448
1555
|
}
|
|
1449
|
-
}
|
|
1556
|
+
});
|
|
1557
|
+
},
|
|
1450
1558
|
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1559
|
+
/**
|
|
1560
|
+
* Override render to throw in an async call in IE8. Otherwise it chokes on the US counties demo.
|
|
1561
|
+
*/
|
|
1562
|
+
render: function () {
|
|
1563
|
+
var series = this,
|
|
1564
|
+
render = Series.prototype.render;
|
|
1565
|
+
|
|
1566
|
+
// Give IE8 some time to breathe.
|
|
1567
|
+
if (series.chart.renderer.isVML && series.data.length > 3000) {
|
|
1568
|
+
setTimeout(function () {
|
|
1569
|
+
render.call(series);
|
|
1570
|
+
});
|
|
1571
|
+
} else {
|
|
1572
|
+
render.call(series);
|
|
1573
|
+
}
|
|
1574
|
+
},
|
|
1575
|
+
|
|
1576
|
+
/**
|
|
1577
|
+
* The initial animation for the map series. By default, animation is disabled.
|
|
1578
|
+
* Animation of map shapes is not at all supported in VML browsers.
|
|
1579
|
+
*/
|
|
1580
|
+
animate: function (init) {
|
|
1581
|
+
var chart = this.chart,
|
|
1582
|
+
animation = this.options.animation,
|
|
1583
|
+
group = this.group,
|
|
1584
|
+
xAxis = this.xAxis,
|
|
1585
|
+
yAxis = this.yAxis,
|
|
1586
|
+
left = xAxis.pos,
|
|
1587
|
+
top = yAxis.pos;
|
|
1588
|
+
|
|
1589
|
+
if (chart.renderer.isSVG) {
|
|
1590
|
+
|
|
1591
|
+
if (animation === true) {
|
|
1592
|
+
animation = {
|
|
1593
|
+
duration: 1000
|
|
1470
1594
|
};
|
|
1471
|
-
|
|
1472
|
-
// TODO: Animate this.group instead
|
|
1473
|
-
each(this.points, function (point) {
|
|
1474
|
-
|
|
1475
|
-
point.graphic
|
|
1476
|
-
.attr(level.shapeArgs)
|
|
1477
|
-
.animate({
|
|
1478
|
-
scaleX: 1,
|
|
1479
|
-
scaleY: 1,
|
|
1480
|
-
translateX: 0,
|
|
1481
|
-
translateY: 0
|
|
1482
|
-
}, animationOptions);
|
|
1595
|
+
}
|
|
1483
1596
|
|
|
1597
|
+
// Initialize the animation
|
|
1598
|
+
if (init) {
|
|
1599
|
+
|
|
1600
|
+
// Scale down the group and place it in the center
|
|
1601
|
+
group.attr({
|
|
1602
|
+
translateX: left + xAxis.len / 2,
|
|
1603
|
+
translateY: top + yAxis.len / 2,
|
|
1604
|
+
scaleX: 0.001, // #1499
|
|
1605
|
+
scaleY: 0.001
|
|
1484
1606
|
});
|
|
1485
|
-
|
|
1607
|
+
|
|
1608
|
+
// Run the animation
|
|
1609
|
+
} else {
|
|
1610
|
+
group.animate({
|
|
1611
|
+
translateX: left,
|
|
1612
|
+
translateY: top,
|
|
1613
|
+
scaleX: 1,
|
|
1614
|
+
scaleY: 1
|
|
1615
|
+
}, animation);
|
|
1616
|
+
|
|
1617
|
+
// Delete this function to allow it only once
|
|
1486
1618
|
this.animate = null;
|
|
1487
1619
|
}
|
|
1488
|
-
|
|
1489
|
-
|
|
1620
|
+
}
|
|
1621
|
+
},
|
|
1490
1622
|
|
|
1491
|
-
|
|
1623
|
+
/**
|
|
1624
|
+
* Animate in the new series from the clicked point in the old series.
|
|
1625
|
+
* Depends on the drilldown.js module
|
|
1626
|
+
*/
|
|
1627
|
+
animateDrilldown: function (init) {
|
|
1628
|
+
var toBox = this.chart.plotBox,
|
|
1629
|
+
level = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1],
|
|
1630
|
+
fromBox = level.bBox,
|
|
1631
|
+
animationOptions = this.chart.options.drilldown.animation,
|
|
1632
|
+
scale;
|
|
1633
|
+
|
|
1634
|
+
if (!init) {
|
|
1635
|
+
|
|
1636
|
+
scale = Math.min(fromBox.width / toBox.width, fromBox.height / toBox.height);
|
|
1637
|
+
level.shapeArgs = {
|
|
1638
|
+
scaleX: scale,
|
|
1639
|
+
scaleY: scale,
|
|
1640
|
+
translateX: fromBox.x,
|
|
1641
|
+
translateY: fromBox.y
|
|
1642
|
+
};
|
|
1643
|
+
|
|
1644
|
+
// TODO: Animate this.group instead
|
|
1645
|
+
each(this.points, function (point) {
|
|
1492
1646
|
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1647
|
+
point.graphic
|
|
1648
|
+
.attr(level.shapeArgs)
|
|
1649
|
+
.animate({
|
|
1650
|
+
scaleX: 1,
|
|
1651
|
+
scaleY: 1,
|
|
1652
|
+
translateX: 0,
|
|
1653
|
+
translateY: 0
|
|
1654
|
+
}, animationOptions);
|
|
1500
1655
|
|
|
1656
|
+
});
|
|
1501
1657
|
|
|
1502
|
-
|
|
1503
|
-
* When drilling up, keep the upper series invisible until the lower series has
|
|
1504
|
-
* moved into place
|
|
1505
|
-
*/
|
|
1506
|
-
animateDrillupTo: function (init) {
|
|
1507
|
-
seriesTypes.column.prototype.animateDrillupTo.call(this, init);
|
|
1658
|
+
this.animate = null;
|
|
1508
1659
|
}
|
|
1509
|
-
|
|
1660
|
+
|
|
1661
|
+
},
|
|
1510
1662
|
|
|
1663
|
+
drawLegendSymbol: LegendSymbolMixin.drawRectangle,
|
|
1511
1664
|
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1665
|
+
/**
|
|
1666
|
+
* When drilling up, pull out the individual point graphics from the lower series
|
|
1667
|
+
* and animate them into the origin point in the upper series.
|
|
1668
|
+
*/
|
|
1669
|
+
animateDrillupFrom: function (level) {
|
|
1670
|
+
seriesTypes.column.prototype.animateDrillupFrom.call(this, level);
|
|
1671
|
+
},
|
|
1672
|
+
|
|
1673
|
+
|
|
1674
|
+
/**
|
|
1675
|
+
* When drilling up, keep the upper series invisible until the lower series has
|
|
1676
|
+
* moved into place
|
|
1677
|
+
*/
|
|
1678
|
+
animateDrillupTo: function (init) {
|
|
1679
|
+
seriesTypes.column.prototype.animateDrillupTo.call(this, init);
|
|
1680
|
+
}
|
|
1681
|
+
}));
|
|
1682
|
+
|
|
1683
|
+
|
|
1684
|
+
// The mapline series type
|
|
1685
|
+
defaultPlotOptions.mapline = merge(defaultPlotOptions.map, {
|
|
1686
|
+
lineWidth: 1,
|
|
1687
|
+
fillColor: 'none'
|
|
1688
|
+
});
|
|
1689
|
+
seriesTypes.mapline = extendClass(seriesTypes.map, {
|
|
1690
|
+
type: 'mapline',
|
|
1691
|
+
pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
|
|
1692
|
+
stroke: 'color',
|
|
1693
|
+
'stroke-width': 'lineWidth',
|
|
1694
|
+
fill: 'fillColor',
|
|
1695
|
+
dashstyle: 'dashStyle'
|
|
1696
|
+
},
|
|
1697
|
+
drawLegendSymbol: seriesTypes.line.prototype.drawLegendSymbol
|
|
1698
|
+
});
|
|
1699
|
+
|
|
1700
|
+
// The mappoint series type
|
|
1701
|
+
defaultPlotOptions.mappoint = merge(defaultPlotOptions.scatter, {
|
|
1702
|
+
dataLabels: {
|
|
1703
|
+
enabled: true,
|
|
1704
|
+
formatter: function () { // #2945
|
|
1705
|
+
return this.point.name;
|
|
1523
1706
|
},
|
|
1524
|
-
|
|
1525
|
-
|
|
1707
|
+
color: 'black',
|
|
1708
|
+
crop: false,
|
|
1709
|
+
defer: false,
|
|
1710
|
+
overflow: false,
|
|
1711
|
+
style: {
|
|
1712
|
+
HcTextStroke: '3px rgba(255,255,255,0.5)'
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
});
|
|
1716
|
+
seriesTypes.mappoint = extendClass(seriesTypes.scatter, {
|
|
1717
|
+
type: 'mappoint',
|
|
1718
|
+
forceDL: true
|
|
1719
|
+
});
|
|
1526
1720
|
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
textShadow: '0 0 5px white'
|
|
1535
|
-
}
|
|
1721
|
+
// The mapbubble series type
|
|
1722
|
+
if (seriesTypes.bubble) {
|
|
1723
|
+
|
|
1724
|
+
defaultPlotOptions.mapbubble = merge(defaultPlotOptions.bubble, {
|
|
1725
|
+
animationLimit: 500,
|
|
1726
|
+
tooltip: {
|
|
1727
|
+
pointFormat: '{point.name}: {point.z}'
|
|
1536
1728
|
}
|
|
1537
1729
|
});
|
|
1538
|
-
seriesTypes.
|
|
1539
|
-
|
|
1730
|
+
seriesTypes.mapbubble = extendClass(seriesTypes.bubble, {
|
|
1731
|
+
pointClass: extendClass(Point, {
|
|
1732
|
+
applyOptions: MapAreaPoint.prototype.applyOptions
|
|
1733
|
+
}),
|
|
1734
|
+
xyFromShape: true,
|
|
1735
|
+
type: 'mapbubble',
|
|
1736
|
+
pointArrayMap: ['z'], // If one single value is passed, it is interpreted as z
|
|
1737
|
+
/**
|
|
1738
|
+
* Return the map area identified by the dataJoinBy option
|
|
1739
|
+
*/
|
|
1740
|
+
getMapData: seriesTypes.map.prototype.getMapData,
|
|
1741
|
+
getBox: seriesTypes.map.prototype.getBox,
|
|
1742
|
+
setData: seriesTypes.map.prototype.setData
|
|
1540
1743
|
});
|
|
1744
|
+
}
|
|
1541
1745
|
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
return ['M', x + rTopLeft, y,
|
|
1574
|
-
// top side
|
|
1575
|
-
'L', x + w - rTopRight, y,
|
|
1576
|
-
// top right corner
|
|
1577
|
-
'C', x + w - rTopRight / 2, y, x + w, y + rTopRight / 2, x + w, y + rTopRight,
|
|
1578
|
-
// right side
|
|
1579
|
-
'L', x + w, y + h - rBottomRight,
|
|
1580
|
-
// bottom right corner
|
|
1581
|
-
'C', x + w, y + h - rBottomRight / 2, x + w - rBottomRight / 2, y + h, x + w - rBottomRight, y + h,
|
|
1582
|
-
// bottom side
|
|
1583
|
-
'L', x + rBottomLeft, y + h,
|
|
1584
|
-
// bottom left corner
|
|
1585
|
-
'C', x + rBottomLeft / 2, y + h, x, y + h - rBottomLeft / 2, x, y + h - rBottomLeft,
|
|
1586
|
-
// left side
|
|
1587
|
-
'L', x, y + rTopLeft,
|
|
1588
|
-
// top left corner
|
|
1589
|
-
'C', x, y + rTopLeft / 2, x + rTopLeft / 2, y, x + rTopLeft, y,
|
|
1590
|
-
'Z'
|
|
1591
|
-
];
|
|
1746
|
+
/**
|
|
1747
|
+
* Extend the default options with map options
|
|
1748
|
+
*/
|
|
1749
|
+
defaultOptions.plotOptions.heatmap = merge(defaultOptions.plotOptions.scatter, {
|
|
1750
|
+
animation: false,
|
|
1751
|
+
borderWidth: 0,
|
|
1752
|
+
nullColor: '#F8F8F8',
|
|
1753
|
+
dataLabels: {
|
|
1754
|
+
formatter: function () { // #2945
|
|
1755
|
+
return this.point.value;
|
|
1756
|
+
},
|
|
1757
|
+
verticalAlign: 'middle',
|
|
1758
|
+
crop: false,
|
|
1759
|
+
overflow: false,
|
|
1760
|
+
style: {
|
|
1761
|
+
color: 'white',
|
|
1762
|
+
fontWeight: 'bold',
|
|
1763
|
+
HcTextStroke: '1px rgba(0,0,0,0.5)'
|
|
1764
|
+
}
|
|
1765
|
+
},
|
|
1766
|
+
marker: null,
|
|
1767
|
+
tooltip: {
|
|
1768
|
+
pointFormat: '{point.x}, {point.y}: {point.value}<br/>'
|
|
1769
|
+
},
|
|
1770
|
+
states: {
|
|
1771
|
+
normal: {
|
|
1772
|
+
animation: true
|
|
1773
|
+
},
|
|
1774
|
+
hover: {
|
|
1775
|
+
brightness: 0.2
|
|
1776
|
+
}
|
|
1592
1777
|
}
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1778
|
+
});
|
|
1779
|
+
|
|
1780
|
+
// The Heatmap series type
|
|
1781
|
+
seriesTypes.heatmap = extendClass(seriesTypes.scatter, merge(colorSeriesMixin, {
|
|
1782
|
+
type: 'heatmap',
|
|
1783
|
+
pointArrayMap: ['y', 'value'],
|
|
1784
|
+
hasPointSpecificOptions: true,
|
|
1785
|
+
supportsDrilldown: true,
|
|
1786
|
+
getExtremesFromAll: true,
|
|
1787
|
+
init: function () {
|
|
1788
|
+
seriesTypes.scatter.prototype.init.apply(this, arguments);
|
|
1789
|
+
this.pointRange = this.options.colsize || 1;
|
|
1790
|
+
this.yAxis.axisPointRange = this.options.rowsize || 1; // general point range
|
|
1791
|
+
},
|
|
1792
|
+
translate: function () {
|
|
1793
|
+
var series = this,
|
|
1794
|
+
options = series.options,
|
|
1795
|
+
xAxis = series.xAxis,
|
|
1796
|
+
yAxis = series.yAxis;
|
|
1797
|
+
|
|
1798
|
+
series.generatePoints();
|
|
1799
|
+
|
|
1800
|
+
each(series.points, function (point) {
|
|
1801
|
+
var xPad = (options.colsize || 1) / 2,
|
|
1802
|
+
yPad = (options.rowsize || 1) / 2,
|
|
1803
|
+
x1 = Math.round(xAxis.len - xAxis.translate(point.x - xPad, 0, 1, 0, 1)),
|
|
1804
|
+
x2 = Math.round(xAxis.len - xAxis.translate(point.x + xPad, 0, 1, 0, 1)),
|
|
1805
|
+
y1 = Math.round(yAxis.translate(point.y - yPad, 0, 1, 0, 1)),
|
|
1806
|
+
y2 = Math.round(yAxis.translate(point.y + yPad, 0, 1, 0, 1));
|
|
1807
|
+
|
|
1808
|
+
// Set plotX and plotY for use in K-D-Tree and more
|
|
1809
|
+
point.plotX = (x1 + x2) / 2;
|
|
1810
|
+
point.plotY = (y1 + y2) / 2;
|
|
1811
|
+
|
|
1812
|
+
point.shapeType = 'rect';
|
|
1813
|
+
point.shapeArgs = {
|
|
1814
|
+
x: Math.min(x1, x2),
|
|
1815
|
+
y: Math.min(y1, y2),
|
|
1816
|
+
width: Math.abs(x2 - x1),
|
|
1817
|
+
height: Math.abs(y2 - y1)
|
|
1818
|
+
};
|
|
1605
1819
|
});
|
|
1820
|
+
|
|
1821
|
+
series.translateColors();
|
|
1822
|
+
|
|
1823
|
+
// Make sure colors are updated on colorAxis update (#2893)
|
|
1824
|
+
if (this.chart.hasRendered) {
|
|
1825
|
+
each(series.points, function (point) {
|
|
1826
|
+
point.shapeArgs.fill = point.options.color || point.color; // #3311
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1829
|
+
},
|
|
1830
|
+
drawPoints: seriesTypes.column.prototype.drawPoints,
|
|
1831
|
+
animate: noop,
|
|
1832
|
+
getBox: noop,
|
|
1833
|
+
drawLegendSymbol: LegendSymbolMixin.drawRectangle,
|
|
1834
|
+
|
|
1835
|
+
getExtremes: function () {
|
|
1836
|
+
// Get the extremes from the value data
|
|
1837
|
+
Series.prototype.getExtremes.call(this, this.valueData);
|
|
1838
|
+
this.valueMin = this.dataMin;
|
|
1839
|
+
this.valueMax = this.dataMax;
|
|
1840
|
+
|
|
1841
|
+
// Get the extremes from the y data
|
|
1842
|
+
Series.prototype.getExtremes.call(this);
|
|
1606
1843
|
}
|
|
1844
|
+
|
|
1845
|
+
}));
|
|
1846
|
+
|
|
1607
1847
|
|
|
1848
|
+
/**
|
|
1849
|
+
* Convert a geojson object to map data of a given Highcharts type (map, mappoint or mapline).
|
|
1850
|
+
*/
|
|
1851
|
+
Highcharts.geojson = function (geojson, hType, series) {
|
|
1852
|
+
var mapData = [],
|
|
1853
|
+
path = [],
|
|
1854
|
+
polygonToPath = function (polygon) {
|
|
1855
|
+
var i = 0,
|
|
1856
|
+
len = polygon.length;
|
|
1857
|
+
path.push('M');
|
|
1858
|
+
for (; i < len; i++) {
|
|
1859
|
+
if (i === 1) {
|
|
1860
|
+
path.push('L');
|
|
1861
|
+
}
|
|
1862
|
+
path.push(polygon[i][0], -polygon[i][1]);
|
|
1863
|
+
}
|
|
1864
|
+
};
|
|
1865
|
+
|
|
1866
|
+
hType = hType || 'map';
|
|
1608
1867
|
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1868
|
+
each(geojson.features, function (feature) {
|
|
1869
|
+
|
|
1870
|
+
var geometry = feature.geometry,
|
|
1871
|
+
type = geometry.type,
|
|
1872
|
+
coordinates = geometry.coordinates,
|
|
1873
|
+
properties = feature.properties,
|
|
1874
|
+
point;
|
|
1613
1875
|
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1876
|
+
path = [];
|
|
1877
|
+
|
|
1878
|
+
if (hType === 'map' || hType === 'mapbubble') {
|
|
1879
|
+
if (type === 'Polygon') {
|
|
1880
|
+
each(coordinates, polygonToPath);
|
|
1881
|
+
path.push('Z');
|
|
1882
|
+
|
|
1883
|
+
} else if (type === 'MultiPolygon') {
|
|
1884
|
+
each(coordinates, function (items) {
|
|
1885
|
+
each(items, polygonToPath);
|
|
1886
|
+
});
|
|
1887
|
+
path.push('Z');
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
if (path.length) {
|
|
1891
|
+
point = { path: path };
|
|
1892
|
+
}
|
|
1627
1893
|
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1894
|
+
} else if (hType === 'mapline') {
|
|
1895
|
+
if (type === 'LineString') {
|
|
1896
|
+
polygonToPath(coordinates);
|
|
1897
|
+
} else if (type === 'MultiLineString') {
|
|
1898
|
+
each(coordinates, polygonToPath);
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
if (path.length) {
|
|
1902
|
+
point = { path: path };
|
|
1903
|
+
}
|
|
1631
1904
|
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1905
|
+
} else if (hType === 'mappoint') {
|
|
1906
|
+
if (type === 'Point') {
|
|
1907
|
+
point = {
|
|
1908
|
+
x: coordinates[0],
|
|
1909
|
+
y: -coordinates[1]
|
|
1910
|
+
};
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
if (point) {
|
|
1914
|
+
mapData.push(extend(point, {
|
|
1915
|
+
name: properties.name || properties.NAME,
|
|
1916
|
+
properties: properties
|
|
1917
|
+
}));
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
});
|
|
1921
|
+
|
|
1922
|
+
// Create a credits text that includes map source, to be picked up in Chart.showCredits
|
|
1923
|
+
if (series) {
|
|
1924
|
+
series.chart.mapCredits = '<a href="http://www.highcharts.com">Highcharts</a> \u00A9 ' +
|
|
1925
|
+
'<a href="' + geojson.copyrightUrl + '">' + geojson.copyrightShort + '</a>';
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
return mapData;
|
|
1929
|
+
};
|
|
1930
|
+
|
|
1931
|
+
/**
|
|
1932
|
+
* Override showCredits to include map source by default
|
|
1933
|
+
*/
|
|
1934
|
+
wrap(Chart.prototype, 'showCredits', function (proceed, credits) {
|
|
1935
|
+
|
|
1936
|
+
if (defaultOptions.credits.text === this.options.credits.text && this.mapCredits) { // default text and mapCredits is set
|
|
1937
|
+
credits.text = this.mapCredits;
|
|
1938
|
+
credits.href = null;
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
proceed.call(this, credits);
|
|
1942
|
+
});
|
|
1943
|
+
|
|
1944
|
+
// Add language
|
|
1945
|
+
extend(defaultOptions.lang, {
|
|
1946
|
+
zoomIn: 'Zoom in',
|
|
1947
|
+
zoomOut: 'Zoom out'
|
|
1948
|
+
});
|
|
1949
|
+
|
|
1950
|
+
|
|
1951
|
+
// Set the default map navigation options
|
|
1952
|
+
defaultOptions.mapNavigation = {
|
|
1953
|
+
buttonOptions: {
|
|
1954
|
+
alignTo: 'plotBox',
|
|
1955
|
+
align: 'left',
|
|
1956
|
+
verticalAlign: 'top',
|
|
1957
|
+
x: 0,
|
|
1958
|
+
width: 18,
|
|
1959
|
+
height: 18,
|
|
1960
|
+
style: {
|
|
1961
|
+
fontSize: '15px',
|
|
1962
|
+
fontWeight: 'bold',
|
|
1963
|
+
textAlign: 'center'
|
|
1964
|
+
},
|
|
1965
|
+
theme: {
|
|
1966
|
+
'stroke-width': 1
|
|
1967
|
+
}
|
|
1968
|
+
},
|
|
1969
|
+
buttons: {
|
|
1970
|
+
zoomIn: {
|
|
1971
|
+
onclick: function () {
|
|
1972
|
+
this.mapZoom(0.5);
|
|
1636
1973
|
},
|
|
1637
|
-
|
|
1638
|
-
|
|
1974
|
+
text: '+',
|
|
1975
|
+
y: 0
|
|
1639
1976
|
},
|
|
1640
|
-
|
|
1977
|
+
zoomOut: {
|
|
1978
|
+
onclick: function () {
|
|
1979
|
+
this.mapZoom(2);
|
|
1980
|
+
},
|
|
1981
|
+
text: '-',
|
|
1982
|
+
y: 28
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
// enabled: false,
|
|
1986
|
+
// enableButtons: null, // inherit from enabled
|
|
1987
|
+
// enableTouchZoom: null, // inherit from enabled
|
|
1988
|
+
// enableDoubleClickZoom: null, // inherit from enabled
|
|
1989
|
+
// enableDoubleClickZoomTo: false
|
|
1990
|
+
// enableMouseWheelZoom: null, // inherit from enabled
|
|
1991
|
+
};
|
|
1992
|
+
|
|
1993
|
+
/**
|
|
1994
|
+
* Utility for reading SVG paths directly.
|
|
1995
|
+
*/
|
|
1996
|
+
Highcharts.splitPath = function (path) {
|
|
1997
|
+
var i;
|
|
1998
|
+
|
|
1999
|
+
// Move letters apart
|
|
2000
|
+
path = path.replace(/([A-Za-z])/g, ' $1 ');
|
|
2001
|
+
// Trim
|
|
2002
|
+
path = path.replace(/^\s*/, "").replace(/\s*$/, "");
|
|
1641
2003
|
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
inverted: false,
|
|
1645
|
-
alignTicks: false,
|
|
1646
|
-
preserveAspectRatio: true
|
|
1647
|
-
}
|
|
1648
|
-
});
|
|
2004
|
+
// Split on spaces and commas
|
|
2005
|
+
path = path.split(/[ ,]+/);
|
|
1649
2006
|
|
|
1650
|
-
|
|
2007
|
+
// Parse numbers
|
|
2008
|
+
for (i = 0; i < path.length; i++) {
|
|
2009
|
+
if (!/[a-zA-Z]/.test(path[i])) {
|
|
2010
|
+
path[i] = parseFloat(path[i]);
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
return path;
|
|
2014
|
+
};
|
|
2015
|
+
|
|
2016
|
+
// A placeholder for map definitions
|
|
2017
|
+
Highcharts.maps = {};
|
|
2018
|
+
|
|
2019
|
+
|
|
2020
|
+
|
|
2021
|
+
|
|
2022
|
+
|
|
2023
|
+
// Create symbols for the zoom buttons
|
|
2024
|
+
function selectiveRoundedRect(attr, x, y, w, h, rTopLeft, rTopRight, rBottomRight, rBottomLeft) {
|
|
2025
|
+
var normalize = (attr['stroke-width'] % 2 / 2);
|
|
2026
|
+
|
|
2027
|
+
x -= normalize;
|
|
2028
|
+
y -= normalize;
|
|
2029
|
+
|
|
2030
|
+
return ['M', x + rTopLeft, y,
|
|
2031
|
+
// top side
|
|
2032
|
+
'L', x + w - rTopRight, y,
|
|
2033
|
+
// top right corner
|
|
2034
|
+
'C', x + w - rTopRight / 2, y, x + w, y + rTopRight / 2, x + w, y + rTopRight,
|
|
2035
|
+
// right side
|
|
2036
|
+
'L', x + w, y + h - rBottomRight,
|
|
2037
|
+
// bottom right corner
|
|
2038
|
+
'C', x + w, y + h - rBottomRight / 2, x + w - rBottomRight / 2, y + h, x + w - rBottomRight, y + h,
|
|
2039
|
+
// bottom side
|
|
2040
|
+
'L', x + rBottomLeft, y + h,
|
|
2041
|
+
// bottom left corner
|
|
2042
|
+
'C', x + rBottomLeft / 2, y + h, x, y + h - rBottomLeft / 2, x, y + h - rBottomLeft,
|
|
2043
|
+
// left side
|
|
2044
|
+
'L', x, y + rTopLeft,
|
|
2045
|
+
// top left corner
|
|
2046
|
+
'C', x, y + rTopLeft / 2, x + rTopLeft / 2, y, x + rTopLeft, y,
|
|
2047
|
+
'Z'
|
|
2048
|
+
];
|
|
2049
|
+
}
|
|
2050
|
+
SVGRenderer.prototype.symbols.topbutton = function (x, y, w, h, attr) {
|
|
2051
|
+
return selectiveRoundedRect(attr, x, y, w, h, attr.r, attr.r, 0, 0);
|
|
2052
|
+
};
|
|
2053
|
+
SVGRenderer.prototype.symbols.bottombutton = function (x, y, w, h, attr) {
|
|
2054
|
+
return selectiveRoundedRect(attr, x, y, w, h, 0, 0, attr.r, attr.r);
|
|
2055
|
+
};
|
|
2056
|
+
// The symbol callbacks are generated on the SVGRenderer object in all browsers. Even
|
|
2057
|
+
// VML browsers need this in order to generate shapes in export. Now share
|
|
2058
|
+
// them with the VMLRenderer.
|
|
2059
|
+
if (Renderer === VMLRenderer) {
|
|
2060
|
+
each(['topbutton', 'bottombutton'], function (shape) {
|
|
2061
|
+
VMLRenderer.prototype.symbols[shape] = SVGRenderer.prototype.symbols[shape];
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
|
|
2066
|
+
/**
|
|
2067
|
+
* A wrapper for Chart with all the default values for a Map
|
|
2068
|
+
*/
|
|
2069
|
+
Highcharts.Map = function (options, callback) {
|
|
1651
2070
|
|
|
2071
|
+
var hiddenAxis = {
|
|
2072
|
+
endOnTick: false,
|
|
2073
|
+
gridLineWidth: 0,
|
|
2074
|
+
lineWidth: 0,
|
|
2075
|
+
minPadding: 0,
|
|
2076
|
+
maxPadding: 0,
|
|
2077
|
+
startOnTick: false,
|
|
2078
|
+
title: null,
|
|
2079
|
+
tickPositions: []
|
|
2080
|
+
},
|
|
2081
|
+
seriesOptions;
|
|
2082
|
+
|
|
2083
|
+
/* For visual testing
|
|
2084
|
+
hiddenAxis.gridLineWidth = 1;
|
|
2085
|
+
hiddenAxis.gridZIndex = 10;
|
|
2086
|
+
hiddenAxis.tickPositions = undefined;
|
|
2087
|
+
// */
|
|
1652
2088
|
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
2089
|
+
// Don't merge the data
|
|
2090
|
+
seriesOptions = options.series;
|
|
2091
|
+
options.series = null;
|
|
1656
2092
|
|
|
2093
|
+
options = merge({
|
|
2094
|
+
chart: {
|
|
2095
|
+
panning: 'xy',
|
|
2096
|
+
type: 'map'
|
|
2097
|
+
},
|
|
2098
|
+
xAxis: hiddenAxis,
|
|
2099
|
+
yAxis: merge(hiddenAxis, { reversed: true })
|
|
2100
|
+
},
|
|
2101
|
+
options, // user's options
|
|
2102
|
+
|
|
2103
|
+
{ // forced options
|
|
2104
|
+
chart: {
|
|
2105
|
+
inverted: false,
|
|
2106
|
+
alignTicks: false,
|
|
2107
|
+
preserveAspectRatio: true
|
|
2108
|
+
}
|
|
2109
|
+
});
|
|
2110
|
+
|
|
2111
|
+
options.series = seriesOptions;
|
|
2112
|
+
|
|
2113
|
+
|
|
2114
|
+
return new Chart(options, callback);
|
|
2115
|
+
};
|
|
2116
|
+
|
|
2117
|
+
}(Highcharts));
|