Вход Регистрация
Файл: protected/extensions/widgets/highcharts/assets/highcharts-more.src.js
Строк: 2528
<?php
// ==ClosureCompiler==
// @compilation_level SIMPLE_OPTIMIZATIONS

/**
 * @license Highcharts JS v3.0.4 (2013-08-02)
 *
 * (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 (HighchartsUNDEFINED) {
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(optionschartfirstAxis) {
    
this.init.call(thisoptionschartfirstAxis);
}

// Extend the Pane prototype
extend(Pane.prototype, {
    
    
/**
     * Initiate the Pane object
     */
    
init: function (optionschartfirstAxis) {
        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(defaultOptionsoptions);
        
        
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.defaultBackgroundOptionsconfig);
                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%',
        
startAngle0
        
//endAngle: startAngle + 360
    
},    
    
    
/**
     * The default background options
     */
    
defaultBackgroundOptions: {
        
shape'circle',
        
borderWidth1,
        
borderColor'silver',
        
backgroundColor: {
            
linearGradient: { x10y10x20y2},
            
stops: [
                [
0'#FFF'],
                [
1'#DDD']
            ]
        },
        
fromNumber.MIN_VALUE// corrected to axis min
        
innerRadius0,
        
toNumber.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 = {
    
getOffsetnoop,
    
redraw: function () {
        
this.isDirty false// prevent setting Y axis dirty
    
},
    
render: function () {
        
this.isDirty false// prevent setting Y axis dirty
    
},
    
setScalenoop,
    
setCategoriesnoop,
    
setTitlenoop
};

/**
 * Augmented methods for the value axis
 */
/*jslint unparam: true*/
var radialAxisMixin = {
    
isRadialtrue,
    
    
/**
     * The default options extend defaultYAxisOptions
     */
    
defaultRadialGaugeOptions: {
        
labels: {
            
align'center',
            
x0,
            
ynull // auto
        
},
        
minorGridLineWidth0,
        
minorTickInterval'auto',
        
minorTickLength10,
        
minorTickPosition'inside',
        
minorTickWidth1,
        
plotBands: [],
        
tickLength10,
        
tickPosition'inside',
        
tickWidth2,
        
title: {
            
rotation0
        
},
        
zIndex// behind dials, points in the series group
    
},
    
    
// Circular axis around the perimeter of a polar chart
    
defaultRadialXOptions: {
        
gridLineWidth1// spokes
        
labels: {
            
alignnull// auto
            
distance15,
            
x0,
            
ynull // auto
        
},
        
maxPadding0,
        
minPadding0,
        
plotBands: [],
        
showLastLabelfalse
        
tickLength0
    
},
    
    
// Radial axis, like a spoke in a polar chart
    
defaultRadialYOptions: {
        
gridLineInterpolation'circle',
        
labels: {
            
align'right',
            
x: -3,
            
y: -2
        
},
        
plotBands: [],
        
showLastLabelfalse,
        
title: {
            
x4,
            
textnull,
            
rotation90
        
}
    },
    
    
/**
     * 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;
        
        
// Set the center array
        
this.center this.pane.center seriesTypes.pie.prototype.getCenter.call(this.pane);
    },


    
/**
     * Get the path for the axis line. This method is also referenced in the getPlotLinePath
     * method.
     */
    
getLinePath: function (lineWidthradius) {
        var 
center this.center;
        
radius pick(radiuscenter[2] / this.offset);
        
        return 
this.chart.renderer.symbols.arc(
            
this.left center[0],
            
this.top center[1],
            
radius,
            
radius
            {
                
startthis.startAngleRad,
                
endthis.endAngleRad,
                
opentrue,
                
innerR0
            
}
        );
    },

    
/**
     * 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) / 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// #1197
        
}
    },
    
    
/**
     * 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.center) { // it's not defined the first time
            
this.len this.width this.height this.isCircular ?
                
this.center[2] * (this.endAngleRad this.startAngleRad) / :
                
this.center[2] / 2;
        }
    },
    
    
/**
     * Returns the x, y coordinate of a point given by a value and a pixel distance
     * from center
     */
    
getPosition: function (valuelength) {
        if (!
this.isCircular) {
            
length this.translate(value);
            
value this.min;    
        }
        
        return 
this.postTranslate(
            
this.translate(value),
            
pick(lengththis.center[2] / 2) - this.offset
        
);        
    },
    
    
/**
     * Translate from intermediate plotX (angle), plotY (axis.len - radius) to final chart coordinates. 
     */
    
postTranslate: function (angleradius) {
        
        var 
chart this.chart,
            
center this.center;
            
        
angle this.startAngleRad angle;
        
        return {
            
xchart.plotLeft center[0] + Math.cos(angle) * radius,
            
ychart.plotTop center[1] + Math.sin(angle) * radius
        
}; 
        
    },
    
    
/**
     * Find the path for plot bands along the radial axis
     */
    
getPlotBandPath: function (fromtooptions) {
        var 
center this.center,
            
startAngleRad this.startAngleRad,
            
fullRadius center[2] / 2,
            
radii = [
                
pick(options.outerRadius'100%'),
                
options.innerRadius,
                
pick(options.thickness10)
            ],
            
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(totrue));
        
        
// 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(radius10) * 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],
                {
                    
startstart,
                    
endend,
                    
innerRpick(radii[1], radii[0] - radii[2]),
                    
openopen
                
}
            );
        }
         
        return 
