Subversion-Projekte lars-tiefland.ci

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
776 lars 1
/**
2
 * @license
3
 * Highcharts funnel module
4
 *
5
 * (c) 2010-2014 Torstein Honsi
6
 *
7
 * License: www.highcharts.com/license
8
 */
9
 
10
/*global Highcharts */
11
(function (Highcharts) {
12
 
13
'use strict';
14
 
15
// create shortcuts
16
var defaultOptions = Highcharts.getOptions(),
17
	defaultPlotOptions = defaultOptions.plotOptions,
18
	seriesTypes = Highcharts.seriesTypes,
19
	merge = Highcharts.merge,
20
	noop = function () {},
21
	each = Highcharts.each,
22
	pick = Highcharts.pick;
23
 
24
// set default options
25
defaultPlotOptions.funnel = merge(defaultPlotOptions.pie, {
26
	animation: false,
27
	center: ['50%', '50%'],
28
	width: '90%',
29
	neckWidth: '30%',
30
	height: '100%',
31
	neckHeight: '25%',
32
	reversed: false,
33
	dataLabels: {
34
		//position: 'right',
35
		connectorWidth: 1,
36
		connectorColor: '#606060'
37
	},
38
	size: true, // to avoid adapting to data label size in Pie.drawDataLabels
39
	states: {
40
		select: {
41
			color: '#C0C0C0',
42
			borderColor: '#000000',
43
			shadow: false
44
		}
45
	}
46
});
47
 
48
 
49
seriesTypes.funnel = Highcharts.extendClass(seriesTypes.pie, {
50
 
51
	type: 'funnel',
52
	animate: noop,
53
 
54
	/**
55
	 * Overrides the pie translate method
56
	 */
57
	translate: function () {
58
 
59
		var
60
			// Get positions - either an integer or a percentage string must be given
61
			getLength = function (length, relativeTo) {
62
				return (/%$/).test(length) ?
63
					relativeTo * parseInt(length, 10) / 100 :
64
					parseInt(length, 10);
65
			},
66
 
67
			sum = 0,
68
			series = this,
69
			chart = series.chart,
70
			options = series.options,
71
			reversed = options.reversed,
72
			ignoreHiddenPoint = options.ignoreHiddenPoint,
73
			plotWidth = chart.plotWidth,
74
			plotHeight = chart.plotHeight,
75
			cumulative = 0, // start at top
76
			center = options.center,
77
			centerX = getLength(center[0], plotWidth),
78
			centerY = getLength(center[1], plotHeight),
79
			width = getLength(options.width, plotWidth),
80
			tempWidth,
81
			getWidthAt,
82
			height = getLength(options.height, plotHeight),
83
			neckWidth = getLength(options.neckWidth, plotWidth),
84
			neckHeight = getLength(options.neckHeight, plotHeight),
85
			neckY = height - neckHeight,
86
			data = series.data,
87
			path,
88
			fraction,
89
			half = options.dataLabels.position === 'left' ? 1 : 0,
90
 
91
			x1,
92
			y1,
93
			x2,
94
			x3,
95
			y3,
96
			x4,
97
			y5;
98
 
99
		// Return the width at a specific y coordinate
100
		series.getWidthAt = getWidthAt = function (y) {
101
			return y > height - neckHeight || height === neckHeight ?
102
				neckWidth :
103
				neckWidth + (width - neckWidth) * ((height - neckHeight - y) / (height - neckHeight));
104
		};
105
		series.getX = function (y, half) {
106
					return centerX + (half ? -1 : 1) * ((getWidthAt(reversed ? plotHeight - y : y) / 2) + options.dataLabels.distance);
107
		};
108
 
109
		// Expose
110
		series.center = [centerX, centerY, height];
111
		series.centerX = centerX;
112
 
113
		/*
114
		 * Individual point coordinate naming:
115
		 *
116
		 * x1,y1 _________________ x2,y1
117
		 *  \                         /
118
		 *   \                       /
119
		 *    \                     /
120
		 *     \                   /
121
		 *      \                 /
122
		 *     x3,y3 _________ x4,y3
123
		 *
124
		 * Additional for the base of the neck:
125
		 *
126
		 *       |               |
127
		 *       |               |
128
		 *       |               |
129
		 *     x3,y5 _________ x4,y5
130
		 */
131
 
132
 
133
 
134
 
135
		// get the total sum
136
		each(data, function (point) {
137
			if (!ignoreHiddenPoint || point.visible !== false) {
138
				sum += point.y;
139
			}
140
		});
141
 
142
		each(data, function (point) {
143
			// set start and end positions
144
			y5 = null;
145
			fraction = sum ? point.y / sum : 0;
146
			y1 = centerY - height / 2 + cumulative * height;
147
			y3 = y1 + fraction * height;
148
			//tempWidth = neckWidth + (width - neckWidth) * ((height - neckHeight - y1) / (height - neckHeight));
149
			tempWidth = getWidthAt(y1);
150
			x1 = centerX - tempWidth / 2;
151
			x2 = x1 + tempWidth;
152
			tempWidth = getWidthAt(y3);
153
			x3 = centerX - tempWidth / 2;
154
			x4 = x3 + tempWidth;
155
 
156
			// the entire point is within the neck
157
			if (y1 > neckY) {
158
				x1 = x3 = centerX - neckWidth / 2;
159
				x2 = x4 = centerX + neckWidth / 2;
160
 
161
			// the base of the neck
162
			} else if (y3 > neckY) {
163
				y5 = y3;
164
 
165
				tempWidth = getWidthAt(neckY);
166
				x3 = centerX - tempWidth / 2;
167
				x4 = x3 + tempWidth;
168
 
169
				y3 = neckY;
170
			}
171
 
172
			if (reversed) {
173
				y1 = height - y1;
174
				y3 = height - y3;
175
				y5 = (y5 ? height - y5 : null);
176
			}
177
			// save the path
178
			path = [
179
				'M',
180
				x1, y1,
181
				'L',
182
				x2, y1,
183
				x4, y3
184
			];
185
			if (y5) {
186
				path.push(x4, y5, x3, y5);
187
			}
188
			path.push(x3, y3, 'Z');
189
 
190
			// prepare for using shared dr
191
			point.shapeType = 'path';
192
			point.shapeArgs = { d: path };
193
 
194
 
195
			// for tooltips and data labels
196
			point.percentage = fraction * 100;
197
			point.plotX = centerX;
198
			point.plotY = (y1 + (y5 || y3)) / 2;
199
 
200
			// Placement of tooltips and data labels
201
			point.tooltipPos = [
202
				centerX,
203
				point.plotY
204
			];
205
 
206
			// Slice is a noop on funnel points
207
			point.slice = noop;
208
 
209
			// Mimicking pie data label placement logic
210
			point.half = half;
211
 
212
			if (!ignoreHiddenPoint || point.visible !== false) {
213
				cumulative += fraction;
214
			}
215
		});
216
	},
217
	/**
218
	 * Draw a single point (wedge)
219
	 * @param {Object} point The point object
220
	 * @param {Object} color The color of the point
221
	 * @param {Number} brightness The brightness relative to the color
222
	 */
223
	drawPoints: function () {
224
		var series = this,
225
			options = series.options,
226
			chart = series.chart,
227
			renderer = chart.renderer;
228
 
229
		each(series.data, function (point) {
230
			var pointOptions = point.options,
231
				graphic = point.graphic,
232
				shapeArgs = point.shapeArgs;
233
 
234
			if (!graphic) { // Create the shapes
235
				point.graphic = renderer.path(shapeArgs).
236
					attr({
237
						fill: point.color,
238
						stroke: pick(pointOptions.borderColor, options.borderColor),
239
						'stroke-width': pick(pointOptions.borderWidth, options.borderWidth)
240
					}).
241
					add(series.group);
242
 
243
			} else { // Update the shapes
244
				graphic.animate(shapeArgs);
245
			}
246
		});
247
	},
248
 
249
	/**
250
	 * Funnel items don't have angles (#2289)
251
	 */
252
	sortByAngle: function (points) {
253
		points.sort(function (a, b) {
254
			return a.plotY - b.plotY;
255
		});
256
	},
257
 
258
	/**
259
	 * Extend the pie data label method
260
	 */
261
	drawDataLabels: function () {
262
		var data = this.data,
263
			labelDistance = this.options.dataLabels.distance,
264
			leftSide,
265
			sign,
266
			point,
267
			i = data.length,
268
			x,
269
			y;
270
 
271
		// In the original pie label anticollision logic, the slots are distributed
272
		// from one labelDistance above to one labelDistance below the pie. In funnels
273
		// we don't want this.
274
		this.center[2] -= 2 * labelDistance;
275
 
276
		// Set the label position array for each point.
277
		while (i--) {
278
			point = data[i];
279
			leftSide = point.half;
280
			sign = leftSide ? 1 : -1;
281
			y = point.plotY;
282
			x = this.getX(y, leftSide);
283
 
284
			// set the anchor point for data labels
285
			point.labelPos = [
286
				0, // first break of connector
287
				y, // a/a
288
				x + (labelDistance - 5) * sign, // second break, right outside point shape
289
				y, // a/a
290
				x + labelDistance * sign, // landing point for connector
291
				y, // a/a
292
				leftSide ? 'right' : 'left', // alignment
293
 
294
			];
295
		}
296
 
297
		seriesTypes.pie.prototype.drawDataLabels.call(this);
298
	}
299
 
300
});
301
 
302
/**
303
 * Pyramid series type.
304
 * A pyramid series is a special type of funnel, without neck and reversed by default.
305
 */
306
defaultOptions.plotOptions.pyramid = Highcharts.merge(defaultOptions.plotOptions.funnel, {
307
	neckWidth: '0%',
308
	neckHeight: '0%',
309
	reversed: true
310
});
311
Highcharts.seriesTypes.pyramid = Highcharts.extendClass(Highcharts.seriesTypes.funnel, {
312
	type: 'pyramid'
313
});
314
 
315
}(Highcharts));