diff options
Diffstat (limited to 'linegraph-test/lc.js')
| -rw-r--r-- | linegraph-test/lc.js | 856 |
1 files changed, 0 insertions, 856 deletions
diff --git a/linegraph-test/lc.js b/linegraph-test/lc.js deleted file mode 100644 index 658562d..0000000 --- a/linegraph-test/lc.js +++ /dev/null @@ -1,856 +0,0 @@ -/* - * Raphael Line Chart 1.2 - Raphael Line Charts plugin - * - * Copyright (c) 2011 Sagie Maoz (http://sagie.maoz.info) - * Dual-licensed under the GPL (http://www.opensource.org/licenses/gpl-3.0) - * and the MIT (http://www.opensource.org/licenses/mit-license) licenses. - */ -(function() { - -// modified version of Raphael.fn.drawGrid() from the Raphael Analytics example -Raphael.fn.drawGrid = function(x, y, width, height, x_step, x_size, y_count, y_size) { - var path, - rowHeight, - columnWidth; - - // frame border - path = ["M", Math.round(x) + 0.5, Math.round(y) + 0.5, - "L", Math.round(x + width) + 0.5, Math.round(y) + 0.5, - Math.round(x + width) + 0.5, Math.round(y + height) + 0.5, - Math.round(x) + 0.5, Math.round(y + height) + 0.5, - Math.round(x) + 0.5, Math.round(y) + 0.5]; - - // horizontal lines - rowHeight = Math.ceil(height / y_count); - for (var i = 0; i < y_count; i++) { - path = path.concat(["M", Math.round(x) + 0.5, Math.round(y + i * rowHeight) + 0.5, - "H", Math.round(x + width) + 0.5]); - } - - // vertical lines - if (!x_step) { - x_step = 1; - x_size = 10; - } - columnWidth = Math.ceil(width / x_size); - for (i = 0; i < x_size; i+= x_step) { - path = path.concat(["M", Math.round(x + i * (columnWidth + 1.1)) + 0.5, Math.round(y) + 0.5, - "V", Math.round(y + height) + 0.5]); - } - - return this.path(path.join(",")); -}; - -Raphael.fn.popup = function(X, Y, set, position, ret) { - var pos = String(position || "top-middle").split("-"), - pos_x = pos[1] || "middle", - tokenRegex = /\{([^\}]+)\}/g, - objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, - - replacer = function(all, key, obj) { - var res = obj; - key.replace(objNotationRegex, - function(all, name, quote, quotedName, isFunc) { - name = name || quotedName; - if (res) { - if (name in res) { - res = res[name]; - } - return (typeof res == "function") && isFunc && (res = res()); - } - }); - res = (res === null || res == obj ? all: res) + ""; - return res; - }, - - fill = function(str, obj) { - return String(str).replace(tokenRegex, - function(all, key) { - return replacer(all, key, obj); - }); - }, - - r = 5, - bb = set.getBBox(), - w = Math.round(bb.width), - h = Math.round(bb.height), - x = Math.round(bb.x) - r, - y = Math.round(bb.y) - r, - gap = Math.min(h / 2, w / 2, 10), - shapes = { - top: "M{x},{y}h{w4},{w4},{w4},{w4}a{r},{r},0,0,1,{r},{r}v{h4},{h4},{h4},{h4}a{r},{r},0,0,1,-{r},{r}l-{right},0-{gap},{gap}-{gap}-{gap}-{left},0a{r},{r},0,0,1-{r}-{r}v-{h4}-{h4}-{h4}-{h4}a{r},{r},0,0,1,{r}-{r}z", - bottom: "M{x},{y}l{left},0,{gap}-{gap},{gap},{gap},{right},0a{r},{r},0,0,1,{r},{r}v{h4},{h4},{h4},{h4}a{r},{r},0,0,1,-{r},{r}h-{w4}-{w4}-{w4}-{w4}a{r},{r},0,0,1-{r}-{r}v-{h4}-{h4}-{h4}-{h4}a{r},{r},0,0,1,{r}-{r}z", - right: "M{x},{y}h{w4},{w4},{w4},{w4}a{r},{r},0,0,1,{r},{r}v{h4},{h4},{h4},{h4}a{r},{r},0,0,1,-{r},{r}h-{w4}-{w4}-{w4}-{w4}a{r},{r},0,0,1-{r}-{r}l0-{bottom}-{gap}-{gap},{gap}-{gap},0-{top}a{r},{r},0,0,1,{r}-{r}z", - left: "M{x},{y}h{w4},{w4},{w4},{w4}a{r},{r},0,0,1,{r},{r}l0,{top},{gap},{gap}-{gap},{gap},0,{bottom}a{r},{r},0,0,1,-{r},{r}h-{w4}-{w4}-{w4}-{w4}a{r},{r},0,0,1-{r}-{r}v-{h4}-{h4}-{h4}-{h4}a{r},{r},0,0,1,{r}-{r}z" - }, - offset = { - hx0: X - (x + r + w - gap * 2), - hx1: X - (x + r + w / 2 - gap), - hx2: X - (x + r + gap), - vhy: Y - (y + r + h + r + gap), - "^hy": Y - (y - gap) - }, - mask = [{ - x: x + r, - y: y, - w: w, - w4: w / 4, - h4: h / 4, - right: 0, - left: w - gap * 2, - bottom: 0, - top: h - gap * 2, - r: r, - h: h, - gap: gap - }, - { - x: x + r, - y: y, - w: w, - w4: w / 4, - h4: h / 4, - left: w / 2 - gap, - right: w / 2 - gap, - top: h / 2 - gap, - bottom: h / 2 - gap, - r: r, - h: h, - gap: gap - }, - { - x: x + r, - y: y, - w: w, - w4: w / 4, - h4: h / 4, - left: 0, - right: w - gap * 2, - top: 0, - bottom: h - gap * 2, - r: r, - h: h, - gap: gap - }][pos_x == "middle" ? 1: (pos_x == "top" || pos_x == "left") * 2], - dx = 0, - dy = 0, - out = this.path(fill(shapes[pos[0]], mask)).insertBefore(set); - - switch (pos[0]) { - case "top": - dx = X - (x + r + mask.left + gap); - dy = Y - (y + r + h + r + gap); - break; - case "bottom": - dx = X - (x + r + mask.left + gap); - dy = Y - (y - gap); - break; - case "left": - dx = X - (x + r + w + r + gap); - dy = Y - (y + r + mask.top + gap); - break; - case "right": - dx = X - (x - gap); - dy = Y - (y + r + mask.top + gap); - break; - } - out.translate(dx, dy); - if (ret) { - ret = out.attr("path"); - out.remove(); - return { - path: ret, - dx: dx, - dy: dy - }; - } - set.translate(dx, dy); - return out; -}; - -Raphael.fn.lineChart = function(method) { - - // public methods - var methods = { - - init: function(options) { - - this.lineChart.settings = helpers.extend(true, {}, this.lineChart.defaults, options); - this.customAttributes.lineChart = {}; - - //TODO either data or data_holder is a must - - // let's go - var element = this, - o = this.customAttributes.lineChart, - settings = this.lineChart.settings, - width = settings.width, - height = settings.height, - - table = helpers.getTable(element, o, settings.data, settings.data_holder), - size = table.labels.length, - - max = Math.max.apply(Math, table.data), - - YLabelWidth = element.text(-50, -50, max).attr(settings.text.axis_labels).getBBox().width, - gutter = { - top: settings.gutter.top, - right: settings.gutter.right, - bottom: settings.gutter.bottom, - left: settings.gutter.left + YLabelWidth - }, - blanket = element.set(), - - X = (width - gutter.left) / size, - Y, p, bgpp, x, y; - - // fix max. value - if (max > settings.y_labels_count*10) { - p = 25*settings.y_labels_count; - max = Math.ceil(max/p)*p; - } - Y = max ? ((height - gutter.bottom - gutter.top) / max) : 0; - - o.gutter = gutter; - o.labelGutter = settings.gutter.left; - - o.size = size; - o.dots = []; - o.rects = []; - o.info = []; - //TODO allow customizing - o.path = element.path().attr({ - stroke: settings.colors.master, - "stroke-width": 4, - "stroke-linejoin": "round" - }); - // chart area - //TODO allow customizing - if (settings.show_area) { - o.bgp = element.path().attr({ - stroke: "none", - opacity: 0.3, - fill: settings.colors.master - }); - } - else { - o.bgp = element.path().attr({ - stroke: "none", - opacity: 0, - fill: settings.colors.master - }).hide(); - } - - // draw background grid - if (!o.gridDrawn && settings.no_grid === false) { - var grid = element.drawGrid(gutter.left + X * 0.5 + 0.5, - gutter.top + 0.5, - width - gutter.left - X, - height - gutter.top - gutter.bottom, - settings.x_labels_step, - size, - settings.y_labels_count, - max) - .attr({ stroke: "#eaeaea" }); - - grid.toBack(); - } - o.gridDrawn = true; - - // draw x axis labels - o.XLabels = []; - if (settings.x_labels_step) { - helpers.drawXLabels(element, table.labels); - } - - // draw y axis labels - o.YLabels = []; - if (settings.y_labels_count) { - helpers.drawYLabels(element, max); - } - - // prepare popup - o.label = element.set(); - //TODO ?? - o.label.push(element.text(60, 12, "24 hits").attr(settings.text.popup_line1)); - o.label.push(element.text(60, 27, "22 September 2008").attr(settings.text.popup_line2).attr({ - fill: settings.colors.master - })); - o.label.hide(); - - //TODO allow customizing - o.frame = element.popup(100, 100, o.label, "right").attr({ - fill: "#ffffff", - stroke: "#666", - "stroke-width": 2, - "fill-opacity": 0.8 - }).hide(); - - for (var i = 0, ii = size; i < ii; i++) { - var dot, rect; - - // calculate current x, y - y = Math.round(height - gutter.bottom - Y * table.data[i]) || 0; - x = Math.round(gutter.left + X * (i + 0.5)); - - if (!i) { - p = ["M", x, y, "C", x, y]; - bgpp = ["M", gutter.left + X * 0.5, height - gutter.bottom, "L", x, y, "C", x, y]; - } - else if (i < ii - 1) { - var Y0 = Math.round(height - gutter.bottom - Y * table.data[i - 1]), - X0 = Math.round(gutter.left + X * (i - 0.5)), - Y2 = Math.round(height - gutter.bottom - Y * table.data[i + 1]), - X2 = Math.round(gutter.left + X * (i + 1.5)), - a = helpers.getAnchors(X0, Y0, x, y, X2, Y2); - p = p.concat([a.x1, a.y1, x, y, a.x2, a.y2]); - bgpp = bgpp.concat([a.x1, a.y1, x, y, a.x2, a.y2]); - } - - //TODO allow customizing all of these - dot = element.circle(x, y, 4).attr({ - fill: "#ffffff", - stroke: settings.colors.master, - "stroke-width": 2 - }); - if (y === 0) { - dot.attr({ - opacity: 0 - }); - } - - o.dots.push(dot); - - if (settings.mouse_coords == 'circle') { - blanket.push(element.circle(x, y, 14).attr({ - stroke: "none", - fill: "#fff", - opacity: 0 - })); - } else if (settings.mouse_coords == 'rect') { - blanket.push(element.rect(gutter.left + X * i, 0, X, height - gutter.bottom).attr({ - stroke: "none", - fill: "#fff", - opacity: 0 - })); - } - rect = blanket[blanket.length - 1]; - o.rects.push(rect); - - o.info.push({ - x: x, - y: y, - data: table.data[i], - label: table.labels[i], - line1: table.lines1[i], - line2: table.lines2[i] - }); - helpers.bindHoverEvent(this, i, dot, rect, o.frame, o.label); - } - - p = p.concat([x, y, x, y]); - bgpp = bgpp.concat([x, y, x, y, "L", x, height - gutter.bottom, "z"]); - o.path.attr({ - path: p - }); - o.bgp.attr({ - path: bgpp - }); - o.frame.toFront(); - o.label[0].toFront(); - o.label[1].toFront(); - blanket.toFront(); - }, - - setDataIndex: function(index) { - var o = this.customAttributes.lineChart; - - if (index < o.dataArray.data.length) { - var one = { - labels: o.dataArray.labels, - data: o.dataArray.data[index], - lines1: o.dataArray.lines1[index], - lines2: o.dataArray.lines2[index] - }; - return this.lineChart('setData', one); - } - else - { - return helpers.error('Data index out of range.'); - } - }, - - setDataHolder: function(holder) { - var table = helpers.loadTableData(this, holder); - if (table) { - return this.lineChart('setData', table); - } - else { - return helpers.error('No data holder element supplied.'); - } - }, - - // Caution: this would only work for the same number of records - setData: function(table) { - var element = this, - settings = this.lineChart.settings, - o = this.customAttributes.lineChart, - width = settings.width, - height = settings.height, - gutter = o.gutter, - - X = (width - gutter.left) / table.labels.length, - max = Math.max.apply(Math, table.data), - Y, p, bgpp; - - table = helpers.getTable(element, o, table); - - if (table.labels.length != o.size) { - return helpers.error('New data source has to be of same size'); - } - - // fix max. value - if (max > settings.y_labels_count*10) { - p = 25*settings.y_labels_count; - max = Math.ceil(max/p)*p; - } - Y = max ? ((height - gutter.bottom - gutter.top) / max) : 0; - - for (var i = 0, ii = table.labels.length; i < ii; i++) { - var dot = o.dots[i], - rect = o.rects[i]; - - // calculate current x, y - y = Math.round(height - gutter.bottom - Y * table.data[i]) || 0; - x = Math.round(gutter.left + X * (i + 0.5)); - - if (!i) { - p = ["M", x, y, "C", x, y]; - bgpp = ["M", gutter.left + X * 0.5, height - gutter.bottom, "L", x, y, "C", x, y]; - } - else if (i < ii - 1) { - var Y0 = Math.round(height - gutter.bottom - Y * table.data[i - 1]), - X0 = Math.round(gutter.left + X * (i - 0.5)), - Y2 = Math.round(height - gutter.bottom - Y * table.data[i + 1]), - X2 = Math.round(gutter.left + X * (i + 1.5)), - a = helpers.getAnchors(X0, Y0, x, y, X2, Y2); - - p = p.concat([a.x1, a.y1, x, y, a.x2, a.y2]); - bgpp = bgpp.concat([a.x1, a.y1, x, y, a.x2, a.y2]); - } - - dot.animate({cy: y}, - settings.animation.speed, - settings.animation.easing); - - // new popup data - o.info[i] = { - x: x, - y: y, - data: table.data[i], - label: table.labels[i], - line1: table.lines1[i], - line2: table.lines2[i] - }; - } - - // animate paths - p = p.concat([x, y, x, y]); - bgpp = bgpp.concat([x, y, x, y, "L", x, height - gutter.bottom, "z"]); - o.path.animate({path: p}, - settings.animation.speed, - settings.animation.easing); - o.bgp.animate({path: bgpp}, - settings.animation.speed, - settings.animation.easing); - - // update x axis labels - if (settings.x_labels_step) { - helpers.drawXLabels(element, table.labels); - } - - // draw y axis labels - if (settings.y_labels_count) { - helpers.drawYLabels(element, max); - } - } - - }; - - // private methods - var helpers = { - extend: function () { // copied from jQuery source - // copy reference to target object - var target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false, - options, name, src, copy; - - // Handle a deep copy situation - if (typeof target === "boolean") { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if (typeof target !== "object" && typeof target !== "function") { - target = {}; - } - - // extend myself if only one argument is passed - if (length === i) { - target = this; - --i; - } - - for (; i < length; i++) { - // Only deal with non-null/undefined values - if ((options = arguments[i]) !== null) { - // Extend the base object - for (name in options) { - if (options.hasOwnProperty(name)) - { - src = target[name]; - copy = options[name]; - - // Prevent never-ending loop - if (target === copy) { - continue; - } - - // Recurse if we're merging object literal values or arrays - if (deep && copy && (copy.constructor == Object || copy.constructor == Array)) { - var clone = src && (src.constructor == Object || src.constructor == Array) ? src : copy.constructor == Array ? [] : {}; - - // Never move original objects, clone them - target[name] = helpers.extend(deep, clone, copy); - - // Don't bring in undefined values - } else if (copy !== undefined) { - target[name] = copy; - } - } - } - } - } - - // Return the modified object - return target; - }, - - getAnchors: function(p1x, p1y, p2x, p2y, p3x, p3y) { - var l1 = (p2x - p1x) / 2, - l2 = (p3x - p2x) / 2, - a = Math.atan((p2x - p1x) / Math.abs(p2y - p1y)), - b = Math.atan((p3x - p2x) / Math.abs(p2y - p3y)), - dx1 = dy1 = dx2 = dy2 = 0, - alpha; - - a = p1y < p2y ? Math.PI - a: a; - b = p3y < p2y ? Math.PI - b: b; - alpha = Math.PI / 2 - ((a + b) % (Math.PI * 2)) / 2; - dx1 = l1 * Math.sin(alpha + a); - dx2 = l2 * Math.sin(alpha + b); - if (p1y != p2y) { - dy1 = l1 * Math.cos(alpha + a); - } - if (p2y != p3y) { - dy2 = l2 * Math.cos(alpha + b); - } - - return { - x1: p2x - dx1, - y1: p2y + dy1, - x2: p2x + dx2, - y2: p2y + dy2 - }; - }, - - getTable: function(elm, o, obj, table_elm) { - if (obj) { - // handle multiple data rows - if (obj.data[0].constructor == Array) { - o.dataArray = obj; - var one = {}; - one.labels = obj.labels; - one.data = obj.data[0]; - one.lines1 = obj.lines1[0]; - one.lines2 = obj.lines2[0]; - return one; - } - else { - return obj; - } - } - else { - return helpers.loadTableData(elm, table_elm); - } - }, - - loadTableData: function(elm, table_elm) { - var settings = elm.lineChart.settings, - table = (table_elm && table_elm.constructor == String) ? document.getElementById(table_elm) : table_elm, - res = { - labels: [], - data: [], - lines1: [], - lines2: [] - }, - tds = {}, - curr, td, i, j; - - if (table) { - // find elements to collect - for (i=0; i < table.childNodes.length; i++, curr = null, td = 'td') { - if (table.childNodes[i].tagName == 'TFOOT') { - curr = 'labels'; - td = 'th'; - } - else if (table.childNodes[i].tagName == 'TBODY') { - if (table.childNodes[i].className == settings.table_classes.data) { - curr = 'data'; - } - else if (table.childNodes[i].className == settings.table_classes.line1) { - curr = 'lines1'; - } - else if (table.childNodes[i].className == settings.table_classes.line2) { - curr = 'lines2'; - } - } - - if (curr) { - tds[curr] = table.childNodes[i].getElementsByTagName(td); - } - } - - // populate res - if (tds.labels && tds.data && tds.lines1 && tds.lines2) { - for (j=0; j < tds.labels.length; j++) { - res.labels.push(tds.labels[j].innerHTML); - } - for (j=0; j < tds.data.length; j++) { - res.data.push(tds.data[j].innerHTML); - } - for (j=0; j < tds.lines1.length; j++) { - res.lines1.push(tds.lines1[j].innerHTML); - } - for (j=0; j < tds.lines2.length; j++) { - res.lines2.push(tds.lines2[j].innerHTML); - } - } - return res; - } else { - return false; - } - }, - - bindHoverEvent: function(elm, i, dot, rect, frame, label) { - var settings = elm.lineChart.settings, - o = elm.customAttributes.lineChart, - f_in = function() { - var side = "right", - info = o.info[i], - x = info.x, - y = info.y; - - window.clearTimeout(elm.leave_timer); - if (x + frame.getBBox().width > settings.width) { - side = "left"; - } - var ppp = elm.popup(x, y, label, side, 1); - if (settings.mouse_coords == 'circle') { - frame.attr({ - path: ppp.path, - width: '200px' - }).show(); - label[0].attr({ - text: info.line1, - fill: settings.colors.line1, - translation: [ppp.dx, ppp.dy] - }).show(); - label[1].attr({ - text: info.line2, - fill: settings.colors.line2, - translation: [ppp.dx, ppp.dy] - }).show(); - } else if (settings.mouse_coords == 'rect') { - frame.show().stop().animate({ - path: ppp.path - }, - 200 * o.is_label_visible); - label[0].attr({ - text: info.line1 - }).show().stop().animateWith(frame, { - translation: [ppp.dx, ppp.dy] - }, - 200 * o.is_label_visible); - label[1].attr({ - text: info.line2 - }).show().stop().animateWith(frame, { - translation: [ppp.dx, ppp.dy] - }, - 200 * o.is_label_visible); - } - frame.toFront(); - label[0].toFront(); - label[1].toFront(); - this.toFront(); - dot.attr("r", 6); - o.is_label_visible = true; - }, - f_out = function() { - dot.attr("r", 4); - - elm.leave_timer = window.setTimeout(function() { - frame.hide(); - label[0].hide(); - label[1].hide(); - o.is_label_visible = false; - }, - 1); - }; - - rect.hover(f_in, f_out); - }, - - drawXLabels: function(elm, labels) { - var settings = elm.lineChart.settings, - o = elm.customAttributes.lineChart, - x = (settings.width - o.gutter.left) / o.size, - y = settings.height - o.gutter.bottom + 18, - step = settings.x_labels_step, - style = settings.text.axis_labels, - i; - - // reset old labels - if (o.XLabels.length) { - for (i = 0; i < o.XLabels.length; i++) { - o.XLabels[i].remove(); - } - } - - o.XLabels = []; - for (i = 0; i < o.size; i++) { - var label_x = Math.round(o.gutter.left + x * (i + 0.5)); - - if (i % step === 0) { - var l = elm.text(label_x, y, labels[i]) - .attr(style).toBack(); - o.XLabels.push(l); - } - } - }, - - drawYLabels: function(elm, max) { - var settings = elm.lineChart.settings, - o = elm.customAttributes.lineChart, - x = o.labelGutter + 20, - y = o.gutter.bottom, - top = o.gutter.top, - height = settings.height, - count = settings.y_labels_count, - step = Math.round(max / count), - labelHeight = (height - top - y) / count; - - // reset old labels - if (o.YLabels.length) { - for (var i = 0; i < o.YLabels.length; i++) { - o.YLabels[i].remove(); - } - } - - - o.YLabels = []; - for (var j = 0; j <= count; j++) { - var txt = (j * (max/count)), - l; - - l = elm - .text(x, height - y - (j*labelHeight), - settings.y_labels_format(txt, max, count)) - .attr(settings.text.axis_labels); - o.YLabels.push(l); - - } - }, - - error: function(message) { - if (console && console.error) { - console.error('lineChart Error: ' + message); - } - return false; - } - }; - - // go go go! - if (methods[method]) { - return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } else if (typeof method === 'object' || !method) { - return methods.init.apply(this, arguments); - } else { - return helpers.error('Method "' + method + '" not found.'); - } -}; - -Raphael.fn.lineChart.defaults = { - data_holder: null, // table element holding the data to display - data: null, // alternatively, supply a data object - width: 500, // chart width - height: 250, // chart height - gutter: { // gutter dimensions - top: 20, - right: 0, - bottom: 50, - left: 30 - }, - show_area: false, // whether to fill the area below the line - mouse_coords: 'rect', // way to capture mouse events - no_grid: false, // whether to display background grid - x_labels_step: false, // X axis: either false or a step integer - y_labels_count: false, // Y axis: either false or a labels count - y_labels_format: function(txt, max, count) { // function to handle display of Y labels - if (max > count) { - txt = Math.floor(txt) + ''; - } - else { - txt = txt + ''; - } - txt = txt.replace(/\.(\d{3})\d*/, '.$1'); - txt = txt.replace(/(\d{1,3})(?=(?:\d{3})+$)/g,"$1,"); - return txt; - }, - animation: { // animation (on data source change) settings - speed: 600, - easing: "backOut" - }, - colors: { // color settings - master: '#01A8F0', - line1: '#000000', - line2: '#01A8F0' - }, - text: { // text style settings - axis_labels: { - font: '10px Helvetica, Arial', - fill: "#000000" - }, - popup_line1: { - font: 'bold 11px Helvetica, Arial', - fill: "#000000" - }, - popup_line2: { - font: 'bold 10px Helvetica, Arial', - fill: "#000000" - } - }, - table_classes: { - data: 'data', - line1: 'line1', - line2: 'line2' - } -}; - -})(); - |
