highcharts-rails 4.2.7 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.markdown +34 -0
  3. data/Gemfile +4 -0
  4. data/Rakefile +53 -32
  5. data/app/assets/javascripts/highcharts.js +18775 -17176
  6. data/app/assets/javascripts/highcharts/highcharts-3d.js +1849 -1563
  7. data/app/assets/javascripts/highcharts/highcharts-more.js +2162 -1988
  8. data/app/assets/javascripts/highcharts/modules/accessibility.js +1005 -0
  9. data/app/assets/javascripts/highcharts/modules/annotations.js +408 -401
  10. data/app/assets/javascripts/highcharts/modules/boost.js +561 -546
  11. data/app/assets/javascripts/highcharts/modules/broken-axis.js +330 -324
  12. data/app/assets/javascripts/highcharts/modules/data.js +973 -965
  13. data/app/assets/javascripts/highcharts/modules/drilldown.js +783 -723
  14. data/app/assets/javascripts/highcharts/modules/exporting.js +864 -785
  15. data/app/assets/javascripts/highcharts/modules/funnel.js +290 -306
  16. data/app/assets/javascripts/highcharts/modules/heatmap.js +701 -645
  17. data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +150 -132
  18. data/app/assets/javascripts/highcharts/modules/offline-exporting.js +414 -355
  19. data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +164 -0
  20. data/app/assets/javascripts/highcharts/modules/series-label.js +473 -448
  21. data/app/assets/javascripts/highcharts/modules/solid-gauge.js +279 -271
  22. data/app/assets/javascripts/highcharts/modules/treemap.js +921 -886
  23. data/app/assets/javascripts/highcharts/themes/dark-blue.js +307 -244
  24. data/app/assets/javascripts/highcharts/themes/dark-green.js +303 -244
  25. data/app/assets/javascripts/highcharts/themes/dark-unica.js +231 -201
  26. data/app/assets/javascripts/highcharts/themes/gray.js +314 -245
  27. data/app/assets/javascripts/highcharts/themes/grid-light.js +91 -66
  28. data/app/assets/javascripts/highcharts/themes/grid.js +124 -96
  29. data/app/assets/javascripts/highcharts/themes/sand-signika.js +119 -94
  30. data/app/assets/javascripts/highcharts/themes/skies.js +108 -85
  31. data/lib/highcharts/version.rb +1 -1
  32. metadata +13 -14
  33. data/app/assets/javascripts/highcharts/adapters/standalone-framework.js +0 -1
  34. data/app/assets/javascripts/highcharts/modules/canvas-tools.js +0 -3115
  35. 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));