ret;
    },
    
    
/**
     * Find the path for plot lines perpendicular to the radial axis.
     */
    
getPlotLinePath: function (valuereverse) {
        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.plotLeftcenter[1] + chart.plotTop'L'end.xend.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(0value);
            }
        
// 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 (posi) {
                
xy xAxis.getPosition(posvalue);
                
ret.push('L' 'M'xy.xxy.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 { 
            
xchart.plotLeft center[0] + (titleOptions.|| 0), 
            
ychart.plotTop center[1] - ({ high0.5middle0.25low}[titleOptions.align] * 
                
center[2]) + (titleOptions.|| 0)  
        };
    }
    
};
/*jslint unparam: false*/

/**
 * Override axisProto.init to mix in special axis instance functions and function overrides
 */
wrap(axisProto'init', function (proceedchartuserOptions) {
    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(thisisHidden hiddenAxisMixin radialAxisMixin);
        
isCircular =  !isX;
        if (
isCircular) {
            
this.defaultRadialOptions this.defaultRadialGaugeOptions;
        }
        
    } else if (
polar) {
        
//extend(this, userOptions.isX ? radialAxisMixin : radialAxisMixin);
        
extend(thisradialAxisMixin);
        
isCircular isX;
        
this.defaultRadialOptions isX this.defaultRadialXOptions merge(this.defaultYAxisOptionsthis.defaultRadialYOptions);
        
    }
    
    
// Run prototype.init
    
proceed.call(thischartuserOptions);
    
    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.endAnglepaneOptions.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 === Math.PI) {
            
this.autoConnect true;
        }
    }
    
});

/**
 * Add special cases within the Tick class' methods for radial axes.
 */    
wrap(tickProto'getPosition', function (proceedhorizpostickmarkOffsetold) {
    var 
axis this.axis;
    
    return 
axis.getPosition 
        
axis.getPosition(pos) :
        
proceed.call(thishorizpostickmarkOffsetold);    
});

/**
 * Wrap the getLabelPosition function to find the center position of the label
 * based on the distance option
 */    
wrap(tickProto'getLabelPosition', function (proceedxylabelhorizlabelOptionstickmarkOffsetindexstep) {
    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({ 
                
rotationangle
            
});
        
        
// 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({
                
alignalign
            
});
        }
        
        
ret.+= labelOptions.x;
        
ret.+= optionsY;
        
    } else {
        
ret proceed.call(thisxylabelhorizlabelOptionstickmarkOffsetindexstep);
    }
    return 
ret;
});

/**
 * Wrap the getMarkPath function to return the path of the radial marker
 */
