From 554de444b87aab5f93cb1593a8095612cf9479a7 Mon Sep 17 00:00:00 2001
From: yujian <yujian@163.com>
Date: 星期二, 09 六月 2020 17:34:30 +0800
Subject: [PATCH] 订单

---
 fanli/src/main/webapp/admin/new/js/third-party/highcharts/modules/map.src.js | 2004 +++++++++++++++++++++++++++++-----------------------------
 1 files changed, 1,002 insertions(+), 1,002 deletions(-)

diff --git a/fanli/src/main/webapp/admin/new/js/third-party/highcharts/modules/map.src.js b/fanli/src/main/webapp/admin/new/js/third-party/highcharts/modules/map.src.js
index 6af8e21..671ed6c 100644
--- a/fanli/src/main/webapp/admin/new/js/third-party/highcharts/modules/map.src.js
+++ b/fanli/src/main/webapp/admin/new/js/third-party/highcharts/modules/map.src.js
@@ -1,1002 +1,1002 @@
-/**
- * @license Map plugin v0.1 for Highcharts
- *
- * (c) 2011-2013 Torstein H酶nsi
- *
- * License: www.highcharts.com/license
- */
-
-/* 
- * See www.highcharts.com/studies/world-map.htm for use case.
- *
- * To do:
- * - Optimize long variable names and alias adapter methods and Highcharts namespace variables
- * - Zoom and pan GUI
- */
-(function (Highcharts) {
-	var UNDEFINED,
-		Axis = Highcharts.Axis,
-		Chart = Highcharts.Chart,
-		Point = Highcharts.Point,
-		Pointer = Highcharts.Pointer,
-		each = Highcharts.each,
-		extend = Highcharts.extend,
-		merge = Highcharts.merge,
-		pick = Highcharts.pick,
-		numberFormat = Highcharts.numberFormat,
-		defaultOptions = Highcharts.getOptions(),
-		seriesTypes = Highcharts.seriesTypes,
-		plotOptions = defaultOptions.plotOptions,
-		wrap = Highcharts.wrap,
-		Color = Highcharts.Color,
-		noop = function () {};
-
-	
-
-	/*
-	 * Return an intermediate color between two colors, according to pos where 0
-	 * is the from color and 1 is the to color
-	 */
-	function tweenColors(from, to, pos) {
-		var i = 4,
-			rgba = [];
-
-		while (i--) {
-			rgba[i] = Math.round(
-				to.rgba[i] + (from.rgba[i] - to.rgba[i]) * (1 - pos)
-			);
-		}
-		return 'rgba(' + rgba.join(',') + ')';
-	}
-
-	// Set the default map navigation options
-	defaultOptions.mapNavigation = {
-		buttonOptions: {
-			align: 'right',
-			verticalAlign: 'bottom',
-			x: 0,
-			width: 18,
-			height: 18,
-			style: {
-				fontSize: '15px',
-				fontWeight: 'bold',
-				textAlign: 'center'
-			}
-		},
-		buttons: {
-			zoomIn: {
-				onclick: function () {
-					this.mapZoom(0.5);
-				},
-				text: '+',
-				y: -32
-			},
-			zoomOut: {
-				onclick: function () {
-					this.mapZoom(2);
-				},
-				text: '-',
-				y: 0
-			}
-		}
-		// enableButtons: false,
-		// enableTouchZoom: false,
-		// zoomOnDoubleClick: false,
-		// zoomOnMouseWheel: false
-
-	};
-	
-	/**
-	 * Utility for reading SVG paths directly.
-	 */
-	Highcharts.splitPath = function (path) {
-		var i;
-
-		// Move letters apart
-		path = path.replace(/([A-Za-z])/g, ' $1 ');
-		// Trim
-		path = path.replace(/^\s*/, "").replace(/\s*$/, "");
-		
-		// Split on spaces and commas
-		path = path.split(/[ ,]+/);
-		
-		// Parse numbers
-		for (i = 0; i < path.length; i++) {
-			if (!/[a-zA-Z]/.test(path[i])) {
-				path[i] = parseFloat(path[i]);
-			}
-		}
-		return path;
-	};
-
-	// A placeholder for map definitions
-	Highcharts.maps = {};
-	
-	/**
-	 * Override to use the extreme coordinates from the SVG shape, not the
-	 * data values
-	 */
-	wrap(Axis.prototype, 'getSeriesExtremes', function (proceed) {
-		var isXAxis = this.isXAxis,
-			dataMin,
-			dataMax,
-			xData = [];
-
-		// Remove the xData array and cache it locally so that the proceed method doesn't use it
-		each(this.series, function (series, i) {
-			if (series.useMapGeometry) {
-				xData[i] = series.xData;
-				series.xData = [];
-			}
-		});
-
-		// Call base to reach normal cartesian series (like mappoint)
-		proceed.call(this);
-
-		// Run extremes logic for map and mapline
-		dataMin = pick(this.dataMin, Number.MAX_VALUE);
-		dataMax = pick(this.dataMax, Number.MIN_VALUE);
-		each(this.series, function (series, i) {
-			if (series.useMapGeometry) {
-				dataMin = Math.min(dataMin, series[isXAxis ? 'minX' : 'minY']);
-				dataMax = Math.max(dataMax, series[isXAxis ? 'maxX' : 'maxY']);
-				series.xData = xData[i]; // Reset xData array
-			}
-		});
-		
-		this.dataMin = dataMin;
-		this.dataMax = dataMax;
-	});
-	
-	/**
-	 * Override axis translation to make sure the aspect ratio is always kept
-	 */
-	wrap(Axis.prototype, 'setAxisTranslation', function (proceed) {
-		var chart = this.chart,
-			mapRatio,
-			plotRatio = chart.plotWidth / chart.plotHeight,
-			isXAxis = this.isXAxis,
-			adjustedAxisLength,
-			xAxis = chart.xAxis[0],
-			padAxis;
-		
-		// Run the parent method
-		proceed.call(this);
-		
-		// On Y axis, handle both
-		if (chart.options.chart.type === 'map' && !isXAxis && xAxis.transA !== UNDEFINED) {
-			
-			// Use the same translation for both axes
-			this.transA = xAxis.transA = Math.min(this.transA, xAxis.transA);
-			
-			mapRatio = (xAxis.max - xAxis.min) / (this.max - this.min);
-			
-			// What axis to pad to put the map in the middle
-			padAxis = mapRatio > plotRatio ? this : xAxis;
-			
-			// Pad it
-			adjustedAxisLength = (padAxis.max - padAxis.min) * padAxis.transA;
-			padAxis.minPixelPadding = (padAxis.len - adjustedAxisLength) / 2;
-		}
-	});
-
-
-	//--- Start zooming and panning features
-
-	wrap(Chart.prototype, 'render', function (proceed) {
-		var chart = this,
-			mapNavigation = chart.options.mapNavigation;
-
-		proceed.call(chart);
-
-		// Render the plus and minus buttons
-		chart.renderMapNavigation();
-
-		// Add the double click event
-		if (mapNavigation.zoomOnDoubleClick) {
-			Highcharts.addEvent(chart.container, 'dblclick', function (e) {
-				chart.pointer.onContainerDblClick(e);
-			});
-		}
-
-		// Add the mousewheel event
-		if (mapNavigation.zoomOnMouseWheel) {
-			Highcharts.addEvent(chart.container, document.onmousewheel === undefined ? 'DOMMouseScroll' : 'mousewheel', function (e) {
-				chart.pointer.onContainerMouseWheel(e);
-			});
-		}
-	});
-
-	// Extend the Pointer
-	extend(Pointer.prototype, {
-
-		/**
-		 * The event handler for the doubleclick event
-		 */
-		onContainerDblClick: function (e) {
-			var chart = this.chart;
-
-			e = this.normalize(e);
-
-			if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
-				chart.mapZoom(
-					0.5,
-					chart.xAxis[0].toValue(e.chartX),
-					chart.yAxis[0].toValue(e.chartY)
-				);
-			}
-		},
-
-		/**
-		 * The event handler for the mouse scroll event
-		 */
-		onContainerMouseWheel: function (e) {
-			var chart = this.chart,
-				delta;
-
-			e = this.normalize(e);
-
-			// Firefox uses e.detail, WebKit and IE uses wheelDelta
-			delta = e.detail || -(e.wheelDelta / 120);
-			if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
-				chart.mapZoom(
-					delta > 0 ? 2 : 0.5,
-					chart.xAxis[0].toValue(e.chartX),
-					chart.yAxis[0].toValue(e.chartY)
-				);
-			}
-		}
-	});
-	// Implement the pinchType option
-	wrap(Pointer.prototype, 'init', function (proceed, chart, options) {
-
-		proceed.call(this, chart, options);
-
-		// Pinch status
-		if (options.mapNavigation.enableTouchZoom) {
-			this.pinchX = this.pinchHor = 
-				this.pinchY = this.pinchVert = true;
-		}
-	});
-
-	// Add events to the Chart object itself
-	extend(Chart.prototype, {
-		renderMapNavigation: function () {
-			var chart = this,
-				options = this.options.mapNavigation,
-				buttons = options.buttons,
-				n,
-				button,
-				buttonOptions,
-				outerHandler = function () { 
-					this.handler.call(chart); 
-				};
-
-			if (options.enableButtons) {
-				for (n in buttons) {
-					if (buttons.hasOwnProperty(n)) {
-						buttonOptions = merge(options.buttonOptions, buttons[n]);
-
-						button = chart.renderer.button(buttonOptions.text, 0, 0, outerHandler)
-							.attr({
-								width: buttonOptions.width,
-								height: buttonOptions.height
-							})
-							.css(buttonOptions.style)
-							.add();
-						button.handler = buttonOptions.onclick;
-						button.align(extend(buttonOptions, { width: button.width, height: button.height }), null, 'spacingBox');
-					}
-				}
-			}
-		},
-
-		/**
-		 * Fit an inner box to an outer. If the inner box overflows left or right, align it to the sides of the
-		 * outer. If it overflows both sides, fit it within the outer. This is a pattern that occurs more places
-		 * in Highcharts, perhaps it should be elevated to a common utility function.
-		 */
-		fitToBox: function (inner, outer) {
-			each([['x', 'width'], ['y', 'height']], function (dim) {
-				var pos = dim[0],
-					size = dim[1];
-				if (inner[pos] + inner[size] > outer[pos] + outer[size]) { // right overflow
-					if (inner[size] > outer[size]) { // the general size is greater, fit fully to outer
-						inner[size] = outer[size];
-						inner[pos] = outer[pos];
-					} else { // align right
-						inner[pos] = outer[pos] + outer[size] - inner[size];
-					}
-				}
-				if (inner[size] > outer[size]) {
-					inner[size] = outer[size];
-				}
-				if (inner[pos] < outer[pos]) {
-					inner[pos] = outer[pos];
-				}
-				
-			});
-
-			return inner;
-		},
-
-		/**
-		 * Zoom the map in or out by a certain amount. Less than 1 zooms in, greater than 1 zooms out.
-		 */
-		mapZoom: function (howMuch, centerXArg, centerYArg) {
-
-			if (this.isMapZooming) {
-				return;
-			}
-
-			var chart = this,
-				xAxis = chart.xAxis[0],
-				xRange = xAxis.max - xAxis.min,
-				centerX = pick(centerXArg, xAxis.min + xRange / 2),
-				newXRange = xRange * howMuch,
-				yAxis = chart.yAxis[0],
-				yRange = yAxis.max - yAxis.min,
-				centerY = pick(centerYArg, yAxis.min + yRange / 2),
-				newYRange = yRange * howMuch,
-				newXMin = centerX - newXRange / 2,
-				newYMin = centerY - newYRange / 2,
-				animation = pick(chart.options.chart.animation, true),
-				delay,
-				newExt = chart.fitToBox({
-					x: newXMin,
-					y: newYMin,
-					width: newXRange,
-					height: newYRange
-				}, {
-					x: xAxis.dataMin,
-					y: yAxis.dataMin,
-					width: xAxis.dataMax - xAxis.dataMin,
-					height: yAxis.dataMax - yAxis.dataMin
-				});
-
-			xAxis.setExtremes(newExt.x, newExt.x + newExt.width, false);
-			yAxis.setExtremes(newExt.y, newExt.y + newExt.height, false);
-
-			// Prevent zooming until this one is finished animating
-			delay = animation ? animation.duration || 500 : 0;
-			if (delay) {
-				chart.isMapZooming = true;
-				setTimeout(function () {
-					chart.isMapZooming = false;
-				}, delay);
-			}
-
-			chart.redraw();
-		}
-	});
-	
-	/**
-	 * Extend the default options with map options
-	 */
-	plotOptions.map = merge(plotOptions.scatter, {
-		animation: false, // makes the complex shapes slow
-		nullColor: '#F8F8F8',
-		borderColor: 'silver',
-		borderWidth: 1,
-		marker: null,
-		stickyTracking: false,
-		dataLabels: {
-			verticalAlign: 'middle'
-		},
-		turboThreshold: 0,
-		tooltip: {
-			followPointer: true,
-			pointFormat: '{point.name}: {point.y}<br/>'
-		},
-		states: {
-			normal: {
-				animation: true
-			}
-		}
-	});
-
-	var MapAreaPoint = Highcharts.extendClass(Point, {
-		/**
-		 * Extend the Point object to split paths
-		 */
-		applyOptions: function (options, x) {
-
-			var point = Point.prototype.applyOptions.call(this, options, x);
-
-			if (point.path && typeof point.path === 'string') {
-				point.path = point.options.path = Highcharts.splitPath(point.path);
-			}
-
-			return point;
-		},
-		/**
-		 * Stop the fade-out 
-		 */
-		onMouseOver: function () {
-			clearTimeout(this.colorInterval);
-			Point.prototype.onMouseOver.call(this);
-		},
-		/**
-		 * Custom animation for tweening out the colors. Animation reduces blinking when hovering
-		 * over islands and coast lines. We run a custom implementation of animation becuase we
-		 * need to be able to run this independently from other animations like zoom redraw. Also,
-		 * adding color animation to the adapters would introduce almost the same amount of code.
-		 */
-		onMouseOut: function () {
-			var point = this,
-				start = +new Date(),
-				normalColor = Color(point.options.color),
-				hoverColor = Color(point.pointAttr.hover.fill),
-				animation = point.series.options.states.normal.animation,
-				duration = animation && (animation.duration || 500);
-
-			if (duration && normalColor.rgba.length === 4 && hoverColor.rgba.length === 4) {
-				delete point.pointAttr[''].fill; // avoid resetting it in Point.setState
-
-				clearTimeout(point.colorInterval);
-				point.colorInterval = setInterval(function () {
-					var pos = (new Date() - start) / duration,
-						graphic = point.graphic;
-					if (pos > 1) {
-						pos = 1;
-					}
-					if (graphic) {
-						graphic.attr('fill', tweenColors(hoverColor, normalColor, pos));
-					}
-					if (pos >= 1) {
-						clearTimeout(point.colorInterval);
-					}
-				}, 13);
-			}
-			Point.prototype.onMouseOut.call(point);
-		}
-	});
-
-	/**
-	 * Add the series type
-	 */
-	seriesTypes.map = Highcharts.extendClass(seriesTypes.scatter, {
-		type: 'map',
-		pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
-			stroke: 'borderColor',
-			'stroke-width': 'borderWidth',
-			fill: 'color'
-		},
-		colorKey: 'y',
-		pointClass: MapAreaPoint,
-		trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'],
-		getSymbol: noop,
-		supportsDrilldown: true,
-		getExtremesFromAll: true,
-		useMapGeometry: true, // get axis extremes from paths, not values
-		init: function (chart) {
-			var series = this,
-				valueDecimals = chart.options.legend.valueDecimals,
-				legendItems = [],
-				name,
-				from,
-				to,
-				fromLabel,
-				toLabel,
-				colorRange,
-				valueRanges,
-				gradientColor,
-				grad,
-				tmpLabel,
-				horizontal = chart.options.legend.layout === 'horizontal';
-
-			
-			Highcharts.Series.prototype.init.apply(this, arguments);
-			colorRange = series.options.colorRange;
-			valueRanges = series.options.valueRanges;
-
-			if (valueRanges) {
-				each(valueRanges, function (range) {
-					from = range.from;
-					to = range.to;
-					
-					// Assemble the default name. This can be overridden by legend.options.labelFormatter
-					name = '';
-					if (from === UNDEFINED) {
-						name = '< ';
-					} else if (to === UNDEFINED) {
-						name = '> ';
-					}
-					if (from !== UNDEFINED) {
-						name += numberFormat(from, valueDecimals);
-					}
-					if (from !== UNDEFINED && to !== UNDEFINED) {
-						name += ' - ';
-					}
-					if (to !== UNDEFINED) {
-						name += numberFormat(to, valueDecimals);
-					}
-					
-					// Add a mock object to the legend items
-					legendItems.push(Highcharts.extend({
-						chart: series.chart,
-						name: name,
-						options: {},
-						drawLegendSymbol: seriesTypes.area.prototype.drawLegendSymbol,
-						visible: true,
-						setState: function () {},
-						setVisible: function () {}
-					}, range));
-				});
-				series.legendItems = legendItems;
-
-			} else if (colorRange) {
-
-				from = colorRange.from;
-				to = colorRange.to;
-				fromLabel = colorRange.fromLabel;
-				toLabel = colorRange.toLabel;
-
-				// Flips linearGradient variables and label text.
-				grad = horizontal ? [0, 0, 1, 0] : [0, 1, 0, 0]; 
-				if (!horizontal) {
-					tmpLabel = fromLabel;
-					fromLabel = toLabel;
-					toLabel = tmpLabel;
-				} 
-
-				// Creates color gradient.
-				gradientColor = {
-					linearGradient: { x1: grad[0], y1: grad[1], x2: grad[2], y2: grad[3] },
-					stops: 
-					[
-						[0, from],
-						[1, to]
-					]
-				};
-
-				// Add a mock object to the legend items.
-				legendItems = [{
-					chart: series.chart,
-					options: {},
-					fromLabel: fromLabel,
-					toLabel: toLabel,
-					color: gradientColor,
-					drawLegendSymbol: this.drawLegendSymbolGradient,
-					visible: true,
-					setState: function () {},
-					setVisible: function () {}
-				}];
-
-				series.legendItems = legendItems;
-			}
-		},
-
-		/**
-		 * If neither valueRanges nor colorRanges are defined, use basic area symbol.
-		 */
-		drawLegendSymbol: seriesTypes.area.prototype.drawLegendSymbol,
-
-		/**
-		 * Gets the series' symbol in the legend and extended legend with more information.
-		 * 
-		 * @param {Object} legend The legend object
-		 * @param {Object} item The series (this) or point
-		 */
-		drawLegendSymbolGradient: function (legend, item) {
-			var spacing = legend.options.symbolPadding,
-				padding = pick(legend.options.padding, 8),
-				positionY,
-				positionX,
-				gradientSize = this.chart.renderer.fontMetrics(legend.options.itemStyle.fontSize).h,
-				horizontal = legend.options.layout === 'horizontal',
-				box1,
-				box2,
-				box3,
-				rectangleLength = pick(legend.options.rectangleLength, 200);
-
-			// Set local variables based on option.
-			if (horizontal) {
-				positionY = -(spacing / 2);
-				positionX = 0;
-			} else {
-				positionY = -rectangleLength + legend.baseline - (spacing / 2);
-				positionX = padding + gradientSize;
-			}
-
-			// Creates the from text.
-			item.fromText = this.chart.renderer.text(
-					item.fromLabel,	// Text.
-					positionX,		// Lower left x.
-					positionY		// Lower left y.
-				).attr({
-					zIndex: 2
-				}).add(item.legendGroup);
-			box1 = item.fromText.getBBox();
-
-			// Creates legend symbol.
-			// Ternary changes variables based on option.
-			item.legendSymbol = this.chart.renderer.rect(
-				horizontal ? box1.x + box1.width + spacing : box1.x - gradientSize - spacing,		// Upper left x.
-				box1.y,																				// Upper left y.
-				horizontal ? rectangleLength : gradientSize,											// Width.
-				horizontal ? gradientSize : rectangleLength,										// Height.
-				2																					// Corner radius.
-			).attr({
-				zIndex: 1
-			}).add(item.legendGroup);
-			box2 = item.legendSymbol.getBBox();
-
-			// Creates the to text.
-			// Vertical coordinate changed based on option.
-			item.toText = this.chart.renderer.text(
-					item.toLabel,
-					box2.x + box2.width + spacing,
-					horizontal ? positionY : box2.y + box2.height - spacing
-				).attr({
-					zIndex: 2
-				}).add(item.legendGroup);
-			box3 = item.toText.getBBox();
-
-			// Changes legend box settings based on option.
-			if (horizontal) {
-				legend.offsetWidth = box1.width + box2.width + box3.width + (spacing * 2) + padding;
-				legend.itemY = gradientSize + padding;
-			} else {
-				legend.offsetWidth = Math.max(box1.width, box3.width) + (spacing) + box2.width + padding;
-				legend.itemY = box2.height + padding;
-				legend.itemX = spacing;
-			}
-		},
-
-		/**
-		 * Get the bounding box of all paths in the map combined.
-		 */
-		getBox: function (paths) {
-			var maxX = Number.MIN_VALUE, 
-				minX =  Number.MAX_VALUE, 
-				maxY = Number.MIN_VALUE, 
-				minY =  Number.MAX_VALUE;
-			
-			
-			// Find the bounding box
-			each(paths || this.options.data, function (point) {
-				var path = point.path,
-					i = path.length,
-					even = false, // while loop reads from the end
-					pointMaxX = Number.MIN_VALUE, 
-					pointMinX =  Number.MAX_VALUE, 
-					pointMaxY = Number.MIN_VALUE, 
-					pointMinY =  Number.MAX_VALUE;
-					
-				while (i--) {
-					if (typeof path[i] === 'number' && !isNaN(path[i])) {
-						if (even) { // even = x
-							pointMaxX = Math.max(pointMaxX, path[i]);
-							pointMinX = Math.min(pointMinX, path[i]);
-						} else { // odd = Y
-							pointMaxY = Math.max(pointMaxY, path[i]);
-							pointMinY = Math.min(pointMinY, path[i]);
-						}
-						even = !even;
-					}
-				}
-				// Cache point bounding box for use to position data labels
-				point._maxX = pointMaxX;
-				point._minX = pointMinX;
-				point._maxY = pointMaxY;
-				point._minY = pointMinY;
-
-				maxX = Math.max(maxX, pointMaxX);
-				minX = Math.min(minX, pointMinX);
-				maxY = Math.max(maxY, pointMaxY);
-				minY = Math.min(minY, pointMinY);
-			});
-			this.minY = minY;
-			this.maxY = maxY;
-			this.minX = minX;
-			this.maxX = maxX;
-			
-		},
-		
-		
-		
-		/**
-		 * Translate the path so that it automatically fits into the plot area box
-		 * @param {Object} path
-		 */
-		translatePath: function (path) {
-			
-			var series = this,
-				even = false, // while loop reads from the end
-				xAxis = series.xAxis,
-				yAxis = series.yAxis,
-				i;
-				
-			// Preserve the original
-			path = [].concat(path);
-				
-			// Do the translation
-			i = path.length;
-			while (i--) {
-				if (typeof path[i] === 'number') {
-					if (even) { // even = x
-						path[i] = Math.round(xAxis.translate(path[i]));
-					} else { // odd = Y
-						path[i] = Math.round(yAxis.len - yAxis.translate(path[i]));
-					}
-					even = !even;
-				}
-			}
-			return path;
-		},
-		
-		setData: function () {
-			Highcharts.Series.prototype.setData.apply(this, arguments);
-			this.getBox();
-		},
-		
-		/**
-		 * Add the path option for data points. Find the max value for color calculation.
-		 */
-		translate: function () {
-			var series = this,
-				dataMin = Number.MAX_VALUE,
-				dataMax = Number.MIN_VALUE;
-	
-			series.generatePoints();
-	
-			each(series.data, function (point) {
-				
-				point.shapeType = 'path';
-				point.shapeArgs = {
-					d: series.translatePath(point.path)
-				};
-				
-				// TODO: do point colors in drawPoints instead of point.init
-				if (typeof point.y === 'number') {
-					if (point.y > dataMax) {
-						dataMax = point.y;
-					} else if (point.y < dataMin) {
-						dataMin = point.y;
-					}
-				}
-			});
-			
-			series.translateColors(dataMin, dataMax);
-		},
-		
-		/**
-		 * In choropleth maps, the color is a result of the value, so this needs translation too
-		 */
-		translateColors: function (dataMin, dataMax) {
-			
-			var seriesOptions = this.options,
-				valueRanges = seriesOptions.valueRanges,
-				colorRange = seriesOptions.colorRange,
-				colorKey = this.colorKey,
-				from,
-				to;
-
-			if (colorRange) {
-				from = Color(colorRange.from);
-				to = Color(colorRange.to);
-			}
-			
-			each(this.data, function (point) {
-				var value = point[colorKey],
-					range,
-					color,
-					i,
-					pos;
-
-				if (valueRanges) {
-					i = valueRanges.length;
-					while (i--) {
-						range = valueRanges[i];
-						from = range.from;
-						to = range.to;
-						if ((from === UNDEFINED || value >= from) && (to === UNDEFINED || value <= to)) {
-							color = range.color;
-							break;
-						}
-							
-					}
-				} else if (colorRange && value !== undefined) {
-
-					pos = 1 - ((dataMax - value) / (dataMax - dataMin));
-					color = value === null ? seriesOptions.nullColor : tweenColors(from, to, pos);
-				}
-
-				if (color) {
-					point.color = null; // reset from previous drilldowns, use of the same data options
-					point.options.color = color;
-				}
-			});
-		},
-		
-		drawGraph: noop,
-		
-		/**
-		 * We need the points' bounding boxes in order to draw the data labels, so 
-		 * we skip it now and call if from drawPoints instead.
-		 */
-		drawDataLabels: noop,
-		
-		/** 
-		 * Use the drawPoints method of column, that is able to handle simple shapeArgs.
-		 * Extend it by assigning the tooltip position.
-		 */
-		drawPoints: function () {
-			var series = this,
-				xAxis = series.xAxis,
-				yAxis = series.yAxis,
-				colorKey = series.colorKey;
-			
-			// Make points pass test in drawing
-			each(series.data, function (point) {
-				point.plotY = 1; // pass null test in column.drawPoints
-				if (point[colorKey] === null) {
-					point[colorKey] = 0;
-					point.isNull = true;
-				}
-			});
-			
-			// Draw them
-			seriesTypes.column.prototype.drawPoints.apply(series);
-			
-			each(series.data, function (point) {
-
-				var dataLabels = point.dataLabels,
-					minX = xAxis.toPixels(point._minX, true),
-					maxX = xAxis.toPixels(point._maxX, true),
-					minY = yAxis.toPixels(point._minY, true),
-					maxY = yAxis.toPixels(point._maxY, true);
-
-				point.plotX = Math.round(minX + (maxX - minX) * pick(dataLabels && dataLabels.anchorX, 0.5));
-				point.plotY = Math.round(minY + (maxY - minY) * pick(dataLabels && dataLabels.anchorY, 0.5)); 
-				
-				
-				// Reset escaped null points
-				if (point.isNull) {
-					point[colorKey] = null;
-				}
-			});
-
-			// Now draw the data labels
-			Highcharts.Series.prototype.drawDataLabels.call(series);
-			
-		},
-
-		/**
-		 * Animate in the new series from the clicked point in the old series.
-		 * Depends on the drilldown.js module
-		 */
-		animateDrilldown: function (init) {
-			var toBox = this.chart.plotBox,
-				level = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1],
-				fromBox = level.bBox,
-				animationOptions = this.chart.options.drilldown.animation,
-				scale;
-				
-			if (!init) {
-
-				scale = Math.min(fromBox.width / toBox.width, fromBox.height / toBox.height);
-				level.shapeArgs = {
-					scaleX: scale,
-					scaleY: scale,
-					translateX: fromBox.x,
-					translateY: fromBox.y
-				};
-				
-				// TODO: Animate this.group instead
-				each(this.points, function (point) {
-
-					point.graphic
-						.attr(level.shapeArgs)
-						.animate({
-							scaleX: 1,
-							scaleY: 1,
-							translateX: 0,
-							translateY: 0
-						}, animationOptions);
-
-				});
-
-				delete this.animate;
-			}
-			
-		},
-
-		/**
-		 * When drilling up, pull out the individual point graphics from the lower series
-		 * and animate them into the origin point in the upper series.
-		 */
-		animateDrillupFrom: function (level) {
-			seriesTypes.column.prototype.animateDrillupFrom.call(this, level);
-		},
-
-
-		/**
-		 * When drilling up, keep the upper series invisible until the lower series has
-		 * moved into place
-		 */
-		animateDrillupTo: function (init) {
-			seriesTypes.column.prototype.animateDrillupTo.call(this, init);
-		}
-	});
-
-
-	// The mapline series type
-	plotOptions.mapline = merge(plotOptions.map, {
-		lineWidth: 1,
-		backgroundColor: 'none'
-	});
-	seriesTypes.mapline = Highcharts.extendClass(seriesTypes.map, {
-		type: 'mapline',
-		pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
-			stroke: 'color',
-			'stroke-width': 'lineWidth',
-			fill: 'backgroundColor'
-		},
-		drawLegendSymbol: seriesTypes.line.prototype.drawLegendSymbol
-	});
-
-	// The mappoint series type
-	plotOptions.mappoint = merge(plotOptions.scatter, {
-		dataLabels: {
-			enabled: true,
-			format: '{point.name}',
-			color: 'black',
-			style: {
-				textShadow: '0 0 5px white'
-			}
-		}
-	});
-	seriesTypes.mappoint = Highcharts.extendClass(seriesTypes.scatter, {
-		type: 'mappoint'
-	});
-	
-
-	
-	/**
-	 * A wrapper for Chart with all the default values for a Map
-	 */
-	Highcharts.Map = function (options, callback) {
-		
-		var hiddenAxis = {
-				endOnTick: false,
-				gridLineWidth: 0,
-				labels: {
-					enabled: false
-				},
-				lineWidth: 0,
-				minPadding: 0,
-				maxPadding: 0,
-				startOnTick: false,
-				tickWidth: 0,
-				title: null
-			},
-			seriesOptions;
-		
-		// Don't merge the data
-		seriesOptions = options.series;
-		options.series = null;
-		
-		options = merge({
-			chart: {
-				type: 'map',
-				panning: 'xy'
-			},
-			xAxis: hiddenAxis,
-			yAxis: merge(hiddenAxis, { reversed: true })	
-		},
-		options, // user's options
-	
-		{ // forced options
-			chart: {
-				inverted: false
-			}
-		});
-	
-		options.series = seriesOptions;
-	
-	
-		return new Highcharts.Chart(options, callback);
-	};
-}(Highcharts));
+/**
+ * @license Map plugin v0.1 for Highcharts
+ *
+ * (c) 2011-2013 Torstein H酶nsi
+ *
+ * License: www.highcharts.com/license
+ */
+
+/* 
+ * See www.highcharts.com/studies/world-map.htm for use case.
+ *
+ * To do:
+ * - Optimize long variable names and alias adapter methods and Highcharts namespace variables
+ * - Zoom and pan GUI
+ */
+(function (Highcharts) {
+	var UNDEFINED,
+		Axis = Highcharts.Axis,
+		Chart = Highcharts.Chart,
+		Point = Highcharts.Point,
+		Pointer = Highcharts.Pointer,
+		each = Highcharts.each,
+		extend = Highcharts.extend,
+		merge = Highcharts.merge,
+		pick = Highcharts.pick,
+		numberFormat = Highcharts.numberFormat,
+		defaultOptions = Highcharts.getOptions(),
+		seriesTypes = Highcharts.seriesTypes,
+		plotOptions = defaultOptions.plotOptions,
+		wrap = Highcharts.wrap,
+		Color = Highcharts.Color,
+		noop = function () {};
+
+	
+
+	/*
+	 * Return an intermediate color between two colors, according to pos where 0
+	 * is the from color and 1 is the to color
+	 */
+	function tweenColors(from, to, pos) {
+		var i = 4,
+			rgba = [];
+
+		while (i--) {
+			rgba[i] = Math.round(
+				to.rgba[i] + (from.rgba[i] - to.rgba[i]) * (1 - pos)
+			);
+		}
+		return 'rgba(' + rgba.join(',') + ')';
+	}
+
+	// Set the default map navigation options
+	defaultOptions.mapNavigation = {
+		buttonOptions: {
+			align: 'right',
+			verticalAlign: 'bottom',
+			x: 0,
+			width: 18,
+			height: 18,
+			style: {
+				fontSize: '15px',
+				fontWeight: 'bold',
+				textAlign: 'center'
+			}
+		},
+		buttons: {
+			zoomIn: {
+				onclick: function () {
+					this.mapZoom(0.5);
+				},
+				text: '+',
+				y: -32
+			},
+			zoomOut: {
+				onclick: function () {
+					this.mapZoom(2);
+				},
+				text: '-',
+				y: 0
+			}
+		}
+		// enableButtons: false,
+		// enableTouchZoom: false,
+		// zoomOnDoubleClick: false,
+		// zoomOnMouseWheel: false
+
+	};
+	
+	/**
+	 * Utility for reading SVG paths directly.
+	 */
+	Highcharts.splitPath = function (path) {
+		var i;
+
+		// Move letters apart
+		path = path.replace(/([A-Za-z])/g, ' $1 ');
+		// Trim
+		path = path.replace(/^\s*/, "").replace(/\s*$/, "");
+		
+		// Split on spaces and commas
+		path = path.split(/[ ,]+/);
+		
+		// Parse numbers
+		for (i = 0; i < path.length; i++) {
+			if (!/[a-zA-Z]/.test(path[i])) {
+				path[i] = parseFloat(path[i]);
+			}
+		}
+		return path;
+	};
+
+	// A placeholder for map definitions
+	Highcharts.maps = {};
+	
+	/**
+	 * Override to use the extreme coordinates from the SVG shape, not the
+	 * data values
+	 */
+	wrap(Axis.prototype, 'getSeriesExtremes', function (proceed) {
+		var isXAxis = this.isXAxis,
+			dataMin,
+			dataMax,
+			xData = [];
+
+		// Remove the xData array and cache it locally so that the proceed method doesn't use it
+		each(this.series, function (series, i) {
+			if (series.useMapGeometry) {
+				xData[i] = series.xData;
+				series.xData = [];
+			}
+		});
+
+		// Call base to reach normal cartesian series (like mappoint)
+		proceed.call(this);
+
+		// Run extremes logic for map and mapline
+		dataMin = pick(this.dataMin, Number.MAX_VALUE);
+		dataMax = pick(this.dataMax, Number.MIN_VALUE);
+		each(this.series, function (series, i) {
+			if (series.useMapGeometry) {
+				dataMin = Math.min(dataMin, series[isXAxis ? 'minX' : 'minY']);
+				dataMax = Math.max(dataMax, series[isXAxis ? 'maxX' : 'maxY']);
+				series.xData = xData[i]; // Reset xData array
+			}
+		});
+		
+		this.dataMin = dataMin;
+		this.dataMax = dataMax;
+	});
+	
+	/**
+	 * Override axis translation to make sure the aspect ratio is always kept
+	 */
+	wrap(Axis.prototype, 'setAxisTranslation', function (proceed) {
+		var chart = this.chart,
+			mapRatio,
+			plotRatio = chart.plotWidth / chart.plotHeight,
+			isXAxis = this.isXAxis,
+			adjustedAxisLength,
+			xAxis = chart.xAxis[0],
+			padAxis;
+		
+		// Run the parent method
+		proceed.call(this);
+		
+		// On Y axis, handle both
+		if (chart.options.chart.type === 'map' && !isXAxis && xAxis.transA !== UNDEFINED) {
+			
+			// Use the same translation for both axes
+			this.transA = xAxis.transA = Math.min(this.transA, xAxis.transA);
+			
+			mapRatio = (xAxis.max - xAxis.min) / (this.max - this.min);
+			
+			// What axis to pad to put the map in the middle
+			padAxis = mapRatio > plotRatio ? this : xAxis;
+			
+			// Pad it
+			adjustedAxisLength = (padAxis.max - padAxis.min) * padAxis.transA;
+			padAxis.minPixelPadding = (padAxis.len - adjustedAxisLength) / 2;
+		}
+	});
+
+
+	//--- Start zooming and panning features
+
+	wrap(Chart.prototype, 'render', function (proceed) {
+		var chart = this,
+			mapNavigation = chart.options.mapNavigation;
+
+		proceed.call(chart);
+
+		// Render the plus and minus buttons
+		chart.renderMapNavigation();
+
+		// Add the double click event
+		if (mapNavigation.zoomOnDoubleClick) {
+			Highcharts.addEvent(chart.container, 'dblclick', function (e) {
+				chart.pointer.onContainerDblClick(e);
+			});
+		}
+
+		// Add the mousewheel event
+		if (mapNavigation.zoomOnMouseWheel) {
+			Highcharts.addEvent(chart.container, document.onmousewheel === undefined ? 'DOMMouseScroll' : 'mousewheel', function (e) {
+				chart.pointer.onContainerMouseWheel(e);
+			});
+		}
+	});
+
+	// Extend the Pointer
+	extend(Pointer.prototype, {
+
+		/**
+		 * The event handler for the doubleclick event
+		 */
+		onContainerDblClick: function (e) {
+			var chart = this.chart;
+
+			e = this.normalize(e);
+
+			if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
+				chart.mapZoom(
+					0.5,
+					chart.xAxis[0].toValue(e.chartX),
+					chart.yAxis[0].toValue(e.chartY)
+				);
+			}
+		},
+
+		/**
+		 * The event handler for the mouse scroll event
+		 */
+		onContainerMouseWheel: function (e) {
+			var chart = this.chart,
+				delta;
+
+			e = this.normalize(e);
+
+			// Firefox uses e.detail, WebKit and IE uses wheelDelta
+			delta = e.detail || -(e.wheelDelta / 120);
+			if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
+				chart.mapZoom(
+					delta > 0 ? 2 : 0.5,
+					chart.xAxis[0].toValue(e.chartX),
+					chart.yAxis[0].toValue(e.chartY)
+				);
+			}
+		}
+	});
+	// Implement the pinchType option
+	wrap(Pointer.prototype, 'init', function (proceed, chart, options) {
+
+		proceed.call(this, chart, options);
+
+		// Pinch status
+		if (options.mapNavigation.enableTouchZoom) {
+			this.pinchX = this.pinchHor = 
+				this.pinchY = this.pinchVert = true;
+		}
+	});
+
+	// Add events to the Chart object itself
+	extend(Chart.prototype, {
+		renderMapNavigation: function () {
+			var chart = this,
+				options = this.options.mapNavigation,
+				buttons = options.buttons,
+				n,
+				button,
+				buttonOptions,
+				outerHandler = function () { 
+					this.handler.call(chart); 
+				};
+
+			if (options.enableButtons) {
+				for (n in buttons) {
+					if (buttons.hasOwnProperty(n)) {
+						buttonOptions = merge(options.buttonOptions, buttons[n]);
+
+						button = chart.renderer.button(buttonOptions.text, 0, 0, outerHandler)
+							.attr({
+								width: buttonOptions.width,
+								height: buttonOptions.height
+							})
+							.css(buttonOptions.style)
+							.add();
+						button.handler = buttonOptions.onclick;
+						button.align(extend(buttonOptions, { width: button.width, height: button.height }), null, 'spacingBox');
+					}
+				}
+			}
+		},
+
+		/**
+		 * Fit an inner box to an outer. If the inner box overflows left or right, align it to the sides of the
+		 * outer. If it overflows both sides, fit it within the outer. This is a pattern that occurs more places
+		 * in Highcharts, perhaps it should be elevated to a common utility function.
+		 */
+		fitToBox: function (inner, outer) {
+			each([['x', 'width'], ['y', 'height']], function (dim) {
+				var pos = dim[0],
+					size = dim[1];
+				if (inner[pos] + inner[size] > outer[pos] + outer[size]) { // right overflow
+					if (inner[size] > outer[size]) { // the general size is greater, fit fully to outer
+						inner[size] = outer[size];
+						inner[pos] = outer[pos];
+					} else { // align right
+						inner[pos] = outer[pos] + outer[size] - inner[size];
+					}
+				}
+				if (inner[size] > outer[size]) {
+					inner[size] = outer[size];
+				}
+				if (inner[pos] < outer[pos]) {
+					inner[pos] = outer[pos];
+				}
+				
+			});
+
+			return inner;
+		},
+
+		/**
+		 * Zoom the map in or out by a certain amount. Less than 1 zooms in, greater than 1 zooms out.
+		 */
+		mapZoom: function (howMuch, centerXArg, centerYArg) {
+
+			if (this.isMapZooming) {
+				return;
+			}
+
+			var chart = this,
+				xAxis = chart.xAxis[0],
+				xRange = xAxis.max - xAxis.min,
+				centerX = pick(centerXArg, xAxis.min + xRange / 2),
+				newXRange = xRange * howMuch,
+				yAxis = chart.yAxis[0],
+				yRange = yAxis.max - yAxis.min,
+				centerY = pick(centerYArg, yAxis.min + yRange / 2),
+				newYRange = yRange * howMuch,
+				newXMin = centerX - newXRange / 2,
+				newYMin = centerY - newYRange / 2,
+				animation = pick(chart.options.chart.animation, true),
+				delay,
+				newExt = chart.fitToBox({
+					x: newXMin,
+					y: newYMin,
+					width: newXRange,
+					height: newYRange
+				}, {
+					x: xAxis.dataMin,
+					y: yAxis.dataMin,
+					width: xAxis.dataMax - xAxis.dataMin,
+					height: yAxis.dataMax - yAxis.dataMin
+				});
+
+			xAxis.setExtremes(newExt.x, newExt.x + newExt.width, false);
+			yAxis.setExtremes(newExt.y, newExt.y + newExt.height, false);
+
+			// Prevent zooming until this one is finished animating
+			delay = animation ? animation.duration || 500 : 0;
+			if (delay) {
+				chart.isMapZooming = true;
+				setTimeout(function () {
+					chart.isMapZooming = false;
+				}, delay);
+			}
+
+			chart.redraw();
+		}
+	});
+	
+	/**
+	 * Extend the default options with map options
+	 */
+	plotOptions.map = merge(plotOptions.scatter, {
+		animation: false, // makes the complex shapes slow
+		nullColor: '#F8F8F8',
+		borderColor: 'silver',
+		borderWidth: 1,
+		marker: null,
+		stickyTracking: false,
+		dataLabels: {
+			verticalAlign: 'middle'
+		},
+		turboThreshold: 0,
+		tooltip: {
+			followPointer: true,
+			pointFormat: '{point.name}: {point.y}<br/>'
+		},
+		states: {
+			normal: {
+				animation: true
+			}
+		}
+	});
+
+	var MapAreaPoint = Highcharts.extendClass(Point, {
+		/**
+		 * Extend the Point object to split paths
+		 */
+		applyOptions: function (options, x) {
+
+			var point = Point.prototype.applyOptions.call(this, options, x);
+
+			if (point.path && typeof point.path === 'string') {
+				point.path = point.options.path = Highcharts.splitPath(point.path);
+			}
+
+			return point;
+		},
+		/**
+		 * Stop the fade-out 
+		 */
+		onMouseOver: function () {
+			clearTimeout(this.colorInterval);
+			Point.prototype.onMouseOver.call(this);
+		},
+		/**
+		 * Custom animation for tweening out the colors. Animation reduces blinking when hovering
+		 * over islands and coast lines. We run a custom implementation of animation becuase we
+		 * need to be able to run this independently from other animations like zoom redraw. Also,
+		 * adding color animation to the adapters would introduce almost the same amount of code.
+		 */
+		onMouseOut: function () {
+			var point = this,
+				start = +new Date(),
+				normalColor = Color(point.options.color),
+				hoverColor = Color(point.pointAttr.hover.fill),
+				animation = point.series.options.states.normal.animation,
+				duration = animation && (animation.duration || 500);
+
+			if (duration && normalColor.rgba.length === 4 && hoverColor.rgba.length === 4) {
+				delete point.pointAttr[''].fill; // avoid resetting it in Point.setState
+
+				clearTimeout(point.colorInterval);
+				point.colorInterval = setInterval(function () {
+					var pos = (new Date() - start) / duration,
+						graphic = point.graphic;
+					if (pos > 1) {
+						pos = 1;
+					}
+					if (graphic) {
+						graphic.attr('fill', tweenColors(hoverColor, normalColor, pos));
+					}
+					if (pos >= 1) {
+						clearTimeout(point.colorInterval);
+					}
+				}, 13);
+			}
+			Point.prototype.onMouseOut.call(point);
+		}
+	});
+
+	/**
+	 * Add the series type
+	 */
+	seriesTypes.map = Highcharts.extendClass(seriesTypes.scatter, {
+		type: 'map',
+		pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
+			stroke: 'borderColor',
+			'stroke-width': 'borderWidth',
+			fill: 'color'
+		},
+		colorKey: 'y',
+		pointClass: MapAreaPoint,
+		trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'],
+		getSymbol: noop,
+		supportsDrilldown: true,
+		getExtremesFromAll: true,
+		useMapGeometry: true, // get axis extremes from paths, not values
+		init: function (chart) {
+			var series = this,
+				valueDecimals = chart.options.legend.valueDecimals,
+				legendItems = [],
+				name,
+				from,
+				to,
+				fromLabel,
+				toLabel,
+				colorRange,
+				valueRanges,
+				gradientColor,
+				grad,
+				tmpLabel,
+				horizontal = chart.options.legend.layout === 'horizontal';
+
+			
+			Highcharts.Series.prototype.init.apply(this, arguments);
+			colorRange = series.options.colorRange;
+			valueRanges = series.options.valueRanges;
+
+			if (valueRanges) {
+				each(valueRanges, function (range) {
+					from = range.from;
+					to = range.to;
+					
+					// Assemble the default name. This can be overridden by legend.options.labelFormatter
+					name = '';
+					if (from === UNDEFINED) {
+						name = '< ';
+					} else if (to === UNDEFINED) {
+						name = '> ';
+					}
+					if (from !== UNDEFINED) {
+						name += numberFormat(from, valueDecimals);
+					}
+					if (from !== UNDEFINED && to !== UNDEFINED) {
+						name += ' - ';
+					}
+					if (to !== UNDEFINED) {
+						name += numberFormat(to, valueDecimals);
+					}
+					
+					// Add a mock object to the legend items
+					legendItems.push(Highcharts.extend({
+						chart: series.chart,
+						name: name,
+						options: {},
+						drawLegendSymbol: seriesTypes.area.prototype.drawLegendSymbol,
+						visible: true,
+						setState: function () {},
+						setVisible: function () {}
+					}, range));
+				});
+				series.legendItems = legendItems;
+
+			} else if (colorRange) {
+
+				from = colorRange.from;
+				to = colorRange.to;
+				fromLabel = colorRange.fromLabel;
+				toLabel = colorRange.toLabel;
+
+				// Flips linearGradient variables and label text.
+				grad = horizontal ? [0, 0, 1, 0] : [0, 1, 0, 0]; 
+				if (!horizontal) {
+					tmpLabel = fromLabel;
+					fromLabel = toLabel;
+					toLabel = tmpLabel;
+				} 
+
+				// Creates color gradient.
+				gradientColor = {
+					linearGradient: { x1: grad[0], y1: grad[1], x2: grad[2], y2: grad[3] },
+					stops: 
+					[
+						[0, from],
+						[1, to]
+					]
+				};
+
+				// Add a mock object to the legend items.
+				legendItems = [{
+					chart: series.chart,
+					options: {},
+					fromLabel: fromLabel,
+					toLabel: toLabel,
+					color: gradientColor,
+					drawLegendSymbol: this.drawLegendSymbolGradient,
+					visible: true,
+					setState: function () {},
+					setVisible: function () {}
+				}];
+
+				series.legendItems = legendItems;
+			}
+		},
+
+		/**
+		 * If neither valueRanges nor colorRanges are defined, use basic area symbol.
+		 */
+		drawLegendSymbol: seriesTypes.area.prototype.drawLegendSymbol,
+
+		/**
+		 * Gets the series' symbol in the legend and extended legend with more information.
+		 * 
+		 * @param {Object} legend The legend object
+		 * @param {Object} item The series (this) or point
+		 */
+		drawLegendSymbolGradient: function (legend, item) {
+			var spacing = legend.options.symbolPadding,
+				padding = pick(legend.options.padding, 8),
+				positionY,
+				positionX,
+				gradientSize = this.chart.renderer.fontMetrics(legend.options.itemStyle.fontSize).h,
+				horizontal = legend.options.layout === 'horizontal',
+				box1,
+				box2,
+				box3,
+				rectangleLength = pick(legend.options.rectangleLength, 200);
+
+			// Set local variables based on option.
+			if (horizontal) {
+				positionY = -(spacing / 2);
+				positionX = 0;
+			} else {
+				positionY = -rectangleLength + legend.baseline - (spacing / 2);
+				positionX = padding + gradientSize;
+			}
+
+			// Creates the from text.
+			item.fromText = this.chart.renderer.text(
+					item.fromLabel,	// Text.
+					positionX,		// Lower left x.
+					positionY		// Lower left y.
+				).attr({
+					zIndex: 2
+				}).add(item.legendGroup);
+			box1 = item.fromText.getBBox();
+
+			// Creates legend symbol.
+			// Ternary changes variables based on option.
+			item.legendSymbol = this.chart.renderer.rect(
+				horizontal ? box1.x + box1.width + spacing : box1.x - gradientSize - spacing,		// Upper left x.
+				box1.y,																				// Upper left y.
+				horizontal ? rectangleLength : gradientSize,											// Width.
+				horizontal ? gradientSize : rectangleLength,										// Height.
+				2																					// Corner radius.
+			).attr({
+				zIndex: 1
+			}).add(item.legendGroup);
+			box2 = item.legendSymbol.getBBox();
+
+			// Creates the to text.
+			// Vertical coordinate changed based on option.
+			item.toText = this.chart.renderer.text(
+					item.toLabel,
+					box2.x + box2.width + spacing,
+					horizontal ? positionY : box2.y + box2.height - spacing
+				).attr({
+					zIndex: 2
+				}).add(item.legendGroup);
+			box3 = item.toText.getBBox();
+
+			// Changes legend box settings based on option.
+			if (horizontal) {
+				legend.offsetWidth = box1.width + box2.width + box3.width + (spacing * 2) + padding;
+				legend.itemY = gradientSize + padding;
+			} else {
+				legend.offsetWidth = Math.max(box1.width, box3.width) + (spacing) + box2.width + padding;
+				legend.itemY = box2.height + padding;
+				legend.itemX = spacing;
+			}
+		},
+
+		/**
+		 * Get the bounding box of all paths in the map combined.
+		 */
+		getBox: function (paths) {
+			var maxX = Number.MIN_VALUE, 
+				minX =  Number.MAX_VALUE, 
+				maxY = Number.MIN_VALUE, 
+				minY =  Number.MAX_VALUE;
+			
+			
+			// Find the bounding box
+			each(paths || this.options.data, function (point) {
+				var path = point.path,
+					i = path.length,
+					even = false, // while loop reads from the end
+					pointMaxX = Number.MIN_VALUE, 
+					pointMinX =  Number.MAX_VALUE, 
+					pointMaxY = Number.MIN_VALUE, 
+					pointMinY =  Number.MAX_VALUE;
+					
+				while (i--) {
+					if (typeof path[i] === 'number' && !isNaN(path[i])) {
+						if (even) { // even = x
+							pointMaxX = Math.max(pointMaxX, path[i]);
+							pointMinX = Math.min(pointMinX, path[i]);
+						} else { // odd = Y
+							pointMaxY = Math.max(pointMaxY, path[i]);
+							pointMinY = Math.min(pointMinY, path[i]);
+						}
+						even = !even;
+					}
+				}
+				// Cache point bounding box for use to position data labels
+				point._maxX = pointMaxX;
+				point._minX = pointMinX;
+				point._maxY = pointMaxY;
+				point._minY = pointMinY;
+
+				maxX = Math.max(maxX, pointMaxX);
+				minX = Math.min(minX, pointMinX);
+				maxY = Math.max(maxY, pointMaxY);
+				minY = Math.min(minY, pointMinY);
+			});
+			this.minY = minY;
+			this.maxY = maxY;
+			this.minX = minX;
+			this.maxX = maxX;
+			
+		},
+		
+		
+		
+		/**
+		 * Translate the path so that it automatically fits into the plot area box
+		 * @param {Object} path
+		 */
+		translatePath: function (path) {
+			
+			var series = this,
+				even = false, // while loop reads from the end
+				xAxis = series.xAxis,
+				yAxis = series.yAxis,
+				i;
+				
+			// Preserve the original
+			path = [].concat(path);
+				
+			// Do the translation
+			i = path.length;
+			while (i--) {
+				if (typeof path[i] === 'number') {
+					if (even) { // even = x
+						path[i] = Math.round(xAxis.translate(path[i]));
+					} else { // odd = Y
+						path[i] = Math.round(yAxis.len - yAxis.translate(path[i]));
+					}
+					even = !even;
+				}
+			}
+			return path;
+		},
+		
+		setData: function () {
+			Highcharts.Series.prototype.setData.apply(this, arguments);
+			this.getBox();
+		},
+		
+		/**
+		 * Add the path option for data points. Find the max value for color calculation.
+		 */
+		translate: function () {
+			var series = this,
+				dataMin = Number.MAX_VALUE,
+				dataMax = Number.MIN_VALUE;
+	
+			series.generatePoints();
+	
+			each(series.data, function (point) {
+				
+				point.shapeType = 'path';
+				point.shapeArgs = {
+					d: series.translatePath(point.path)
+				};
+				
+				// TODO: do point colors in drawPoints instead of point.init
+				if (typeof point.y === 'number') {
+					if (point.y > dataMax) {
+						dataMax = point.y;
+					} else if (point.y < dataMin) {
+						dataMin = point.y;
+					}
+				}
+			});
+			
+			series.translateColors(dataMin, dataMax);
+		},
+		
+		/**
+		 * In choropleth maps, the color is a result of the value, so this needs translation too
+		 */
+		translateColors: function (dataMin, dataMax) {
+			
+			var seriesOptions = this.options,
+				valueRanges = seriesOptions.valueRanges,
+				colorRange = seriesOptions.colorRange,
+				colorKey = this.colorKey,
+				from,
+				to;
+
+			if (colorRange) {
+				from = Color(colorRange.from);
+				to = Color(colorRange.to);
+			}
+			
+			each(this.data, function (point) {
+				var value = point[colorKey],
+					range,
+					color,
+					i,
+					pos;
+
+				if (valueRanges) {
+					i = valueRanges.length;
+					while (i--) {
+						range = valueRanges[i];
+						from = range.from;
+						to = range.to;
+						if ((from === UNDEFINED || value >= from) && (to === UNDEFINED || value <= to)) {
+							color = range.color;
+							break;
+						}
+							
+					}
+				} else if (colorRange && value !== undefined) {
+
+					pos = 1 - ((dataMax - value) / (dataMax - dataMin));
+					color = value === null ? seriesOptions.nullColor : tweenColors(from, to, pos);
+				}
+
+				if (color) {
+					point.color = null; // reset from previous drilldowns, use of the same data options
+					point.options.color = color;
+				}
+			});
+		},
+		
+		drawGraph: noop,
+		
+		/**
+		 * We need the points' bounding boxes in order to draw the data labels, so 
+		 * we skip it now and call if from drawPoints instead.
+		 */
+		drawDataLabels: noop,
+		
+		/** 
+		 * Use the drawPoints method of column, that is able to handle simple shapeArgs.
+		 * Extend it by assigning the tooltip position.
+		 */
+		drawPoints: function () {
+			var series = this,
+				xAxis = series.xAxis,
+				yAxis = series.yAxis,
+				colorKey = series.colorKey;
+			
+			// Make points pass test in drawing
+			each(series.data, function (point) {
+				point.plotY = 1; // pass null test in column.drawPoints
+				if (point[colorKey] === null) {
+					point[colorKey] = 0;
+					point.isNull = true;
+				}
+			});
+			
+			// Draw them
+			seriesTypes.column.prototype.drawPoints.apply(series);
+			
+			each(series.data, function (point) {
+
+				var dataLabels = point.dataLabels,
+					minX = xAxis.toPixels(point._minX, true),
+					maxX = xAxis.toPixels(point._maxX, true),
+					minY = yAxis.toPixels(point._minY, true),
+					maxY = yAxis.toPixels(point._maxY, true);
+
+				point.plotX = Math.round(minX + (maxX - minX) * pick(dataLabels && dataLabels.anchorX, 0.5));
+				point.plotY = Math.round(minY + (maxY - minY) * pick(dataLabels && dataLabels.anchorY, 0.5)); 
+				
+				
+				// Reset escaped null points
+				if (point.isNull) {
+					point[colorKey] = null;
+				}
+			});
+
+			// Now draw the data labels
+			Highcharts.Series.prototype.drawDataLabels.call(series);
+			
+		},
+
+		/**
+		 * Animate in the new series from the clicked point in the old series.
+		 * Depends on the drilldown.js module
+		 */
+		animateDrilldown: function (init) {
+			var toBox = this.chart.plotBox,
+				level = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1],
+				fromBox = level.bBox,
+				animationOptions = this.chart.options.drilldown.animation,
+				scale;
+				
+			if (!init) {
+
+				scale = Math.min(fromBox.width / toBox.width, fromBox.height / toBox.height);
+				level.shapeArgs = {
+					scaleX: scale,
+					scaleY: scale,
+					translateX: fromBox.x,
+					translateY: fromBox.y
+				};
+				
+				// TODO: Animate this.group instead
+				each(this.points, function (point) {
+
+					point.graphic
+						.attr(level.shapeArgs)
+						.animate({
+							scaleX: 1,
+							scaleY: 1,
+							translateX: 0,
+							translateY: 0
+						}, animationOptions);
+
+				});
+
+				delete this.animate;
+			}
+			
+		},
+
+		/**
+		 * When drilling up, pull out the individual point graphics from the lower series
+		 * and animate them into the origin point in the upper series.
+		 */
+		animateDrillupFrom: function (level) {
+			seriesTypes.column.prototype.animateDrillupFrom.call(this, level);
+		},
+
+
+		/**
+		 * When drilling up, keep the upper series invisible until the lower series has
+		 * moved into place
+		 */
+		animateDrillupTo: function (init) {
+			seriesTypes.column.prototype.animateDrillupTo.call(this, init);
+		}
+	});
+
+
+	// The mapline series type
+	plotOptions.mapline = merge(plotOptions.map, {
+		lineWidth: 1,
+		backgroundColor: 'none'
+	});
+	seriesTypes.mapline = Highcharts.extendClass(seriesTypes.map, {
+		type: 'mapline',
+		pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
+			stroke: 'color',
+			'stroke-width': 'lineWidth',
+			fill: 'backgroundColor'
+		},
+		drawLegendSymbol: seriesTypes.line.prototype.drawLegendSymbol
+	});
+
+	// The mappoint series type
+	plotOptions.mappoint = merge(plotOptions.scatter, {
+		dataLabels: {
+			enabled: true,
+			format: '{point.name}',
+			color: 'black',
+			style: {
+				textShadow: '0 0 5px white'
+			}
+		}
+	});
+	seriesTypes.mappoint = Highcharts.extendClass(seriesTypes.scatter, {
+		type: 'mappoint'
+	});
+	
+
+	
+	/**
+	 * A wrapper for Chart with all the default values for a Map
+	 */
+	Highcharts.Map = function (options, callback) {
+		
+		var hiddenAxis = {
+				endOnTick: false,
+				gridLineWidth: 0,
+				labels: {
+					enabled: false
+				},
+				lineWidth: 0,
+				minPadding: 0,
+				maxPadding: 0,
+				startOnTick: false,
+				tickWidth: 0,
+				title: null
+			},
+			seriesOptions;
+		
+		// Don't merge the data
+		seriesOptions = options.series;
+		options.series = null;
+		
+		options = merge({
+			chart: {
+				type: 'map',
+				panning: 'xy'
+			},
+			xAxis: hiddenAxis,
+			yAxis: merge(hiddenAxis, { reversed: true })	
+		},
+		options, // user's options
+	
+		{ // forced options
+			chart: {
+				inverted: false
+			}
+		});
+	
+		options.series = seriesOptions;
+	
+	
+		return new Highcharts.Chart(options, callback);
+	};
+}(Highcharts));

--
Gitblit v1.8.0