Blame | Letzte Änderung | Log anzeigen | RSS feed
/*** @license* Highcharts funnel module** (c) 2010-2014 Torstein Honsi** License: www.highcharts.com/license*//*global Highcharts */(function (Highcharts) {'use strict';// create shortcutsvar defaultOptions = Highcharts.getOptions(),defaultPlotOptions = defaultOptions.plotOptions,seriesTypes = Highcharts.seriesTypes,merge = Highcharts.merge,noop = function () {},each = Highcharts.each,pick = Highcharts.pick;// set default optionsdefaultPlotOptions.funnel = merge(defaultPlotOptions.pie, {animation: false,center: ['50%', '50%'],width: '90%',neckWidth: '30%',height: '100%',neckHeight: '25%',reversed: false,dataLabels: {//position: 'right',connectorWidth: 1,connectorColor: '#606060'},size: true, // to avoid adapting to data label size in Pie.drawDataLabelsstates: {select: {color: '#C0C0C0',borderColor: '#000000',shadow: false}}});seriesTypes.funnel = Highcharts.extendClass(seriesTypes.pie, {type: 'funnel',animate: noop,/*** Overrides the pie translate method*/translate: function () {var// Get positions - either an integer or a percentage string must be givengetLength = function (length, relativeTo) {return (/%$/).test(length) ?relativeTo * parseInt(length, 10) / 100 :parseInt(length, 10);},sum = 0,series = this,chart = series.chart,options = series.options,reversed = options.reversed,ignoreHiddenPoint = options.ignoreHiddenPoint,plotWidth = chart.plotWidth,plotHeight = chart.plotHeight,cumulative = 0, // start at topcenter = options.center,centerX = getLength(center[0], plotWidth),centerY = getLength(center[1], plotHeight),width = getLength(options.width, plotWidth),tempWidth,getWidthAt,height = getLength(options.height, plotHeight),neckWidth = getLength(options.neckWidth, plotWidth),neckHeight = getLength(options.neckHeight, plotHeight),neckY = height - neckHeight,data = series.data,path,fraction,half = options.dataLabels.position === 'left' ? 1 : 0,x1,y1,x2,x3,y3,x4,y5;// Return the width at a specific y coordinateseries.getWidthAt = getWidthAt = function (y) {return y > height - neckHeight || height === neckHeight ?neckWidth :neckWidth + (width - neckWidth) * ((height - neckHeight - y) / (height - neckHeight));};series.getX = function (y, half) {return centerX + (half ? -1 : 1) * ((getWidthAt(reversed ? plotHeight - y : y) / 2) + options.dataLabels.distance);};// Exposeseries.center = [centerX, centerY, height];series.centerX = centerX;/** Individual point coordinate naming:** x1,y1 _________________ x2,y1* \ /* \ /* \ /* \ /* \ /* x3,y3 _________ x4,y3** Additional for the base of the neck:** | |* | |* | |* x3,y5 _________ x4,y5*/// get the total sumeach(data, function (point) {if (!ignoreHiddenPoint || point.visible !== false) {sum += point.y;}});each(data, function (point) {// set start and end positionsy5 = null;fraction = sum ? point.y / sum : 0;y1 = centerY - height / 2 + cumulative * height;y3 = y1 + fraction * height;//tempWidth = neckWidth + (width - neckWidth) * ((height - neckHeight - y1) / (height - neckHeight));tempWidth = getWidthAt(y1);x1 = centerX - tempWidth / 2;x2 = x1 + tempWidth;tempWidth = getWidthAt(y3);x3 = centerX - tempWidth / 2;x4 = x3 + tempWidth;// the entire point is within the neckif (y1 > neckY) {x1 = x3 = centerX - neckWidth / 2;x2 = x4 = centerX + neckWidth / 2;// the base of the neck} else if (y3 > neckY) {y5 = y3;tempWidth = getWidthAt(neckY);x3 = centerX - tempWidth / 2;x4 = x3 + tempWidth;y3 = neckY;}if (reversed) {y1 = height - y1;y3 = height - y3;y5 = (y5 ? height - y5 : null);}// save the pathpath = ['M',x1, y1,'L',x2, y1,x4, y3];if (y5) {path.push(x4, y5, x3, y5);}path.push(x3, y3, 'Z');// prepare for using shared drpoint.shapeType = 'path';point.shapeArgs = { d: path };// for tooltips and data labelspoint.percentage = fraction * 100;point.plotX = centerX;point.plotY = (y1 + (y5 || y3)) / 2;// Placement of tooltips and data labelspoint.tooltipPos = [centerX,point.plotY];// Slice is a noop on funnel pointspoint.slice = noop;// Mimicking pie data label placement logicpoint.half = half;if (!ignoreHiddenPoint || point.visible !== false) {cumulative += fraction;}});},/*** Draw a single point (wedge)* @param {Object} point The point object* @param {Object} color The color of the point* @param {Number} brightness The brightness relative to the color*/drawPoints: function () {var series = this,options = series.options,chart = series.chart,renderer = chart.renderer;each(series.data, function (point) {var pointOptions = point.options,graphic = point.graphic,shapeArgs = point.shapeArgs;if (!graphic) { // Create the shapespoint.graphic = renderer.path(shapeArgs).attr({fill: point.color,stroke: pick(pointOptions.borderColor, options.borderColor),'stroke-width': pick(pointOptions.borderWidth, options.borderWidth)}).add(series.group);} else { // Update the shapesgraphic.animate(shapeArgs);}});},/*** Funnel items don't have angles (#2289)*/sortByAngle: function (points) {points.sort(function (a, b) {return a.plotY - b.plotY;});},/*** Extend the pie data label method*/drawDataLabels: function () {var data = this.data,labelDistance = this.options.dataLabels.distance,leftSide,sign,point,i = data.length,x,y;// In the original pie label anticollision logic, the slots are distributed// from one labelDistance above to one labelDistance below the pie. In funnels// we don't want this.this.center[2] -= 2 * labelDistance;// Set the label position array for each point.while (i--) {point = data[i];leftSide = point.half;sign = leftSide ? 1 : -1;y = point.plotY;x = this.getX(y, leftSide);// set the anchor point for data labelspoint.labelPos = [0, // first break of connectory, // a/ax + (labelDistance - 5) * sign, // second break, right outside point shapey, // a/ax + labelDistance * sign, // landing point for connectory, // a/aleftSide ? 'right' : 'left', // alignment0 // center angle];}seriesTypes.pie.prototype.drawDataLabels.call(this);}});/*** Pyramid series type.* A pyramid series is a special type of funnel, without neck and reversed by default.*/defaultOptions.plotOptions.pyramid = Highcharts.merge(defaultOptions.plotOptions.funnel, {neckWidth: '0%',neckHeight: '0%',reversed: true});Highcharts.seriesTypes.pyramid = Highcharts.extendClass(Highcharts.seriesTypes.funnel, {type: 'pyramid'});}(Highcharts));