wrap(tickProto'getMarkPath', function (proceedxytickLengthtickWidthhorizrenderer) {
    var 
axis this.axis,
        
endPoint,
        
ret;
        
    if (
axis.isRadial) {
        
endPoint axis.getPosition(this.posaxis.center[2] / tickLength);
        
ret = [
            
'M',
            
x,
            
y,
            
'L',
            
endPoint.x,
            
endPoint.y
        
];
    } else {
        
ret proceed.call(thisxytickLengthtickWidthhorizrenderer);
    }
    return 
ret;
});
/* 
 * The AreaRangeSeries class
 * 
 */

/**
 * Extend the default options with map options
 */
defaultPlotOptions.arearange merge(defaultPlotOptions.area, {
    
lineWidth1,
    
markernull,
    
thresholdnull,
    
tooltip: {
        
pointFormat'<span style="color:{series.color}">{series.name}</span>: <b>{point.low}</b> - <b>{point.high}</b><br/>' 
    
},
    
trackByAreatrue,
    
dataLabels: {
        
verticalAlignnull,
        
xLow0,
        
xHigh0,
        
yLow0,
        
yHigh0    
    
}
});

/**
 * Add the series type
 */
seriesTypes.arearange Highcharts.extendClass(seriesTypes.area, {
    
type'arearange',
    
pointArrayMap: ['low''high'],
    
toYData: function (point) {
        return [
point.lowpoint.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.null;
            } else if (
point.low === null && point.high !== null) {
                
point.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.null;
            } else if (
low === null) {
                
point.plotLow point.plotY null;
                
point.plotHigh yAxis.translate(high0101);
            } else if (
high === null) {
                
point.plotLow plotY;
                
point.plotHigh null;
            } else {
                
point.plotLow plotY;
                
point.plotHigh yAxis.translate(high0101);
            }
        });
    },
    
    
/**
     * 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 = [],
            
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({
                    
plotXpoint.plotX,
                    
plotYpoint.plotHigh
                
});
            }
        }
        
        
// Get the paths
        
lowerPath baseGetSegmentPath.call(thislowSegment);
        if (
step) {
            if (
step === true) {
                
step 'left';
            }
            
options.step = { left'right'center'center'right'left' }[step]; // swap for reading in getSegmentPath
        
}
        
higherPath baseGetSegmentPath.call(thishighSegment);
        
options.step step;
        
        
// Create a line on both top and bottom of the range
        
linePath = [].concat(lowerPathhigherPath);
        
        
// 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(lowerPathhigherPath);
        
        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
            
length;
            while (
i--) {
                
point data[i];
                
                
// Set preliminary values
                
point.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.dataLabelOptions.xHigh;                                
                } else {
                    
dataLabelOptions.dataLabelOptions.yHigh;
                }
            }
            
seriesProto.drawDataLabels.apply(thisarguments); // #1209
            
            // Step 2: reorganize and handle data labels for the lower values
            
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.point.low;
                
point.plotY point.plotLow;
                
                
// Set the default offset
                
point.below true;
                if (
inverted) {
                    
dataLabelOptions.align 'right';
                    
dataLabelOptions.dataLabelOptions.xLow;
                } else {
                    
dataLabelOptions.dataLabelOptions.yLow;
                }
            }
            
seriesProto.drawDataLabels.apply(thisarguments);
        }
    
    },
    
    
alignDataLabelseriesTypes.column.prototype.alignDataLabel,
    
    
getSymbolseriesTypes.column.prototype.getSymbol,
    
    
drawPointsnoop
});/**
 * The AreaSplineRangeSeries class
 */

defaultPlotOptions.areasplinerange merge(defaultPlotOptions.arearange);

/**
 * AreaSplineRangeSeries object
 */
seriesTypes.areasplinerange extendClass(seriesTypes.arearange, {
    
type'areasplinerange',
    
getPointSplineseriesTypes.spline.prototype.getPointSpline
});/**
 * The ColumnRangeSeries class
 */
defaultPlotOptions.columnrange merge(defaultPlotOptions.columndefaultPlotOptions.arearange, {
    
lineWidth1,
    
pointRangenull
});

