throw { name: 'FatalError', message: 'Do not call this file. If you want to use it, remove this line.' }; /*! * g.Raphael 0.4.1 - Charting library, based on Raphaël * * improved by frostbytten https://github.com/open-agroclimate/g.raphael * * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com) * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. */ (function () { var mmax = Math.max, mmin = Math.min; Raphael.fn.g = Raphael.fn.g || {}; Raphael.fn.g.markers = { disc: "disc", o: "disc", flower: "flower", f: "flower", diamond: "diamond", d: "diamond", square: "square", s: "square", triangle: "triangle", t: "triangle", star: "star", "*": "star", cross: "cross", x: "cross", plus: "plus", "+": "plus", arrow: "arrow", "->": "arrow" }; Raphael.fn.g.shim = {stroke: "none", fill: "#000", "fill-opacity": 0}; Raphael.fn.g.txtattr = {font: "12px Arial, sans-serif"}; Raphael.fn.g.colors = []; var hues = [.6, .2, .05, .1333, .75, 0]; for (var i = 0; i < 10; i++) { if (i < hues.length) { Raphael.fn.g.colors.push("hsb(" + hues[i] + ", .75, .75)"); } else { Raphael.fn.g.colors.push("hsb(" + hues[i - hues.length] + ", 1, .5)"); } } Raphael.fn.g.text = function (x, y, text) { return this.text(x, y, text).attr(this.g.txtattr); }; Raphael.fn.g.labelise = function (label, val, total) { if (label) { return (label + "").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g, function (all, value, percent) { if (value) { return (+val).toFixed(value.replace(/^#+\.?/g, "").length); } if (percent) { return (val * 100 / total).toFixed(percent.replace(/^%+\.?/g, "").length) + "%"; } }); } else { return (+val).toFixed(0); } }; Raphael.fn.g.finger = function (x, y, width, height, dir, ending, isPath) { // dir 0 for horisontal and 1 for vertical if ((dir && !height) || (!dir && !width)) { return isPath ? "" : this.path(); } ending = {square: "square", sharp: "sharp", soft: "soft"}[ending] || "round"; var path; height = Math.round(height); width = Math.round(width); x = Math.round(x); y = Math.round(y); switch (ending) { case "round": if (!dir) { var r = ~~(height / 2); if (width < r) { r = width; path = ["M", x + .5, y + .5 - ~~(height / 2), "l", 0, 0, "a", r, ~~(height / 2), 0, 0, 1, 0, height, "l", 0, 0, "z"]; } else { path = ["M", x + .5, y + .5 - r, "l", width - r, 0, "a", r, r, 0, 1, 1, 0, height, "l", r - width, 0, "z"]; } } else { r = ~~(width / 2); if (height < r) { r = height; path = ["M", x - ~~(width / 2), y, "l", 0, 0, "a", ~~(width / 2), r, 0, 0, 1, width, 0, "l", 0, 0, "z"]; } else { path = ["M", x - r, y, "l", 0, r - height, "a", r, r, 0, 1, 1, width, 0, "l", 0, height - r, "z"]; } } break; case "sharp": if (!dir) { var half = ~~(height / 2); path = ["M", x, y + half, "l", 0, -height, mmax(width - half, 0), 0, mmin(half, width), half, -mmin(half, width), half + (half * 2 < height), "z"]; } else { half = ~~(width / 2); path = ["M", x + half, y, "l", -width, 0, 0, -mmax(height - half, 0), half, -mmin(half, height), half, mmin(half, height), half, "z"]; } break; case "square": if (!dir) { path = ["M", x, y + ~~(height / 2), "l", 0, -height, width, 0, 0, height, "z"]; } else { path = ["M", x + ~~(width / 2), y, "l", 1 - width, 0, 0, -height, width - 1, 0, "z"]; } break; case "soft": if (!dir) { r = mmin(width, Math.round(height / 5)); path = ["M", x + .5, y + .5 - ~~(height / 2), "l", width - r, 0, "a", r, r, 0, 0, 1, r, r, "l", 0, height - r * 2, "a", r, r, 0, 0, 1, -r, r, "l", r - width, 0, "z"]; } else { r = mmin(Math.round(width / 5), height); path = ["M", x - ~~(width / 2), y, "l", 0, r - height, "a", r, r, 0, 0, 1, r, -r, "l", width - 2 * r, 0, "a", r, r, 0, 0, 1, r, r, "l", 0, height - r, "z"]; } } if (isPath) { return path.join(","); } else { return this.path(path); } }; // Symbols Raphael.fn.g.disc = function (cx, cy, r) { return this.circle(cx, cy, r); }; Raphael.fn.g.line = function (cx, cy, r) { return this.rect(cx - r, cy - r / 5, 2 * r, 2 * r / 5); }; Raphael.fn.g.square = function (cx, cy, r) { r = r * .7; return this.rect(cx - r, cy - r, 2 * r, 2 * r); }; Raphael.fn.g.triangle = function (cx, cy, r) { r *= 1.75; return this.path("M".concat(cx, ",", cy, "m0-", r * .58, "l", r * .5, ",", r * .87, "-", r, ",0z")); }; Raphael.fn.g.diamond = function (cx, cy, r) { return this.path(["M", cx, cy - r, "l", r, r, -r, r, -r, -r, r, -r, "z"]); }; Raphael.fn.g.flower = function (cx, cy, r, n) { r = r * 1.25; var rout = r, rin = rout * .5; n = +n < 3 || !n ? 5 : n; var points = ["M", cx, cy + rin, "Q"], R; for (var i = 1; i < n * 2 + 1; i++) { R = i % 2 ? rout : rin; points = points.concat([+(cx + R * Math.sin(i * Math.PI / n)).toFixed(3), +(cy + R * Math.cos(i * Math.PI / n)).toFixed(3)]); } points.push("z"); return this.path(points.join(",")); }; Raphael.fn.g.star = function (cx, cy, r, r2, rays) { r2 = r2 || r * .382; rays = rays || 5; var points = ["M", cx, cy + r2, "L"], R; for (var i = 1; i < rays * 2; i++) { R = i % 2 ? r : r2; points = points.concat([(cx + R * Math.sin(i * Math.PI / rays)), (cy + R * Math.cos(i * Math.PI / rays))]); } points.push("z"); return this.path(points.join(",")); }; Raphael.fn.g.cross = function (cx, cy, r) { r = r / 2.5; return this.path("M".concat(cx - r, ",", cy, "l", [-r, -r, r, -r, r, r, r, -r, r, r, -r, r, r, r, -r, r, -r, -r, -r, r, -r, -r, "z"])); }; Raphael.fn.g.plus = function (cx, cy, r) { r = r / 2; return this.path("M".concat(cx - r / 2, ",", cy - r / 2, "l", [0, -r, r, 0, 0, r, r, 0, 0, r, -r, 0, 0, r, -r, 0, 0, -r, -r, 0, 0, -r, "z"])); }; Raphael.fn.g.arrow = function (cx, cy, r) { return this.path("M".concat(cx - r * .7, ",", cy - r * .4, "l", [r * .6, 0, 0, -r * .4, r, r * .8, -r, r * .8, 0, -r * .4, -r * .6, 0], "z")); }; // Tooltips Raphael.fn.g.tag = function (x, y, text, angle, r) { angle = angle || 0; r = r == null ? 5 : r; text = text == null ? "$9.99" : text; var R = .5522 * r, res = this.set(), d = 3; res.push(this.path().attr({fill: "#000", stroke: "#000"})); res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff", "font-family": "Helvetica, Arial"})); res.update = function () { this.rotate(0, x, y); var bb = this[1].getBBox(); if (bb.height >= r * 2) { this[0].attr({path: ["M", x, y + r, "a", r, r, 0, 1, 1, 0, -r * 2, r, r, 0, 1, 1, 0, r * 2, "m", 0, -r * 2 -d, "a", r + d, r + d, 0, 1, 0, 0, (r + d) * 2, "L", x + r + d, y + bb.height / 2 + d, "l", bb.width + 2 * d, 0, 0, -bb.height - 2 * d, -bb.width - 2 * d, 0, "L", x, y - r - d].join(",")}); } else { var dx = Math.sqrt(Math.pow(r + d, 2) - Math.pow(bb.height / 2 + d, 2)); this[0].attr({path: ["M", x, y + r, "c", -R, 0, -r, R - r, -r, -r, 0, -R, r - R, -r, r, -r, R, 0, r, r - R, r, r, 0, R, R - r, r, -r, r, "M", x + dx, y - bb.height / 2 - d, "a", r + d, r + d, 0, 1, 0, 0, bb.height + 2 * d, "l", r + d - dx + bb.width + 2 * d, 0, 0, -bb.height - 2 * d, "L", x + dx, y - bb.height / 2 - d].join(",")}); } this[1].attr({x: x + r + d + bb.width / 2, y: y}); angle = (360 - angle) % 360; this.rotate(angle, x, y); angle > 90 && angle < 270 && this[1].attr({x: x - r - d - bb.width / 2, y: y, rotation: [180 + angle, x, y]}); return this; }; res.update(); return res; }; Raphael.fn.g.popupit = function (x, y, set, dir, size) { dir = dir == null ? 2 : dir; size = size || 5; x = Math.round(x); y = Math.round(y); var bb = set.getBBox(), w = Math.round(bb.width / 2), h = Math.round(bb.height / 2), dx = [0, w + size * 2, 0, -w - size * 2], dy = [-h * 2 - size * 3, -h - size, 0, -h - size], p = ["M", x - dx[dir], y - dy[dir], "l", -size, (dir == 2) * -size, -mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, -size, -size, "l", 0, -mmax(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, -mmax(h - size, 0), "a", size, size, 0, 0, 1, size, -size, "l", mmax(w - size, 0), 0, size, !dir * -size, size, !dir * size, mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, size, size, "l", 0, mmax(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, mmax(h - size, 0), "a", size, size, 0, 0, 1, -size, size, "l", -mmax(w - size, 0), 0, "z"].join(","), xy = [{x: x, y: y + size * 2 + h}, {x: x - size * 2 - w, y: y}, {x: x, y: y - size * 2 - h}, {x: x + size * 2 + w, y: y}][dir]; set.translate(xy.x - w - bb.x, xy.y - h - bb.y); return this.path(p).attr({fill: "#000", stroke: "none"}).insertBefore(set.node ? set : set[0]); }; Raphael.fn.g.popup = function (x, y, text, dir, size) { dir = dir == null ? 2 : dir > 3 ? 3 : dir; size = size || 5; text = text || "$9.99"; var res = this.set(), d = 3; res.push(this.path().attr({fill: "#000", stroke: "#000"})); res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff", "font-family": "Helvetica, Arial"})); res.update = function (X, Y, withAnimation) { X = X || x; Y = Y || y; var bb = this[1].getBBox(), w = bb.width / 2, h = bb.height / 2, dx = [0, w + size * 2, 0, -w - size * 2], dy = [-h * 2 - size * 3, -h - size, 0, -h - size], p = ["M", X - dx[dir], Y - dy[dir], "l", -size, (dir == 2) * -size, -mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, -size, -size, "l", 0, -mmax(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, -mmax(h - size, 0), "a", size, size, 0, 0, 1, size, -size, "l", mmax(w - size, 0), 0, size, !dir * -size, size, !dir * size, mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, size, size, "l", 0, mmax(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, mmax(h - size, 0), "a", size, size, 0, 0, 1, -size, size, "l", -mmax(w - size, 0), 0, "z"].join(","), xy = [{x: X, y: Y + size * 2 + h}, {x: X - size * 2 - w, y: Y}, {x: X, y: Y - size * 2 - h}, {x: X + size * 2 + w, y: Y}][dir]; xy.path = p; if (withAnimation) { this.animate(xy, 500, ">"); } else { this.attr(xy); } return this; }; return res.update(x, y); }; Raphael.fn.g.flag = function (x, y, text, angle) { angle = angle || 0; text = text || "$9.99"; var res = this.set(), d = 3; res.push(this.path().attr({fill: "#000", stroke: "#000"})); res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff", "font-family": "Helvetica, Arial"})); res.update = function (x, y) { this.rotate(0, x, y); var bb = this[1].getBBox(), h = bb.height / 2; this[0].attr({path: ["M", x, y, "l", h + d, -h - d, bb.width + 2 * d, 0, 0, bb.height + 2 * d, -bb.width - 2 * d, 0, "z"].join(",")}); this[1].attr({x: x + h + d + bb.width / 2, y: y}); angle = 360 - angle; this.rotate(angle, x, y); angle > 90 && angle < 270 && this[1].attr({x: x - r - d - bb.width / 2, y: y, rotation: [180 + angle, x, y]}); return this; }; return res.update(x, y); }; Raphael.fn.g.uslabel = function (x, y, text, bgcolor) { var res = this.set(); res.push(this.rect(x, y, 10, 10).attr({stroke: "none", fill: bgcolor})); res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff"})); res.update = function () { var bb = this[1].getBBox(), r = mmin(bb.width + 10, bb.height + 10) / 2; this[0].attr({x: bb.x - r / 2, y: bb.y - r / 2, width: bb.width + r, height: bb.height + r, r: r}); }; res.update(); return res; }; Raphael.fn.g.label = function (x, y, text) { var res = this.set(); res.push(this.rect(x, y, 10, 10).attr({stroke: "none", fill: "#000"})); res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff"})); res.update = function () { var bb = this[1].getBBox(), r = mmin(bb.width + 10, bb.height + 10) / 2; this[0].attr({x: bb.x - r / 2, y: bb.y - r / 2, width: bb.width + r, height: bb.height + r, r: r}); }; res.update(); return res; }; Raphael.fn.g.labelit = function (set) { var bb = set.getBBox(), r = mmin(20, bb.width + 10, bb.height + 10) / 2; return this.rect(bb.x - r / 2, bb.y - r / 2, bb.width + r, bb.height + r, r).attr({stroke: "none", fill: "#000"}).insertBefore(set.node ? set : set[0]); }; Raphael.fn.g.drop = function (x, y, text, size, angle) { size = size || 30; angle = angle || 0; var res = this.set(); res.push(this.path(["M", x, y, "l", size, 0, "A", size * .4, size * .4, 0, 1, 0, x + size * .7, y - size * .7, "z"]).attr({fill: "#000", stroke: "none", rotation: [22.5 - angle, x, y]})); angle = (angle + 90) * Math.PI / 180; res.push(this.text(x + size * Math.sin(angle), y + size * Math.cos(angle), text).attr(this.g.txtattr).attr({"font-size": size * 12 / 30, fill: "#fff"})); res.drop = res[0]; res.text = res[1]; return res; }; Raphael.fn.g.blob = function (x, y, text, angle, size) { angle = (+angle + 1 ? angle : 45) + 90; size = size || 12; var rad = Math.PI / 180, fontSize = size * 12 / 12; var res = this.set(); res.push(this.path().attr({fill: "#000", stroke: "none"})); res.push(this.text(x + size * Math.sin((angle) * rad), y + size * Math.cos((angle) * rad) - fontSize / 2, text).attr(this.g.txtattr).attr({"font-size": fontSize, fill: "#fff"})); res.update = function (X, Y, withAnimation) { X = X || x; Y = Y || y; var bb = this[1].getBBox(), w = mmax(bb.width + fontSize, size * 25 / 12), h = mmax(bb.height + fontSize, size * 25 / 12), x2 = X + size * Math.sin((angle - 22.5) * rad), y2 = Y + size * Math.cos((angle - 22.5) * rad), x1 = X + size * Math.sin((angle + 22.5) * rad), y1 = Y + size * Math.cos((angle + 22.5) * rad), dx = (x1 - x2) / 2, dy = (y1 - y2) / 2, rx = w / 2, ry = h / 2, k = -Math.sqrt(Math.abs(rx * rx * ry * ry - rx * rx * dy * dy - ry * ry * dx * dx) / (rx * rx * dy * dy + ry * ry * dx * dx)), cx = k * rx * dy / ry + (x1 + x2) / 2, cy = k * -ry * dx / rx + (y1 + y2) / 2; if (withAnimation) { this.animate({x: cx, y: cy, path: ["M", x, y, "L", x1, y1, "A", rx, ry, 0, 1, 1, x2, y2, "z"].join(",")}, 500, ">"); } else { this.attr({x: cx, y: cy, path: ["M", x, y, "L", x1, y1, "A", rx, ry, 0, 1, 1, x2, y2, "z"].join(",")}); } return this; }; res.update(x, y); return res; }; Raphael.fn.g.colorValue = function (value, total, s, b) { return "hsb(" + [mmin((1 - value / total) * .4, 1), s || .75, b || .75] + ")"; }; Raphael.fn.g.snapEnds = function (from, to, steps) { var f = from, t = to; if (f == t) { return {from: f, to: t, power: 0}; } function round(a) { return Math.abs(a - .5) < .25 ? ~~(a) + .5 : Math.round(a); } var d = (t - f) / steps, r = ~~(d), R = r, i = 0; if (r) { while (R) { i--; R = ~~(d * Math.pow(10, i)) / Math.pow(10, i); } i ++; } else { while (!r) { i = i || 1; r = ~~(d * Math.pow(10, i)) / Math.pow(10, i); i++; } i && i--; } t = round(to * Math.pow(10, i)) / Math.pow(10, i); if (t < to) { t = round((to + .5) * Math.pow(10, i)) / Math.pow(10, i); } f = round((from - (i > 0 ? 0 : .5)) * Math.pow(10, i)) / Math.pow(10, i); return {from: f, to: t, power: i}; }; Raphael.fn.g.axis = function (x, y, length, from, to, steps, orientation, labels, type, dashsize, labelangle ) { dashsize = dashsize == null ? 2 : dashsize; labelangle = labelangle == null ? 180 : ((labelangle+360) % 360); type = type || "t"; steps = steps || 10; var path = type == "|" || type == " " ? ["M", x + .5, y, "l", 0, .001] : orientation == 1 || orientation == 3 ? ["M", x + .5, y, "l", 0, -length] : ["M", x, y + .5, "l", length, 0], ends = this.g.snapEnds(from, to, steps), f = ends.from, t = ends.to, i = ends.power, j = 0, text = this.set(); d = (t - f) / steps; var label = f, rnd = i > 0 ? i : 0; dx = length / steps; if (+orientation == 1 || +orientation == 3) { var Y = y, addon = (orientation - 1 ? 1 : -1) * (dashsize + 3 + !!(orientation - 1)); while (Y >= y - length) { type != "-" && type != " " && (path = path.concat(["M", x - (type == "+" || type == "|" ? dashsize : !(orientation - 1) * dashsize * 2), Y + .5, "l", dashsize * 2 + 1, 0])); text.push(this.text(x + addon, Y, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr).attr({"text-anchor": orientation - 1 ? "start" : "end"})); label += d; Y -= dx; } if (Math.round(Y + dx - (y - length))) { type != "-" && type != " " && (path = path.concat(["M", x - (type == "+" || type == "|" ? dashsize : !(orientation - 1) * dashsize * 2), y - length + .5, "l", dashsize * 2 + 1, 0])); text.push(this.text(x + addon, y - length, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr).attr({"text-anchor": orientation - 1 ? "start" : "end"})); } } else { label = f; rnd = (i > 0) * i; addon = (orientation ? -1 : 1) * (dashsize + 9 + !orientation); var X = x, dx = length / steps, txt = 0, prev = 0; while (X <= x + length) { type != "-" && type != " " && (path = path.concat(["M", X + .5, y - (type == "+" ? dashsize : !!orientation * dashsize * 2), "l", 0, dashsize * 2 + 1])); text.push(txt = this.text(X, y + addon, (labels && labels[j++]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr)); var bb = txt.getBBox(); if ((prev >= bb.x - 5) && (labelangle % 180 === 0 )) { text.pop(text.length - 1).remove(); } else { prev = bb.x + bb.width; } if(labelangle != 180) { txt.rotate(labelangle, (labelangle < 180 ? bb.x : bb.x+bb.width), bb.y); txt.translate((labelangle < 180 ? bb.width/2 : -bb.width/2), 0); } label += d; X += dx; } if (Math.round(X - dx - x - length)) { type != "-" && type != " " && (path = path.concat(["M", x + length + .5, y - (type == "+" ? dashsize : !!orientation * dashsize * 2), "l", 0, dashsize * 2 + 1])); text.push(this.text(x + length, y + addon, (labels && labels[j]) || (Math.round(label) == label ? label : +label.toFixed(rnd))).attr(this.g.txtattr)); } } var res = this.path(path); res.text = text; res.all = this.set([res, text]); res.remove = function () { this.text.remove(); this.constructor.prototype.remove.call(this); }; return res; }; Raphael.el.lighter = function (times) { times = times || 2; var fs = [this.attrs.fill, this.attrs.stroke]; this.fs = this.fs || [fs[0], fs[1]]; fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex); fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex); fs[0].b = mmin(fs[0].b * times, 1); fs[0].s = fs[0].s / times; fs[1].b = mmin(fs[1].b * times, 1); fs[1].s = fs[1].s / times; this.attr({fill: "hsb(" + [fs[0].h, fs[0].s, fs[0].b] + ")", stroke: "hsb(" + [fs[1].h, fs[1].s, fs[1].b] + ")"}); }; Raphael.el.darker = function (times) { times = times || 2; var fs = [this.attrs.fill, this.attrs.stroke]; this.fs = this.fs || [fs[0], fs[1]]; fs[0] = Raphael.rgb2hsb(Raphael.getRGB(fs[0]).hex); fs[1] = Raphael.rgb2hsb(Raphael.getRGB(fs[1]).hex); fs[0].s = mmin(fs[0].s * times, 1); fs[0].b = fs[0].b / times; fs[1].s = mmin(fs[1].s * times, 1); fs[1].b = fs[1].b / times; this.attr({fill: "hsb(" + [fs[0].h, fs[0].s, fs[0].b] + ")", stroke: "hsb(" + [fs[1].h, fs[1].s, fs[1].b] + ")"}); }; Raphael.el.original = function () { if (this.fs) { this.attr({fill: this.fs[0], stroke: this.fs[1]}); delete this.fs; } }; })(); /*! * g.Raphael 0.4.1 - Charting library, based on Raphaël * * improved by frostbytten https://github.com/open-agroclimate/g.raphael * * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com) * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. */ Raphael.fn.g.barchart = function (x, y, width, height, values, opts) { opts = opts || {}; var type = {round: "round", sharp: "sharp", soft: "soft"}[opts.type] || "square", gutter = parseFloat(opts.gutter || "20%"), centeraxis = (opts.centeraxis === undefined) ? false : opts.centeraxis, chart = this.set(), bars = this.set(), covers = this.set(), covers2 = this.set(), total = Math.max.apply(Math, values), stacktotal = [], mins = [], negoffset = Math.abs(opts.from || 0), paper = this, multi = 0, colors = opts.colors || this.g.colors, len = values.length, origvalues = values.slice(0), hasneg = Math.min.apply(Math,origvalues) < 0 ? true : false, gheight = height; if (this.raphael.is(values[0], "array")) { total = []; multi = len; len = 0; values = []; for (var i = origvalues.length; i--;) { values[i] = []; l = origvalues[i].length; for(var j = 0; j < l; j++) { values[i].push(Math.abs(origvalues[i][j])); } } for (var i = values.length; i--;) { bars.push(this.set()); total.push(Math.max.apply(Math, values[i])); mins.push(Math.min.apply(Math, origvalues[i])); len = Math.max(len, values[i].length); } if (opts.stacked) { for (var i = len; i--;) { var tot = 0; for (var j = values.length; j--;) { tot +=+ (values[j][i]) || 0; } stacktotal.push(tot); } } for (var i = values.length; i--;) { if (values[i].length < len) { for (var j = len; j--;) { values[i].push(0); } } } hasneg = Math.min.apply(Math, mins) < 0 ? true : false; total = Math.max.apply(Math, opts.stacked ? stacktotal : total); negoffset = (negoffset === undefined ? (hasneg ? Math.abs(Math.min.apply(Math, mins)) : 0) : negoffset); } else { if (hasneg) { negoffset = (negoffset === undefined ? Math.abs(Math.min.apply(values)) : negoffset); values = []; var l = origvalues.length; for(var i = 0; i < l ; i++ ) { values.push(Math.abs(origvalues[i])); } total = Math.max.apply(Math, values); } } total = (opts.to) || total; var barwidth = width / (len * (100 + gutter) + gutter) * 100, barhgutter = barwidth * gutter / 100, barvgutter = opts.vgutter == null ? 20 : opts.vgutter, stack = [], X = x + barhgutter, Y; gheight = ((hasneg && centeraxis) ? ((gheight+barvgutter*2)/2)+1 : gheight); Y = ((gheight - 2 * barvgutter) / total); if (!opts.stretch) { barhgutter = Math.round(barhgutter); barwidth = Math.floor(barwidth); } !opts.stacked && (barwidth /= multi || 1); for (var i = 0; i < len; i++) { stack = []; for (var j = 0; j < (multi || 1); j++) { var h = Math.round((multi ? values[j][i] : values[i]) * Y), top = y + gheight - barvgutter - Math.abs(h), bar = this.g.finger(Math.round(X + barwidth / 2), top+Math.abs(h), barwidth, Math.abs(h), true, type); if(hasneg && ((multi ? origvalues[j][i] : origvalues[i]) < 0)) { bar.rotate(180); bar.translate(0, bar.getBBox().height); } if(negoffset !== 0 && !centeraxis) { if((multi ? origvalues[j][i] : origvalues[i]) !== 0) bar.translate(0, -(negoffset*Y)); } bar.attr({stroke: "none", fill: colors[multi ? j : i]}); if (multi) { bars[j].push(bar); } else { bars.push(bar); } bar.y = multi ? (origvalues[j][i] < 0 ? gheight : top) : (origvalues[i] < 0 ? gheight : top); bar.x = Math.round(X + barwidth / 2); bar.w = barwidth; bar.h = h; bar.value = multi ? origvalues[j][i] : hasneg ? origvalues[i] : values[i]; if (!opts.stacked) { X += barwidth; } else { stack.push(bar); } } if (opts.stacked) { var cvr; covers2.push(cvr = this.rect(stack[0].x - stack[0].w / 2, y, barwidth, height).attr(this.g.shim)); cvr.bars = this.set(); var size = 0; for (var s = stack.length; s--;) { stack[s].toFront(); } for (var s = 0, ss = stack.length; s < ss; s++) { var bar = stack[s], cover, h = (size + bar.value) * Y, path = this.g.finger(bar.x, y + height - barvgutter - !!size * .5, barwidth, h, true, type, 1); cvr.bars.push(bar); size && bar.attr({path: path}); bar.h = h; bar.y = y + height - barvgutter - !!size * .5 - h; covers.push(cover = this.rect(bar.x - bar.w / 2, bar.y, barwidth, bar.value * Y).attr(this.g.shim)); cover.bar = bar; cover.value = bar.value; size += bar.value; } X += barwidth; } X += barhgutter; } covers2.toFront(); X = x + barhgutter; if (!opts.stacked) { for (var i = 0; i < len; i++) { for (var j = 0; j < (multi || 1); j++) { var cover; covers.push(cover = this.rect(Math.round(X), y + barvgutter, barwidth, height - barvgutter).attr(this.g.shim)); cover.bar = multi ? bars[j][i] : bars[i]; cover.value = cover.bar.value; cover.index = i; X += barwidth; } X += barhgutter; } } chart.label = function (labels, isBottom, labelangle) { labels = labels || []; labelangle = labelangle == null ? 180 : ((labelangle + 360) % 360); this.labels = paper.set(); var L, l = -Infinity, ldown = false; if (opts.stacked) { for (var i = 0; i < len; i++) { var tot = 0; for (var j = 0; j < (multi || 1); j++) { tot += multi ? values[j][i] : values[i]; if (j == multi - 1) { var label = paper.g.labelise(labels[i], tot, total); L = paper.g.text(bars[i][j].x, y + height - barvgutter / 2, label).insertBefore(covers[i * (multi || 1) + j]); var bb = L.getBBox(); if ((bb.x - 7 < l) && (labelangle % 180 === 0 )) { L.remove(); } else { if(labelangle != 180) { txt.rotate(labelangle, (labelangle < 180 ? bb.x : bb.x+bb.width), bb.y); txt.translate((labelangle < 180 ? bb.width/2 : -bb.width/2), 0); } this.labels.push(L); l = bb.x + bb.width; } } } } } else { for (var i = 0; i < len; i++) { for (var j = 0; j < (multi || 1); j++) { var label = paper.g.labelise(multi ? labels[j] && labels[j][i] : labels[i], multi ? origvalues[j][i] : origvalues[i], total); L = paper.g.text(bars[j][i].x, isBottom ? y + height - barvgutter / 2 : bars[j][i].y - 10, label).insertBefore(covers[i * (multi || 1) + j]); var bb = L.getBBox(); if ((bb.x - 7 < l) && (labelangle % 180 === 0 )) { L.remove(); } else { if(labelangle != 180) { L.rotate(labelangle, (labelangle < 180 ? bb.x : bb.x+bb.width), bb.y); L.translate((labelangle < 180 ? bb.width/2 : -bb.width/2), 0); } this.labels.push(L); l = bb.x + bb.width; } } } } return this; }; chart.hover = function (fin, fout) { covers2.hide(); covers.show(); covers.mouseover(fin).mouseout(fout); return this; }; chart.hoverColumn = function (fin, fout) { covers.hide(); covers2.show(); fout = fout || function () {}; covers2.mouseover(fin).mouseout(fout); return this; }; chart.click = function (f) { covers2.hide(); covers.show(); covers.click(f); return this; }; chart.each = function (f) { if (!Raphael.is(f, "function")) { return this; } for (var i = covers.length; i--;) { f.call(covers[i]); } return this; }; chart.eachColumn = function (f) { if (!Raphael.is(f, "function")) { return this; } for (var i = covers2.length; i--;) { f.call(covers2[i]); } return this; }; chart.clickColumn = function (f) { covers.hide(); covers2.show(); covers2.click(f); return this; }; chart.push(bars, covers, covers2); chart.bars = bars; chart.covers = covers; return chart; }; Raphael.fn.g.hbarchart = function (x, y, width, height, values, opts) { opts = opts || {}; var type = {round: "round", sharp: "sharp", soft: "soft"}[opts.type] || "square", gutter = parseFloat(opts.gutter || "20%"), chart = this.set(), bars = this.set(), covers = this.set(), covers2 = this.set(), total = Math.max.apply(Math, values), stacktotal = [], paper = this, multi = 0, colors = opts.colors || this.g.colors, len = values.length; if (this.raphael.is(values[0], "array")) { total = []; multi = len; len = 0; for (var i = values.length; i--;) { bars.push(this.set()); total.push(Math.max.apply(Math, values[i])); len = Math.max(len, values[i].length); } if (opts.stacked) { for (var i = len; i--;) { var tot = 0; for (var j = values.length; j--;) { tot +=+ values[j][i] || 0; } stacktotal.push(tot); } } for (var i = values.length; i--;) { if (values[i].length < len) { for (var j = len; j--;) { values[i].push(0); } } } total = Math.max.apply(Math, opts.stacked ? stacktotal : total); } total = (opts.to) || total; var barheight = Math.floor(height / (len * (100 + gutter) + gutter) * 100), bargutter = Math.floor(barheight * gutter / 100), stack = [], Y = y + bargutter, X = (width - 1) / total; !opts.stacked && (barheight /= multi || 1); for (var i = 0; i < len; i++) { stack = []; for (var j = 0; j < (multi || 1); j++) { var val = multi ? values[j][i] : values[i], bar = this.g.finger(x, Y + barheight / 2, Math.round(val * X), barheight - 1, false, type).attr({stroke: "none", fill: colors[multi ? j : i]}); if (multi) { bars[j].push(bar); } else { bars.push(bar); } bar.x = x + Math.round(val * X); bar.y = Y + barheight / 2; bar.w = Math.round(val * X); bar.h = barheight; bar.value = +val; if (!opts.stacked) { Y += barheight; } else { stack.push(bar); } } if (opts.stacked) { var cvr = this.rect(x, stack[0].y - stack[0].h / 2, width, barheight).attr(this.g.shim); covers2.push(cvr); cvr.bars = this.set(); var size = 0; for (var s = stack.length; s--;) { stack[s].toFront(); } for (var s = 0, ss = stack.length; s < ss; s++) { var bar = stack[s], cover, val = Math.round((size + bar.value) * X), path = this.g.finger(x, bar.y, val, barheight - 1, false, type, 1); cvr.bars.push(bar); size && bar.attr({path: path}); bar.w = val; bar.x = x + val; covers.push(cover = this.rect(x + size * X, bar.y - bar.h / 2, bar.value * X, barheight).attr(this.g.shim)); cover.bar = bar; size += bar.value; } Y += barheight; } Y += bargutter; } covers2.toFront(); Y = y + bargutter; if (!opts.stacked) { for (var i = 0; i < len; i++) { for (var j = 0; j < (multi || 1); j++) { var cover = this.rect(x, Y, width, barheight).attr(this.g.shim); covers.push(cover); cover.bar = multi ? bars[j][i] : bars[i]; cover.value = cover.bar.value; Y += barheight; } Y += bargutter; } } chart.label = function (labels, isRight) { labels = labels || []; this.labels = paper.set(); for (var i = 0; i < len; i++) { for (var j = 0; j < multi; j++) { var label = paper.g.labelise(multi ? labels[j] && labels[j][i] : labels[i], multi ? values[j][i] : values[i], total); var X = isRight ? bars[i * (multi || 1) + j].x - barheight / 2 + 3 : x + 5, A = isRight ? "end" : "start", L; this.labels.push(L = paper.g.text(X, bars[i * (multi || 1) + j].y, label).attr({"text-anchor": A}).insertBefore(covers[0])); if (L.getBBox().x < x + 5) { L.attr({x: x + 5, "text-anchor": "start"}); } else { bars[i * (multi || 1) + j].label = L; } } } return this; }; chart.hover = function (fin, fout) { covers2.hide(); covers.show(); fout = fout || function () {}; covers.mouseover(fin).mouseout(fout); return this; }; chart.hoverColumn = function (fin, fout) { covers.hide(); covers2.show(); fout = fout || function () {}; covers2.mouseover(fin).mouseout(fout); return this; }; chart.each = function (f) { if (!Raphael.is(f, "function")) { return this; } for (var i = covers.length; i--;) { f.call(covers[i]); } return this; }; chart.eachColumn = function (f) { if (!Raphael.is(f, "function")) { return this; } for (var i = covers2.length; i--;) { f.call(covers2[i]); } return this; }; chart.click = function (f) { covers2.hide(); covers.show(); covers.click(f); return this; }; chart.clickColumn = function (f) { covers.hide(); covers2.show(); covers2.click(f); return this; }; chart.push(bars, covers, covers2); chart.bars = bars; chart.covers = covers; return chart; };