2 * g.Raphael 0.5 - Charting library, based on Raphaƫl
4 * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
5 * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
8 if (typeof(Raphael) == 'undefined') {
9 // support for seed/simple browser usage
10 importz = imports['seed/importz.js'].importz;
12 Raphael = importz('Raphael');
18 function shrink(values, dim) {
19 var k = values.length / dim,
25 while (j < values.length) {
29 sum += values[j] * (1 + l);
31 sum = values[j++] * -l;
34 sum += values[j++] * 1;
40 function getAnchors(p1x, p1y, p2x, p2y, p3x, p3y) {
41 var l1 = (p2x - p1x) / 2,
43 a = Math.atan((p2x - p1x) / Math.abs(p2y - p1y)),
44 b = Math.atan((p3x - p2x) / Math.abs(p2y - p3y));
46 a = p1y < p2y ? Math.PI - a : a;
47 b = p3y < p2y ? Math.PI - b : b;
49 var alpha = Math.PI / 2 - ((a + b) % (Math.PI * 2)) / 2,
50 dx1 = l1 * Math.sin(alpha + a),
51 dy1 = l1 * Math.cos(alpha + a),
52 dx2 = l2 * Math.sin(alpha + b),
53 dy2 = l2 * Math.cos(alpha + b);
63 function Linechart(paper, x, y, width, height, valuesx, valuesy, opts) {
69 if (!paper.raphael.is(valuesx[0], "array")) {
73 if (!paper.raphael.is(valuesy[0], "array")) {
78 var gutter = opts.gutter || 10,
79 len = Math.max(valuesx[0].length, valuesy[0].length),
80 symbol = opts.symbol || "",
81 colors = opts.colors || chartinst.colors,
87 for (var i = 0, ii = valuesy.length; i < ii; i++) {
88 len = Math.max(len, valuesy[i].length);
91 var shades = paper.set();
93 for (i = 0, ii = valuesy.length; i < ii; i++) {
95 shades.push(paper.path().attr({ stroke: "none", fill: colors[i], opacity: opts.nostroke ? 1 : .3 }));
98 if (valuesy[i].length > width - 2 * gutter) {
99 valuesy[i] = shrink(valuesy[i], width - 2 * gutter);
100 len = width - 2 * gutter;
103 if (valuesx[i] && valuesx[i].length > width - 2 * gutter) {
104 valuesx[i] = shrink(valuesx[i], width - 2 * gutter);
108 var allx = Array.prototype.concat.apply([], valuesx),
109 ally = Array.prototype.concat.apply([], valuesy),
110 xdim = chartinst.snapEnds(
111 Math.min.apply(Math, allx),
112 Math.max.apply(Math, allx),
113 valuesx[0].length - 1
117 ydim = chartinst.snapEnds(
118 Math.min.apply(Math, ally),
119 Math.max.apply(Math, ally),
120 valuesy[0].length - 1
122 miny = typeof(opts.ymin) == 'undefined' ? ydim.from : opts.ymin,
123 maxy = typeof(opts.maxy) == 'undefined' ? ydim.to : opts.maxy,
124 kx = (width - gutter * 2) / ((maxx - minx) || 1),
125 ky = (height - gutter * 2) / ((maxy - miny) || 1);
127 var axis = paper.set();
129 // Roo.log("Checking for AXIS");
133 // Roo.log(opts.axis);
135 // Value - "top right bottom left". If
136 var ax = (opts.axis + "").split(/[,\s]+/);
146 opts.axisxstep || Math.floor((width - 2 * gutter) / 20),
156 opts.axisystep || Math.floor((height - 2 * gutter) / 20),
161 opts.axisxlabels = opts.axisxlabels || [];
163 opts.axisxstep = opts.axisxstep || (opts.axisxlabels ? opts.axisxlabels.length -1 : false ) || len;
167 y: y + height - gutter,
168 length : width - 2 * gutter + 20, // total width
169 from: minx , // from -- infinity??? if no 'xvalues set'
171 steps : opts.axisxstep , // 9 when we have 8 items?
172 orientation : 0, // orientation
173 labels : opts.axisxlabels || false, // labels
174 type : "-", // type ofbarhgutter line
175 dashsize : 5, // dash size
177 loffset : Math.round(gutter / 100 + (1)),
178 roffset : Math.round(gutter / 100 + (1)) + 20,
181 // +ax[2] && axis.push(
183 // // x, y, length, from, to, steps, orientation, labels, type, dashsize, paper
184 // //chartinst.axis( ax_args, paper)
189 // x, y, length, from, to, steps, orientation, labels, type, dashsize, paper
196 opts.axisxstep || Math.floor((width - 2 * gutter) / 20),
198 opts.axisxlabels || false,
210 opts.axisystep || Math.floor((height - 2 * gutter) / 20),
216 var lines = paper.set(),
217 symbols = paper.set(),
220 for (i = 0, ii = valuesy.length; i < ii; i++) {
221 if (!opts.nostroke) {
222 lines.push(line = paper.path().attr({
224 "stroke-width": opts.width || 2,
225 "stroke-linejoin": "round",
226 "stroke-linecap": "round",
227 "stroke-dasharray": opts.dash || ""
231 var sym = Raphael.is(symbol, "array") ? symbol[i] : symbol,
232 symset = paper.set();
236 for (var j = 0, jj = valuesy[i].length; j < jj; j++) {
237 var X = x + gutter + ((valuesx[i] || valuesx[0])[j] - minx) * kx,
238 Y = y + height - gutter - (valuesy[i][j] - miny) * ky;
240 (Raphael.is(sym, "array") ? sym[j] : sym) && symset.push(paper[Raphael.is(sym, "array") ? sym[j] : sym](X, Y, (opts.width || 2) * 3).attr({ fill: colors[i], stroke: "none" }));
242 var vx = X - (opts.label_padding_x || 0);
243 var vy = Y - (opts.label_padding_y || 10);
245 if(opts.linelabels && opts.linelabels[i] && opts.linelabels[i][j]){
246 paper.text(vx, vy, opts.linelabels[i][j]);
250 if (j && j != jj - 1) {
251 var X0 = x + gutter + ((valuesx[i] || valuesx[0])[j - 1] - minx) * kx,
252 Y0 = y + height - gutter - (valuesy[i][j - 1] - miny) * ky,
253 X2 = x + gutter + ((valuesx[i] || valuesx[0])[j + 1] - minx) * kx,
254 Y2 = y + height - gutter - (valuesy[i][j + 1] - miny) * ky,
255 a = getAnchors(X0, Y0, X, Y, X2, Y2);
257 path = path.concat([a.x1, a.y1, X, Y, a.x2, a.y2]);
261 path = ["M", X, Y, "C", X, Y];
264 path = path.concat([j ? "L" : "M", X, Y]);
269 path = path.concat([X, Y, X, Y]);
272 symbols.push(symset);
275 shades[i].attr({ path: path.concat(["L", X, y + height - gutter, "L", x + gutter + ((valuesx[i] || valuesx[0])[0] - minx) * kx, y + height - gutter, "z"]).join(",") });
278 !opts.nostroke && line.attr({ path: path.join(",") });
281 function createColumns(f) {
285 for (var i = 0, ii = valuesx.length; i < ii; i++) {
286 Xs = Xs.concat(valuesx[i]);
290 Xs.sort(function(a,b) { return a - b; });
296 for (i = 0, ii = Xs.length; i < ii; i++) {
297 Xs[i] != Xs[i - 1] && Xs2.push(Xs[i]) && xs.push(x + gutter + (Xs[i] - minx) * kx);
303 var cvrs = f || paper.set();
305 for (i = 0; i < ii; i++) {
306 var X = xs[i] - (xs[i] - (xs[i - 1] || x)) / 2,
307 w = ((xs[i + 1] || x + width) - xs[i]) / 2 + (xs[i] - (xs[i - 1] || x)) / 2,
310 f ? (C = {}) : cvrs.push(C = paper.rect(X - 1, y, Math.max(w + 1, 1), height).attr({ stroke: "none", fill: "#000", opacity: 0 }));
312 C.symbols = paper.set();
317 for (var j = 0, jj = valuesy.length; j < jj; j++) {
318 Xs2 = valuesx[j] || valuesx[0];
320 for (var k = 0, kk = Xs2.length; k < kk; k++) {
321 if (Xs2[k] == Xs[i]) {
322 C.values.push(valuesy[j][k]);
323 C.y.push(y + height - gutter - (valuesy[j][k] - miny) * ky);
324 C.symbols.push(chart.symbols[j][k]);
332 !f && (columns = cvrs);
335 function createDots(f) {
336 var cvrs = f || paper.set(),
339 for (var i = 0, ii = valuesy.length; i < ii; i++) {
340 for (var j = 0, jj = valuesy[i].length; j < jj; j++) {
341 var X = x + gutter + ((valuesx[i] || valuesx[0])[j] - minx) * kx,
342 nearX = x + gutter + ((valuesx[i] || valuesx[0])[j ? j - 1 : 1] - minx) * kx,
343 Y = y + height - gutter - (valuesy[i][j] - miny) * ky;
345 f ? (C = {}) : cvrs.push(C = paper.circle(X, Y, Math.abs(nearX - X) / 2).attr({ stroke: "none", fill: "#000", opacity: 0 }));
348 C.value = valuesy[i][j];
349 C.line = chart.lines[i];
350 C.shade = chart.shades[i];
351 C.symbol = chart.symbols[i][j];
352 C.symbols = chart.symbols[i];
353 C.axis = (valuesx[i] || valuesx[0])[j];
361 chart.push(lines, shades, symbols, axis, columns, dots);
363 chart.shades = shades;
364 chart.symbols = symbols;
367 chart.hoverColumn = function (fin, fout) {
368 !columns && createColumns();
369 columns.mouseover(fin).mouseout(fout);
373 chart.clickColumn = function (f) {
374 !columns && createColumns();
379 chart.hrefColumn = function (cols) {
380 var hrefs = paper.raphael.is(arguments[0], "array") ? arguments[0] : arguments;
382 if (!(arguments.length - 1) && typeof cols == "object") {
383 for (var x in cols) {
384 for (var i = 0, ii = columns.length; i < ii; i++) if (columns[i].axis == x) {
385 columns[i].attr("href", cols[x]);
390 !columns && createColumns();
392 for (i = 0, ii = hrefs.length; i < ii; i++) {
393 columns[i] && columns[i].attr("href", hrefs[i]);
399 chart.hover = function (fin, fout) {
400 !dots && createDots();
401 dots.mouseover(fin).mouseout(fout);
405 chart.click = function (f) {
406 !dots && createDots();
411 chart.each = function (f) {
416 chart.eachColumn = function (f) {
425 var F = function() {};
426 F.prototype = Raphael.g;
427 Linechart.prototype = new F;
430 Raphael.fn.linechart = function(x, y, width, height, valuesx, valuesy, opts) {
431 return new Linechart(this, x, y, width, height, valuesx, valuesy, opts);
438 Raphael.fn.drawGrid = function (x, y, w, h, wv, hv, color) {
439 color = color || "#000";
444 Math.round(x + w) + .5,
446 Math.round(x + w) + .5,
447 Math.round(y + h) + .5,
449 Math.round(y + h) + .5,
455 //var columnWidth = w / wv;
456 var columnWidth = w / wv;
458 for (var i = 1; i < hv; i++) {
459 path = path.concat(["M", Math.round(x) + .5, Math.round(y + i * rowHeight) + .5, "H", Math.round(x + w) + .5]);
461 for (i = 1; i < wv; i++) {
462 path = path.concat(["M", Math.round(x + i * columnWidth) + .5, Math.round(y) + .5, "V", Math.round(y + h) + .5]);
464 return this.path(path.join(",")).attr({stroke: color});