/**
 * 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.high0101);
            
point.plotLow point.plotY;

            
// adjust shape
            
plotHigh;
            
height point.plotY plotHigh;

            if (
height minPointLength) {
                
heightDifference = (minPointLength height);
                
height += heightDifference;
                
-= heightDifference 2;
            }
            
shapeArgs.height height;
            
shapeArgs.y;
        });
    },
    
trackerGroups: ['group''dataLabels'],
    
drawGraphnoop,
    
pointAttrToOptionscolProto.pointAttrToOptions,
    
drawPointscolProto.drawPoints,
    
drawTrackercolProto.drawTracker,
    
animatecolProto.animate,
    
getColumnMetricscolProto.getColumnMetrics
});
/* 
 * The GaugeSeries class
 */



/**
 * Extend the default options
 */
defaultPlotOptions.gauge merge(defaultPlotOptions.line, {
    
dataLabels: {
        
enabledtrue,
        
y15,
        
borderWidth1,
        
borderColor'silver',
        
borderRadius3,
        
style: {
            
fontWeight'bold'
        
},
        
verticalAlign'top',
        
zIndex2
    
},
    
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''
    
},
    
showInLegendfalse
});

/**
 * 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',
    
pointClassGaugePoint,
    
    
// chart.angular will be set to true when a gauge series is present, and this will
    // be used on the axes
    
angulartrue
    
drawGraphnoop,
    
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.dialpoint.dial),
                
radius = (pInt(pick(dialOptions.radius80)) * center[2]) / 200,
                
baseLength = (pInt(pick(dialOptions.baseLength70)) * radius) / 100,
                
rearLength = (pInt(pick(dialOptions.rearLength10)) * radius) / 100,
                
baseWidth dialOptions.baseWidth || 3,
                
topWidth dialOptions.topWidth || 1,
                
rotation yAxis.startAngleRad yAxis.translate(point.ynullnullnulltrue);

            
// Handle the wrap option
            
if (options.wrap === false) {
                
rotation Math.max(yAxis.startAngleRadMath.min(yAxis.endAngleRadrotation));
            }
            
rotation rotation 180 Math.PI;
                
            
point.shapeType 'path';
            
point.shapeArgs = {
                
ddialOptions.path || [
                    
'M'
                    -
rearLength, -baseWidth 2
                    
'L'
                    
baseLength, -baseWidth 2,
                    
radius, -topWidth 2,
                    
radiustopWidth 2,
                    
baseLengthbaseWidth 2,
                    -
rearLengthbaseWidth 2,
                    
'z'
                
],
                
translateXcenter[0],
                
translateYcenter[1],
                
rotationrotation
            
};
            
            
// 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,
                
shapeArgs.d,
                
dialOptions merge(options.dialpoint.dial); // #1233
            
            
if (graphic) {
                
graphic.animate(shapeArgs);
                
shapeArgs.d// animate alters it
            
} else {
                
point.graphic renderer[point.shapeType](shapeArgs)
                    .
attr({
                        
strokedialOptions.borderColor || 'none',
                        
'stroke-width'dialOptions.borderWidth || 0,
                        
filldialOptions.backgroundColor || 'black',
                        
rotationshapeArgs.rotation // required by VML when animation is false
                    
})
                    .
add(series.group);
            }
        });
        
        
// Add or move the pivot
        
if (pivot) {
            
pivot.animate({ // #1235
                
translateXcenter[0],
                
translateYcenter[1]
            });
        } else {
            
series.pivot renderer.circle(00pick(pivotOptions.radius5))
                .
attr({
                    
'stroke-width'pivotOptions.borderWidth || 0,
                    
strokepivotOptions.borderColor || 'silver',
                    
fillpivotOptions.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({
                        
rotationseries.yAxis.startAngleRad 180 Math.PI
                    
});

                    
// animate
                    
graphic.animate({
                        
rotationpoint.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);
    },
    
    
setDataseriesTypes.pie.prototype.setData,
    
drawTrackerseriesTypes.column.prototype.drawTracker
};
seriesTypes.gauge Highcharts.extendClass(seriesTypes.lineGaugeSeries);/* ****************************************************************************
 * Start Box plot series code                                                  *
 *****************************************************************************/

