highstocks-rails 0.0.2 → 0.0.3

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.
@@ -1,289 +0,0 @@
1
- /**
2
- * @license
3
- * Highcharts funnel module, Beta
4
- *
5
- * (c) 2010-2012 Torstein Hønsi
6
- *
7
- * License: www.highcharts.com/license
8
- */
9
-
10
- /*global Highcharts */
11
- (function (Highcharts) {
12
-
13
- 'use strict';
14
-
15
- // create shortcuts
16
- var defaultOptions = Highcharts.getOptions(),
17
- defaultPlotOptions = defaultOptions.plotOptions,
18
- seriesTypes = Highcharts.seriesTypes,
19
- merge = Highcharts.merge,
20
- noop = function () {},
21
- each = Highcharts.each;
22
-
23
- // set default options
24
- defaultPlotOptions.funnel = merge(defaultPlotOptions.pie, {
25
- center: ['50%', '50%'],
26
- width: '90%',
27
- neckWidth: '30%',
28
- height: '100%',
29
- neckHeight: '25%',
30
-
31
- dataLabels: {
32
- //position: 'right',
33
- connectorWidth: 1,
34
- connectorColor: '#606060'
35
- },
36
- size: true, // to avoid adapting to data label size in Pie.drawDataLabels
37
- states: {
38
- select: {
39
- color: '#C0C0C0',
40
- borderColor: '#000000',
41
- shadow: false
42
- }
43
- }
44
- });
45
-
46
-
47
- seriesTypes.funnel = Highcharts.extendClass(seriesTypes.pie, {
48
-
49
- type: 'funnel',
50
- animate: noop,
51
-
52
- /**
53
- * Overrides the pie translate method
54
- */
55
- translate: function () {
56
-
57
- var
58
- // Get positions - either an integer or a percentage string must be given
59
- getLength = function (length, relativeTo) {
60
- return (/%$/).test(length) ?
61
- relativeTo * parseInt(length, 10) / 100 :
62
- parseInt(length, 10);
63
- },
64
-
65
- sum = 0,
66
- series = this,
67
- chart = series.chart,
68
- plotWidth = chart.plotWidth,
69
- plotHeight = chart.plotHeight,
70
- cumulative = 0, // start at top
71
- options = series.options,
72
- center = options.center,
73
- centerX = getLength(center[0], plotWidth),
74
- centerY = getLength(center[0], plotHeight),
75
- width = getLength(options.width, plotWidth),
76
- tempWidth,
77
- getWidthAt,
78
- height = getLength(options.height, plotHeight),
79
- neckWidth = getLength(options.neckWidth, plotWidth),
80
- neckHeight = getLength(options.neckHeight, plotHeight),
81
- neckY = height - neckHeight,
82
- data = series.data,
83
- path,
84
- fraction,
85
- half = options.dataLabels.position === 'left' ? 1 : 0,
86
-
87
- x1,
88
- y1,
89
- x2,
90
- x3,
91
- y3,
92
- x4,
93
- y5;
94
-
95
- // Return the width at a specific y coordinate
96
- series.getWidthAt = getWidthAt = function (y) {
97
- return y > height - neckHeight || height === neckHeight ?
98
- neckWidth :
99
- neckWidth + (width - neckWidth) * ((height - neckHeight - y) / (height - neckHeight));
100
- };
101
- series.getX = function (y, half) {
102
- return centerX + (half ? -1 : 1) * ((getWidthAt(y) / 2) + options.dataLabels.distance);
103
- };
104
-
105
- // Expose
106
- series.center = [centerX, centerY, height];
107
- series.centerX = centerX;
108
-
109
- /*
110
- * Individual point coordinate naming:
111
- *
112
- * x1,y1 _________________ x2,y1
113
- * \ /
114
- * \ /
115
- * \ /
116
- * \ /
117
- * \ /
118
- * x3,y3 _________ x4,y3
119
- *
120
- * Additional for the base of the neck:
121
- *
122
- * | |
123
- * | |
124
- * | |
125
- * x3,y5 _________ x4,y5
126
- */
127
-
128
-
129
-
130
-
131
- // get the total sum
132
- each(data, function (point) {
133
- sum += point.y;
134
- });
135
-
136
- each(data, function (point) {
137
- // set start and end positions
138
- y5 = null;
139
- fraction = sum ? point.y / sum : 0;
140
- y1 = centerY - height / 2 + cumulative * height;
141
- y3 = y1 + fraction * height;
142
- //tempWidth = neckWidth + (width - neckWidth) * ((height - neckHeight - y1) / (height - neckHeight));
143
- tempWidth = getWidthAt(y1);
144
- x1 = centerX - tempWidth / 2;
145
- x2 = x1 + tempWidth;
146
- tempWidth = getWidthAt(y3);
147
- x3 = centerX - tempWidth / 2;
148
- x4 = x3 + tempWidth;
149
-
150
- // the entire point is within the neck
151
- if (y1 > neckY) {
152
- x1 = x3 = centerX - neckWidth / 2;
153
- x2 = x4 = centerX + neckWidth / 2;
154
-
155
- // the base of the neck
156
- } else if (y3 > neckY) {
157
- y5 = y3;
158
-
159
- tempWidth = getWidthAt(neckY);
160
- x3 = centerX - tempWidth / 2;
161
- x4 = x3 + tempWidth;
162
-
163
- y3 = neckY;
164
- }
165
-
166
- // save the path
167
- path = [
168
- 'M',
169
- x1, y1,
170
- 'L',
171
- x2, y1,
172
- x4, y3
173
- ];
174
- if (y5) {
175
- path.push(x4, y5, x3, y5);
176
- }
177
- path.push(x3, y3, 'Z');
178
-
179
- // prepare for using shared dr
180
- point.shapeType = 'path';
181
- point.shapeArgs = { d: path };
182
-
183
-
184
- // for tooltips and data labels
185
- point.percentage = fraction * 100;
186
- point.plotX = centerX;
187
- point.plotY = (y1 + (y5 || y3)) / 2;
188
-
189
- // Placement of tooltips and data labels
190
- point.tooltipPos = [
191
- centerX,
192
- point.plotY
193
- ];
194
-
195
- // Slice is a noop on funnel points
196
- point.slice = noop;
197
-
198
- // Mimicking pie data label placement logic
199
- point.half = half;
200
-
201
- cumulative += fraction;
202
- });
203
-
204
-
205
- series.setTooltipPoints();
206
- },
207
- /**
208
- * Draw a single point (wedge)
209
- * @param {Object} point The point object
210
- * @param {Object} color The color of the point
211
- * @param {Number} brightness The brightness relative to the color
212
- */
213
- drawPoints: function () {
214
- var series = this,
215
- options = series.options,
216
- chart = series.chart,
217
- renderer = chart.renderer;
218
-
219
- each(series.data, function (point) {
220
-
221
- var graphic = point.graphic,
222
- shapeArgs = point.shapeArgs;
223
-
224
- if (!graphic) { // Create the shapes
225
- point.graphic = renderer.path(shapeArgs).
226
- attr({
227
- fill: point.color,
228
- stroke: options.borderColor,
229
- 'stroke-width': options.borderWidth
230
- }).
231
- add(series.group);
232
-
233
- } else { // Update the shapes
234
- graphic.animate(shapeArgs);
235
- }
236
- });
237
- },
238
-
239
- /**
240
- * Funnel items don't have angles (#2289)
241
- */
242
- sortByAngle: noop,
243
-
244
- /**
245
- * Extend the pie data label method
246
- */
247
- drawDataLabels: function () {
248
- var data = this.data,
249
- labelDistance = this.options.dataLabels.distance,
250
- leftSide,
251
- sign,
252
- point,
253
- i = data.length,
254
- x,
255
- y;
256
-
257
- // In the original pie label anticollision logic, the slots are distributed
258
- // from one labelDistance above to one labelDistance below the pie. In funnels
259
- // we don't want this.
260
- this.center[2] -= 2 * labelDistance;
261
-
262
- // Set the label position array for each point.
263
- while (i--) {
264
- point = data[i];
265
- leftSide = point.half;
266
- sign = leftSide ? 1 : -1;
267
- y = point.plotY;
268
- x = this.getX(y, leftSide);
269
-
270
- // set the anchor point for data labels
271
- point.labelPos = [
272
- 0, // first break of connector
273
- y, // a/a
274
- x + (labelDistance - 5) * sign, // second break, right outside point shape
275
- y, // a/a
276
- x + labelDistance * sign, // landing point for connector
277
- y, // a/a
278
- leftSide ? 'right' : 'left', // alignment
279
- 0 // center angle
280
- ];
281
- }
282
-
283
- seriesTypes.pie.prototype.drawDataLabels.call(this);
284
- }
285
-
286
- });
287
-
288
-
289
- }(Highcharts));
@@ -1,54 +0,0 @@
1
- (function (H) {
2
- var seriesTypes = H.seriesTypes,
3
- each = H.each;
4
-
5
- seriesTypes.heatmap = H.extendClass(seriesTypes.map, {
6
- colorKey: 'z',
7
- useMapGeometry: false,
8
- pointArrayMap: ['y', 'z'],
9
- translate: function () {
10
- var series = this,
11
- options = series.options,
12
- dataMin = Number.MAX_VALUE,
13
- dataMax = Number.MIN_VALUE;
14
-
15
- series.generatePoints();
16
-
17
- each(series.data, function (point) {
18
- var x = point.x,
19
- y = point.y,
20
- value = point.z,
21
- xPad = (options.colsize || 1) / 2,
22
- yPad = (options.rowsize || 1) / 2;
23
-
24
- point.path = [
25
- 'M', x - xPad, y - yPad,
26
- 'L', x + xPad, y - yPad,
27
- 'L', x + xPad, y + yPad,
28
- 'L', x - xPad, y + yPad,
29
- 'Z'
30
- ];
31
-
32
- point.shapeType = 'path';
33
- point.shapeArgs = {
34
- d: series.translatePath(point.path)
35
- };
36
-
37
- if (typeof value === 'number') {
38
- if (value > dataMax) {
39
- dataMax = value;
40
- } else if (value < dataMin) {
41
- dataMin = value;
42
- }
43
- }
44
- });
45
-
46
- series.translateColors(dataMin, dataMax);
47
- },
48
-
49
- getBox: function () {},
50
- getExtremes: H.Series.prototype.getExtremes
51
-
52
- });
53
-
54
- }(Highcharts));
@@ -1,1273 +0,0 @@
1
- /**
2
- * @license Map plugin v0.1 for Highcharts
3
- *
4
- * (c) 2011-2013 Torstein Hønsi
5
- *
6
- * License: www.highcharts.com/license
7
- */
8
-
9
- /*
10
- * See www.H.com/studies/world-map.htm for use case.
11
- *
12
- * To do:
13
- * - Optimize long variable names and alias adapter methods and Highcharts namespace variables
14
- * - Zoom and pan GUI
15
- */
16
- /*global HighchartsAdapter*/
17
- (function (H) {
18
- var UNDEFINED,
19
- Axis = H.Axis,
20
- Chart = H.Chart,
21
- Point = H.Point,
22
- Pointer = H.Pointer,
23
- SVGRenderer = H.SVGRenderer,
24
- VMLRenderer = H.VMLRenderer,
25
- symbols = SVGRenderer.prototype.symbols,
26
- each = H.each,
27
- extend = H.extend,
28
- extendClass = H.extendClass,
29
- merge = H.merge,
30
- pick = H.pick,
31
- numberFormat = H.numberFormat,
32
- defaultOptions = H.getOptions(),
33
- seriesTypes = H.seriesTypes,
34
- inArray = HighchartsAdapter.inArray,
35
- plotOptions = defaultOptions.plotOptions,
36
- wrap = H.wrap,
37
- Color = H.Color,
38
- noop = function () {};
39
-
40
- // Add language
41
- extend(defaultOptions.lang, {
42
- zoomIn: 'Zoom in',
43
- zoomOut: 'Zoom out'
44
- });
45
-
46
- /*
47
- * Return an intermediate color between two colors, according to pos where 0
48
- * is the from color and 1 is the to color
49
- */
50
- function tweenColors(from, to, pos) {
51
- var i = 4,
52
- val,
53
- rgba = [];
54
-
55
- while (i--) {
56
- val = to.rgba[i] + (from.rgba[i] - to.rgba[i]) * (1 - pos);
57
- rgba[i] = i === 3 ? val : Math.round(val); // Do not round opacity
58
- }
59
- return 'rgba(' + rgba.join(',') + ')';
60
- }
61
-
62
- // Set the default map navigation options
63
- defaultOptions.mapNavigation = {
64
- buttonOptions: {
65
- alignTo: 'plotBox',
66
- align: 'left',
67
- verticalAlign: 'top',
68
- x: 0,
69
- width: 18,
70
- height: 18,
71
- style: {
72
- fontSize: '15px',
73
- fontWeight: 'bold',
74
- textAlign: 'center'
75
- },
76
- theme: {
77
- 'stroke-width': 1
78
- }
79
- },
80
- buttons: {
81
- zoomIn: {
82
- onclick: function () {
83
- this.mapZoom(0.5);
84
- },
85
- text: '+',
86
- y: 0
87
- },
88
- zoomOut: {
89
- onclick: function () {
90
- this.mapZoom(2);
91
- },
92
- text: '-',
93
- y: 28
94
- }
95
- }
96
- // enabled: false,
97
- // enableButtons: null, // inherit from enabled
98
- // enableTouchZoom: null, // inherit from enabled
99
- // enableDoubleClickZoom: null, // inherit from enabled
100
- // enableDoubleClickZoomTo: false
101
- // enableMouseWheelZoom: null, // inherit from enabled
102
- };
103
-
104
- /**
105
- * Utility for reading SVG paths directly.
106
- */
107
- H.splitPath = function (path) {
108
- var i;
109
-
110
- // Move letters apart
111
- path = path.replace(/([A-Za-z])/g, ' $1 ');
112
- // Trim
113
- path = path.replace(/^\s*/, "").replace(/\s*$/, "");
114
-
115
- // Split on spaces and commas
116
- path = path.split(/[ ,]+/);
117
-
118
- // Parse numbers
119
- for (i = 0; i < path.length; i++) {
120
- if (!/[a-zA-Z]/.test(path[i])) {
121
- path[i] = parseFloat(path[i]);
122
- }
123
- }
124
- return path;
125
- };
126
-
127
- // A placeholder for map definitions
128
- H.maps = {};
129
-
130
- /**
131
- * Override to use the extreme coordinates from the SVG shape, not the
132
- * data values
133
- */
134
- wrap(Axis.prototype, 'getSeriesExtremes', function (proceed) {
135
- var isXAxis = this.isXAxis,
136
- dataMin,
137
- dataMax,
138
- xData = [];
139
-
140
- // Remove the xData array and cache it locally so that the proceed method doesn't use it
141
- if (isXAxis) {
142
- each(this.series, function (series, i) {
143
- if (series.useMapGeometry) {
144
- xData[i] = series.xData;
145
- series.xData = [];
146
- }
147
- });
148
- }
149
-
150
- // Call base to reach normal cartesian series (like mappoint)
151
- proceed.call(this);
152
-
153
- // Run extremes logic for map and mapline
154
- if (isXAxis) {
155
- dataMin = pick(this.dataMin, Number.MAX_VALUE);
156
- dataMax = pick(this.dataMax, Number.MIN_VALUE);
157
- each(this.series, function (series, i) {
158
- if (series.useMapGeometry) {
159
- dataMin = Math.min(dataMin, pick(series.minX, dataMin));
160
- dataMax = Math.max(dataMax, pick(series.maxX, dataMin));
161
- series.xData = xData[i]; // Reset xData array
162
- }
163
- });
164
-
165
- this.dataMin = dataMin;
166
- this.dataMax = dataMax;
167
- }
168
- });
169
-
170
- /**
171
- * Override axis translation to make sure the aspect ratio is always kept
172
- */
173
- wrap(Axis.prototype, 'setAxisTranslation', function (proceed) {
174
- var chart = this.chart,
175
- mapRatio,
176
- plotRatio = chart.plotWidth / chart.plotHeight,
177
- isXAxis = this.isXAxis,
178
- adjustedAxisLength,
179
- xAxis = chart.xAxis[0],
180
- padAxis;
181
-
182
- // Run the parent method
183
- proceed.call(this);
184
-
185
- // On Y axis, handle both
186
- if (chart.options.chart.type === 'map' && !isXAxis && xAxis.transA !== UNDEFINED) {
187
-
188
- // Use the same translation for both axes
189
- this.transA = xAxis.transA = Math.min(this.transA, xAxis.transA);
190
-
191
- mapRatio = (xAxis.max - xAxis.min) / (this.max - this.min);
192
-
193
- // What axis to pad to put the map in the middle
194
- padAxis = mapRatio > plotRatio ? this : xAxis;
195
-
196
- // Pad it
197
- adjustedAxisLength = (padAxis.max - padAxis.min) * padAxis.transA;
198
- padAxis.minPixelPadding = (padAxis.len - adjustedAxisLength) / 2;
199
- }
200
- });
201
-
202
-
203
- //--- Start zooming and panning features
204
- wrap(Chart.prototype, 'render', function (proceed) {
205
- var chart = this,
206
- mapNavigation = chart.options.mapNavigation;
207
-
208
- proceed.call(chart);
209
-
210
- // Render the plus and minus buttons
211
- chart.renderMapNavigation();
212
-
213
- // Add the double click event
214
- if (pick(mapNavigation.enableDoubleClickZoom, mapNavigation.enabled) || mapNavigation.enableDoubleClickZoomTo) {
215
- H.addEvent(chart.container, 'dblclick', function (e) {
216
- chart.pointer.onContainerDblClick(e);
217
- });
218
- }
219
-
220
- // Add the mousewheel event
221
- if (pick(mapNavigation.enableMouseWheelZoom, mapNavigation.enabled)) {
222
- H.addEvent(chart.container, document.onmousewheel === undefined ? 'DOMMouseScroll' : 'mousewheel', function (e) {
223
- chart.pointer.onContainerMouseWheel(e);
224
- });
225
- }
226
- });
227
-
228
- // Extend the Pointer
229
- extend(Pointer.prototype, {
230
-
231
- /**
232
- * The event handler for the doubleclick event
233
- */
234
- onContainerDblClick: function (e) {
235
- var chart = this.chart;
236
-
237
- e = this.normalize(e);
238
-
239
- if (chart.options.mapNavigation.enableDoubleClickZoomTo) {
240
- if (chart.pointer.inClass(e.target, 'highcharts-tracker')) {
241
- chart.zoomToShape(chart.hoverPoint);
242
- }
243
- } else if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
244
- chart.mapZoom(
245
- 0.5,
246
- chart.xAxis[0].toValue(e.chartX),
247
- chart.yAxis[0].toValue(e.chartY)
248
- );
249
- }
250
- },
251
-
252
- /**
253
- * The event handler for the mouse scroll event
254
- */
255
- onContainerMouseWheel: function (e) {
256
- var chart = this.chart,
257
- delta;
258
-
259
- e = this.normalize(e);
260
-
261
- // Firefox uses e.detail, WebKit and IE uses wheelDelta
262
- delta = e.detail || -(e.wheelDelta / 120);
263
- if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
264
- chart.mapZoom(
265
- delta > 0 ? 2 : 0.5,
266
- chart.xAxis[0].toValue(e.chartX),
267
- chart.yAxis[0].toValue(e.chartY)
268
- );
269
- }
270
- }
271
- });
272
-
273
- // Implement the pinchType option
274
- wrap(Pointer.prototype, 'init', function (proceed, chart, options) {
275
-
276
- proceed.call(this, chart, options);
277
-
278
- // Pinch status
279
- if (pick(options.mapNavigation.enableTouchZoom, options.mapNavigation.enabled)) {
280
- this.pinchX = this.pinchHor =
281
- this.pinchY = this.pinchVert = true;
282
- }
283
- });
284
-
285
- // Extend the pinchTranslate method to preserve fixed ratio when zooming
286
- wrap(Pointer.prototype, 'pinchTranslate', function (proceed, zoomHor, zoomVert, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch) {
287
- var xBigger;
288
-
289
- proceed.call(this, zoomHor, zoomVert, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
290
-
291
- // Keep ratio
292
- if (this.chart.options.chart.type === 'map') {
293
- xBigger = transform.scaleX > transform.scaleY;
294
- this.pinchTranslateDirection(
295
- !xBigger,
296
- pinchDown,
297
- touches,
298
- transform,
299
- selectionMarker,
300
- clip,
301
- lastValidTouch,
302
- xBigger ? transform.scaleX : transform.scaleY
303
- );
304
- }
305
- });
306
-
307
- // Add events to the Chart object itself
308
- extend(Chart.prototype, {
309
- renderMapNavigation: function () {
310
- var chart = this,
311
- options = this.options.mapNavigation,
312
- buttons = options.buttons,
313
- n,
314
- button,
315
- buttonOptions,
316
- attr,
317
- states,
318
- outerHandler = function () {
319
- this.handler.call(chart);
320
- };
321
-
322
- if (pick(options.enableButtons, options.enabled)) {
323
- for (n in buttons) {
324
- if (buttons.hasOwnProperty(n)) {
325
- buttonOptions = merge(options.buttonOptions, buttons[n]);
326
- attr = buttonOptions.theme;
327
- states = attr.states;
328
- button = chart.renderer.button(
329
- buttonOptions.text,
330
- 0,
331
- 0,
332
- outerHandler,
333
- attr,
334
- states && states.hover,
335
- states && states.select,
336
- 0,
337
- n === 'zoomIn' ? 'topbutton' : 'bottombutton'
338
- )
339
- .attr({
340
- width: buttonOptions.width,
341
- height: buttonOptions.height,
342
- title: chart.options.lang[n],
343
- zIndex: 5
344
- })
345
- .css(buttonOptions.style)
346
- .add();
347
- button.handler = buttonOptions.onclick;
348
- button.align(extend(buttonOptions, { width: button.width, height: 2 * button.height }), null, buttonOptions.alignTo);
349
- }
350
- }
351
- }
352
- },
353
-
354
- /**
355
- * Fit an inner box to an outer. If the inner box overflows left or right, align it to the sides of the
356
- * outer. If it overflows both sides, fit it within the outer. This is a pattern that occurs more places
357
- * in Highcharts, perhaps it should be elevated to a common utility function.
358
- */
359
- fitToBox: function (inner, outer) {
360
- each([['x', 'width'], ['y', 'height']], function (dim) {
361
- var pos = dim[0],
362
- size = dim[1];
363
-
364
- if (inner[pos] + inner[size] > outer[pos] + outer[size]) { // right overflow
365
- if (inner[size] > outer[size]) { // the general size is greater, fit fully to outer
366
- inner[size] = outer[size];
367
- inner[pos] = outer[pos];
368
- } else { // align right
369
- inner[pos] = outer[pos] + outer[size] - inner[size];
370
- }
371
- }
372
- if (inner[size] > outer[size]) {
373
- inner[size] = outer[size];
374
- }
375
- if (inner[pos] < outer[pos]) {
376
- inner[pos] = outer[pos];
377
- }
378
- });
379
-
380
-
381
- return inner;
382
- },
383
-
384
- /**
385
- * Zoom the map in or out by a certain amount. Less than 1 zooms in, greater than 1 zooms out.
386
- */
387
- mapZoom: function (howMuch, centerXArg, centerYArg) {
388
-
389
- if (this.isMapZooming) {
390
- return;
391
- }
392
-
393
- var chart = this,
394
- xAxis = chart.xAxis[0],
395
- xRange = xAxis.max - xAxis.min,
396
- centerX = pick(centerXArg, xAxis.min + xRange / 2),
397
- newXRange = xRange * howMuch,
398
- yAxis = chart.yAxis[0],
399
- yRange = yAxis.max - yAxis.min,
400
- centerY = pick(centerYArg, yAxis.min + yRange / 2),
401
- newYRange = yRange * howMuch,
402
- newXMin = centerX - newXRange / 2,
403
- newYMin = centerY - newYRange / 2,
404
- animation = pick(chart.options.chart.animation, true),
405
- delay,
406
- newExt = chart.fitToBox({
407
- x: newXMin,
408
- y: newYMin,
409
- width: newXRange,
410
- height: newYRange
411
- }, {
412
- x: xAxis.dataMin,
413
- y: yAxis.dataMin,
414
- width: xAxis.dataMax - xAxis.dataMin,
415
- height: yAxis.dataMax - yAxis.dataMin
416
- });
417
-
418
- xAxis.setExtremes(newExt.x, newExt.x + newExt.width, false);
419
- yAxis.setExtremes(newExt.y, newExt.y + newExt.height, false);
420
-
421
- // Prevent zooming until this one is finished animating
422
- delay = animation ? animation.duration || 500 : 0;
423
- if (delay) {
424
- chart.isMapZooming = true;
425
- setTimeout(function () {
426
- chart.isMapZooming = false;
427
- }, delay);
428
- }
429
-
430
-
431
- chart.redraw();
432
- },
433
-
434
- /**
435
- * Zoom the chart to view a specific area point
436
- */
437
- zoomToShape: function (point) {
438
- var series = point.series,
439
- chart = series.chart;
440
-
441
- series.xAxis.setExtremes(
442
- point._minX,
443
- point._maxX,
444
- false
445
- );
446
- series.yAxis.setExtremes(
447
- point._minY,
448
- point._maxY,
449
- false
450
- );
451
- chart.redraw();
452
- }
453
- });
454
-
455
- /**
456
- * Extend the default options with map options
457
- */
458
- plotOptions.map = merge(plotOptions.scatter, {
459
- animation: false, // makes the complex shapes slow
460
- nullColor: '#F8F8F8',
461
- borderColor: 'silver',
462
- borderWidth: 1,
463
- marker: null,
464
- stickyTracking: false,
465
- dataLabels: {
466
- verticalAlign: 'middle'
467
- },
468
- turboThreshold: 0,
469
- tooltip: {
470
- followPointer: true,
471
- pointFormat: '{point.name}: {point.y}<br/>'
472
- },
473
- states: {
474
- normal: {
475
- animation: true
476
- }
477
- }
478
- });
479
-
480
- var MapAreaPoint = extendClass(Point, {
481
- /**
482
- * Extend the Point object to split paths
483
- */
484
- applyOptions: function (options, x) {
485
-
486
- var point = Point.prototype.applyOptions.call(this, options, x),
487
- series = this.series,
488
- seriesOptions = series.options,
489
- joinBy = seriesOptions.dataJoinBy,
490
- mapPoint;
491
-
492
- if (joinBy && seriesOptions.mapData) {
493
- mapPoint = series.getMapData(joinBy, point[joinBy]);
494
-
495
- if (mapPoint) {
496
- // This applies only to bubbles
497
- if (series.xyFromShape) {
498
- point.x = mapPoint._midX;
499
- point.y = mapPoint._midY;
500
- }
501
- extend(point, mapPoint); // copy over properties
502
- } else {
503
- point.y = point.y || null;
504
- }
505
- }
506
-
507
- return point;
508
- },
509
-
510
- /**
511
- * Set the visibility of a single map area
512
- */
513
- setVisible: function (vis) {
514
- var point = this,
515
- method = vis ? 'show' : 'hide';
516
-
517
- // Show and hide associated elements
518
- each(['graphic', 'dataLabel'], function (key) {
519
- if (point[key]) {
520
- point[key][method]();
521
- }
522
- });
523
- },
524
-
525
- /**
526
- * Stop the fade-out
527
- */
528
- onMouseOver: function (e) {
529
- clearTimeout(this.colorInterval);
530
- Point.prototype.onMouseOver.call(this, e);
531
- },
532
- /**
533
- * Custom animation for tweening out the colors. Animation reduces blinking when hovering
534
- * over islands and coast lines. We run a custom implementation of animation becuase we
535
- * need to be able to run this independently from other animations like zoom redraw. Also,
536
- * adding color animation to the adapters would introduce almost the same amount of code.
537
- */
538
- onMouseOut: function () {
539
- var point = this,
540
- start = +new Date(),
541
- normalColor = Color(point.options.color),
542
- hoverColor = Color(point.pointAttr.hover.fill),
543
- animation = point.series.options.states.normal.animation,
544
- duration = animation && (animation.duration || 500);
545
-
546
- if (duration && normalColor.rgba.length === 4 && hoverColor.rgba.length === 4) {
547
- delete point.pointAttr[''].fill; // avoid resetting it in Point.setState
548
-
549
- clearTimeout(point.colorInterval);
550
- point.colorInterval = setInterval(function () {
551
- var pos = (new Date() - start) / duration,
552
- graphic = point.graphic;
553
- if (pos > 1) {
554
- pos = 1;
555
- }
556
- if (graphic) {
557
- graphic.attr('fill', tweenColors(hoverColor, normalColor, pos));
558
- }
559
- if (pos >= 1) {
560
- clearTimeout(point.colorInterval);
561
- }
562
- }, 13);
563
- }
564
- Point.prototype.onMouseOut.call(point);
565
- }
566
- });
567
-
568
- /**
569
- * Add the series type
570
- */
571
- seriesTypes.map = extendClass(seriesTypes.scatter, {
572
- type: 'map',
573
- pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
574
- stroke: 'borderColor',
575
- 'stroke-width': 'borderWidth',
576
- fill: 'color'
577
- },
578
- colorKey: 'y',
579
- pointClass: MapAreaPoint,
580
- trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'],
581
- getSymbol: noop,
582
- supportsDrilldown: true,
583
- getExtremesFromAll: true,
584
- useMapGeometry: true, // get axis extremes from paths, not values
585
- init: function (chart) {
586
- var series = this,
587
- legendOptions = chart.options.legend,
588
- valueDecimals = legendOptions.valueDecimals,
589
- valueSuffix = legendOptions.valueSuffix || '',
590
- legendItems = [],
591
- name,
592
- from,
593
- to,
594
- fromLabel,
595
- toLabel,
596
- colorRange,
597
- valueRanges,
598
- gradientColor,
599
- grad,
600
- tmpLabel,
601
- horizontal = chart.options.legend.layout === 'horizontal';
602
-
603
-
604
- H.Series.prototype.init.apply(this, arguments);
605
- colorRange = series.options.colorRange;
606
- valueRanges = series.options.valueRanges;
607
-
608
- if (valueRanges) {
609
- each(valueRanges, function (range, i) {
610
- var vis = true;
611
- from = range.from;
612
- to = range.to;
613
-
614
- // Assemble the default name. This can be overridden by legend.options.labelFormatter
615
- name = '';
616
- if (from === UNDEFINED) {
617
- name = '< ';
618
- } else if (to === UNDEFINED) {
619
- name = '> ';
620
- }
621
- if (from !== UNDEFINED) {
622
- name += numberFormat(from, valueDecimals) + valueSuffix;
623
- }
624
- if (from !== UNDEFINED && to !== UNDEFINED) {
625
- name += ' - ';
626
- }
627
- if (to !== UNDEFINED) {
628
- name += numberFormat(to, valueDecimals) + valueSuffix;
629
- }
630
-
631
- // Add a mock object to the legend items
632
- legendItems.push(H.extend({
633
- chart: series.chart,
634
- name: name,
635
- options: {},
636
- drawLegendSymbol: seriesTypes.area.prototype.drawLegendSymbol,
637
- visible: true,
638
- setState: noop,
639
- setVisible: function () {
640
- vis = this.visible = !vis;
641
- each(series.points, function (point) {
642
- if (point.valueRange === i) {
643
- point.setVisible(vis);
644
- }
645
- });
646
-
647
- chart.legend.colorizeItem(this, vis);
648
- }
649
- }, range));
650
- });
651
- series.legendItems = legendItems;
652
-
653
- } else if (colorRange) {
654
-
655
- from = colorRange.from;
656
- to = colorRange.to;
657
- fromLabel = colorRange.fromLabel;
658
- toLabel = colorRange.toLabel;
659
-
660
- // Flips linearGradient variables and label text.
661
- grad = horizontal ? [0, 0, 1, 0] : [0, 1, 0, 0];
662
- if (!horizontal) {
663
- tmpLabel = fromLabel;
664
- fromLabel = toLabel;
665
- toLabel = tmpLabel;
666
- }
667
-
668
- // Creates color gradient.
669
- gradientColor = {
670
- linearGradient: { x1: grad[0], y1: grad[1], x2: grad[2], y2: grad[3] },
671
- stops:
672
- [
673
- [0, from],
674
- [1, to]
675
- ]
676
- };
677
-
678
- // Add a mock object to the legend items.
679
- legendItems = [{
680
- chart: series.chart,
681
- options: {},
682
- fromLabel: fromLabel,
683
- toLabel: toLabel,
684
- color: gradientColor,
685
- drawLegendSymbol: this.drawLegendSymbolGradient,
686
- visible: true,
687
- setState: noop,
688
- setVisible: noop
689
- }];
690
-
691
- series.legendItems = legendItems;
692
- }
693
- },
694
-
695
- /**
696
- * If neither valueRanges nor colorRanges are defined, use basic area symbol.
697
- */
698
- drawLegendSymbol: seriesTypes.area.prototype.drawLegendSymbol,
699
-
700
- /**
701
- * Gets the series' symbol in the legend and extended legend with more information.
702
- *
703
- * @param {Object} legend The legend object
704
- * @param {Object} item The series (this) or point
705
- */
706
- drawLegendSymbolGradient: function (legend, item) {
707
- var spacing = legend.options.symbolPadding,
708
- padding = pick(legend.options.padding, 8),
709
- positionY,
710
- positionX,
711
- gradientSize = this.chart.renderer.fontMetrics(legend.options.itemStyle.fontSize).h,
712
- horizontal = legend.options.layout === 'horizontal',
713
- box1,
714
- box2,
715
- box3,
716
- rectangleLength = pick(legend.options.rectangleLength, 200);
717
-
718
- // Set local variables based on option.
719
- if (horizontal) {
720
- positionY = -(spacing / 2);
721
- positionX = 0;
722
- } else {
723
- positionY = -rectangleLength + legend.baseline - (spacing / 2);
724
- positionX = padding + gradientSize;
725
- }
726
-
727
- // Creates the from text.
728
- item.fromText = this.chart.renderer.text(
729
- item.fromLabel, // Text.
730
- positionX, // Lower left x.
731
- positionY // Lower left y.
732
- ).attr({
733
- zIndex: 2
734
- }).add(item.legendGroup);
735
- box1 = item.fromText.getBBox();
736
-
737
- // Creates legend symbol.
738
- // Ternary changes variables based on option.
739
- item.legendSymbol = this.chart.renderer.rect(
740
- horizontal ? box1.x + box1.width + spacing : box1.x - gradientSize - spacing, // Upper left x.
741
- box1.y, // Upper left y.
742
- horizontal ? rectangleLength : gradientSize, // Width.
743
- horizontal ? gradientSize : rectangleLength, // Height.
744
- 2 // Corner radius.
745
- ).attr({
746
- zIndex: 1
747
- }).add(item.legendGroup);
748
- box2 = item.legendSymbol.getBBox();
749
-
750
- // Creates the to text.
751
- // Vertical coordinate changed based on option.
752
- item.toText = this.chart.renderer.text(
753
- item.toLabel,
754
- box2.x + box2.width + spacing,
755
- horizontal ? positionY : box2.y + box2.height - spacing
756
- ).attr({
757
- zIndex: 2
758
- }).add(item.legendGroup);
759
- box3 = item.toText.getBBox();
760
-
761
- // Changes legend box settings based on option.
762
- if (horizontal) {
763
- legend.offsetWidth = box1.width + box2.width + box3.width + (spacing * 2) + padding;
764
- legend.itemY = gradientSize + padding;
765
- } else {
766
- legend.offsetWidth = Math.max(box1.width, box3.width) + (spacing) + box2.width + padding;
767
- legend.itemY = box2.height + padding;
768
- legend.itemX = spacing;
769
- }
770
- },
771
-
772
- /**
773
- * Get the bounding box of all paths in the map combined.
774
- */
775
- getBox: function (paths) {
776
- var maxX = Number.MIN_VALUE,
777
- minX = Number.MAX_VALUE,
778
- maxY = Number.MIN_VALUE,
779
- minY = Number.MAX_VALUE,
780
- hasBox;
781
-
782
- // Find the bounding box
783
- each(paths || [], function (point) {
784
-
785
- if (point.path) {
786
- if (typeof point.path === 'string') {
787
- point.path = H.splitPath(point.path);
788
- }
789
-
790
- var path = point.path || [],
791
- i = path.length,
792
- even = false, // while loop reads from the end
793
- pointMaxX = Number.MIN_VALUE,
794
- pointMinX = Number.MAX_VALUE,
795
- pointMaxY = Number.MIN_VALUE,
796
- pointMinY = Number.MAX_VALUE;
797
-
798
- // The first time a map point is used, analyze its box
799
- if (!point._foundBox) {
800
- while (i--) {
801
- if (typeof path[i] === 'number' && !isNaN(path[i])) {
802
- if (even) { // even = x
803
- pointMaxX = Math.max(pointMaxX, path[i]);
804
- pointMinX = Math.min(pointMinX, path[i]);
805
- } else { // odd = Y
806
- pointMaxY = Math.max(pointMaxY, path[i]);
807
- pointMinY = Math.min(pointMinY, path[i]);
808
- }
809
- even = !even;
810
- }
811
- }
812
- // Cache point bounding box for use to position data labels, bubbles etc
813
- point._midX = pointMinX + (pointMaxX - pointMinX) * pick(point.middleX, 0.5);
814
- point._midY = pointMinY + (pointMaxY - pointMinY) * pick(point.middleY, 0.5);
815
- point._maxX = pointMaxX;
816
- point._minX = pointMinX;
817
- point._maxY = pointMaxY;
818
- point._minY = pointMinY;
819
- point._foundBox = true;
820
- }
821
-
822
- maxX = Math.max(maxX, point._maxX);
823
- minX = Math.min(minX, point._minX);
824
- maxY = Math.max(maxY, point._maxY);
825
- minY = Math.min(minY, point._minY);
826
-
827
- hasBox = true;
828
- }
829
- });
830
-
831
- // Set the box for the whole series
832
- if (hasBox) {
833
- this.minY = Math.min(minY, pick(this.minY, Number.MAX_VALUE));
834
- this.maxY = Math.max(maxY, pick(this.maxY, Number.MIN_VALUE));
835
- this.minX = Math.min(minX, pick(this.minX, Number.MAX_VALUE));
836
- this.maxX = Math.max(maxX, pick(this.maxX, Number.MIN_VALUE));
837
- }
838
- },
839
-
840
- getExtremes: function () {
841
- this.dataMin = this.minY;
842
- this.dataMax = this.maxY;
843
- },
844
-
845
- /**
846
- * Translate the path so that it automatically fits into the plot area box
847
- * @param {Object} path
848
- */
849
- translatePath: function (path) {
850
-
851
- var series = this,
852
- even = false, // while loop reads from the end
853
- xAxis = series.xAxis,
854
- yAxis = series.yAxis,
855
- i;
856
-
857
- // Preserve the original
858
- path = [].concat(path);
859
-
860
- // Do the translation
861
- i = path.length;
862
- while (i--) {
863
- if (typeof path[i] === 'number') {
864
- if (even) { // even = x
865
- path[i] = xAxis.translate(path[i]);
866
- } else { // odd = Y
867
- path[i] = yAxis.len - yAxis.translate(path[i]);
868
- }
869
- even = !even;
870
- }
871
- }
872
-
873
-
874
- return path;
875
- },
876
-
877
- /**
878
- * Extend setData to join in mapData. If the allAreas option is true, all areas
879
- * from the mapData are used, and those that don't correspond to a data value
880
- * are given null values.
881
- */
882
- setData: function (data, redraw) {
883
- var options = this.options,
884
- mapData = options.mapData,
885
- joinBy = options.dataJoinBy,
886
- dataUsed = [];
887
-
888
-
889
- this.getBox(data);
890
- this.getBox(mapData);
891
- if (options.allAreas && mapData) {
892
-
893
- data = data || [];
894
-
895
- // Registered the point codes that actually hold data
896
- if (joinBy) {
897
- each(data, function (point) {
898
- dataUsed.push(point[joinBy]);
899
- });
900
- }
901
-
902
- // Add those map points that don't correspond to data, which will be drawn as null points
903
- each(mapData, function (mapPoint) {
904
- if (!joinBy || inArray(mapPoint[joinBy], dataUsed) === -1) {
905
- data.push(merge(mapPoint, { y: null }));
906
- }
907
- });
908
- }
909
- H.Series.prototype.setData.call(this, data, redraw);
910
- },
911
-
912
- /**
913
- * For each point, get the corresponding map data
914
- */
915
- getMapData: function (key, value) {
916
- var options = this.options,
917
- mapData = options.mapData,
918
- mapMap = this.mapMap,
919
- i = mapData.length;
920
-
921
- // Create a cache for quicker lookup second time
922
- if (!mapMap) {
923
- mapMap = this.mapMap = [];
924
- }
925
- if (mapMap[value] !== undefined) {
926
- return mapData[mapMap[value]];
927
-
928
- } else if (value !== undefined) {
929
- while (i--) {
930
- if (mapData[i][key] === value) {
931
- mapMap[value] = i; // cache it
932
- return mapData[i];
933
- }
934
- }
935
- }
936
- },
937
-
938
- /**
939
- * Add the path option for data points. Find the max value for color calculation.
940
- */
941
- translate: function () {
942
- var series = this,
943
- dataMin = Number.MAX_VALUE,
944
- dataMax = Number.MIN_VALUE;
945
-
946
- series.generatePoints();
947
-
948
- each(series.data, function (point) {
949
-
950
- point.shapeType = 'path';
951
- point.shapeArgs = {
952
- d: series.translatePath(point.path)
953
- };
954
-
955
- // TODO: do point colors in drawPoints instead of point.init
956
- if (typeof point.y === 'number') {
957
- if (point.y > dataMax) {
958
- dataMax = point.y;
959
- } else if (point.y < dataMin) {
960
- dataMin = point.y;
961
- }
962
- }
963
- });
964
-
965
- series.translateColors(dataMin, dataMax);
966
- },
967
-
968
- /**
969
- * In choropleth maps, the color is a result of the value, so this needs translation too
970
- */
971
- translateColors: function (dataMin, dataMax) {
972
-
973
- var seriesOptions = this.options,
974
- valueRanges = seriesOptions.valueRanges,
975
- colorRange = seriesOptions.colorRange,
976
- colorKey = this.colorKey,
977
- nullColor = seriesOptions.nullColor,
978
- from,
979
- to;
980
-
981
- if (colorRange) {
982
- from = Color(colorRange.from);
983
- to = Color(colorRange.to);
984
- }
985
- each(this.data, function (point) {
986
- var value = point[colorKey],
987
- isNull = value === null,
988
- range,
989
- color,
990
- i,
991
- pos;
992
-
993
- if (valueRanges) {
994
- i = valueRanges.length;
995
- if (isNull) {
996
- color = nullColor;
997
- } else {
998
- while (i--) {
999
- range = valueRanges[i];
1000
- from = range.from;
1001
- to = range.to;
1002
- if ((from === UNDEFINED || value >= from) && (to === UNDEFINED || value <= to)) {
1003
- color = range.color;
1004
- break;
1005
- }
1006
- }
1007
- point.valueRange = i;
1008
- }
1009
- } else if (colorRange && !isNull) {
1010
-
1011
- pos = 1 - ((dataMax - value) / (dataMax - dataMin));
1012
- color = tweenColors(from, to, pos);
1013
- } else if (isNull) {
1014
- color = nullColor;
1015
- }
1016
-
1017
- if (color) {
1018
- point.color = null; // reset from previous drilldowns, use of the same data options
1019
- point.options.color = color;
1020
- }
1021
- });
1022
- },
1023
-
1024
- drawGraph: noop,
1025
-
1026
- /**
1027
- * We need the points' bounding boxes in order to draw the data labels, so
1028
- * we skip it now and call it from drawPoints instead.
1029
- */
1030
- drawDataLabels: noop,
1031
-
1032
- /**
1033
- * Use the drawPoints method of column, that is able to handle simple shapeArgs.
1034
- * Extend it by assigning the tooltip position.
1035
- */
1036
- drawPoints: function () {
1037
- var series = this,
1038
- xAxis = series.xAxis,
1039
- yAxis = series.yAxis,
1040
- colorKey = series.colorKey;
1041
-
1042
- // Make points pass test in drawing
1043
- each(series.data, function (point) {
1044
- point.plotY = 1; // pass null test in column.drawPoints
1045
- if (point[colorKey] === null) {
1046
- point[colorKey] = 0;
1047
- point.isNull = true;
1048
- }
1049
- });
1050
-
1051
- // Draw them
1052
- seriesTypes.column.prototype.drawPoints.apply(series);
1053
-
1054
- each(series.data, function (point) {
1055
-
1056
- // Record the middle point (loosely based on centroid), determined
1057
- // by the middleX and middleY options.
1058
- point.plotX = xAxis.toPixels(point._midX, true);
1059
- point.plotY = yAxis.toPixels(point._midY, true);
1060
-
1061
- // Reset escaped null points
1062
- if (point.isNull) {
1063
- point[colorKey] = null;
1064
- }
1065
- });
1066
-
1067
- // Now draw the data labels
1068
- H.Series.prototype.drawDataLabels.call(series);
1069
-
1070
- },
1071
-
1072
- /**
1073
- * Animate in the new series from the clicked point in the old series.
1074
- * Depends on the drilldown.js module
1075
- */
1076
- animateDrilldown: function (init) {
1077
- var toBox = this.chart.plotBox,
1078
- level = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1],
1079
- fromBox = level.bBox,
1080
- animationOptions = this.chart.options.drilldown.animation,
1081
- scale;
1082
-
1083
- if (!init) {
1084
-
1085
- scale = Math.min(fromBox.width / toBox.width, fromBox.height / toBox.height);
1086
- level.shapeArgs = {
1087
- scaleX: scale,
1088
- scaleY: scale,
1089
- translateX: fromBox.x,
1090
- translateY: fromBox.y
1091
- };
1092
-
1093
- // TODO: Animate this.group instead
1094
- each(this.points, function (point) {
1095
-
1096
- point.graphic
1097
- .attr(level.shapeArgs)
1098
- .animate({
1099
- scaleX: 1,
1100
- scaleY: 1,
1101
- translateX: 0,
1102
- translateY: 0
1103
- }, animationOptions);
1104
-
1105
- });
1106
-
1107
- delete this.animate;
1108
- }
1109
-
1110
- },
1111
-
1112
- /**
1113
- * When drilling up, pull out the individual point graphics from the lower series
1114
- * and animate them into the origin point in the upper series.
1115
- */
1116
- animateDrillupFrom: function (level) {
1117
- seriesTypes.column.prototype.animateDrillupFrom.call(this, level);
1118
- },
1119
-
1120
-
1121
- /**
1122
- * When drilling up, keep the upper series invisible until the lower series has
1123
- * moved into place
1124
- */
1125
- animateDrillupTo: function (init) {
1126
- seriesTypes.column.prototype.animateDrillupTo.call(this, init);
1127
- }
1128
- });
1129
-
1130
-
1131
- // The mapline series type
1132
- plotOptions.mapline = merge(plotOptions.map, {
1133
- lineWidth: 1,
1134
- backgroundColor: 'none'
1135
- });
1136
- seriesTypes.mapline = extendClass(seriesTypes.map, {
1137
- type: 'mapline',
1138
- pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
1139
- stroke: 'color',
1140
- 'stroke-width': 'lineWidth',
1141
- fill: 'backgroundColor'
1142
- },
1143
- drawLegendSymbol: seriesTypes.line.prototype.drawLegendSymbol
1144
- });
1145
-
1146
- // The mappoint series type
1147
- plotOptions.mappoint = merge(plotOptions.scatter, {
1148
- dataLabels: {
1149
- enabled: true,
1150
- format: '{point.name}',
1151
- color: 'black',
1152
- style: {
1153
- textShadow: '0 0 5px white'
1154
- }
1155
- }
1156
- });
1157
- seriesTypes.mappoint = extendClass(seriesTypes.scatter, {
1158
- type: 'mappoint'
1159
- });
1160
-
1161
- // The mapbubble series type
1162
- if (seriesTypes.bubble) {
1163
-
1164
- plotOptions.mapbubble = merge(plotOptions.bubble, {
1165
- tooltip: {
1166
- pointFormat: '{point.name}: {point.z}'
1167
- }
1168
- });
1169
- seriesTypes.mapbubble = extendClass(seriesTypes.bubble, {
1170
- pointClass: extendClass(Point, {
1171
- applyOptions: MapAreaPoint.prototype.applyOptions
1172
- }),
1173
- xyFromShape: true,
1174
- type: 'mapbubble',
1175
- pointArrayMap: ['z'], // If one single value is passed, it is interpreted as z
1176
- /**
1177
- * Return the map area identified by the dataJoinBy option
1178
- */
1179
- getMapData: seriesTypes.map.prototype.getMapData,
1180
- getBox: seriesTypes.map.prototype.getBox,
1181
- setData: seriesTypes.map.prototype.setData
1182
- });
1183
- }
1184
-
1185
- // Create symbols for the zoom buttons
1186
- function selectiveRoundedRect(attr, x, y, w, h, rTopLeft, rTopRight, rBottomRight, rBottomLeft) {
1187
- var normalize = (attr['stroke-width'] % 2 / 2);
1188
-
1189
- x -= normalize;
1190
- y -= normalize;
1191
-
1192
- return ['M', x + rTopLeft, y,
1193
- // top side
1194
- 'L', x + w - rTopRight, y,
1195
- // top right corner
1196
- 'C', x + w - rTopRight / 2, y, x + w, y + rTopRight / 2, x + w, y + rTopRight,
1197
- // right side
1198
- 'L', x + w, y + h - rBottomRight,
1199
- // bottom right corner
1200
- 'C', x + w, y + h - rBottomRight / 2, x + w - rBottomRight / 2, y + h, x + w - rBottomRight, y + h,
1201
- // bottom side
1202
- 'L', x + rBottomLeft, y + h,
1203
- // bottom left corner
1204
- 'C', x + rBottomLeft / 2, y + h, x, y + h - rBottomLeft / 2, x, y + h - rBottomLeft,
1205
- // left side
1206
- 'L', x, y + rTopLeft,
1207
- // top left corner
1208
- 'C', x, y + rTopLeft / 2, x + rTopLeft / 2, y, x + rTopLeft, y,
1209
- 'Z'
1210
- ];
1211
- }
1212
- symbols.topbutton = function (x, y, w, h, attr) {
1213
- return selectiveRoundedRect(attr, x, y, w, h, attr.r, attr.r, 0, 0);
1214
- };
1215
- symbols.bottombutton = function (x, y, w, h, attr) {
1216
- return selectiveRoundedRect(attr, x, y, w, h, 0, 0, attr.r, attr.r);
1217
- };
1218
- // The symbol callbacks are generated on the SVGRenderer object in all browsers. Even
1219
- // VML browsers need this in order to generate shapes in export. Now share
1220
- // them with the VMLRenderer.
1221
- if (H.Renderer === VMLRenderer) {
1222
- each(['topbutton', 'bottombutton'], function (shape) {
1223
- VMLRenderer.prototype.symbols[shape] = symbols[shape];
1224
- });
1225
- }
1226
-
1227
-
1228
- /**
1229
- * A wrapper for Chart with all the default values for a Map
1230
- */
1231
- H.Map = function (options, callback) {
1232
-
1233
- var hiddenAxis = {
1234
- endOnTick: false,
1235
- gridLineWidth: 0,
1236
- labels: {
1237
- enabled: false
1238
- },
1239
- lineWidth: 0,
1240
- minPadding: 0,
1241
- maxPadding: 0,
1242
- startOnTick: false,
1243
- tickWidth: 0,
1244
- title: null
1245
- },
1246
- seriesOptions;
1247
-
1248
- // Don't merge the data
1249
- seriesOptions = options.series;
1250
- options.series = null;
1251
-
1252
- options = merge({
1253
- chart: {
1254
- panning: 'xy'
1255
- },
1256
- xAxis: hiddenAxis,
1257
- yAxis: merge(hiddenAxis, { reversed: true })
1258
- },
1259
- options, // user's options
1260
-
1261
- { // forced options
1262
- chart: {
1263
- type: 'map',
1264
- inverted: false
1265
- }
1266
- });
1267
-
1268
- options.series = seriesOptions;
1269
-
1270
-
1271
- return new Chart(options, callback);
1272
- };
1273
- }(Highcharts));