.=< { Star Gans Tq } >=.

  • Home

  • Killme
  • Download
  • Current Path : /home/m/e/h/meharicl/www/recensement2/js/
    Upload File
    @Command ~ $  
    Current File : /home/m/e/h/meharicl/www/recensement2/js/highcharts-more.src.js

    // ==ClosureCompiler==
    // @compilation_level SIMPLE_OPTIMIZATIONS
    
    /**
     * @license Highcharts JS v3.0.6 (2013-10-04)
     *
     * (c) 2009-2013 Torstein Hønsi
     *
     * License: www.highcharts.com/license
     */
    
    // JSLint options:
    /*global Highcharts, HighchartsAdapter, document, window, navigator, setInterval, clearInterval, clearTimeout, setTimeout, location, jQuery, $, console */
    
    (function (Highcharts, UNDEFINED) {
    var arrayMin = Highcharts.arrayMin,
    	arrayMax = Highcharts.arrayMax,
    	each = Highcharts.each,
    	extend = Highcharts.extend,
    	merge = Highcharts.merge,
    	map = Highcharts.map,
    	pick = Highcharts.pick,
    	pInt = Highcharts.pInt,
    	defaultPlotOptions = Highcharts.getOptions().plotOptions,
    	seriesTypes = Highcharts.seriesTypes,
    	extendClass = Highcharts.extendClass,
    	splat = Highcharts.splat,
    	wrap = Highcharts.wrap,
    	Axis = Highcharts.Axis,
    	Tick = Highcharts.Tick,
    	Series = Highcharts.Series,
    	colProto = seriesTypes.column.prototype,
    	math = Math,
    	mathRound = math.round,
    	mathFloor = math.floor,
    	mathMax = math.max,
    	noop = function () {};/**
     * The Pane object allows options that are common to a set of X and Y axes.
     * 
     * In the future, this can be extended to basic Highcharts and Highstock.
     */
    function Pane(options, chart, firstAxis) {
    	this.init.call(this, options, chart, firstAxis);
    }
    
    // Extend the Pane prototype
    extend(Pane.prototype, {
    	
    	/**
    	 * Initiate the Pane object
    	 */
    	init: function (options, chart, firstAxis) {
    		var pane = this,
    			backgroundOption,
    			defaultOptions = pane.defaultOptions;
    		
    		pane.chart = chart;
    		
    		// Set options
    		if (chart.angular) { // gauges
    			defaultOptions.background = {}; // gets extended by this.defaultBackgroundOptions
    		}
    		pane.options = options = merge(defaultOptions, options);
    		
    		backgroundOption = options.background;
    		
    		// To avoid having weighty logic to place, update and remove the backgrounds,
    		// push them to the first axis' plot bands and borrow the existing logic there.
    		if (backgroundOption) {
    			each([].concat(splat(backgroundOption)).reverse(), function (config) {
    				var backgroundColor = config.backgroundColor; // if defined, replace the old one (specific for gradients)
    				config = merge(pane.defaultBackgroundOptions, config);
    				if (backgroundColor) {
    					config.backgroundColor = backgroundColor;
    				}
    				config.color = config.backgroundColor; // due to naming in plotBands
    				firstAxis.options.plotBands.unshift(config);
    			});
    		}
    	},
    	
    	/**
    	 * The default options object
    	 */
    	defaultOptions: {
    		// background: {conditional},
    		center: ['50%', '50%'],
    		size: '85%',
    		startAngle: 0
    		//endAngle: startAngle + 360
    	},	
    	
    	/**
    	 * The default background options
    	 */
    	defaultBackgroundOptions: {
    		shape: 'circle',
    		borderWidth: 1,
    		borderColor: 'silver',
    		backgroundColor: {
    			linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
    			stops: [
    				[0, '#FFF'],
    				[1, '#DDD']
    			]
    		},
    		from: Number.MIN_VALUE, // corrected to axis min
    		innerRadius: 0,
    		to: Number.MAX_VALUE, // corrected to axis max
    		outerRadius: '105%'
    	}
    	
    });
    var axisProto = Axis.prototype,
    	tickProto = Tick.prototype;
    	
    /**
     * Augmented methods for the x axis in order to hide it completely, used for the X axis in gauges
     */
    var hiddenAxisMixin = {
    	getOffset: noop,
    	redraw: function () {
    		this.isDirty = false; // prevent setting Y axis dirty
    	},
    	render: function () {
    		this.isDirty = false; // prevent setting Y axis dirty
    	},
    	setScale: noop,
    	setCategories: noop,
    	setTitle: noop
    };
    
    /**
     * Augmented methods for the value axis
     */
    /*jslint unparam: true*/
    var radialAxisMixin = {
    	isRadial: true,
    	
    	/**
    	 * The default options extend defaultYAxisOptions
    	 */
    	defaultRadialGaugeOptions: {
    		labels: {
    			align: 'center',
    			x: 0,
    			y: null // auto
    		},
    		minorGridLineWidth: 0,
    		minorTickInterval: 'auto',
    		minorTickLength: 10,
    		minorTickPosition: 'inside',
    		minorTickWidth: 1,
    		plotBands: [],
    		tickLength: 10,
    		tickPosition: 'inside',
    		tickWidth: 2,
    		title: {
    			rotation: 0
    		},
    		zIndex: 2 // behind dials, points in the series group
    	},
    	
    	// Circular axis around the perimeter of a polar chart
    	defaultRadialXOptions: {
    		gridLineWidth: 1, // spokes
    		labels: {
    			align: null, // auto
    			distance: 15,
    			x: 0,
    			y: null // auto
    		},
    		maxPadding: 0,
    		minPadding: 0,
    		plotBands: [],
    		showLastLabel: false, 
    		tickLength: 0
    	},
    	
    	// Radial axis, like a spoke in a polar chart
    	defaultRadialYOptions: {
    		gridLineInterpolation: 'circle',
    		labels: {
    			align: 'right',
    			x: -3,
    			y: -2
    		},
    		plotBands: [],
    		showLastLabel: false,
    		title: {
    			x: 4,
    			text: null,
    			rotation: 90
    		}
    	},
    	
    	/**
    	 * Merge and set options
    	 */
    	setOptions: function (userOptions) {
    		
    		this.options = merge(
    			this.defaultOptions,
    			this.defaultRadialOptions,
    			userOptions
    		);
    		
    	},
    	
    	/**
    	 * Wrap the getOffset method to return zero offset for title or labels in a radial 
    	 * axis
    	 */
    	getOffset: function () {
    		// Call the Axis prototype method (the method we're in now is on the instance)
    		axisProto.getOffset.call(this);
    		
    		// Title or label offsets are not counted
    		this.chart.axisOffset[this.side] = 0;
    	},
    
    
    	/**
    	 * Get the path for the axis line. This method is also referenced in the getPlotLinePath
    	 * method.
    	 */
    	getLinePath: function (lineWidth, radius) {
    		var center = this.center;
    		radius = pick(radius, center[2] / 2 - this.offset);
    		
    		return this.chart.renderer.symbols.arc(
    			this.left + center[0],
    			this.top + center[1],
    			radius,
    			radius, 
    			{
    				start: this.startAngleRad,
    				end: this.endAngleRad,
    				open: true,
    				innerR: 0
    			}
    		);
    	},
    
    	/**
    	 * Override setAxisTranslation by setting the translation to the difference
    	 * in rotation. This allows the translate method to return angle for 
    	 * any given value.
    	 */
    	setAxisTranslation: function () {
    		
    		// Call uber method		
    		axisProto.setAxisTranslation.call(this);
    			
    		// Set transA and minPixelPadding
    		if (this.center) { // it's not defined the first time
    			if (this.isCircular) {
    				
    				this.transA = (this.endAngleRad - this.startAngleRad) / 
    					((this.max - this.min) || 1);
    					
    				
    			} else { 
    				this.transA = (this.center[2] / 2) / ((this.max - this.min) || 1);
    			}
    			
    			if (this.isXAxis) {
    				this.minPixelPadding = this.transA * this.minPointOffset +
    					(this.reversed ? (this.endAngleRad - this.startAngleRad) / 4 : 0); // ???
    			}
    		}
    	},
    	
    	/**
    	 * In case of auto connect, add one closestPointRange to the max value right before
    	 * tickPositions are computed, so that ticks will extend passed the real max.
    	 */
    	beforeSetTickPositions: function () {
    		if (this.autoConnect) {
    			this.max += (this.categories && 1) || this.pointRange || this.closestPointRange || 0; // #1197, #2260
    		}
    	},
    	
    	/**
    	 * Override the setAxisSize method to use the arc's circumference as length. This
    	 * allows tickPixelInterval to apply to pixel lengths along the perimeter
    	 */
    	setAxisSize: function () {
    		
    		axisProto.setAxisSize.call(this);
    
    		if (this.isRadial) {
    
    			// Set the center array
    			this.center = this.pane.center = seriesTypes.pie.prototype.getCenter.call(this.pane);
    			
    			this.len = this.width = this.height = this.isCircular ?
    				this.center[2] * (this.endAngleRad - this.startAngleRad) / 2 :
    				this.center[2] / 2;
    		}
    	},
    	
    	/**
    	 * Returns the x, y coordinate of a point given by a value and a pixel distance
    	 * from center
    	 */
    	getPosition: function (value, length) {
    		if (!this.isCircular) {
    			length = this.translate(value);
    			value = this.min;	
    		}
    		
    		return this.postTranslate(
    			this.translate(value),
    			pick(length, this.center[2] / 2) - this.offset
    		);		
    	},
    	
    	/**
    	 * Translate from intermediate plotX (angle), plotY (axis.len - radius) to final chart coordinates. 
    	 */
    	postTranslate: function (angle, radius) {
    		
    		var chart = this.chart,
    			center = this.center;
    			
    		angle = this.startAngleRad + angle;
    		
    		return {
    			x: chart.plotLeft + center[0] + Math.cos(angle) * radius,
    			y: chart.plotTop + center[1] + Math.sin(angle) * radius
    		}; 
    		
    	},
    	
    	/**
    	 * Find the path for plot bands along the radial axis
    	 */
    	getPlotBandPath: function (from, to, options) {
    		var center = this.center,
    			startAngleRad = this.startAngleRad,
    			fullRadius = center[2] / 2,
    			radii = [
    				pick(options.outerRadius, '100%'),
    				options.innerRadius,
    				pick(options.thickness, 10)
    			],
    			percentRegex = /%$/,
    			start,
    			end,
    			open,
    			isCircular = this.isCircular, // X axis in a polar chart
    			ret;
    			
    		// Polygonal plot bands
    		if (this.options.gridLineInterpolation === 'polygon') {
    			ret = this.getPlotLinePath(from).concat(this.getPlotLinePath(to, true));
    		
    		// Circular grid bands
    		} else {
    			
    			// Plot bands on Y axis (radial axis) - inner and outer radius depend on to and from
    			if (!isCircular) {
    				radii[0] = this.translate(from);
    				radii[1] = this.translate(to);
    			}
    			
    			// Convert percentages to pixel values
    			radii = map(radii, function (radius) {
    				if (percentRegex.test(radius)) {
    					radius = (pInt(radius, 10) * fullRadius) / 100;
    				}
    				return radius;
    			});
    			
    			// Handle full circle
    			if (options.shape === 'circle' || !isCircular) {
    				start = -Math.PI / 2;
    				end = Math.PI * 1.5;
    				open = true;
    			} else {
    				start = startAngleRad + this.translate(from);
    				end = startAngleRad + this.translate(to);
    			}
    		
    		
    			ret = this.chart.renderer.symbols.arc(
    				this.left + center[0],
    				this.top + center[1],
    				radii[0],
    				radii[0],
    				{
    					start: start,
    					end: end,
    					innerR: pick(radii[1], radii[0] - radii[2]),
    					open: open
    				}
    			);
    		}
    		 
    		return ret;
    	},
    	
    	/**
    	 * Find the path for plot lines perpendicular to the radial axis.
    	 */
    	getPlotLinePath: function (value, reverse) {
    		var axis = this,
    			center = axis.center,
    			chart = axis.chart,
    			end = axis.getPosition(value),
    			xAxis,
    			xy,
    			tickPositions,
    			ret;
    		
    		// Spokes
    		if (axis.isCircular) {
    			ret = ['M', center[0] + chart.plotLeft, center[1] + chart.plotTop, 'L', end.x, end.y];
    		
    		// Concentric circles			
    		} else if (axis.options.gridLineInterpolation === 'circle') {
    			value = axis.translate(value);
    			if (value) { // a value of 0 is in the center
    				ret = axis.getLinePath(0, value);
    			}
    		// Concentric polygons 
    		} else {
    			xAxis = chart.xAxis[0];
    			ret = [];
    			value = axis.translate(value);
    			tickPositions = xAxis.tickPositions;
    			if (xAxis.autoConnect) {
    				tickPositions = tickPositions.concat([tickPositions[0]]);
    			}
    			// Reverse the positions for concatenation of polygonal plot bands
    			if (reverse) {
    				tickPositions = [].concat(tickPositions).reverse();
    			}
    				
    			each(tickPositions, function (pos, i) {
    				xy = xAxis.getPosition(pos, value);
    				ret.push(i ? 'L' : 'M', xy.x, xy.y);
    			});
    			
    		}
    		return ret;
    	},
    	
    	/**
    	 * Find the position for the axis title, by default inside the gauge
    	 */
    	getTitlePosition: function () {
    		var center = this.center,
    			chart = this.chart,
    			titleOptions = this.options.title;
    		
    		return { 
    			x: chart.plotLeft + center[0] + (titleOptions.x || 0), 
    			y: chart.plotTop + center[1] - ({ high: 0.5, middle: 0.25, low: 0 }[titleOptions.align] * 
    				center[2]) + (titleOptions.y || 0)  
    		};
    	}
    	
    };
    /*jslint unparam: false*/
    
    /**
     * Override axisProto.init to mix in special axis instance functions and function overrides
     */
    wrap(axisProto, 'init', function (proceed, chart, userOptions) {
    	var axis = this,
    		angular = chart.angular,
    		polar = chart.polar,
    		isX = userOptions.isX,
    		isHidden = angular && isX,
    		isCircular,
    		startAngleRad,
    		endAngleRad,
    		options,
    		chartOptions = chart.options,
    		paneIndex = userOptions.pane || 0,
    		pane,
    		paneOptions;
    		
    	// Before prototype.init
    	if (angular) {
    		extend(this, isHidden ? hiddenAxisMixin : radialAxisMixin);
    		isCircular =  !isX;
    		if (isCircular) {
    			this.defaultRadialOptions = this.defaultRadialGaugeOptions;
    		}
    		
    	} else if (polar) {
    		//extend(this, userOptions.isX ? radialAxisMixin : radialAxisMixin);
    		extend(this, radialAxisMixin);
    		isCircular = isX;
    		this.defaultRadialOptions = isX ? this.defaultRadialXOptions : merge(this.defaultYAxisOptions, this.defaultRadialYOptions);
    		
    	}
    	
    	// Run prototype.init
    	proceed.call(this, chart, userOptions);
    	
    	if (!isHidden && (angular || polar)) {
    		options = this.options;
    		
    		// Create the pane and set the pane options.
    		if (!chart.panes) {
    			chart.panes = [];
    		}
    		this.pane = pane = chart.panes[paneIndex] = chart.panes[paneIndex] || new Pane(
    			splat(chartOptions.pane)[paneIndex],
    			chart,
    			axis
    		);
    		paneOptions = pane.options;
    		
    			
    		// Disable certain features on angular and polar axes
    		chart.inverted = false;
    		chartOptions.chart.zoomType = null;
    		
    		// Start and end angle options are
    		// given in degrees relative to top, while internal computations are
    		// in radians relative to right (like SVG).
    		this.startAngleRad = startAngleRad = (paneOptions.startAngle - 90) * Math.PI / 180;
    		this.endAngleRad = endAngleRad = (pick(paneOptions.endAngle, paneOptions.startAngle + 360)  - 90) * Math.PI / 180;
    		this.offset = options.offset || 0;
    		
    		this.isCircular = isCircular;
    		
    		// Automatically connect grid lines?
    		if (isCircular && userOptions.max === UNDEFINED && endAngleRad - startAngleRad === 2 * Math.PI) {
    			this.autoConnect = true;
    		}
    	}
    	
    });
    
    /**
     * Add special cases within the Tick class' methods for radial axes.
     */	
    wrap(tickProto, 'getPosition', function (proceed, horiz, pos, tickmarkOffset, old) {
    	var axis = this.axis;
    	
    	return axis.getPosition ? 
    		axis.getPosition(pos) :
    		proceed.call(this, horiz, pos, tickmarkOffset, old);	
    });
    
    /**
     * Wrap the getLabelPosition function to find the center position of the label
     * based on the distance option
     */	
    wrap(tickProto, 'getLabelPosition', function (proceed, x, y, label, horiz, labelOptions, tickmarkOffset, index, step) {
    	var axis = this.axis,
    		optionsY = labelOptions.y,
    		ret,
    		align = labelOptions.align,
    		angle = ((axis.translate(this.pos) + axis.startAngleRad + Math.PI / 2) / Math.PI * 180) % 360;
    	
    	if (axis.isRadial) {
    		ret = axis.getPosition(this.pos, (axis.center[2] / 2) + pick(labelOptions.distance, -25));
    		
    		// Automatically rotated
    		if (labelOptions.rotation === 'auto') {
    			label.attr({ 
    				rotation: angle
    			});
    		
    		// Vertically centered
    		} else if (optionsY === null) {
    			optionsY = pInt(label.styles.lineHeight) * 0.9 - label.getBBox().height / 2;
    		
    		}
    		
    		// Automatic alignment
    		if (align === null) {
    			if (axis.isCircular) {
    				if (angle > 20 && angle < 160) {
    					align = 'left'; // right hemisphere
    				} else if (angle > 200 && angle < 340) {
    					align = 'right'; // left hemisphere
    				} else {
    					align = 'center'; // top or bottom
    				}
    			} else {
    				align = 'center';
    			}
    			label.attr({
    				align: align
    			});
    		}
    		
    		ret.x += labelOptions.x;
    		ret.y += optionsY;
    		
    	} else {
    		ret = proceed.call(this, x, y, label, horiz, labelOptions, tickmarkOffset, index, step);
    	}
    	return ret;
    });
    
    /**
     * Wrap the getMarkPath function to return the path of the radial marker
     */
    wrap(tickProto, 'getMarkPath', function (proceed, x, y, tickLength, tickWidth, horiz, renderer) {
    	var axis = this.axis,
    		endPoint,
    		ret;
    		
    	if (axis.isRadial) {
    		endPoint = axis.getPosition(this.pos, axis.center[2] / 2 + tickLength);
    		ret = [
    			'M',
    			x,
    			y,
    			'L',
    			endPoint.x,
    			endPoint.y
    		];
    	} else {
    		ret = proceed.call(this, x, y, tickLength, tickWidth, horiz, renderer);
    	}
    	return ret;
    });/* 
     * The AreaRangeSeries class
     * 
     */
    
    /**
     * Extend the default options with map options
     */
    defaultPlotOptions.arearange = merge(defaultPlotOptions.area, {
    	lineWidth: 1,
    	marker: null,
    	threshold: null,
    	tooltip: {
    		pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.low}</b> - <b>{point.high}</b><br/>' 
    	},
    	trackByArea: true,
    	dataLabels: {
    		verticalAlign: null,
    		xLow: 0,
    		xHigh: 0,
    		yLow: 0,
    		yHigh: 0	
    	}
    });
    
    /**
     * Add the series type
     */
    seriesTypes.arearange = Highcharts.extendClass(seriesTypes.area, {
    	type: 'arearange',
    	pointArrayMap: ['low', 'high'],
    	toYData: function (point) {
    		return [point.low, point.high];
    	},
    	pointValKey: 'low',
    	
    	/**
    	 * Extend getSegments to force null points if the higher value is null. #1703.
    	 */
    	getSegments: function () {
    		var series = this;
    
    		each(series.points, function (point) {
    			if (!series.options.connectNulls && (point.low === null || point.high === null)) {
    				point.y = null;
    			} else if (point.low === null && point.high !== null) {
    				point.y = point.high;
    			}
    		});
    		Series.prototype.getSegments.call(this);
    	},
    	
    	/**
    	 * Translate data points from raw values x and y to plotX and plotY
    	 */
    	translate: function () {
    		var series = this,
    			yAxis = series.yAxis;
    
    		seriesTypes.area.prototype.translate.apply(series);
    
    		// Set plotLow and plotHigh
    		each(series.points, function (point) {
    
    			var low = point.low,
    				high = point.high,
    				plotY = point.plotY;
    
    			if (high === null && low === null) {
    				point.y = null;
    			} else if (low === null) {
    				point.plotLow = point.plotY = null;
    				point.plotHigh = yAxis.translate(high, 0, 1, 0, 1);
    			} else if (high === null) {
    				point.plotLow = plotY;
    				point.plotHigh = null;
    			} else {
    				point.plotLow = plotY;
    				point.plotHigh = yAxis.translate(high, 0, 1, 0, 1);
    			}
    		});
    	},
    	
    	/**
    	 * Extend the line series' getSegmentPath method by applying the segment
    	 * path to both lower and higher values of the range
    	 */
    	getSegmentPath: function (segment) {
    		
    		var lowSegment,
    			highSegment = [],
    			i = segment.length,
    			baseGetSegmentPath = Series.prototype.getSegmentPath,
    			point,
    			linePath,
    			lowerPath,
    			options = this.options,
    			step = options.step,
    			higherPath;
    			
    		// Remove nulls from low segment
    		lowSegment = HighchartsAdapter.grep(segment, function (point) {
    			return point.plotLow !== null;
    		});
    		
    		// Make a segment with plotX and plotY for the top values
    		while (i--) {
    			point = segment[i];
    			if (point.plotHigh !== null) {
    				highSegment.push({
    					plotX: point.plotX,
    					plotY: point.plotHigh
    				});
    			}
    		}
    		
    		// Get the paths
    		lowerPath = baseGetSegmentPath.call(this, lowSegment);
    		if (step) {
    			if (step === true) {
    				step = 'left';
    			}
    			options.step = { left: 'right', center: 'center', right: 'left' }[step]; // swap for reading in getSegmentPath
    		}
    		higherPath = baseGetSegmentPath.call(this, highSegment);
    		options.step = step;
    		
    		// Create a line on both top and bottom of the range
    		linePath = [].concat(lowerPath, higherPath);
    		
    		// For the area path, we need to change the 'move' statement into 'lineTo' or 'curveTo'
    		higherPath[0] = 'L'; // this probably doesn't work for spline			
    		this.areaPath = this.areaPath.concat(lowerPath, higherPath);
    		
    		return linePath;
    	},
    	
    	/**
    	 * Extend the basic drawDataLabels method by running it for both lower and higher
    	 * values.
    	 */
    	drawDataLabels: function () {
    		
    		var data = this.data,
    			length = data.length,
    			i,
    			originalDataLabels = [],
    			seriesProto = Series.prototype,
    			dataLabelOptions = this.options.dataLabels,
    			point,
    			inverted = this.chart.inverted;
    			
    		if (dataLabelOptions.enabled || this._hasPointLabels) {
    			
    			// Step 1: set preliminary values for plotY and dataLabel and draw the upper labels
    			i = length;
    			while (i--) {
    				point = data[i];
    				
    				// Set preliminary values
    				point.y = point.high;
    				point.plotY = point.plotHigh;
    				
    				// Store original data labels and set preliminary label objects to be picked up 
    				// in the uber method
    				originalDataLabels[i] = point.dataLabel;
    				point.dataLabel = point.dataLabelUpper;
    				
    				// Set the default offset
    				point.below = false;
    				if (inverted) {
    					dataLabelOptions.align = 'left';
    					dataLabelOptions.x = dataLabelOptions.xHigh;								
    				} else {
    					dataLabelOptions.y = dataLabelOptions.yHigh;
    				}
    			}
    			seriesProto.drawDataLabels.apply(this, arguments); // #1209
    			
    			// Step 2: reorganize and handle data labels for the lower values
    			i = length;
    			while (i--) {
    				point = data[i];
    				
    				// Move the generated labels from step 1, and reassign the original data labels
    				point.dataLabelUpper = point.dataLabel;
    				point.dataLabel = originalDataLabels[i];
    				
    				// Reset values
    				point.y = point.low;
    				point.plotY = point.plotLow;
    				
    				// Set the default offset
    				point.below = true;
    				if (inverted) {
    					dataLabelOptions.align = 'right';
    					dataLabelOptions.x = dataLabelOptions.xLow;
    				} else {
    					dataLabelOptions.y = dataLabelOptions.yLow;
    				}
    			}
    			seriesProto.drawDataLabels.apply(this, arguments);
    		}
    	
    	},
    	
    	alignDataLabel: seriesTypes.column.prototype.alignDataLabel,
    	
    	getSymbol: seriesTypes.column.prototype.getSymbol,
    	
    	drawPoints: noop
    });/**
     * The AreaSplineRangeSeries class
     */
    
    defaultPlotOptions.areasplinerange = merge(defaultPlotOptions.arearange);
    
    /**
     * AreaSplineRangeSeries object
     */
    seriesTypes.areasplinerange = extendClass(seriesTypes.arearange, {
    	type: 'areasplinerange',
    	getPointSpline: seriesTypes.spline.prototype.getPointSpline
    });/**
     * The ColumnRangeSeries class
     */
    defaultPlotOptions.columnrange = merge(defaultPlotOptions.column, defaultPlotOptions.arearange, {
    	lineWidth: 1,
    	pointRange: null
    });
    
    /**
     * ColumnRangeSeries object
     */
    seriesTypes.columnrange = extendClass(seriesTypes.arearange, {
    	type: 'columnrange',
    	/**
    	 * Translate data points from raw values x and y to plotX and plotY
    	 */
    	translate: function () {
    		var series = this,
    			yAxis = series.yAxis,
    			plotHigh;
    
    		colProto.translate.apply(series);
    
    		// Set plotLow and plotHigh
    		each(series.points, function (point) {
    			var shapeArgs = point.shapeArgs,
    				minPointLength = series.options.minPointLength,
    				heightDifference,
    				height,
    				y;
    
    			point.plotHigh = plotHigh = yAxis.translate(point.high, 0, 1, 0, 1);
    			point.plotLow = point.plotY;
    
    			// adjust shape
    			y = plotHigh;
    			height = point.plotY - plotHigh;
    
    			if (height < minPointLength) {
    				heightDifference = (minPointLength - height);
    				height += heightDifference;
    				y -= heightDifference / 2;
    			}
    			shapeArgs.height = height;
    			shapeArgs.y = y;
    		});
    	},
    	trackerGroups: ['group', 'dataLabels'],
    	drawGraph: noop,
    	pointAttrToOptions: colProto.pointAttrToOptions,
    	drawPoints: colProto.drawPoints,
    	drawTracker: colProto.drawTracker,
    	animate: colProto.animate,
    	getColumnMetrics: colProto.getColumnMetrics
    });
    /* 
     * The GaugeSeries class
     */
    
    
    
    /**
     * Extend the default options
     */
    defaultPlotOptions.gauge = merge(defaultPlotOptions.line, {
    	dataLabels: {
    		enabled: true,
    		y: 15,
    		borderWidth: 1,
    		borderColor: 'silver',
    		borderRadius: 3,
    		style: {
    			fontWeight: 'bold'
    		},
    		verticalAlign: 'top',
    		zIndex: 2
    	},
    	dial: {
    		// radius: '80%',
    		// backgroundColor: 'black',
    		// borderColor: 'silver',
    		// borderWidth: 0,
    		// baseWidth: 3,
    		// topWidth: 1,
    		// baseLength: '70%' // of radius
    		// rearLength: '10%'
    	},
    	pivot: {
    		//radius: 5,
    		//borderWidth: 0
    		//borderColor: 'silver',
    		//backgroundColor: 'black'
    	},
    	tooltip: {
    		headerFormat: ''
    	},
    	showInLegend: false
    });
    
    /**
     * Extend the point object
     */
    var GaugePoint = Highcharts.extendClass(Highcharts.Point, {
    	/**
    	 * Don't do any hover colors or anything
    	 */
    	setState: function (state) {
    		this.state = state;
    	}
    });
    
    
    /**
     * Add the series type
     */
    var GaugeSeries = {
    	type: 'gauge',
    	pointClass: GaugePoint,
    	
    	// chart.angular will be set to true when a gauge series is present, and this will
    	// be used on the axes
    	angular: true, 
    	drawGraph: noop,
    	fixedBox: true,
    	trackerGroups: ['group', 'dataLabels'],
    	
    	/**
    	 * Calculate paths etc
    	 */
    	translate: function () {
    		
    		var series = this,
    			yAxis = series.yAxis,
    			options = series.options,
    			center = yAxis.center;
    			
    		series.generatePoints();
    		
    		each(series.points, function (point) {
    			
    			var dialOptions = merge(options.dial, point.dial),
    				radius = (pInt(pick(dialOptions.radius, 80)) * center[2]) / 200,
    				baseLength = (pInt(pick(dialOptions.baseLength, 70)) * radius) / 100,
    				rearLength = (pInt(pick(dialOptions.rearLength, 10)) * radius) / 100,
    				baseWidth = dialOptions.baseWidth || 3,
    				topWidth = dialOptions.topWidth || 1,
    				rotation = yAxis.startAngleRad + yAxis.translate(point.y, null, null, null, true);
    
    			// Handle the wrap option
    			if (options.wrap === false) {
    				rotation = Math.max(yAxis.startAngleRad, Math.min(yAxis.endAngleRad, rotation));
    			}
    			rotation = rotation * 180 / Math.PI;
    				
    			point.shapeType = 'path';
    			point.shapeArgs = {
    				d: dialOptions.path || [
    					'M', 
    					-rearLength, -baseWidth / 2, 
    					'L', 
    					baseLength, -baseWidth / 2,
    					radius, -topWidth / 2,
    					radius, topWidth / 2,
    					baseLength, baseWidth / 2,
    					-rearLength, baseWidth / 2,
    					'z'
    				],
    				translateX: center[0],
    				translateY: center[1],
    				rotation: rotation
    			};
    			
    			// Positions for data label
    			point.plotX = center[0];
    			point.plotY = center[1];
    		});
    	},
    	
    	/**
    	 * Draw the points where each point is one needle
    	 */
    	drawPoints: function () {
    		
    		var series = this,
    			center = series.yAxis.center,
    			pivot = series.pivot,
    			options = series.options,
    			pivotOptions = options.pivot,
    			renderer = series.chart.renderer;
    		
    		each(series.points, function (point) {
    			
    			var graphic = point.graphic,
    				shapeArgs = point.shapeArgs,
    				d = shapeArgs.d,
    				dialOptions = merge(options.dial, point.dial); // #1233
    			
    			if (graphic) {
    				graphic.animate(shapeArgs);
    				shapeArgs.d = d; // animate alters it
    			} else {
    				point.graphic = renderer[point.shapeType](shapeArgs)
    					.attr({
    						stroke: dialOptions.borderColor || 'none',
    						'stroke-width': dialOptions.borderWidth || 0,
    						fill: dialOptions.backgroundColor || 'black',
    						rotation: shapeArgs.rotation // required by VML when animation is false
    					})
    					.add(series.group);
    			}
    		});
    		
    		// Add or move the pivot
    		if (pivot) {
    			pivot.animate({ // #1235
    				translateX: center[0],
    				translateY: center[1]
    			});
    		} else {
    			series.pivot = renderer.circle(0, 0, pick(pivotOptions.radius, 5))
    				.attr({
    					'stroke-width': pivotOptions.borderWidth || 0,
    					stroke: pivotOptions.borderColor || 'silver',
    					fill: pivotOptions.backgroundColor || 'black'
    				})
    				.translate(center[0], center[1])
    				.add(series.group);
    		}
    	},
    	
    	/**
    	 * Animate the arrow up from startAngle
    	 */
    	animate: function (init) {
    		var series = this;
    
    		if (!init) {
    			each(series.points, function (point) {
    				var graphic = point.graphic;
    
    				if (graphic) {
    					// start value
    					graphic.attr({
    						rotation: series.yAxis.startAngleRad * 180 / Math.PI
    					});
    
    					// animate
    					graphic.animate({
    						rotation: point.shapeArgs.rotation
    					}, series.options.animation);
    				}
    			});
    
    			// delete this function to allow it only once
    			series.animate = null;
    		}
    	},
    	
    	render: function () {
    		this.group = this.plotGroup(
    			'group', 
    			'series', 
    			this.visible ? 'visible' : 'hidden', 
    			this.options.zIndex, 
    			this.chart.seriesGroup
    		);
    		seriesTypes.pie.prototype.render.call(this);
    		this.group.clip(this.chart.clipRect);
    	},
    	
    	setData: seriesTypes.pie.prototype.setData,
    	drawTracker: seriesTypes.column.prototype.drawTracker
    };
    seriesTypes.gauge = Highcharts.extendClass(seriesTypes.line, GaugeSeries);/* ****************************************************************************
     * Start Box plot series code											      *
     *****************************************************************************/
    
    // Set default options
    defaultPlotOptions.boxplot = merge(defaultPlotOptions.column, {
    	fillColor: '#FFFFFF',
    	lineWidth: 1,
    	//medianColor: null,
    	medianWidth: 2,
    	states: {
    		hover: {
    			brightness: -0.3
    		}
    	},
    	//stemColor: null,
    	//stemDashStyle: 'solid'
    	//stemWidth: null,
    	threshold: null,
    	tooltip: {
    		pointFormat: '<span style="color:{series.color};font-weight:bold">{series.name}</span><br/>' +
    			'Maximum: {point.high}<br/>' +
    			'Upper quartile: {point.q3}<br/>' +
    			'Median: {point.median}<br/>' +
    			'Lower quartile: {point.q1}<br/>' +
    			'Minimum: {point.low}<br/>'
    			
    	},
    	//whiskerColor: null,
    	whiskerLength: '50%',
    	whiskerWidth: 2
    });
    
    // Create the series object
    seriesTypes.boxplot = extendClass(seriesTypes.column, {
    	type: 'boxplot',
    	pointArrayMap: ['low', 'q1', 'median', 'q3', 'high'], // array point configs are mapped to this
    	toYData: function (point) { // return a plain array for speedy calculation
    		return [point.low, point.q1, point.median, point.q3, point.high];
    	},
    	pointValKey: 'high', // defines the top of the tracker
    	
    	/**
    	 * One-to-one mapping from options to SVG attributes
    	 */
    	pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
    		fill: 'fillColor',
    		stroke: 'color',
    		'stroke-width': 'lineWidth'
    	},
    	
    	/**
    	 * Disable data labels for box plot
    	 */
    	drawDataLabels: noop,
    
    	/**
    	 * Translate data points from raw values x and y to plotX and plotY
    	 */
    	translate: function () {
    		var series = this,
    			yAxis = series.yAxis,
    			pointArrayMap = series.pointArrayMap;
    
    		seriesTypes.column.prototype.translate.apply(series);
    
    		// do the translation on each point dimension
    		each(series.points, function (point) {
    			each(pointArrayMap, function (key) {
    				if (point[key] !== null) {
    					point[key + 'Plot'] = yAxis.translate(point[key], 0, 1, 0, 1);
    				}
    			});
    		});
    	},
    
    	/**
    	 * Draw the data points
    	 */
    	drawPoints: function () {
    		var series = this,  //state = series.state,
    			points = series.points,
    			options = series.options,
    			chart = series.chart,
    			renderer = chart.renderer,
    			pointAttr,
    			q1Plot,
    			q3Plot,
    			highPlot,
    			lowPlot,
    			medianPlot,
    			crispCorr,
    			crispX,
    			graphic,
    			stemPath,
    			stemAttr,
    			boxPath,
    			whiskersPath,
    			whiskersAttr,
    			medianPath,
    			medianAttr,
    			width,
    			left,
    			right,
    			halfWidth,
    			shapeArgs,
    			color,
    			doQuartiles = series.doQuartiles !== false, // error bar inherits this series type but doesn't do quartiles
    			whiskerLength = parseInt(series.options.whiskerLength, 10) / 100;
    
    
    		each(points, function (point) {
    
    			graphic = point.graphic;
    			shapeArgs = point.shapeArgs; // the box
    			stemAttr = {};
    			whiskersAttr = {};
    			medianAttr = {};
    			color = point.color || series.color;
    			
    			if (point.plotY !== UNDEFINED) {
    
    				pointAttr = point.pointAttr[point.selected ? 'selected' : ''];
    
    				// crisp vector coordinates
    				width = shapeArgs.width;
    				left = mathFloor(shapeArgs.x);
    				right = left + width;
    				halfWidth = mathRound(width / 2);
    				//crispX = mathRound(left + halfWidth) + crispCorr;
    				q1Plot = mathFloor(doQuartiles ? point.q1Plot : point.lowPlot);// + crispCorr;
    				q3Plot = mathFloor(doQuartiles ? point.q3Plot : point.lowPlot);// + crispCorr;
    				highPlot = mathFloor(point.highPlot);// + crispCorr;
    				lowPlot = mathFloor(point.lowPlot);// + crispCorr;
    				
    				// Stem attributes
    				stemAttr.stroke = point.stemColor || options.stemColor || color;
    				stemAttr['stroke-width'] = pick(point.stemWidth, options.stemWidth, options.lineWidth);
    				stemAttr.dashstyle = point.stemDashStyle || options.stemDashStyle;
    				
    				// Whiskers attributes
    				whiskersAttr.stroke = point.whiskerColor || options.whiskerColor || color;
    				whiskersAttr['stroke-width'] = pick(point.whiskerWidth, options.whiskerWidth, options.lineWidth);
    				
    				// Median attributes
    				medianAttr.stroke = point.medianColor || options.medianColor || color;
    				medianAttr['stroke-width'] = pick(point.medianWidth, options.medianWidth, options.lineWidth);
    				
    				
    				// The stem
    				crispCorr = (stemAttr['stroke-width'] % 2) / 2;
    				crispX = left + halfWidth + crispCorr;				
    				stemPath = [
    					// stem up
    					'M',
    					crispX, q3Plot,
    					'L',
    					crispX, highPlot,
    					
    					// stem down
    					'M',
    					crispX, q1Plot,
    					'L',
    					crispX, lowPlot,
    					'z'
    				];
    				
    				// The box
    				if (doQuartiles) {
    					crispCorr = (pointAttr['stroke-width'] % 2) / 2;
    					crispX = mathFloor(crispX) + crispCorr;
    					q1Plot = mathFloor(q1Plot) + crispCorr;
    					q3Plot = mathFloor(q3Plot) + crispCorr;
    					left += crispCorr;
    					right += crispCorr;
    					boxPath = [
    						'M',
    						left, q3Plot,
    						'L',
    						left, q1Plot,
    						'L',
    						right, q1Plot,
    						'L',
    						right, q3Plot,
    						'L',
    						left, q3Plot,
    						'z'
    					];
    				}
    				
    				// The whiskers
    				if (whiskerLength) {
    					crispCorr = (whiskersAttr['stroke-width'] % 2) / 2;
    					highPlot = highPlot + crispCorr;
    					lowPlot = lowPlot + crispCorr;
    					whiskersPath = [
    						// High whisker
    						'M',
    						crispX - halfWidth * whiskerLength, 
    						highPlot,
    						'L',
    						crispX + halfWidth * whiskerLength, 
    						highPlot,
    						
    						// Low whisker
    						'M',
    						crispX - halfWidth * whiskerLength, 
    						lowPlot,
    						'L',
    						crispX + halfWidth * whiskerLength, 
    						lowPlot
    					];
    				}
    				
    				// The median
    				crispCorr = (medianAttr['stroke-width'] % 2) / 2;				
    				medianPlot = mathRound(point.medianPlot) + crispCorr;
    				medianPath = [
    					'M',
    					left, 
    					medianPlot,
    					'L',
    					right, 
    					medianPlot,
    					'z'
    				];
    				
    				// Create or update the graphics
    				if (graphic) { // update
    					
    					point.stem.animate({ d: stemPath });
    					if (whiskerLength) {
    						point.whiskers.animate({ d: whiskersPath });
    					}
    					if (doQuartiles) {
    						point.box.animate({ d: boxPath });
    					}
    					point.medianShape.animate({ d: medianPath });
    					
    				} else { // create new
    					point.graphic = graphic = renderer.g()
    						.add(series.group);
    					
    					point.stem = renderer.path(stemPath)
    						.attr(stemAttr)
    						.add(graphic);
    						
    					if (whiskerLength) {
    						point.whiskers = renderer.path(whiskersPath) 
    							.attr(whiskersAttr)
    							.add(graphic);
    					}
    					if (doQuartiles) {
    						point.box = renderer.path(boxPath)
    							.attr(pointAttr)
    							.add(graphic);
    					}	
    					point.medianShape = renderer.path(medianPath)
    						.attr(medianAttr)
    						.add(graphic);
    				}
    			}
    		});
    
    	}
    
    
    });
    
    /* ****************************************************************************
     * End Box plot series code												*
     *****************************************************************************/
    /* ****************************************************************************
     * Start error bar series code                                                *
     *****************************************************************************/
    
    // 1 - set default options
    defaultPlotOptions.errorbar = merge(defaultPlotOptions.boxplot, {
    	color: '#000000',
    	grouping: false,
    	linkedTo: ':previous',
    	tooltip: {
    		pointFormat: defaultPlotOptions.arearange.tooltip.pointFormat
    	},
    	whiskerWidth: null
    });
    
    // 2 - Create the series object
    seriesTypes.errorbar = extendClass(seriesTypes.boxplot, {
    	type: 'errorbar',
    	pointArrayMap: ['low', 'high'], // array point configs are mapped to this
    	toYData: function (point) { // return a plain array for speedy calculation
    		return [point.low, point.high];
    	},
    	pointValKey: 'high', // defines the top of the tracker
    	doQuartiles: false,
    
    	/**
    	 * Get the width and X offset, either on top of the linked series column
    	 * or standalone
    	 */
    	getColumnMetrics: function () {
    		return (this.linkedParent && this.linkedParent.columnMetrics) || 
    			seriesTypes.column.prototype.getColumnMetrics.call(this);
    	}
    });
    
    /* ****************************************************************************
     * End error bar series code                                                  *
     *****************************************************************************/
    /* ****************************************************************************
     * Start Waterfall series code                                                *
     *****************************************************************************/
    
    // 1 - set default options
    defaultPlotOptions.waterfall = merge(defaultPlotOptions.column, {
    	lineWidth: 1,
    	lineColor: '#333',
    	dashStyle: 'dot',
    	borderColor: '#333'
    });
    
    
    // 2 - Create the series object
    seriesTypes.waterfall = extendClass(seriesTypes.column, {
    	type: 'waterfall',
    
    	upColorProp: 'fill',
    
    	pointArrayMap: ['low', 'y'],
    
    	pointValKey: 'y',
    
    	/**
    	 * Init waterfall series, force stacking
    	 */
    	init: function (chart, options) {
    		// force stacking
    		options.stacking = true;
    
    		seriesTypes.column.prototype.init.call(this, chart, options);
    	},
    
    
    	/**
    	 * Translate data points from raw values
    	 */
    	translate: function () {
    		var series = this,
    			options = series.options,
    			axis = series.yAxis,
    			len,
    			i,
    			points,
    			point,
    			shapeArgs,
    			stack,
    			y,
    			previousY,
    			stackPoint,
    			threshold = options.threshold,
    			crispCorr = (options.borderWidth % 2) / 2;
    
    		// run column series translate
    		seriesTypes.column.prototype.translate.apply(this);
    
    		previousY = threshold;
    		points = series.points;
    
    		for (i = 0, len = points.length; i < len; i++) {
    			// cache current point object
    			point = points[i];
    			shapeArgs = point.shapeArgs;
    
    			// get current stack
    			stack = series.getStack(i);
    			stackPoint = stack.points[series.index];
    
    			// override point value for sums
    			if (isNaN(point.y)) {
    				point.y = series.yData[i];
    			}
    
    			// up points
    			y = mathMax(previousY, previousY + point.y) + stackPoint[0];
    			shapeArgs.y = axis.translate(y, 0, 1);
    
    
    			// sum points
    			if (point.isSum || point.isIntermediateSum) {
    				shapeArgs.y = axis.translate(stackPoint[1], 0, 1);
    				shapeArgs.height = axis.translate(stackPoint[0], 0, 1) - shapeArgs.y;
    
    			// if it's not the sum point, update previous stack end position
    			} else {
    				previousY += stack.total;
    			}
    
    			// negative points
    			if (shapeArgs.height < 0) {
    				shapeArgs.y += shapeArgs.height;
    				shapeArgs.height *= -1;
    			}
    
    			point.plotY = shapeArgs.y = mathRound(shapeArgs.y) - crispCorr;
    			shapeArgs.height = mathRound(shapeArgs.height);
    			point.yBottom = shapeArgs.y + shapeArgs.height;
    		}
    	},
    
    	/**
    	 * Call default processData then override yData to reflect waterfall's extremes on yAxis
    	 */
    	processData: function (force) {
    		var series = this,
    			options = series.options,
    			yData = series.yData,
    			points = series.points,
    			point,
    			dataLength = yData.length,
    			threshold = options.threshold || 0,
    			subSum,
    			sum,
    			dataMin,
    			dataMax,
    			y,
    			i;
    
    		sum = subSum = dataMin = dataMax = threshold;
    
    		for (i = 0; i < dataLength; i++) {
    			y = yData[i];
    			point = points && points[i] ? points[i] : {};
    
    			if (y === "sum" || point.isSum) {
    				yData[i] = sum;
    			} else if (y === "intermediateSum" || point.isIntermediateSum) {
    				yData[i] = subSum;
    				subSum = threshold;
    			} else {
    				sum += y;
    				subSum += y;
    			}
    			dataMin = Math.min(sum, dataMin);
    			dataMax = Math.max(sum, dataMax);
    		}
    
    		Series.prototype.processData.call(this, force);
    
    		// Record extremes
    		series.dataMin = dataMin;
    		series.dataMax = dataMax;
    	},
    
    	/**
    	 * Return y value or string if point is sum
    	 */
    	toYData: function (pt) {
    		if (pt.isSum) {
    			return "sum";
    		} else if (pt.isIntermediateSum) {
    			return "intermediateSum";
    		}
    
    		return pt.y;
    	},
    
    	/**
    	 * Postprocess mapping between options and SVG attributes
    	 */
    	getAttribs: function () {
    		seriesTypes.column.prototype.getAttribs.apply(this, arguments);
    
    		var series = this,
    			options = series.options,
    			stateOptions = options.states,
    			upColor = options.upColor || series.color,
    			hoverColor = Highcharts.Color(upColor).brighten(0.1).get(),
    			seriesDownPointAttr = merge(series.pointAttr),
    			upColorProp = series.upColorProp;
    
    		seriesDownPointAttr[''][upColorProp] = upColor;
    		seriesDownPointAttr.hover[upColorProp] = stateOptions.hover.upColor || hoverColor;
    		seriesDownPointAttr.select[upColorProp] = stateOptions.select.upColor || upColor;
    
    		each(series.points, function (point) {
    			if (point.y > 0 && !point.color) {
    				point.pointAttr = seriesDownPointAttr;
    				point.color = upColor;
    			}
    		});
    	},
    
    	/**
    	 * Draw columns' connector lines
    	 */
    	getGraphPath: function () {
    
    		var data = this.data,
    			length = data.length,
    			lineWidth = this.options.lineWidth + this.options.borderWidth,
    			normalizer = mathRound(lineWidth) % 2 / 2,
    			path = [],
    			M = 'M',
    			L = 'L',
    			prevArgs,
    			pointArgs,
    			i,
    			d;
    
    		for (i = 1; i < length; i++) {
    			pointArgs = data[i].shapeArgs;
    			prevArgs = data[i - 1].shapeArgs;
    
    			d = [
    				M,
    				prevArgs.x + prevArgs.width, prevArgs.y + normalizer,
    				L,
    				pointArgs.x, prevArgs.y + normalizer
    			];
    
    			if (data[i - 1].y < 0) {
    				d[2] += prevArgs.height;
    				d[5] += prevArgs.height;
    			}
    
    			path = path.concat(d);
    		}
    
    		return path;
    	},
    
    	/**
    	 * Extremes are recorded in processData
    	 */
    	getExtremes: noop,
    
    	/**
    	 * Return stack for given index
    	 */
    	getStack: function (i) {
    		var axis = this.yAxis,
    			stacks = axis.stacks,
    			key = this.stackKey;
    
    		if (this.processedYData[i] < this.options.threshold) {
    			key = '-' + key;
    		}
    
    		return stacks[key][i];
    	},
    
    	drawGraph: Series.prototype.drawGraph
    });
    
    /* ****************************************************************************
     * End Waterfall series code                                                  *
     *****************************************************************************/
    /* ****************************************************************************
     * Start Bubble series code											          *
     *****************************************************************************/
    
    // 1 - set default options
    defaultPlotOptions.bubble = merge(defaultPlotOptions.scatter, {
    	dataLabels: {
    		inside: true,
    		style: {
    			color: 'white',
    			textShadow: '0px 0px 3px black'
    		},
    		verticalAlign: 'middle'
    	},
    	// displayNegative: true,
    	marker: {
    		// fillOpacity: 0.5,
    		lineColor: null, // inherit from series.color
    		lineWidth: 1
    	},
    	minSize: 8,
    	maxSize: '20%',
    	// negativeColor: null,
    	tooltip: {
    		pointFormat: '({point.x}, {point.y}), Size: {point.z}'
    	},
    	turboThreshold: 0,
    	zThreshold: 0
    });
    
    // 2 - Create the series object
    seriesTypes.bubble = extendClass(seriesTypes.scatter, {
    	type: 'bubble',
    	pointArrayMap: ['y', 'z'],
    	trackerGroups: ['group', 'dataLabelsGroup'],
    	
    	/**
    	 * Mapping between SVG attributes and the corresponding options
    	 */
    	pointAttrToOptions: { 
    		stroke: 'lineColor',
    		'stroke-width': 'lineWidth',
    		fill: 'fillColor'
    	},
    	
    	/**
    	 * Apply the fillOpacity to all fill positions
    	 */
    	applyOpacity: function (fill) {
    		var markerOptions = this.options.marker,
    			fillOpacity = pick(markerOptions.fillOpacity, 0.5);
    		
    		// When called from Legend.colorizeItem, the fill isn't predefined
    		fill = fill || markerOptions.fillColor || this.color; 
    		
    		if (fillOpacity !== 1) {
    			fill = Highcharts.Color(fill).setOpacity(fillOpacity).get('rgba');
    		}
    		return fill;
    	},
    	
    	/**
    	 * Extend the convertAttribs method by applying opacity to the fill
    	 */
    	convertAttribs: function () {
    		var obj = Series.prototype.convertAttribs.apply(this, arguments);
    		
    		obj.fill = this.applyOpacity(obj.fill);
    		
    		return obj;
    	},
    
    	/**
    	 * Get the radius for each point based on the minSize, maxSize and each point's Z value. This
    	 * must be done prior to Series.translate because the axis needs to add padding in 
    	 * accordance with the point sizes.
    	 */
    	getRadii: function (zMin, zMax, minSize, maxSize) {
    		var len,
    			i,
    			pos,
    			zData = this.zData,
    			radii = [],
    			zRange;
    		
    		// Set the shape type and arguments to be picked up in drawPoints
    		for (i = 0, len = zData.length; i < len; i++) {
    			zRange = zMax - zMin;
    			pos = zRange > 0 ? // relative size, a number between 0 and 1
    				(zData[i] - zMin) / (zMax - zMin) : 
    				0.5;
    			radii.push(math.ceil(minSize + pos * (maxSize - minSize)) / 2);
    		}
    		this.radii = radii;
    	},
    	
    	/**
    	 * Perform animation on the bubbles
    	 */
    	animate: function (init) {
    		var animation = this.options.animation;
    		
    		if (!init) { // run the animation
    			each(this.points, function (point) {
    				var graphic = point.graphic,
    					shapeArgs = point.shapeArgs;
    
    				if (graphic && shapeArgs) {
    					// start values
    					graphic.attr('r', 1);
    
    					// animate
    					graphic.animate({
    						r: shapeArgs.r
    					}, animation);
    				}
    			});
    
    			// delete this function to allow it only once
    			this.animate = null;
    		}
    	},
    	
    	/**
    	 * Extend the base translate method to handle bubble size
    	 */
    	translate: function () {
    		
    		var i,
    			data = this.data,
    			point,
    			radius,
    			radii = this.radii;
    		
    		// Run the parent method
    		seriesTypes.scatter.prototype.translate.call(this);
    		
    		// Set the shape type and arguments to be picked up in drawPoints
    		i = data.length;
    		
    		while (i--) {
    			point = data[i];
    			radius = radii ? radii[i] : 0; // #1737
    
    			// Flag for negativeColor to be applied in Series.js
    			point.negative = point.z < (this.options.zThreshold || 0);
    			
    			if (radius >= this.minPxSize / 2) {
    				// Shape arguments
    				point.shapeType = 'circle';
    				point.shapeArgs = {
    					x: point.plotX,
    					y: point.plotY,
    					r: radius
    				};
    				
    				// Alignment box for the data label
    				point.dlBox = {
    					x: point.plotX - radius,
    					y: point.plotY - radius,
    					width: 2 * radius,
    					height: 2 * radius
    				};
    			} else { // below zThreshold
    				point.shapeArgs = point.plotY = point.dlBox = UNDEFINED; // #1691
    			}
    		}
    	},
    	
    	/**
    	 * Get the series' symbol in the legend
    	 * 
    	 * @param {Object} legend The legend object
    	 * @param {Object} item The series (this) or point
    	 */
    	drawLegendSymbol: function (legend, item) {
    		var radius = pInt(legend.itemStyle.fontSize) / 2;
    		
    		item.legendSymbol = this.chart.renderer.circle(
    			radius,
    			legend.baseline - radius,
    			radius
    		).attr({
    			zIndex: 3
    		}).add(item.legendGroup);
    		item.legendSymbol.isMarker = true;	
    		
    	},
    	
    	drawPoints: seriesTypes.column.prototype.drawPoints,
    	alignDataLabel: seriesTypes.column.prototype.alignDataLabel
    });
    
    /**
     * Add logic to pad each axis with the amount of pixels
     * necessary to avoid the bubbles to overflow.
     */
    Axis.prototype.beforePadding = function () {
    	var axis = this,
    		axisLength = this.len,
    		chart = this.chart,
    		pxMin = 0, 
    		pxMax = axisLength,
    		isXAxis = this.isXAxis,
    		dataKey = isXAxis ? 'xData' : 'yData',
    		min = this.min,
    		extremes = {},
    		smallestSize = math.min(chart.plotWidth, chart.plotHeight),
    		zMin = Number.MAX_VALUE,
    		zMax = -Number.MAX_VALUE,
    		range = this.max - min,
    		transA = axisLength / range,
    		activeSeries = [];
    
    	// Handle padding on the second pass, or on redraw
    	if (this.tickPositions) {
    		each(this.series, function (series) {
    
    			var seriesOptions = series.options,
    				zData;
    
    			if (series.type === 'bubble' && series.visible) {
    
    				// Correction for #1673
    				axis.allowZoomOutside = true;
    
    				// Cache it
    				activeSeries.push(series);
    
    				if (isXAxis) { // because X axis is evaluated first
    				
    					// For each series, translate the size extremes to pixel values
    					each(['minSize', 'maxSize'], function (prop) {
    						var length = seriesOptions[prop],
    							isPercent = /%$/.test(length);
    						
    						length = pInt(length);
    						extremes[prop] = isPercent ?
    							smallestSize * length / 100 :
    							length;
    						
    					});
    					series.minPxSize = extremes.minSize;
    					
    					// Find the min and max Z
    					zData = series.zData;
    					if (zData.length) { // #1735
    						zMin = math.min(
    							zMin,
    							math.max(
    								arrayMin(zData), 
    								seriesOptions.displayNegative === false ? seriesOptions.zThreshold : -Number.MAX_VALUE
    							)
    						);
    						zMax = math.max(zMax, arrayMax(zData));
    					}
    				}
    			}
    		});
    
    		each(activeSeries, function (series) {
    
    			var data = series[dataKey],
    				i = data.length,
    				radius;
    
    			if (isXAxis) {
    				series.getRadii(zMin, zMax, extremes.minSize, extremes.maxSize);
    			}
    			
    			if (range > 0) {
    				while (i--) {
    					radius = series.radii[i];
    					pxMin = Math.min(((data[i] - min) * transA) - radius, pxMin);
    					pxMax = Math.max(((data[i] - min) * transA) + radius, pxMax);
    				}
    			}
    		});
    		
    		if (activeSeries.length && range > 0 && pick(this.options.min, this.userMin) === UNDEFINED && pick(this.options.max, this.userMax) === UNDEFINED) {
    			pxMax -= axisLength;
    			transA *= (axisLength + pxMin - pxMax) / axisLength;
    			this.min += pxMin / transA;
    			this.max += pxMax / transA;
    		}
    	}
    };
    
    /* ****************************************************************************
     * End Bubble series code                                                     *
     *****************************************************************************/
    /**
     * Extensions for polar charts. Additionally, much of the geometry required for polar charts is
     * gathered in RadialAxes.js.
     * 
     */
    
    var seriesProto = Series.prototype,
    	pointerProto = Highcharts.Pointer.prototype;
    
    
    
    /**
     * Translate a point's plotX and plotY from the internal angle and radius measures to 
     * true plotX, plotY coordinates
     */
    seriesProto.toXY = function (point) {
    	var xy,
    		chart = this.chart,
    		plotX = point.plotX,
    		plotY = point.plotY;
    	
    	// Save rectangular plotX, plotY for later computation
    	point.rectPlotX = plotX;
    	point.rectPlotY = plotY;
    	
    	// Record the angle in degrees for use in tooltip
    	point.clientX = ((plotX / Math.PI * 180) + this.xAxis.pane.options.startAngle) % 360;
    	
    	// Find the polar plotX and plotY
    	xy = this.xAxis.postTranslate(point.plotX, this.yAxis.len - plotY);
    	point.plotX = point.polarPlotX = xy.x - chart.plotLeft;
    	point.plotY = point.polarPlotY = xy.y - chart.plotTop;
    };
    
    /** 
     * Order the tooltip points to get the mouse capture ranges correct. #1915. 
     */
    seriesProto.orderTooltipPoints = function (points) {
    	if (this.chart.polar) {
    		points.sort(function (a, b) {
    			return a.clientX - b.clientX;
    		});
    
    		// Wrap mouse tracking around to capture movement on the segment to the left
    		// of the north point (#1469, #2093).
    		if (points[0]) {
    			points[0].wrappedClientX = points[0].clientX + 360;
    			points.push(points[0]);
    		}
    	}
    };
    
    
    /**
     * Add some special init logic to areas and areasplines
     */
    function initArea(proceed, chart, options) {
    	proceed.call(this, chart, options);
    	if (this.chart.polar) {
    		
    		/**
    		 * Overridden method to close a segment path. While in a cartesian plane the area 
    		 * goes down to the threshold, in the polar chart it goes to the center.
    		 */
    		this.closeSegment = function (path) {
    			var center = this.xAxis.center;
    			path.push(
    				'L',
    				center[0],
    				center[1]
    			);			
    		};
    		
    		// Instead of complicated logic to draw an area around the inner area in a stack,
    		// just draw it behind
    		this.closedStacks = true;
    	}
    }
    wrap(seriesTypes.area.prototype, 'init', initArea);
    wrap(seriesTypes.areaspline.prototype, 'init', initArea);
    		
    
    /**
     * Overridden method for calculating a spline from one point to the next
     */
    wrap(seriesTypes.spline.prototype, 'getPointSpline', function (proceed, segment, point, i) {
    	
    	var ret,
    		smoothing = 1.5, // 1 means control points midway between points, 2 means 1/3 from the point, 3 is 1/4 etc;
    		denom = smoothing + 1,
    		plotX, 
    		plotY,
    		lastPoint,
    		nextPoint,
    		lastX,
    		lastY,
    		nextX,
    		nextY,
    		leftContX,
    		leftContY,
    		rightContX,
    		rightContY,
    		distanceLeftControlPoint,
    		distanceRightControlPoint,
    		leftContAngle,
    		rightContAngle,
    		jointAngle;
    		
    		
    	if (this.chart.polar) {
    		
    		plotX = point.plotX;
    		plotY = point.plotY;
    		lastPoint = segment[i - 1];
    		nextPoint = segment[i + 1];
    			
    		// Connect ends
    		if (this.connectEnds) {
    			if (!lastPoint) {
    				lastPoint = segment[segment.length - 2]; // not the last but the second last, because the segment is already connected
    			}
    			if (!nextPoint) {
    				nextPoint = segment[1];
    			}	
    		}
    
    		// find control points
    		if (lastPoint && nextPoint) {
    		
    			lastX = lastPoint.plotX;
    			lastY = lastPoint.plotY;
    			nextX = nextPoint.plotX;
    			nextY = nextPoint.plotY;
    			leftContX = (smoothing * plotX + lastX) / denom;
    			leftContY = (smoothing * plotY + lastY) / denom;
    			rightContX = (smoothing * plotX + nextX) / denom;
    			rightContY = (smoothing * plotY + nextY) / denom;
    			distanceLeftControlPoint = Math.sqrt(Math.pow(leftContX - plotX, 2) + Math.pow(leftContY - plotY, 2));
    			distanceRightControlPoint = Math.sqrt(Math.pow(rightContX - plotX, 2) + Math.pow(rightContY - plotY, 2));
    			leftContAngle = Math.atan2(leftContY - plotY, leftContX - plotX);
    			rightContAngle = Math.atan2(rightContY - plotY, rightContX - plotX);
    			jointAngle = (Math.PI / 2) + ((leftContAngle + rightContAngle) / 2);
    				
    				
    			// Ensure the right direction, jointAngle should be in the same quadrant as leftContAngle
    			if (Math.abs(leftContAngle - jointAngle) > Math.PI / 2) {
    				jointAngle -= Math.PI;
    			}
    			
    			// Find the corrected control points for a spline straight through the point
    			leftContX = plotX + Math.cos(jointAngle) * distanceLeftControlPoint;
    			leftContY = plotY + Math.sin(jointAngle) * distanceLeftControlPoint;
    			rightContX = plotX + Math.cos(Math.PI + jointAngle) * distanceRightControlPoint;
    			rightContY = plotY + Math.sin(Math.PI + jointAngle) * distanceRightControlPoint;
    			
    			// Record for drawing in next point
    			point.rightContX = rightContX;
    			point.rightContY = rightContY;
    
    		}
    		
    		
    		// moveTo or lineTo
    		if (!i) {
    			ret = ['M', plotX, plotY];
    		} else { // curve from last point to this
    			ret = [
    				'C',
    				lastPoint.rightContX || lastPoint.plotX,
    				lastPoint.rightContY || lastPoint.plotY,
    				leftContX || plotX,
    				leftContY || plotY,
    				plotX,
    				plotY
    			];
    			lastPoint.rightContX = lastPoint.rightContY = null; // reset for updating series later
    		}
    		
    		
    	} else {
    		ret = proceed.call(this, segment, point, i);
    	}
    	return ret;
    });
    
    /**
     * Extend translate. The plotX and plotY values are computed as if the polar chart were a
     * cartesian plane, where plotX denotes the angle in radians and (yAxis.len - plotY) is the pixel distance from
     * center. 
     */
    wrap(seriesProto, 'translate', function (proceed) {
    		
    	// Run uber method
    	proceed.call(this);
    	
    	// Postprocess plot coordinates
    	if (this.chart.polar && !this.preventPostTranslate) {
    		var points = this.points,
    			i = points.length;
    		while (i--) {
    			// Translate plotX, plotY from angle and radius to true plot coordinates
    			this.toXY(points[i]);
    		}
    	}
    });
    
    /** 
     * Extend getSegmentPath to allow connecting ends across 0 to provide a closed circle in 
     * line-like series.
     */
    wrap(seriesProto, 'getSegmentPath', function (proceed, segment) {
    		
    	var points = this.points;
    	
    	// Connect the path
    	if (this.chart.polar && this.options.connectEnds !== false && 
    			segment[segment.length - 1] === points[points.length - 1] && points[0].y !== null) {
    		this.connectEnds = true; // re-used in splines
    		segment = [].concat(segment, [points[0]]);
    	}
    	
    	// Run uber method
    	return proceed.call(this, segment);
    	
    });
    
    
    function polarAnimate(proceed, init) {
    	var chart = this.chart,
    		animation = this.options.animation,
    		group = this.group,
    		markerGroup = this.markerGroup,
    		center = this.xAxis.center,
    		plotLeft = chart.plotLeft,
    		plotTop = chart.plotTop,
    		attribs;
    
    	// Specific animation for polar charts
    	if (chart.polar) {
    		
    		// Enable animation on polar charts only in SVG. In VML, the scaling is different, plus animation
    		// would be so slow it would't matter.
    		if (chart.renderer.isSVG) {
    
    			if (animation === true) {
    				animation = {};
    			}
    	
    			// Initialize the animation
    			if (init) {
    				
    				// Scale down the group and place it in the center
    				attribs = {
    					translateX: center[0] + plotLeft,
    					translateY: center[1] + plotTop,
    					scaleX: 0.001, // #1499
    					scaleY: 0.001
    				};
    					
    				group.attr(attribs);
    				if (markerGroup) {
    					markerGroup.attrSetters = group.attrSetters;
    					markerGroup.attr(attribs);
    				}
    				
    			// Run the animation
    			} else {
    				attribs = {
    					translateX: plotLeft,
    					translateY: plotTop,
    					scaleX: 1,
    					scaleY: 1
    				};
    				group.animate(attribs, animation);
    				if (markerGroup) {
    					markerGroup.animate(attribs, animation);
    				}
    				
    				// Delete this function to allow it only once
    				this.animate = null;
    			}
    		}
    	
    	// For non-polar charts, revert to the basic animation
    	} else {
    		proceed.call(this, init);
    	} 
    }
    
    // Define the animate method for both regular series and column series and their derivatives
    wrap(seriesProto, 'animate', polarAnimate);
    wrap(colProto, 'animate', polarAnimate);
    
    
    /**
     * Throw in a couple of properties to let setTooltipPoints know we're indexing the points
     * in degrees (0-360), not plot pixel width.
     */
    wrap(seriesProto, 'setTooltipPoints', function (proceed, renew) {
    		
    	if (this.chart.polar) {
    		extend(this.xAxis, {
    			tooltipLen: 360 // degrees are the resolution unit of the tooltipPoints array
    		});	
    	}
    	
    	// Run uber method
    	return proceed.call(this, renew);
    });
    
    
    /**
     * Extend the column prototype's translate method
     */
    wrap(colProto, 'translate', function (proceed) {
    		
    	var xAxis = this.xAxis,
    		len = this.yAxis.len,
    		center = xAxis.center,
    		startAngleRad = xAxis.startAngleRad,
    		renderer = this.chart.renderer,
    		start,
    		points,
    		point,
    		i;
    	
    	this.preventPostTranslate = true;
    	
    	// Run uber method
    	proceed.call(this);
    	
    	// Postprocess plot coordinates
    	if (xAxis.isRadial) {
    		points = this.points;
    		i = points.length;
    		while (i--) {
    			point = points[i];
    			start = point.barX + startAngleRad;
    			point.shapeType = 'path';
    			point.shapeArgs = {
    				d: renderer.symbols.arc(
    					center[0],
    					center[1],
    					len - point.plotY,
    					null, 
    					{
    						start: start,
    						end: start + point.pointWidth,
    						innerR: len - pick(point.yBottom, len)
    					}
    				)
    			};
    			this.toXY(point); // provide correct plotX, plotY for tooltip
    		}
    	}
    });
    
    
    /**
     * Align column data labels outside the columns. #1199.
     */
    wrap(colProto, 'alignDataLabel', function (proceed, point, dataLabel, options, alignTo, isNew) {
    	
    	if (this.chart.polar) {
    		var angle = point.rectPlotX / Math.PI * 180,
    			align,
    			verticalAlign;
    		
    		// Align nicely outside the perimeter of the columns
    		if (options.align === null) {
    			if (angle > 20 && angle < 160) {
    				align = 'left'; // right hemisphere
    			} else if (angle > 200 && angle < 340) {
    				align = 'right'; // left hemisphere
    			} else {
    				align = 'center'; // top or bottom
    			}
    			options.align = align;
    		}
    		if (options.verticalAlign === null) {
    			if (angle < 45 || angle > 315) {
    				verticalAlign = 'bottom'; // top part
    			} else if (angle > 135 && angle < 225) {
    				verticalAlign = 'top'; // bottom part
    			} else {
    				verticalAlign = 'middle'; // left or right
    			}
    			options.verticalAlign = verticalAlign;
    		}
    		
    		seriesProto.alignDataLabel.call(this, point, dataLabel, options, alignTo, isNew);
    	} else {
    		proceed.call(this, point, dataLabel, options, alignTo, isNew);
    	}
    	
    });
    
    /**
     * Extend the mouse tracker to return the tooltip position index in terms of
     * degrees rather than pixels
     */
    wrap(pointerProto, 'getIndex', function (proceed, e) {
    	var ret,
    		chart = this.chart,
    		center,
    		x,
    		y;
    	
    	if (chart.polar) {
    		center = chart.xAxis[0].center;
    		x = e.chartX - center[0] - chart.plotLeft;
    		y = e.chartY - center[1] - chart.plotTop;
    		
    		ret = 180 - Math.round(Math.atan2(x, y) / Math.PI * 180);
    	
    	} else {
    	
    		// Run uber method
    		ret = proceed.call(this, e);
    	}
    	return ret;
    });
    
    /**
     * Extend getCoordinates to prepare for polar axis values
     */
    wrap(pointerProto, 'getCoordinates', function (proceed, e) {
    	var chart = this.chart,
    		ret = {
    			xAxis: [],
    			yAxis: []
    		};
    	
    	if (chart.polar) {	
    
    		each(chart.axes, function (axis) {
    			var isXAxis = axis.isXAxis,
    				center = axis.center,
    				x = e.chartX - center[0] - chart.plotLeft,
    				y = e.chartY - center[1] - chart.plotTop;
    			
    			ret[isXAxis ? 'xAxis' : 'yAxis'].push({
    				axis: axis,
    				value: axis.translate(
    					isXAxis ?
    						Math.PI - Math.atan2(x, y) : // angle 
    						Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)), // distance from center
    					true
    				)
    			});
    		});
    		
    	} else {
    		ret = proceed.call(this, e);
    	}
    	
    	return ret;
    });
    }(Highcharts));