// Set default options
defaultPlotOptions.boxplot merge(defaultPlotOptions.column, {
    
fillColor'#FFFFFF',
    
lineWidth1,
    
//medianColor: null,
    
medianWidth2,
    
states: {
        
hover: {
            
brightness: -0.3
        
}
    },
    
//stemColor: null,
    //stemDashStyle: 'solid'
    //stemWidth: null,
    
thresholdnull,
    
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%',
    
whiskerWidth2
});

// 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.lowpoint.q1point.medianpoint.q3point.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
     */
    
drawDataLabelsnoop,

    
/**
     * 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], 0101);
                }
            });
        });
    },

    
/**
     * 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.whiskerLength10) / 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.stemWidthoptions.stemWidthoptions.lineWidth);
                
stemAttr.dashstyle point.stemDashStyle || options.stemDashStyle;
                
                
// Whiskers attributes
                
whiskersAttr.stroke point.whiskerColor || options.whiskerColor || color;
                
whiskersAttr['stroke-width'] = pick(point.whiskerWidthoptions.whiskerWidthoptions.lineWidth);
                
                
// Median attributes
                
medianAttr.stroke point.medianColor || options.medianColor || color;
                
medianAttr['stroke-width'] = pick(point.medianWidthoptions.medianWidthoptions.lineWidth);
                
                
                
// The stem
                
crispCorr = (stemAttr['stroke-width'] % 2) / 2;
                
crispX left halfWidth crispCorr;                
                
stemPath = [
                    
// stem up
                    
'M',
                    
crispXq3Plot,
                    
'L',
                    
crispXhighPlot,
                    
                    
// stem down
                    
'M',
                    
crispXq1Plot,
                    
'L',
                    
crispXlowPlot,
                    
'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',
                        
leftq3Plot,
                        
'L',
                        
leftq1Plot,
                        
'L',
                        
rightq1Plot,
                        
'L',
                        
rightq3Plot,
                        
'L',
                        
leftq3Plot,
                        
'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({ dstemPath });
                    if (
whiskerLength) {
                        
point.whiskers.animate({ dwhiskersPath });
                    }
                    if (
doQuartiles) {
                        
point.box.animate({ dboxPath });
                    }
                    
point.medianShape.animate({ dmedianPath });
                    
                } 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',
    
groupingfalse,
    
linkedTo':previous',
    
tooltip: {
        
pointFormatdefaultPlotOptions.arearange.tooltip.pointFormat
    
},
    
whiskerWidthnull
});

// 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.lowpoint.high];
    },
    
pointValKey'high'// defines the top of the tracker
    
doQuartilesfalse,

    
/**
     * 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, {
    
lineWidth1,
    
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 (chartoptions) {
        
// force stacking
        
options.stacking true;

        
seriesTypes.column.prototype.init.call(thischartoptions);
    },


    
/**
     * 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 (
0len points.lengthleni++) {
            
// 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.series.yData[i];
            }

            
// up points
            
mathMax(previousYpreviousY point.y) + stackPoint[0];
            
shapeArgs.axis.translate(y01);


            
// sum points
            
if (point.isSum || point.isIntermediateSum) {
                
shapeArgs.axis.translate(stackPoint[1], 01);
                
shapeArgs.height axis.translate(stackPoint[0], 01) - 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.+= shapeArgs.height;
                
shapeArgs.height *= -1;
            }

            
point.plotY shapeArgs.mathRound(shapeArgs.y) - crispCorr;
            
shapeArgs.height mathRound(shapeArgs.height);
            
point.yBottom shapeArgs.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 (
0dataLengthi++) {
            
yData[i];
            
point points points[i] : {};

            if (
=== "sum" || point.isSum) {
                
yData[i] = sum;
            } else if (
=== "intermediateSum" || point.isIntermediateSum) {
                
yData[i] = subSum;
                
subSum threshold;
            } else {
                
sum += y;
                
subSum += y;
            }
            
dataMin Math.min(sumdataMin);
            
dataMax Math.max(sumdataMax);
        }

        
Series.prototype.processData.call(thisforce);

        
// 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(thisarguments);

        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.&& !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,
            
path = [],
            
'M',
            
'L',
            
prevArgs,
            
pointArgs,
            
i,
            
d;

        for (
1lengthi++) {
            
pointArgs data[i].shapeArgs;
            
prevArgs data[1].shapeArgs;

            
= [
                
M,
                
prevArgs.prevArgs.widthprevArgs.normalizer,
                
L,
                
pointArgs.xprevArgs.normalizer
            
];

            if (
data[1].0) {
                
d[2] += prevArgs.height;
                
d[5] += prevArgs.height;
            }

            
path path.concat(d);
        }

        return 
path;
    },

    
/**
     * Extremes are recorded in processData
     */
    
