highcharts-rails 4.2.7 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +34 -0
- data/Gemfile +4 -0
- data/Rakefile +53 -32
- data/app/assets/javascripts/highcharts.js +18775 -17176
- data/app/assets/javascripts/highcharts/highcharts-3d.js +1849 -1563
- data/app/assets/javascripts/highcharts/highcharts-more.js +2162 -1988
- data/app/assets/javascripts/highcharts/modules/accessibility.js +1005 -0
- data/app/assets/javascripts/highcharts/modules/annotations.js +408 -401
- data/app/assets/javascripts/highcharts/modules/boost.js +561 -546
- data/app/assets/javascripts/highcharts/modules/broken-axis.js +330 -324
- data/app/assets/javascripts/highcharts/modules/data.js +973 -965
- data/app/assets/javascripts/highcharts/modules/drilldown.js +783 -723
- data/app/assets/javascripts/highcharts/modules/exporting.js +864 -785
- data/app/assets/javascripts/highcharts/modules/funnel.js +290 -306
- data/app/assets/javascripts/highcharts/modules/heatmap.js +701 -645
- data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +150 -132
- data/app/assets/javascripts/highcharts/modules/offline-exporting.js +414 -355
- data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +164 -0
- data/app/assets/javascripts/highcharts/modules/series-label.js +473 -448
- data/app/assets/javascripts/highcharts/modules/solid-gauge.js +279 -271
- data/app/assets/javascripts/highcharts/modules/treemap.js +921 -886
- data/app/assets/javascripts/highcharts/themes/dark-blue.js +307 -244
- data/app/assets/javascripts/highcharts/themes/dark-green.js +303 -244
- data/app/assets/javascripts/highcharts/themes/dark-unica.js +231 -201
- data/app/assets/javascripts/highcharts/themes/gray.js +314 -245
- data/app/assets/javascripts/highcharts/themes/grid-light.js +91 -66
- data/app/assets/javascripts/highcharts/themes/grid.js +124 -96
- data/app/assets/javascripts/highcharts/themes/sand-signika.js +119 -94
- data/app/assets/javascripts/highcharts/themes/skies.js +108 -85
- data/lib/highcharts/version.rb +1 -1
- metadata +13 -14
- data/app/assets/javascripts/highcharts/adapters/standalone-framework.js +0 -1
- data/app/assets/javascripts/highcharts/modules/canvas-tools.js +0 -3115
- data/app/assets/javascripts/highcharts/modules/map.js +0 -2117
@@ -1,2117 +0,0 @@
|
|
1
|
-
/**
|
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
|
4
|
-
*
|
5
|
-
* (c) 2011-2014 Torstein Honsi
|
6
|
-
*
|
7
|
-
* License: www.highcharts.com/license
|
8
|
-
*/
|
9
|
-
|
10
|
-
/*global HighchartsAdapter*/
|
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,
|
26
|
-
|
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 () {};
|
39
|
-
|
40
|
-
/**
|
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
|
-
}
|
60
|
-
|
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) {
|
77
|
-
this.dataMin = dataMin;
|
78
|
-
this.dataMax = dataMax;
|
79
|
-
}
|
80
|
-
}
|
81
|
-
});
|
82
|
-
|
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;
|
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) {
|
102
|
-
|
103
|
-
// Use the same translation for both axes
|
104
|
-
this.transA = xAxis.transA = Math.min(this.transA, xAxis.transA);
|
105
|
-
|
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;
|
122
|
-
}
|
123
|
-
padAxis.minPixelPadding -= fixDiff;
|
124
|
-
}
|
125
|
-
}
|
126
|
-
});
|
127
|
-
|
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
|
-
});
|
135
|
-
|
136
|
-
|
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
|
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
|
-
});
|
182
|
-
|
183
|
-
Axis.prototype.init.call(this, chart, options);
|
184
|
-
|
185
|
-
// Base init() pushes it to the xAxis array, now pop it again
|
186
|
-
//chart[this.isXAxis ? 'xAxis' : 'yAxis'].pop();
|
187
|
-
|
188
|
-
// Prepare data classes
|
189
|
-
if (userOptions.dataClasses) {
|
190
|
-
this.initDataClasses(userOptions);
|
191
|
-
}
|
192
|
-
this.initStops(userOptions);
|
193
|
-
|
194
|
-
// Override original axis properties
|
195
|
-
this.isXAxis = true;
|
196
|
-
this.horiz = horiz;
|
197
|
-
this.zoomEnabled = false;
|
198
|
-
},
|
199
|
-
|
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
|
203
|
-
*/
|
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;
|
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
|
-
);
|
244
|
-
}
|
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
|
-
},
|
258
|
-
|
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
|
-
},
|
290
|
-
|
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
|
-
}
|
317
|
-
}
|
318
|
-
|
319
|
-
} else {
|
320
|
-
|
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;
|
329
|
-
}
|
330
|
-
}
|
331
|
-
from = stops[i] || stops[i + 1];
|
332
|
-
to = stops[i + 1] || from;
|
333
|
-
|
334
|
-
// The position within the gradient
|
335
|
-
pos = 1 - (to[0] - pos) / ((to[0] - from[0]) || 1);
|
336
|
-
|
337
|
-
color = this.tweenColors(
|
338
|
-
from.color,
|
339
|
-
to.color,
|
340
|
-
pos
|
341
|
-
);
|
342
|
-
}
|
343
|
-
return color;
|
344
|
-
},
|
345
|
-
|
346
|
-
getOffset: function () {
|
347
|
-
var group = this.legendGroup,
|
348
|
-
sideOffset = this.chart.axisOffset[this.side];
|
349
|
-
|
350
|
-
if (group) {
|
351
|
-
|
352
|
-
Axis.prototype.getOffset.call(this);
|
353
|
-
|
354
|
-
if (!this.axisGroup.parentGroup) {
|
355
|
-
|
356
|
-
// Move the axis elements inside the legend group
|
357
|
-
this.axisGroup.add(group);
|
358
|
-
this.gridGroup.add(group);
|
359
|
-
this.labelGroup.add(group);
|
360
|
-
|
361
|
-
this.added = true;
|
362
|
-
}
|
363
|
-
// Reset it to avoid color axis reserving space
|
364
|
-
this.chart.axisOffset[this.side] = sideOffset;
|
365
|
-
}
|
366
|
-
},
|
367
|
-
|
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
|
-
},
|
385
|
-
|
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;
|
444
|
-
}
|
445
|
-
|
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);
|
458
|
-
}
|
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
|
-
},
|
470
|
-
|
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
|
-
},
|
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) {
|
495
|
-
each(this.dataClasses, function (dataClass, i) {
|
496
|
-
var vis = true,
|
497
|
-
from = dataClass.from,
|
498
|
-
to = dataClass.to;
|
499
|
-
|
500
|
-
// Assemble the default name. This can be overridden by legend.options.labelFormatter
|
501
|
-
name = '';
|
502
|
-
if (from === UNDEFINED) {
|
503
|
-
name = '< ';
|
504
|
-
} else if (to === UNDEFINED) {
|
505
|
-
name = '> ';
|
506
|
-
}
|
507
|
-
if (from !== UNDEFINED) {
|
508
|
-
name += numberFormat(from, valueDecimals) + valueSuffix;
|
509
|
-
}
|
510
|
-
if (from !== UNDEFINED && to !== UNDEFINED) {
|
511
|
-
name += ' - ';
|
512
|
-
}
|
513
|
-
if (to !== UNDEFINED) {
|
514
|
-
name += numberFormat(to, valueDecimals) + valueSuffix;
|
515
|
-
}
|
516
|
-
|
517
|
-
// Add a mock object to the legend items
|
518
|
-
legendItems.push(extend({
|
519
|
-
chart: chart,
|
520
|
-
name: name,
|
521
|
-
options: {},
|
522
|
-
drawLegendSymbol: LegendSymbolMixin.drawRectangle,
|
523
|
-
visible: true,
|
524
|
-
setState: noop,
|
525
|
-
setVisible: function () {
|
526
|
-
vis = this.visible = !vis;
|
527
|
-
each(axis.series, function (series) {
|
528
|
-
each(series.points, function (point) {
|
529
|
-
if (point.dataClass === i) {
|
530
|
-
point.setVisible(vis);
|
531
|
-
}
|
532
|
-
});
|
533
|
-
});
|
534
|
-
|
535
|
-
chart.legend.colorizeItem(this, vis);
|
536
|
-
}
|
537
|
-
}, dataClass));
|
538
|
-
});
|
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));
|
551
|
-
});
|
552
|
-
});
|
553
|
-
|
554
|
-
/**
|
555
|
-
* Extend the chart getAxes method to also get the color axis
|
556
|
-
*/
|
557
|
-
wrap(Chart.prototype, 'getAxes', function (proceed) {
|
558
|
-
|
559
|
-
var options = this.options,
|
560
|
-
colorAxisOptions = options.colorAxis;
|
561
|
-
|
562
|
-
proceed.call(this);
|
563
|
-
|
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);
|
588
|
-
}
|
589
|
-
|
590
|
-
// Don't add the color axis' series
|
591
|
-
each(colorAxis.series, function (series) {
|
592
|
-
series.options.showInLegend = false;
|
593
|
-
});
|
594
|
-
}
|
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;
|
624
|
-
|
625
|
-
each(this.data, function (point) {
|
626
|
-
var value = point[colorKey],
|
627
|
-
color;
|
628
|
-
|
629
|
-
color = value === null ? nullColor : (colorAxis && value !== undefined) ? colorAxis.toColor(value, point) : point.color || series.color;
|
630
|
-
|
631
|
-
if (color) {
|
632
|
-
point.color = color;
|
633
|
-
}
|
634
|
-
});
|
635
|
-
}
|
636
|
-
};
|
637
|
-
|
638
|
-
|
639
|
-
/**
|
640
|
-
* Wrap the buildText method and add the hook for add text stroke
|
641
|
-
*/
|
642
|
-
wrap(SVGRenderer.prototype, 'buildText', function (proceed, wrapper) {
|
643
|
-
|
644
|
-
var textStroke = wrapper.styles && wrapper.styles.HcTextStroke;
|
645
|
-
|
646
|
-
proceed.call(this, wrapper);
|
647
|
-
|
648
|
-
// Apply the text stroke
|
649
|
-
if (textStroke && wrapper.applyTextStroke) {
|
650
|
-
wrapper.applyTextStroke(textStroke);
|
651
|
-
}
|
652
|
-
});
|
653
|
-
|
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);
|
677
|
-
}
|
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);
|
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
|
-
},
|
732
|
-
|
733
|
-
/**
|
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.
|
737
|
-
*/
|
738
|
-
fitToBox: function (inner, outer) {
|
739
|
-
each([['x', 'width'], ['y', 'height']], function (dim) {
|
740
|
-
var pos = dim[0],
|
741
|
-
size = dim[1];
|
742
|
-
|
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
|
-
|
759
|
-
|
760
|
-
return inner;
|
761
|
-
},
|
762
|
-
|
763
|
-
/**
|
764
|
-
* Zoom the map in or out by a certain amount. Less than 1 zooms in, greater than 1 zooms out.
|
765
|
-
*/
|
766
|
-
mapZoom: function (howMuch, centerXArg, centerYArg, mouseX, mouseY) {
|
767
|
-
/*if (this.isMapZooming) {
|
768
|
-
this.mapZoomQueue = arguments;
|
769
|
-
return;
|
770
|
-
}*/
|
771
|
-
|
772
|
-
var chart = this,
|
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
|
-
});
|
796
|
-
|
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
|
-
}
|
804
|
-
|
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);
|
809
|
-
|
810
|
-
// Reset zoom
|
811
|
-
} else {
|
812
|
-
xAxis.setExtremes(undefined, undefined, false);
|
813
|
-
yAxis.setExtremes(undefined, undefined, false);
|
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
|
-
}*/
|
832
|
-
|
833
|
-
chart.redraw();
|
834
|
-
}
|
835
|
-
});
|
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
|
-
},
|
890
|
-
|
891
|
-
/**
|
892
|
-
* The event handler for the mouse scroll event
|
893
|
-
*/
|
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;
|
964
|
-
},
|
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
|
983
|
-
},
|
984
|
-
hover: {
|
985
|
-
brightness: 0.2,
|
986
|
-
halo: null
|
987
|
-
}
|
988
|
-
}
|
989
|
-
});
|
990
|
-
|
991
|
-
/**
|
992
|
-
* The MapAreaPoint object
|
993
|
-
*/
|
994
|
-
var MapAreaPoint = extendClass(Point, {
|
995
|
-
/**
|
996
|
-
* Extend the Point object to split paths
|
997
|
-
*/
|
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;
|
1012
|
-
}
|
1013
|
-
extend(point, mapPoint); // copy over properties
|
1014
|
-
} else {
|
1015
|
-
point.value = point.value || null;
|
1016
|
-
}
|
1017
|
-
}
|
1018
|
-
|
1019
|
-
return point;
|
1020
|
-
},
|
1021
|
-
|
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
|
-
},
|
1036
|
-
|
1037
|
-
/**
|
1038
|
-
* Stop the fade-out
|
1039
|
-
*/
|
1040
|
-
onMouseOver: function (e) {
|
1041
|
-
clearTimeout(this.colorInterval);
|
1042
|
-
if (this.value !== null) {
|
1043
|
-
Point.prototype.onMouseOver.call(this, e);
|
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);
|
1081
|
-
|
1082
|
-
if (fill) {
|
1083
|
-
point.pointAttr[''].fill = fill;
|
1084
|
-
}
|
1085
|
-
},
|
1086
|
-
|
1087
|
-
/**
|
1088
|
-
* Zoom the chart to view a specific area point
|
1089
|
-
*/
|
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
|
-
});
|
1107
|
-
|
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) {
|
1134
|
-
|
1135
|
-
if (point.path) {
|
1136
|
-
if (typeof point.path === 'string') {
|
1137
|
-
point.path = Highcharts.splitPath(point.path);
|
1138
|
-
}
|
1139
|
-
|
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]);
|
1159
|
-
}
|
1160
|
-
even = !even;
|
1161
|
-
}
|
1162
|
-
}
|
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;
|
1174
|
-
}
|
1175
|
-
|
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;
|
1182
|
-
}
|
1183
|
-
});
|
1184
|
-
|
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);
|
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
|
-
}
|
1211
|
-
|
1212
|
-
this.valueMin = this.dataMin;
|
1213
|
-
this.valueMax = this.dataMax;
|
1214
|
-
|
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) {
|
1225
|
-
|
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];
|
1250
|
-
}
|
1251
|
-
}
|
1252
|
-
}
|
1253
|
-
|
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
|
-
}
|
1299
|
-
|
1300
|
-
this.getBox(mapData);
|
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) {
|
1317
|
-
|
1318
|
-
data = data || [];
|
1319
|
-
|
1320
|
-
// Registered the point codes that actually hold data
|
1321
|
-
if (joinBy[1]) {
|
1322
|
-
each(data, function (point) {
|
1323
|
-
dataUsed.push(point[joinBy[1]]);
|
1324
|
-
});
|
1325
|
-
}
|
1326
|
-
|
1327
|
-
// Add those map points that don't correspond to data, which will be drawn as null points
|
1328
|
-
dataUsed = '|' + dataUsed.join('|') + '|'; // String search is faster than array.indexOf
|
1329
|
-
|
1330
|
-
each(mapData, function (mapPoint) {
|
1331
|
-
if (!joinBy[0] || dataUsed.indexOf('|' + mapPoint[joinBy[0]] + '|') === -1) {
|
1332
|
-
data.push(merge(mapPoint, { value: null }));
|
1333
|
-
}
|
1334
|
-
});
|
1335
|
-
}
|
1336
|
-
}
|
1337
|
-
Series.prototype.setData.call(this, data, redraw);
|
1338
|
-
},
|
1339
|
-
|
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,
|
1351
|
-
|
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();
|
1368
|
-
|
1369
|
-
series.generatePoints();
|
1370
|
-
|
1371
|
-
each(series.data, function (point) {
|
1372
|
-
|
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);
|
1377
|
-
|
1378
|
-
if (doFullTranslate) {
|
1379
|
-
|
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'
|
1385
|
-
};
|
1386
|
-
}
|
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()) {
|
1422
|
-
|
1423
|
-
// Individual point actions
|
1424
|
-
if (chart.hasRendered && series.pointAttrToOptions.fill === 'color') {
|
1425
|
-
each(series.points, function (point) {
|
1426
|
-
|
1427
|
-
// Reset color on update/redraw
|
1428
|
-
if (point.graphic) {
|
1429
|
-
point.graphic.attr('fill', point.color);
|
1430
|
-
}
|
1431
|
-
|
1432
|
-
});
|
1433
|
-
}
|
1434
|
-
|
1435
|
-
// Draw them in transformGroup
|
1436
|
-
series.group = series.transformGroup;
|
1437
|
-
seriesTypes.column.prototype.drawPoints.apply(series);
|
1438
|
-
series.group = group; // Reset
|
1439
|
-
|
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
|
-
});
|
1451
|
-
|
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
|
-
};
|
1460
|
-
|
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
|
-
});
|
1482
|
-
|
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;
|
1531
|
-
}
|
1532
|
-
});
|
1533
|
-
|
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;
|
1543
|
-
}
|
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));
|
1553
|
-
}
|
1554
|
-
label.isOld = true;
|
1555
|
-
}
|
1556
|
-
});
|
1557
|
-
},
|
1558
|
-
|
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
|
1594
|
-
};
|
1595
|
-
}
|
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
|
1606
|
-
});
|
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
|
1618
|
-
this.animate = null;
|
1619
|
-
}
|
1620
|
-
}
|
1621
|
-
},
|
1622
|
-
|
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) {
|
1646
|
-
|
1647
|
-
point.graphic
|
1648
|
-
.attr(level.shapeArgs)
|
1649
|
-
.animate({
|
1650
|
-
scaleX: 1,
|
1651
|
-
scaleY: 1,
|
1652
|
-
translateX: 0,
|
1653
|
-
translateY: 0
|
1654
|
-
}, animationOptions);
|
1655
|
-
|
1656
|
-
});
|
1657
|
-
|
1658
|
-
this.animate = null;
|
1659
|
-
}
|
1660
|
-
|
1661
|
-
},
|
1662
|
-
|
1663
|
-
drawLegendSymbol: LegendSymbolMixin.drawRectangle,
|
1664
|
-
|
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;
|
1706
|
-
},
|
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
|
-
});
|
1720
|
-
|
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}'
|
1728
|
-
}
|
1729
|
-
});
|
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
|
1743
|
-
});
|
1744
|
-
}
|
1745
|
-
|
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
|
-
}
|
1777
|
-
}
|
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
|
-
};
|
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);
|
1843
|
-
}
|
1844
|
-
|
1845
|
-
}));
|
1846
|
-
|
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';
|
1867
|
-
|
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;
|
1875
|
-
|
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
|
-
}
|
1893
|
-
|
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
|
-
}
|
1904
|
-
|
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);
|
1973
|
-
},
|
1974
|
-
text: '+',
|
1975
|
-
y: 0
|
1976
|
-
},
|
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*$/, "");
|
2003
|
-
|
2004
|
-
// Split on spaces and commas
|
2005
|
-
path = path.split(/[ ,]+/);
|
2006
|
-
|
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) {
|
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
|
-
// */
|
2088
|
-
|
2089
|
-
// Don't merge the data
|
2090
|
-
seriesOptions = options.series;
|
2091
|
-
options.series = null;
|
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));
|