getExtremesnoop,

    
/**
     * 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];
    },

    
drawGraphSeries.prototype.drawGraph
});

/* ****************************************************************************
 * End Waterfall series code                                                  *
 *****************************************************************************/
/* ****************************************************************************
 * Start Bubble series code                                                      *
 *****************************************************************************/

// 1 - set default options
defaultPlotOptions.bubble merge(defaultPlotOptions.scatter, {
    
dataLabels: {
        
insidetrue,
        
style: {
            
color'white',
            
textShadow'0px 0px 3px black'
        
},
        
verticalAlign'middle'
    
},
    
// displayNegative: true,
    
marker: {
        
// fillOpacity: 0.5,
        
lineColornull// inherit from series.color
        
lineWidth1
    
},
    
minSize8,
    
maxSize'20%',
    
// negativeColor: null,
    
tooltip: {
        
pointFormat'({point.x}, {point.y}), Size: {point.z}'
    
},
    
turboThreshold0,
    
zThreshold0
});

// 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.fillOpacity0.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(thisarguments);
        
        
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 (zMinzMaxminSizemaxSize) {
        var 
len,
            
i,
            
pos,
            
zData this.zData,
            
radii = [],
            
zRange;
        
        
// Set the shape type and arguments to be picked up in drawPoints
        
for (0len zData.lengthleni++) {
            
zRange zMax zMin;
            
pos zRange // 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({
                        
rshapeArgs.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
        
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.< (this.options.zThreshold || 0);
            
            if (
radius >= this.minPxSize 2) {
                
// Shape arguments
                
point.shapeType 'circle';
                
point.shapeArgs = {
                    
xpoint.plotX,
                    
ypoint.plotY,
                    
rradius
                
};
                
                
// Alignment box for the data label
                
point.dlBox = {
                    
xpoint.plotX radius,
                    
ypoint.plotY radius,
                    
widthradius,
                    
heightradius
                
};
            } 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 (legenditem) {
        var 
radius pInt(legend.itemStyle.fontSize) / 2;
        
        
item.legendSymbol this.chart.renderer.circle(
            
radius,
            
legend.baseline radius,
            
radius
        
).attr({
            
zIndex3
        
}).add(item.legendGroup);
        
item.legendSymbol.isMarker true;    
        
    },
    
    
drawPointsseriesTypes.column.prototype.drawPoints,
    
alignDataLabelseriesTypes.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.plotWidthchart.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(zMaxarrayMax(zData));
                    }
                }
            }
        });

        
each(activeSeries, function (series) {

            var 
data series[dataKey],
                
data.length,
                
radius;

            if (
isXAxis) {
                
series.getRadii(zMinzMaxextremes.minSizeextremes.maxSize);
            }
            
            if (
range 0) {
                while (
i--) {
                    
radius series.radii[i];
                    
pxMin Math.min(((data[i] - min) * transA) - radiuspxMin);
                    
pxMax Math.max(((data[i] - min) * transA) + radiuspxMax);
                }
            }
        });
        
        if (
range && pick(this.options.minthis.userMin) === UNDEFINED && pick(this.options.maxthis.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.plotXthis.yAxis.len plotY);
    
point.plotX point.polarPlotX xy.chart.plotLeft;
    
point.plotY point.polarPlotY xy.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 (ab) {
            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(proceedchartoptions) {
    
proceed.call(thischartoptions);
    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 (proceedsegmentpointi) {
    
    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[1];
        
nextPoint segment[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 plotX2) + Math.pow(leftContY plotY2));
            
distanceRightControlPoint Math.sqrt(Math.pow(rightContX plotX2) + Math.pow(rightContY plotY2));
            
leftContAngle Math.atan2(leftContY plotYleftContX plotX);
            
rightContAngle Math.atan2(rightContY plotYrightContX 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'plotXplotY];
        } 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(thissegmentpointi);
    }
    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,
            
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 (proceedsegment) {
        
    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].!== null) {
        
this.connectEnds true// re-used in splines
        
segment = [].concat(segment, [points[0]]);
    }
    
    
// Run uber method
    
return proceed.call(thissegment);
    
});


function 
polarAnimate(proceedinit) {
    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 = {
                    
translateXcenter[0] + plotLeft,
                    
translateYcenter[1] + plotTop,
                    
scaleX0.001// #1499
                    
scaleY0.001
                
};
                    
                
group.attr(attribs);
                if (
markerGroup) {
                    
markerGroup.attrSetters group.attrSetters;
                    
markerGroup.attr(attribs);
                }
                
            
// Run the animation
            
} else {
                
attribs = {
                    
translateXplotLeft,
                    
translateYplotTop,
                    
scaleX1,
                    
scaleY1
                
};
                
group.animate(attribsanimation);
                if (
markerGroup) {
                    
markerGroup.animate(attribsanimation);
                }
                
                
// Delete this function to allow it only once
                
this.animate null;
            }
        }
    
    
// For non-polar charts, revert to the basic animation
    
} else {
        
proceed.call(thisinit);
    } 
}

// 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 (proceedrenew) {
        
    if (
this.chart.polar) {
        
extend(this.xAxis, {
            
tooltipLen360 // degrees are the resolution unit of the tooltipPoints array
        
});    
    }
    
    
// Run uber method
    
return proceed.call(thisrenew);
});


/**
 * 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;
        
points.length;
        while (
i--) {
            
point points[i];
            
start point.barX startAngleRad;
            
point.shapeType 'path';
            
point.shapeArgs = {
                
drenderer.symbols.arc(
                    
center[0],
                    
center[1],
                    
len point.plotY,
                    
null
                    {
                        
startstart,
                        
endstart point.pointWidth,
                        
innerRlen pick(point.yBottomlen)
                    }
                )
            };
            
this.toXY(point); // provide correct plotX, plotY for tooltip
        
}
    }
});


/**
 * Align column data labels outside the columns. #1199.
 */
wrap(colProto'alignDataLabel', function (proceedpointdataLabeloptionsalignToisNew) {
    
    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(thispointdataLabeloptionsalignToisNew);
    } else {
        
proceed.call(thispointdataLabeloptionsalignToisNew);
    }
    
});

/**
 * Extend the mouse tracker to return the tooltip position index in terms of
 * degrees rather than pixels
 */
wrap(pointerProto'getIndex', function (proceede) {
    var 
ret,
        
chart this.chart,
        
center,
        
x,
        
y;
    
    if (
chart.polar) {
        
center chart.xAxis[0].center;
        
e.chartX center[0] - chart.plotLeft;
        
e.chartY center[1] - chart.plotTop;
        
        
ret 180 Math.round(Math.atan2(xy) / Math.PI 180);
    
    } else {
    
        
// Run uber method
        
ret proceed.call(thise);
    }
    return 
ret;
});

/**
 * Extend getCoordinates to prepare for polar axis values
 */
wrap(pointerProto'getCoordinates', function (proceede) {
    var 
chart this.chart,
        
ret = {
            
xAxis: [],
            
yAxis: []
        };
    
    if (
chart.polar) {    

        
each(chart.axes, function (axis) {
            var 
isXAxis axis.isXAxis,
                
center axis.center,
                
e.chartX center[0] - chart.plotLeft,
                
e.chartY center[1] - chart.plotTop;
            
            
ret[isXAxis 'xAxis' 'yAxis'].push({
                
axisaxis,
                
valueaxis.translate(
                    
isXAxis ?
                        
Math.PI Math.atan2(xy) : // angle 
                        
Math.sqrt(Math.pow(x2) + Math.pow(y2)), // distance from center
                    
true
                
)
            });
        });
        
    } else {
        
ret proceed.call(thise);
    }
    
    return 
ret;
});
}(
Highcharts));
?>
Онлайн: 1
Реклама