You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stratos.apache.org by im...@apache.org on 2015/09/28 15:14:49 UTC

[17/69] [abbrv] stratos git commit: Removed tenantId from queries and refactore jaggery files

http://git-wip-us.apache.org/repos/asf/stratos/blob/9c1fdc75/extensions/das/metering-service/capps/stratos-metering-service/Gadget_Member_Information/Member_Information/js/vega.js
----------------------------------------------------------------------
diff --git a/extensions/das/metering-service/capps/stratos-metering-service/Gadget_Member_Information/Member_Information/js/vega.js b/extensions/das/metering-service/capps/stratos-metering-service/Gadget_Member_Information/Member_Information/js/vega.js
new file mode 100644
index 0000000..019e421
--- /dev/null
+++ b/extensions/das/metering-service/capps/stratos-metering-service/Gadget_Member_Information/Member_Information/js/vega.js
@@ -0,0 +1,7986 @@
+// Define module using Universal Module Definition pattern
+// https://github.com/umdjs/umd/blob/master/amdWeb.js
+
+(function (factory) {
+    if (typeof define === 'function' && define.amd) {
+        // Support AMD. Register as an anonymous module.
+        // NOTE: List all dependencies in AMD style
+        define(['d3', 'topojson'], factory);
+    } else {
+        // No AMD. Set module as a global variable
+        // NOTE: Pass dependencies to factory function
+        // (assume that both d3 and topojson are also global.)
+        var tj = (typeof topojson === 'undefined') ? null : topojson;
+        vg = factory(d3, tj);
+    }
+}(
+//NOTE: The dependencies are passed to this function
+    function (d3, topojson) {
+//---------------------------------------------------
+// BEGIN code for this module
+//---------------------------------------------------
+
+        var vg = {
+            version: "1.4.3", // semantic versioning
+            d3: d3,      // stash d3 for use in property functions
+            topojson: topojson // stash topojson similarly
+        };
+// type checking functions
+        var toString = Object.prototype.toString;
+
+        vg.isObject = function (obj) {
+            return obj === Object(obj);
+        };
+
+        vg.isFunction = function (obj) {
+            return toString.call(obj) == '[object Function]';
+        };
+
+        vg.isString = function (obj) {
+            return toString.call(obj) == '[object String]';
+        };
+
+        vg.isArray = Array.isArray || function (obj) {
+                return toString.call(obj) == '[object Array]';
+            };
+
+        vg.isNumber = function (obj) {
+            return toString.call(obj) == '[object Number]';
+        };
+
+        vg.isBoolean = function (obj) {
+            return toString.call(obj) == '[object Boolean]';
+        };
+
+        vg.isTree = function (obj) {
+            return obj && obj.__vgtree__;
+        };
+
+        vg.tree = function (obj, children) {
+            var d = [obj];
+            d.__vgtree__ = true;
+            d.children = children || "children";
+            return d;
+        };
+
+        vg.number = function (s) {
+            return +s;
+        };
+
+        vg.boolean = function (s) {
+            return !!s;
+        };
+
+// utility functions
+
+        vg.identity = function (x) {
+            return x;
+        };
+
+        vg.true = function () {
+            return true;
+        };
+
+        vg.extend = function (obj) {
+            for (var x, name, i = 1, len = arguments.length; i < len; ++i) {
+                x = arguments[i];
+                for (name in x) {
+                    obj[name] = x[name];
+                }
+            }
+            return obj;
+        };
+
+        vg.duplicate = function (obj) {
+            return JSON.parse(JSON.stringify(obj));
+        };
+
+        vg.field = function (f) {
+            return f.split("\\.")
+                .map(function (d) {
+                    return d.split(".");
+                })
+                .reduce(function (a, b) {
+                    if (a.length) {
+                        a[a.length - 1] += "." + b.shift();
+                    }
+                    a.push.apply(a, b);
+                    return a;
+                }, []);
+        };
+
+        vg.accessor = function (f) {
+            var s;
+            return (vg.isFunction(f) || f == null)
+                ? f : vg.isString(f) && (s = vg.field(f)).length > 1
+                ? function (x) {
+                return s.reduce(function (x, f) {
+                    return x[f];
+                }, x);
+            }
+                : function (x) {
+                return x[f];
+            };
+        };
+
+        vg.mutator = function (f) {
+            var s;
+            return vg.isString(f) && (s = vg.field(f)).length > 1
+                ? function (x, v) {
+                for (var i = 0; i < s.length - 1; ++i) x = x[s[i]];
+                x[s[i]] = v;
+            }
+                : function (x, v) {
+                x[f] = v;
+            };
+        };
+
+        vg.comparator = function (sort) {
+            var sign = [];
+            if (sort === undefined) sort = [];
+            sort = vg.array(sort).map(function (f) {
+                var s = 1;
+                if (f[0] === "-") {
+                    s = -1;
+                    f = f.slice(1);
+                }
+                else if (f[0] === "+") {
+                    s = +1;
+                    f = f.slice(1);
+                }
+                sign.push(s);
+                return vg.accessor(f);
+            });
+            return function (a, b) {
+                var i, n, f, x, y;
+                for (i = 0, n = sort.length; i < n; ++i) {
+                    f = sort[i];
+                    x = f(a);
+                    y = f(b);
+                    if (x < y) return -1 * sign[i];
+                    if (x > y) return sign[i];
+                }
+                return 0;
+            };
+        };
+
+        vg.cmp = function (a, b) {
+            return a < b ? -1 : a > b ? 1 : 0;
+        };
+
+        vg.numcmp = function (a, b) {
+            return a - b;
+        };
+
+        vg.array = function (x) {
+            return x != null ? (vg.isArray(x) ? x : [x]) : [];
+        };
+
+        vg.values = function (x) {
+            return (vg.isObject(x) && !vg.isArray(x) && x.values) ? x.values : x;
+        };
+
+        vg.str = function (x) {
+            return vg.isArray(x) ? "[" + x.map(vg.str) + "]"
+                : vg.isObject(x) ? JSON.stringify(x)
+                : vg.isString(x) ? ("'" + vg_escape_str(x) + "'") : x;
+        };
+
+        var escape_str_re = /(^|[^\\])'/g;
+
+        function vg_escape_str(x) {
+            return x.replace(escape_str_re, "$1\\'");
+        }
+
+        vg.keys = function (x) {
+            var keys = [];
+            for (var key in x) keys.push(key);
+            return keys;
+        };
+
+        vg.unique = function (data, f, results) {
+            if (!vg.isArray(data) || data.length == 0) return [];
+            f = f || vg.identity;
+            results = results || [];
+            for (var v, i = 0, n = data.length; i < n; ++i) {
+                v = f(data[i]);
+                if (results.indexOf(v) < 0) results.push(v);
+            }
+            return results;
+        };
+
+        vg.minIndex = function (data, f) {
+            if (!vg.isArray(data) || data.length == 0) return -1;
+            f = f || vg.identity;
+            var idx = 0, min = f(data[0]), v = min;
+            for (var i = 1, n = data.length; i < n; ++i) {
+                v = f(data[i]);
+                if (v < min) {
+                    min = v;
+                    idx = i;
+                }
+            }
+            return idx;
+        };
+
+        vg.maxIndex = function (data, f) {
+            if (!vg.isArray(data) || data.length == 0) return -1;
+            f = f || vg.identity;
+            var idx = 0, max = f(data[0]), v = max;
+            for (var i = 1, n = data.length; i < n; ++i) {
+                v = f(data[i]);
+                if (v > max) {
+                    max = v;
+                    idx = i;
+                }
+            }
+            return idx;
+        };
+
+        vg.truncate = function (s, length, pos, word, ellipsis) {
+            var len = s.length;
+            if (len <= length) return s;
+            ellipsis = ellipsis || "...";
+            var l = Math.max(0, length - ellipsis.length);
+
+            switch (pos) {
+                case "left":
+                    return ellipsis + (word ? vg_truncateOnWord(s, l, 1) : s.slice(len - l));
+                case "middle":
+                case "center":
+                    var l1 = Math.ceil(l / 2), l2 = Math.floor(l / 2);
+                    return (word ? vg_truncateOnWord(s, l1) : s.slice(0, l1)) + ellipsis
+                        + (word ? vg_truncateOnWord(s, l2, 1) : s.slice(len - l2));
+                default:
+                    return (word ? vg_truncateOnWord(s, l) : s.slice(0, l)) + ellipsis;
+            }
+        }
+
+        function vg_truncateOnWord(s, len, rev) {
+            var cnt = 0, tok = s.split(vg_truncate_word_re);
+            if (rev) {
+                s = (tok = tok.reverse())
+                    .filter(function (w) {
+                        cnt += w.length;
+                        return cnt <= len;
+                    })
+                    .reverse();
+            } else {
+                s = tok.filter(function (w) {
+                    cnt += w.length;
+                    return cnt <= len;
+                });
+            }
+            return s.length ? s.join("").trim() : tok[0].slice(0, len);
+        }
+
+        var vg_truncate_word_re = /([\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF])/;
+
+// Logging
+
+        function vg_write(msg) {
+            vg.config.isNode
+                ? process.stderr.write(msg + "\n")
+                : console.log(msg);
+        }
+
+        vg.log = function (msg) {
+            vg_write("[Vega Log] " + msg);
+        };
+
+        vg.error = function (msg) {
+            msg = "[Vega Err] " + msg;
+            vg_write(msg);
+            if (typeof alert !== "undefined") alert(msg);
+        };
+        vg.config = {};
+
+// are we running in node.js?
+// via timetler.com/2012/10/13/environment-detection-in-javascript/
+        vg.config.isNode = typeof exports !== 'undefined' && this.exports !== exports;
+
+// Allows domain restriction when using data loading via XHR.
+// To enable, set it to a list of allowed domains
+// e.g., ['wikipedia.org', 'eff.org']
+        vg.config.domainWhiteList = false;
+
+// If true, disable potentially unsafe transforms (filter, formula)
+// involving possible JavaScript injection attacks.
+        vg.config.safeMode = false;
+
+// base url for loading external data files
+// used only for server-side operation
+        vg.config.baseURL = "";
+
+// version and namepsaces for exported svg
+        vg.config.svgNamespace =
+            'version="1.1" xmlns="http://www.w3.org/2000/svg" ' +
+            'xmlns:xlink="http://www.w3.org/1999/xlink"';
+
+// inset padding for automatic padding calculation
+        vg.config.autopadInset = 5;
+
+// extensible scale lookup table
+// all d3.scale.* instances also supported
+        vg.config.scale = {
+            time: d3.time.scale,
+            utc: d3.time.scale.utc
+        };
+
+// default rendering settings
+        vg.config.render = {
+            lineWidth: 1,
+            lineCap: "butt",
+            font: "sans-serif",
+            fontSize: 11
+        };
+
+// default axis properties
+        vg.config.axis = {
+            orient: "bottom",
+            ticks: 10,
+            padding: 3,
+            axisColor: "#000",
+            gridColor: "#d8d8d8",
+            tickColor: "#000",
+            tickLabelColor: "#000",
+            axisWidth: 1,
+            tickWidth: 1,
+            tickSize: 6,
+            tickLabelFontSize: 11,
+            tickLabelFont: "sans-serif",
+            titleColor: "#000",
+            titleFont: "sans-serif",
+            titleFontSize: 11,
+            titleFontWeight: "bold",
+            titleOffset: 35
+        };
+
+// default legend properties
+        vg.config.legend = {
+            orient: "right",
+            offset: 10,
+            padding: 3,
+            gradientStrokeColor: "#888",
+            gradientStrokeWidth: 1,
+            gradientHeight: 16,
+            gradientWidth: 100,
+            labelColor: "#000",
+            labelFontSize: 10,
+            labelFont: "sans-serif",
+            labelAlign: "left",
+            labelBaseline: "middle",
+            labelOffset: 8,
+            symbolShape: "circle",
+            symbolSize: 50,
+            symbolColor: "#888",
+            symbolStrokeWidth: 1,
+            titleColor: "#000",
+            titleFont: "sans-serif",
+            titleFontSize: 11,
+            titleFontWeight: "bold"
+        };
+
+// default color values
+        vg.config.color = {
+            rgb: [128, 128, 128],
+            lab: [50, 0, 0],
+            hcl: [0, 0, 50],
+            hsl: [0, 0, 0.5]
+        };
+
+// default scale ranges
+        vg.config.range = {
+            category10: [
+                "#1f77b4",
+                "#ff7f0e",
+                "#2ca02c",
+                "#d62728",
+                "#9467bd",
+                "#8c564b",
+                "#e377c2",
+                "#7f7f7f",
+                "#bcbd22",
+                "#17becf"
+            ],
+            category20: [
+                "#1f77b4",
+                "#aec7e8",
+                "#ff7f0e",
+                "#ffbb78",
+                "#2ca02c",
+                "#98df8a",
+                "#d62728",
+                "#ff9896",
+                "#9467bd",
+                "#c5b0d5",
+                "#8c564b",
+                "#c49c94",
+                "#e377c2",
+                "#f7b6d2",
+                "#7f7f7f",
+                "#c7c7c7",
+                "#bcbd22",
+                "#dbdb8d",
+                "#17becf",
+                "#9edae5"
+            ],
+            shapes: [
+                "circle",
+                "cross",
+                "diamond",
+                "square",
+                "triangle-down",
+                "triangle-up"
+            ]
+        };
+        vg.Bounds = (function () {
+            var bounds = function (b) {
+                this.clear();
+                if (b) this.union(b);
+            };
+
+            var prototype = bounds.prototype;
+
+            prototype.clear = function () {
+                this.x1 = +Number.MAX_VALUE;
+                this.y1 = +Number.MAX_VALUE;
+                this.x2 = -Number.MAX_VALUE;
+                this.y2 = -Number.MAX_VALUE;
+                return this;
+            };
+
+            prototype.set = function (x1, y1, x2, y2) {
+                this.x1 = x1;
+                this.y1 = y1;
+                this.x2 = x2;
+                this.y2 = y2;
+                return this;
+            };
+
+            prototype.add = function (x, y) {
+                if (x < this.x1) this.x1 = x;
+                if (y < this.y1) this.y1 = y;
+                if (x > this.x2) this.x2 = x;
+                if (y > this.y2) this.y2 = y;
+                return this;
+            };
+
+            prototype.expand = function (d) {
+                this.x1 -= d;
+                this.y1 -= d;
+                this.x2 += d;
+                this.y2 += d;
+                return this;
+            };
+
+            prototype.round = function () {
+                this.x1 = Math.floor(this.x1);
+                this.y1 = Math.floor(this.y1);
+                this.x2 = Math.ceil(this.x2);
+                this.y2 = Math.ceil(this.y2);
+                return this;
+            };
+
+            prototype.translate = function (dx, dy) {
+                this.x1 += dx;
+                this.x2 += dx;
+                this.y1 += dy;
+                this.y2 += dy;
+                return this;
+            };
+
+            prototype.rotate = function (angle, x, y) {
+                var cos = Math.cos(angle),
+                    sin = Math.sin(angle),
+                    cx = x - x * cos + y * sin,
+                    cy = y - x * sin - y * cos,
+                    x1 = this.x1, x2 = this.x2,
+                    y1 = this.y1, y2 = this.y2;
+
+                return this.clear()
+                    .add(cos * x1 - sin * y1 + cx, sin * x1 + cos * y1 + cy)
+                    .add(cos * x1 - sin * y2 + cx, sin * x1 + cos * y2 + cy)
+                    .add(cos * x2 - sin * y1 + cx, sin * x2 + cos * y1 + cy)
+                    .add(cos * x2 - sin * y2 + cx, sin * x2 + cos * y2 + cy);
+            }
+
+            prototype.union = function (b) {
+                if (b.x1 < this.x1) this.x1 = b.x1;
+                if (b.y1 < this.y1) this.y1 = b.y1;
+                if (b.x2 > this.x2) this.x2 = b.x2;
+                if (b.y2 > this.y2) this.y2 = b.y2;
+                return this;
+            };
+
+            prototype.encloses = function (b) {
+                return b && (
+                        this.x1 <= b.x1 &&
+                        this.x2 >= b.x2 &&
+                        this.y1 <= b.y1 &&
+                        this.y2 >= b.y2
+                    );
+            };
+
+            prototype.intersects = function (b) {
+                return b && !(
+                        this.x2 < b.x1 ||
+                        this.x1 > b.x2 ||
+                        this.y2 < b.y1 ||
+                        this.y1 > b.y2
+                    );
+            };
+
+            prototype.contains = function (x, y) {
+                return !(
+                    x < this.x1 ||
+                    x > this.x2 ||
+                    y < this.y1 ||
+                    y > this.y2
+                );
+            };
+
+            prototype.width = function () {
+                return this.x2 - this.x1;
+            };
+
+            prototype.height = function () {
+                return this.y2 - this.y1;
+            };
+
+            return bounds;
+        })();
+        vg.Gradient = (function () {
+
+            function gradient(type) {
+                this.id = "grad_" + (vg_gradient_id++);
+                this.type = type || "linear";
+                this.stops = [];
+                this.x1 = 0;
+                this.x2 = 1;
+                this.y1 = 0;
+                this.y2 = 0;
+            };
+
+            var prototype = gradient.prototype;
+
+            prototype.stop = function (offset, color) {
+                this.stops.push({
+                    offset: offset,
+                    color: color
+                });
+                return this;
+            };
+
+            return gradient;
+        })();
+
+        var vg_gradient_id = 0;
+        vg.canvas = {};
+        vg.canvas.path = (function () {
+
+            // Path parsing and rendering code taken from fabric.js -- Thanks!
+            var cmdLength = {m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7},
+                re = [/([MLHVCSQTAZmlhvcsqtaz])/g, /###/, /(\d)-/g, /\s|,|###/];
+
+            function parse(path) {
+                var result = [],
+                    currentPath,
+                    chunks,
+                    parsed;
+
+                // First, break path into command sequence
+                path = path.slice().replace(re[0], '###$1').split(re[1]).slice(1);
+
+                // Next, parse each command in turn
+                for (var i = 0, j, chunksParsed, len = path.length; i < len; i++) {
+                    currentPath = path[i];
+                    chunks = currentPath.slice(1).trim().replace(re[2], '$1###-').split(re[3]);
+                    chunksParsed = [currentPath.charAt(0)];
+
+                    for (var j = 0, jlen = chunks.length; j < jlen; j++) {
+                        parsed = parseFloat(chunks[j]);
+                        if (!isNaN(parsed)) {
+                            chunksParsed.push(parsed);
+                        }
+                    }
+
+                    var command = chunksParsed[0].toLowerCase(),
+                        commandLength = cmdLength[command];
+
+                    if (chunksParsed.length - 1 > commandLength) {
+                        for (var k = 1, klen = chunksParsed.length; k < klen; k += commandLength) {
+                            result.push([chunksParsed[0]].concat(chunksParsed.slice(k, k + commandLength)));
+                        }
+                    }
+                    else {
+                        result.push(chunksParsed);
+                    }
+                }
+
+                return result;
+            }
+
+            function drawArc(g, x, y, coords, bounds, l, t) {
+                var rx = coords[0];
+                var ry = coords[1];
+                var rot = coords[2];
+                var large = coords[3];
+                var sweep = coords[4];
+                var ex = coords[5];
+                var ey = coords[6];
+                var segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, x, y);
+                for (var i = 0; i < segs.length; i++) {
+                    var bez = segmentToBezier.apply(null, segs[i]);
+                    g.bezierCurveTo.apply(g, bez);
+                    bounds.add(bez[0] - l, bez[1] - t);
+                    bounds.add(bez[2] - l, bez[3] - t);
+                    bounds.add(bez[4] - l, bez[5] - t);
+                }
+            }
+
+            function boundArc(x, y, coords, bounds) {
+                var rx = coords[0];
+                var ry = coords[1];
+                var rot = coords[2];
+                var large = coords[3];
+                var sweep = coords[4];
+                var ex = coords[5];
+                var ey = coords[6];
+                var segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, x, y);
+                for (var i = 0; i < segs.length; i++) {
+                    var bez = segmentToBezier.apply(null, segs[i]);
+                    bounds.add(bez[0], bez[1]);
+                    bounds.add(bez[2], bez[3]);
+                    bounds.add(bez[4], bez[5]);
+                }
+            }
+
+            var arcToSegmentsCache = {},
+                segmentToBezierCache = {},
+                join = Array.prototype.join,
+                argsStr;
+
+            // Copied from Inkscape svgtopdf, thanks!
+            function arcToSegments(x, y, rx, ry, large, sweep, rotateX, ox, oy) {
+                argsStr = join.call(arguments);
+                if (arcToSegmentsCache[argsStr]) {
+                    return arcToSegmentsCache[argsStr];
+                }
+
+                var th = rotateX * (Math.PI / 180);
+                var sin_th = Math.sin(th);
+                var cos_th = Math.cos(th);
+                rx = Math.abs(rx);
+                ry = Math.abs(ry);
+                var px = cos_th * (ox - x) * 0.5 + sin_th * (oy - y) * 0.5;
+                var py = cos_th * (oy - y) * 0.5 - sin_th * (ox - x) * 0.5;
+                var pl = (px * px) / (rx * rx) + (py * py) / (ry * ry);
+                if (pl > 1) {
+                    pl = Math.sqrt(pl);
+                    rx *= pl;
+                    ry *= pl;
+                }
+
+                var a00 = cos_th / rx;
+                var a01 = sin_th / rx;
+                var a10 = (-sin_th) / ry;
+                var a11 = (cos_th) / ry;
+                var x0 = a00 * ox + a01 * oy;
+                var y0 = a10 * ox + a11 * oy;
+                var x1 = a00 * x + a01 * y;
+                var y1 = a10 * x + a11 * y;
+
+                var d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
+                var sfactor_sq = 1 / d - 0.25;
+                if (sfactor_sq < 0) sfactor_sq = 0;
+                var sfactor = Math.sqrt(sfactor_sq);
+                if (sweep == large) sfactor = -sfactor;
+                var xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
+                var yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
+
+                var th0 = Math.atan2(y0 - yc, x0 - xc);
+                var th1 = Math.atan2(y1 - yc, x1 - xc);
+
+                var th_arc = th1 - th0;
+                if (th_arc < 0 && sweep == 1) {
+                    th_arc += 2 * Math.PI;
+                } else if (th_arc > 0 && sweep == 0) {
+                    th_arc -= 2 * Math.PI;
+                }
+
+                var segments = Math.ceil(Math.abs(th_arc / (Math.PI * 0.5 + 0.001)));
+                var result = [];
+                for (var i = 0; i < segments; i++) {
+                    var th2 = th0 + i * th_arc / segments;
+                    var th3 = th0 + (i + 1) * th_arc / segments;
+                    result[i] = [xc, yc, th2, th3, rx, ry, sin_th, cos_th];
+                }
+
+                return (arcToSegmentsCache[argsStr] = result);
+            }
+
+            function segmentToBezier(cx, cy, th0, th1, rx, ry, sin_th, cos_th) {
+                argsStr = join.call(arguments);
+                if (segmentToBezierCache[argsStr]) {
+                    return segmentToBezierCache[argsStr];
+                }
+
+                var a00 = cos_th * rx;
+                var a01 = -sin_th * ry;
+                var a10 = sin_th * rx;
+                var a11 = cos_th * ry;
+
+                var cos_th0 = Math.cos(th0);
+                var sin_th0 = Math.sin(th0);
+                var cos_th1 = Math.cos(th1);
+                var sin_th1 = Math.sin(th1);
+
+                var th_half = 0.5 * (th1 - th0);
+                var sin_th_h2 = Math.sin(th_half * 0.5);
+                var t = (8 / 3) * sin_th_h2 * sin_th_h2 / Math.sin(th_half);
+                var x1 = cx + cos_th0 - t * sin_th0;
+                var y1 = cy + sin_th0 + t * cos_th0;
+                var x3 = cx + cos_th1;
+                var y3 = cy + sin_th1;
+                var x2 = x3 + t * sin_th1;
+                var y2 = y3 - t * cos_th1;
+
+                return (segmentToBezierCache[argsStr] = [
+                    a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
+                    a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
+                    a00 * x3 + a01 * y3, a10 * x3 + a11 * y3
+                ]);
+            }
+
+            function render(g, path, l, t) {
+                var current, // current instruction
+                    previous = null,
+                    x = 0, // current x
+                    y = 0, // current y
+                    controlX = 0, // current control point x
+                    controlY = 0, // current control point y
+                    tempX,
+                    tempY,
+                    tempControlX,
+                    tempControlY,
+                    bounds = new vg.Bounds();
+                if (l == undefined) l = 0;
+                if (t == undefined) t = 0;
+
+                g.beginPath();
+
+                for (var i = 0, len = path.length; i < len; ++i) {
+                    current = path[i];
+
+                    switch (current[0]) { // first letter
+
+                        case 'l': // lineto, relative
+                            x += current[1];
+                            y += current[2];
+                            g.lineTo(x + l, y + t);
+                            bounds.add(x, y);
+                            break;
+
+                        case 'L': // lineto, absolute
+                            x = current[1];
+                            y = current[2];
+                            g.lineTo(x + l, y + t);
+                            bounds.add(x, y);
+                            break;
+
+                        case 'h': // horizontal lineto, relative
+                            x += current[1];
+                            g.lineTo(x + l, y + t);
+                            bounds.add(x, y);
+                            break;
+
+                        case 'H': // horizontal lineto, absolute
+                            x = current[1];
+                            g.lineTo(x + l, y + t);
+                            bounds.add(x, y);
+                            break;
+
+                        case 'v': // vertical lineto, relative
+                            y += current[1];
+                            g.lineTo(x + l, y + t);
+                            bounds.add(x, y);
+                            break;
+
+                        case 'V': // verical lineto, absolute
+                            y = current[1];
+                            g.lineTo(x + l, y + t);
+                            bounds.add(x, y);
+                            break;
+
+                        case 'm': // moveTo, relative
+                            x += current[1];
+                            y += current[2];
+                            g.moveTo(x + l, y + t);
+                            bounds.add(x, y);
+                            break;
+
+                        case 'M': // moveTo, absolute
+                            x = current[1];
+                            y = current[2];
+                            g.moveTo(x + l, y + t);
+                            bounds.add(x, y);
+                            break;
+
+                        case 'c': // bezierCurveTo, relative
+                            tempX = x + current[5];
+                            tempY = y + current[6];
+                            controlX = x + current[3];
+                            controlY = y + current[4];
+                            g.bezierCurveTo(
+                                x + current[1] + l, // x1
+                                y + current[2] + t, // y1
+                                controlX + l, // x2
+                                controlY + t, // y2
+                                tempX + l,
+                                tempY + t
+                            );
+                            bounds.add(x + current[1], y + current[2]);
+                            bounds.add(controlX, controlY);
+                            bounds.add(tempX, tempY);
+                            x = tempX;
+                            y = tempY;
+                            break;
+
+                        case 'C': // bezierCurveTo, absolute
+                            x = current[5];
+                            y = current[6];
+                            controlX = current[3];
+                            controlY = current[4];
+                            g.bezierCurveTo(
+                                current[1] + l,
+                                current[2] + t,
+                                controlX + l,
+                                controlY + t,
+                                x + l,
+                                y + t
+                            );
+                            bounds.add(current[1], current[2]);
+                            bounds.add(controlX, controlY);
+                            bounds.add(x, y);
+                            break;
+
+                        case 's': // shorthand cubic bezierCurveTo, relative
+                                  // transform to absolute x,y
+                            tempX = x + current[3];
+                            tempY = y + current[4];
+                            // calculate reflection of previous control points
+                            controlX = 2 * x - controlX;
+                            controlY = 2 * y - controlY;
+                            g.bezierCurveTo(
+                                controlX + l,
+                                controlY + t,
+                                x + current[1] + l,
+                                y + current[2] + t,
+                                tempX + l,
+                                tempY + t
+                            );
+                            bounds.add(controlX, controlY);
+                            bounds.add(x + current[1], y + current[2]);
+                            bounds.add(tempX, tempY);
+
+                            // set control point to 2nd one of this command
+                            // "... the first control point is assumed to be the reflection of the second control point on the previous command relative to the current point."
+                            controlX = x + current[1];
+                            controlY = y + current[2];
+
+                            x = tempX;
+                            y = tempY;
+                            break;
+
+                        case 'S': // shorthand cubic bezierCurveTo, absolute
+                            tempX = current[3];
+                            tempY = current[4];
+                            // calculate reflection of previous control points
+                            controlX = 2 * x - controlX;
+                            controlY = 2 * y - controlY;
+                            g.bezierCurveTo(
+                                controlX + l,
+                                controlY + t,
+                                current[1] + l,
+                                current[2] + t,
+                                tempX + l,
+                                tempY + t
+                            );
+                            x = tempX;
+                            y = tempY;
+                            bounds.add(current[1], current[2]);
+                            bounds.add(controlX, controlY);
+                            bounds.add(tempX, tempY);
+                            // set control point to 2nd one of this command
+                            // "... the first control point is assumed to be the reflection of the second control point on the previous command relative to the current point."
+                            controlX = current[1];
+                            controlY = current[2];
+
+                            break;
+
+                        case 'q': // quadraticCurveTo, relative
+                                  // transform to absolute x,y
+                            tempX = x + current[3];
+                            tempY = y + current[4];
+
+                            controlX = x + current[1];
+                            controlY = y + current[2];
+
+                            g.quadraticCurveTo(
+                                controlX + l,
+                                controlY + t,
+                                tempX + l,
+                                tempY + t
+                            );
+                            x = tempX;
+                            y = tempY;
+                            bounds.add(controlX, controlY);
+                            bounds.add(tempX, tempY);
+                            break;
+
+                        case 'Q': // quadraticCurveTo, absolute
+                            tempX = current[3];
+                            tempY = current[4];
+
+                            g.quadraticCurveTo(
+                                current[1] + l,
+                                current[2] + t,
+                                tempX + l,
+                                tempY + t
+                            );
+                            x = tempX;
+                            y = tempY;
+                            controlX = current[1];
+                            controlY = current[2];
+                            bounds.add(controlX, controlY);
+                            bounds.add(tempX, tempY);
+                            break;
+
+                        case 't': // shorthand quadraticCurveTo, relative
+
+                            // transform to absolute x,y
+                            tempX = x + current[1];
+                            tempY = y + current[2];
+
+                            if (previous[0].match(/[QqTt]/) === null) {
+                                // If there is no previous command or if the previous command was not a Q, q, T or t,
+                                // assume the control point is coincident with the current point
+                                controlX = x;
+                                controlY = y;
+                            }
+                            else if (previous[0] === 't') {
+                                // calculate reflection of previous control points for t
+                                controlX = 2 * x - tempControlX;
+                                controlY = 2 * y - tempControlY;
+                            }
+                            else if (previous[0] === 'q') {
+                                // calculate reflection of previous control points for q
+                                controlX = 2 * x - controlX;
+                                controlY = 2 * y - controlY;
+                            }
+
+                            tempControlX = controlX;
+                            tempControlY = controlY;
+
+                            g.quadraticCurveTo(
+                                controlX + l,
+                                controlY + t,
+                                tempX + l,
+                                tempY + t
+                            );
+                            x = tempX;
+                            y = tempY;
+                            controlX = x + current[1];
+                            controlY = y + current[2];
+                            bounds.add(controlX, controlY);
+                            bounds.add(tempX, tempY);
+                            break;
+
+                        case 'T':
+                            tempX = current[1];
+                            tempY = current[2];
+
+                            // calculate reflection of previous control points
+                            controlX = 2 * x - controlX;
+                            controlY = 2 * y - controlY;
+                            g.quadraticCurveTo(
+                                controlX + l,
+                                controlY + t,
+                                tempX + l,
+                                tempY + t
+                            );
+                            x = tempX;
+                            y = tempY;
+                            bounds.add(controlX, controlY);
+                            bounds.add(tempX, tempY);
+                            break;
+
+                        case 'a':
+                            drawArc(g, x + l, y + t, [
+                                current[1],
+                                current[2],
+                                current[3],
+                                current[4],
+                                current[5],
+                                current[6] + x + l,
+                                current[7] + y + t
+                            ], bounds, l, t);
+                            x += current[6];
+                            y += current[7];
+                            break;
+
+                        case 'A':
+                            drawArc(g, x + l, y + t, [
+                                current[1],
+                                current[2],
+                                current[3],
+                                current[4],
+                                current[5],
+                                current[6] + l,
+                                current[7] + t
+                            ], bounds, l, t);
+                            x = current[6];
+                            y = current[7];
+                            break;
+
+                        case 'z':
+                        case 'Z':
+                            g.closePath();
+                            break;
+                    }
+                    previous = current;
+                }
+                return bounds.translate(l, t);
+            }
+
+            function bounds(path, bounds) {
+                var current, // current instruction
+                    previous = null,
+                    x = 0, // current x
+                    y = 0, // current y
+                    controlX = 0, // current control point x
+                    controlY = 0, // current control point y
+                    tempX,
+                    tempY,
+                    tempControlX,
+                    tempControlY;
+
+                for (var i = 0, len = path.length; i < len; ++i) {
+                    current = path[i];
+
+                    switch (current[0]) { // first letter
+
+                        case 'l': // lineto, relative
+                            x += current[1];
+                            y += current[2];
+                            bounds.add(x, y);
+                            break;
+
+                        case 'L': // lineto, absolute
+                            x = current[1];
+                            y = current[2];
+                            bounds.add(x, y);
+                            break;
+
+                        case 'h': // horizontal lineto, relative
+                            x += current[1];
+                            bounds.add(x, y);
+                            break;
+
+                        case 'H': // horizontal lineto, absolute
+                            x = current[1];
+                            bounds.add(x, y);
+                            break;
+
+                        case 'v': // vertical lineto, relative
+                            y += current[1];
+                            bounds.add(x, y);
+                            break;
+
+                        case 'V': // verical lineto, absolute
+                            y = current[1];
+                            bounds.add(x, y);
+                            break;
+
+                        case 'm': // moveTo, relative
+                            x += current[1];
+                            y += current[2];
+                            bounds.add(x, y);
+                            break;
+
+                        case 'M': // moveTo, absolute
+                            x = current[1];
+                            y = current[2];
+                            bounds.add(x, y);
+                            break;
+
+                        case 'c': // bezierCurveTo, relative
+                            tempX = x + current[5];
+                            tempY = y + current[6];
+                            controlX = x + current[3];
+                            controlY = y + current[4];
+                            bounds.add(x + current[1], y + current[2]);
+                            bounds.add(controlX, controlY);
+                            bounds.add(tempX, tempY);
+                            x = tempX;
+                            y = tempY;
+                            break;
+
+                        case 'C': // bezierCurveTo, absolute
+                            x = current[5];
+                            y = current[6];
+                            controlX = current[3];
+                            controlY = current[4];
+                            bounds.add(current[1], current[2]);
+                            bounds.add(controlX, controlY);
+                            bounds.add(x, y);
+                            break;
+
+                        case 's': // shorthand cubic bezierCurveTo, relative
+                                  // transform to absolute x,y
+                            tempX = x + current[3];
+                            tempY = y + current[4];
+                            // calculate reflection of previous control points
+                            controlX = 2 * x - controlX;
+                            controlY = 2 * y - controlY;
+                            bounds.add(controlX, controlY);
+                            bounds.add(x + current[1], y + current[2]);
+                            bounds.add(tempX, tempY);
+
+                            // set control point to 2nd one of this command
+                            // "... the first control point is assumed to be the reflection of the second control point on the previous command relative to the current point."
+                            controlX = x + current[1];
+                            controlY = y + current[2];
+
+                            x = tempX;
+                            y = tempY;
+                            break;
+
+                        case 'S': // shorthand cubic bezierCurveTo, absolute
+                            tempX = current[3];
+                            tempY = current[4];
+                            // calculate reflection of previous control points
+                            controlX = 2 * x - controlX;
+                            controlY = 2 * y - controlY;
+                            x = tempX;
+                            y = tempY;
+                            bounds.add(current[1], current[2]);
+                            bounds.add(controlX, controlY);
+                            bounds.add(tempX, tempY);
+                            // set control point to 2nd one of this command
+                            // "... the first control point is assumed to be the reflection of the second control point on the previous command relative to the current point."
+                            controlX = current[1];
+                            controlY = current[2];
+
+                            break;
+
+                        case 'q': // quadraticCurveTo, relative
+                                  // transform to absolute x,y
+                            tempX = x + current[3];
+                            tempY = y + current[4];
+
+                            controlX = x + current[1];
+                            controlY = y + current[2];
+
+                            x = tempX;
+                            y = tempY;
+                            bounds.add(controlX, controlY);
+                            bounds.add(tempX, tempY);
+                            break;
+
+                        case 'Q': // quadraticCurveTo, absolute
+                            tempX = current[3];
+                            tempY = current[4];
+
+                            x = tempX;
+                            y = tempY;
+                            controlX = current[1];
+                            controlY = current[2];
+                            bounds.add(controlX, controlY);
+                            bounds.add(tempX, tempY);
+                            break;
+
+                        case 't': // shorthand quadraticCurveTo, relative
+
+                            // transform to absolute x,y
+                            tempX = x + current[1];
+                            tempY = y + current[2];
+
+                            if (previous[0].match(/[QqTt]/) === null) {
+                                // If there is no previous command or if the previous command was not a Q, q, T or t,
+                                // assume the control point is coincident with the current point
+                                controlX = x;
+                                controlY = y;
+                            }
+                            else if (previous[0] === 't') {
+                                // calculate reflection of previous control points for t
+                                controlX = 2 * x - tempControlX;
+                                controlY = 2 * y - tempControlY;
+                            }
+                            else if (previous[0] === 'q') {
+                                // calculate reflection of previous control points for q
+                                controlX = 2 * x - controlX;
+                                controlY = 2 * y - controlY;
+                            }
+
+                            tempControlX = controlX;
+                            tempControlY = controlY;
+
+                            x = tempX;
+                            y = tempY;
+                            controlX = x + current[1];
+                            controlY = y + current[2];
+                            bounds.add(controlX, controlY);
+                            bounds.add(tempX, tempY);
+                            break;
+
+                        case 'T':
+                            tempX = current[1];
+                            tempY = current[2];
+
+                            // calculate reflection of previous control points
+                            controlX = 2 * x - controlX;
+                            controlY = 2 * y - controlY;
+
+                            x = tempX;
+                            y = tempY;
+                            bounds.add(controlX, controlY);
+                            bounds.add(tempX, tempY);
+                            break;
+
+                        case 'a':
+                            boundArc(x, y, [
+                                current[1],
+                                current[2],
+                                current[3],
+                                current[4],
+                                current[5],
+                                current[6] + x,
+                                current[7] + y
+                            ], bounds);
+                            x += current[6];
+                            y += current[7];
+                            break;
+
+                        case 'A':
+                            boundArc(x, y, [
+                                current[1],
+                                current[2],
+                                current[3],
+                                current[4],
+                                current[5],
+                                current[6],
+                                current[7]
+                            ], bounds);
+                            x = current[6];
+                            y = current[7];
+                            break;
+
+                        case 'z':
+                        case 'Z':
+                            break;
+                    }
+                    previous = current;
+                }
+                return bounds;
+            }
+
+            function area(items) {
+                var o = items[0];
+                var area;
+
+                if (o.orient === "horizontal") {
+                    area = d3.svg.area()
+                        .y(function (d) {
+                            return d.y;
+                        })
+                        .x0(function (d) {
+                            return d.x;
+                        })
+                        .x1(function (d) {
+                            return d.x + d.width;
+                        });
+                } else {
+                    area = d3.svg.area()
+                        .x(function (d) {
+                            return d.x;
+                        })
+                        .y1(function (d) {
+                            return d.y;
+                        })
+                        .y0(function (d) {
+                            return d.y + d.height;
+                        });
+                }
+
+                if (o.interpolate) area.interpolate(o.interpolate);
+                if (o.tension != null) area.tension(o.tension);
+                return area(items);
+            }
+
+            function line(items) {
+                var o = items[0];
+                var line = d3.svg.line()
+                    .x(function (d) {
+                        return d.x;
+                    })
+                    .y(function (d) {
+                        return d.y;
+                    });
+                if (o.interpolate) line.interpolate(o.interpolate);
+                if (o.tension != null) line.tension(o.tension);
+                return line(items);
+            }
+
+            return {
+                parse: parse,
+                render: render,
+                bounds: bounds,
+                area: area,
+                line: line
+            };
+
+        })();
+        vg.canvas.marks = (function () {
+
+            var parsePath = vg.canvas.path.parse,
+                renderPath = vg.canvas.path.render,
+                halfpi = Math.PI / 2,
+                sqrt3 = Math.sqrt(3),
+                tan30 = Math.tan(30 * Math.PI / 180),
+                tmpBounds = new vg.Bounds();
+
+            // path generators
+
+            function arcPath(g, o) {
+                var x = o.x || 0,
+                    y = o.y || 0,
+                    ir = o.innerRadius || 0,
+                    or = o.outerRadius || 0,
+                    sa = (o.startAngle || 0) - Math.PI / 2,
+                    ea = (o.endAngle || 0) - Math.PI / 2;
+                g.beginPath();
+                if (ir === 0) g.moveTo(x, y);
+                else g.arc(x, y, ir, sa, ea, 0);
+                g.arc(x, y, or, ea, sa, 1);
+                g.closePath();
+            }
+
+            function areaPath(g, items) {
+                var o = items[0],
+                    m = o.mark,
+                    p = m.pathCache || (m.pathCache = parsePath(vg.canvas.path.area(items)));
+                renderPath(g, p);
+            }
+
+            function linePath(g, items) {
+                var o = items[0],
+                    m = o.mark,
+                    p = m.pathCache || (m.pathCache = parsePath(vg.canvas.path.line(items)));
+                renderPath(g, p);
+            }
+
+            function pathPath(g, o) {
+                if (o.path == null) return;
+                var p = o.pathCache || (o.pathCache = parsePath(o.path));
+                return renderPath(g, p, o.x, o.y);
+            }
+
+            function symbolPath(g, o) {
+                g.beginPath();
+                var size = o.size != null ? o.size : 100,
+                    x = o.x, y = o.y, r, t, rx, ry;
+
+                if (o.shape == null || o.shape === "circle") {
+                    r = Math.sqrt(size / Math.PI);
+                    g.arc(x, y, r, 0, 2 * Math.PI, 0);
+                    g.closePath();
+                    return;
+                }
+
+                switch (o.shape) {
+                    case "cross":
+                        r = Math.sqrt(size / 5) / 2;
+                        t = 3 * r;
+                        g.moveTo(x - t, y - r);
+                        g.lineTo(x - r, y - r);
+                        g.lineTo(x - r, y - t);
+                        g.lineTo(x + r, y - t);
+                        g.lineTo(x + r, y - r);
+                        g.lineTo(x + t, y - r);
+                        g.lineTo(x + t, y + r);
+                        g.lineTo(x + r, y + r);
+                        g.lineTo(x + r, y + t);
+                        g.lineTo(x - r, y + t);
+                        g.lineTo(x - r, y + r);
+                        g.lineTo(x - t, y + r);
+                        break;
+
+                    case "diamond":
+                        ry = Math.sqrt(size / (2 * tan30));
+                        rx = ry * tan30;
+                        g.moveTo(x, y - ry);
+                        g.lineTo(x + rx, y);
+                        g.lineTo(x, y + ry);
+                        g.lineTo(x - rx, y);
+                        break;
+
+                    case "square":
+                        t = Math.sqrt(size);
+                        r = t / 2;
+                        g.rect(x - r, y - r, t, t);
+                        break;
+
+                    case "triangle-down":
+                        rx = Math.sqrt(size / sqrt3);
+                        ry = rx * sqrt3 / 2;
+                        g.moveTo(x, y + ry);
+                        g.lineTo(x + rx, y - ry);
+                        g.lineTo(x - rx, y - ry);
+                        break;
+
+                    case "triangle-up":
+                        rx = Math.sqrt(size / sqrt3);
+                        ry = rx * sqrt3 / 2;
+                        g.moveTo(x, y - ry);
+                        g.lineTo(x + rx, y + ry);
+                        g.lineTo(x - rx, y + ry);
+                }
+                g.closePath();
+            }
+
+            function lineStroke(g, items) {
+                var o = items[0],
+                    lw = o.strokeWidth,
+                    lc = o.strokeCap;
+                g.lineWidth = lw != null ? lw : vg.config.render.lineWidth;
+                g.lineCap = lc != null ? lc : vg.config.render.lineCap;
+                linePath(g, items);
+            }
+
+            function ruleStroke(g, o) {
+                var x1 = o.x || 0,
+                    y1 = o.y || 0,
+                    x2 = o.x2 != null ? o.x2 : x1,
+                    y2 = o.y2 != null ? o.y2 : y1,
+                    lw = o.strokeWidth,
+                    lc = o.strokeCap;
+
+                g.lineWidth = lw != null ? lw : vg.config.render.lineWidth;
+                g.lineCap = lc != null ? lc : vg.config.render.lineCap;
+                g.beginPath();
+                g.moveTo(x1, y1);
+                g.lineTo(x2, y2);
+            }
+
+            // drawing functions
+
+            function drawPathOne(path, g, o, items) {
+                var fill = o.fill, stroke = o.stroke, opac, lc, lw;
+
+                path(g, items);
+
+                opac = o.opacity == null ? 1 : o.opacity;
+                if (opac == 0 || !fill && !stroke) return;
+
+                if (fill) {
+                    g.globalAlpha = opac * (o.fillOpacity == null ? 1 : o.fillOpacity);
+                    g.fillStyle = color(g, o, fill);
+                    g.fill();
+                }
+
+                if (stroke) {
+                    lw = (lw = o.strokeWidth) != null ? lw : vg.config.render.lineWidth;
+                    if (lw > 0) {
+                        g.globalAlpha = opac * (o.strokeOpacity == null ? 1 : o.strokeOpacity);
+                        g.strokeStyle = color(g, o, stroke);
+                        g.lineWidth = lw;
+                        g.lineCap = (lc = o.strokeCap) != null ? lc : vg.config.render.lineCap;
+                        g.vgLineDash(o.strokeDash || null);
+                        g.vgLineDashOffset(o.strokeDashOffset || 0);
+                        g.stroke();
+                    }
+                }
+            }
+
+            function drawPathAll(path, g, scene, bounds) {
+                var i, len, item;
+                for (i = 0, len = scene.items.length; i < len; ++i) {
+                    item = scene.items[i];
+                    if (bounds && !bounds.intersects(item.bounds))
+                        continue; // bounds check
+                    drawPathOne(path, g, item, item);
+                }
+            }
+
+            function drawRect(g, scene, bounds) {
+                if (!scene.items.length) return;
+                var items = scene.items,
+                    o, fill, stroke, opac, lc, lw, x, y, w, h;
+
+                for (var i = 0, len = items.length; i < len; ++i) {
+                    o = items[i];
+                    if (bounds && !bounds.intersects(o.bounds))
+                        continue; // bounds check
+
+                    x = o.x || 0;
+                    y = o.y || 0;
+                    w = o.width || 0;
+                    h = o.height || 0;
+
+                    opac = o.opacity == null ? 1 : o.opacity;
+                    if (opac == 0) continue;
+
+                    if (fill = o.fill) {
+                        g.globalAlpha = opac * (o.fillOpacity == null ? 1 : o.fillOpacity);
+                        g.fillStyle = color(g, o, fill);
+                        g.fillRect(x, y, w, h);
+                    }
+
+                    if (stroke = o.stroke) {
+                        lw = (lw = o.strokeWidth) != null ? lw : vg.config.render.lineWidth;
+                        if (lw > 0) {
+                            g.globalAlpha = opac * (o.strokeOpacity == null ? 1 : o.strokeOpacity);
+                            g.strokeStyle = color(g, o, stroke);
+                            g.lineWidth = lw;
+                            g.lineCap = (lc = o.strokeCap) != null ? lc : vg.config.render.lineCap;
+                            g.vgLineDash(o.strokeDash || null);
+                            g.vgLineDashOffset(o.strokeDashOffset || 0);
+                            g.strokeRect(x, y, w, h);
+                        }
+                    }
+                }
+            }
+
+            function drawRule(g, scene, bounds) {
+                if (!scene.items.length) return;
+                var items = scene.items,
+                    o, stroke, opac, lc, lw, x1, y1, x2, y2;
+
+                for (var i = 0, len = items.length; i < len; ++i) {
+                    o = items[i];
+                    if (bounds && !bounds.intersects(o.bounds))
+                        continue; // bounds check
+
+                    x1 = o.x || 0;
+                    y1 = o.y || 0;
+                    x2 = o.x2 != null ? o.x2 : x1;
+                    y2 = o.y2 != null ? o.y2 : y1;
+
+                    opac = o.opacity == null ? 1 : o.opacity;
+                    if (opac == 0) continue;
+
+                    if (stroke = o.stroke) {
+                        lw = (lw = o.strokeWidth) != null ? lw : vg.config.render.lineWidth;
+                        if (lw > 0) {
+                            g.globalAlpha = opac * (o.strokeOpacity == null ? 1 : o.strokeOpacity);
+                            g.strokeStyle = color(g, o, stroke);
+                            g.lineWidth = lw;
+                            g.lineCap = (lc = o.strokeCap) != null ? lc : vg.config.render.lineCap;
+                            g.vgLineDash(o.strokeDash || null);
+                            g.vgLineDashOffset(o.strokeDashOffset || 0);
+                            g.beginPath();
+                            g.moveTo(x1, y1);
+                            g.lineTo(x2, y2);
+                            g.stroke();
+                        }
+                    }
+                }
+            }
+
+            function drawImage(g, scene, bounds) {
+                if (!scene.items.length) return;
+                var renderer = this,
+                    items = scene.items, o;
+
+                for (var i = 0, len = items.length; i < len; ++i) {
+                    o = items[i];
+                    if (bounds && !bounds.intersects(o.bounds))
+                        continue; // bounds check
+
+                    if (!(o.image && o.image.url === o.url)) {
+                        o.image = renderer.loadImage(o.url);
+                        o.image.url = o.url;
+                    }
+
+                    var x, y, w, h, opac;
+                    w = o.width || (o.image && o.image.width) || 0;
+                    h = o.height || (o.image && o.image.height) || 0;
+                    x = (o.x || 0) - (o.align === "center"
+                            ? w / 2 : (o.align === "right" ? w : 0));
+                    y = (o.y || 0) - (o.baseline === "middle"
+                            ? h / 2 : (o.baseline === "bottom" ? h : 0));
+
+                    if (o.image.loaded) {
+                        g.globalAlpha = (opac = o.opacity) != null ? opac : 1;
+                        g.drawImage(o.image, x, y, w, h);
+                    }
+                }
+            }
+
+            function drawText(g, scene, bounds) {
+                if (!scene.items.length) return;
+                var items = scene.items,
+                    o, fill, stroke, opac, lw, x, y, r, t;
+
+                for (var i = 0, len = items.length; i < len; ++i) {
+                    o = items[i];
+                    if (bounds && !bounds.intersects(o.bounds))
+                        continue; // bounds check
+
+                    g.font = vg.scene.fontString(o);
+                    g.textAlign = o.align || "left";
+                    g.textBaseline = o.baseline || "alphabetic";
+
+                    opac = o.opacity == null ? 1 : o.opacity;
+                    if (opac == 0) continue;
+
+                    x = o.x || 0;
+                    y = o.y || 0;
+                    if (r = o.radius) {
+                        t = (o.theta || 0) - Math.PI / 2;
+                        x += r * Math.cos(t);
+                        y += r * Math.sin(t);
+                    }
+
+                    if (o.angle) {
+                        g.save();
+                        g.translate(x, y);
+                        g.rotate(o.angle * Math.PI / 180);
+                        x = o.dx || 0;
+                        y = o.dy || 0;
+                    } else {
+                        x += (o.dx || 0);
+                        y += (o.dy || 0);
+                    }
+
+                    if (fill = o.fill) {
+                        g.globalAlpha = opac * (o.fillOpacity == null ? 1 : o.fillOpacity);
+                        g.fillStyle = color(g, o, fill);
+                        g.fillText(o.text, x, y);
+                    }
+
+                    if (stroke = o.stroke) {
+                        lw = (lw = o.strokeWidth) != null ? lw : 1;
+                        if (lw > 0) {
+                            g.globalAlpha = opac * (o.strokeOpacity == null ? 1 : o.strokeOpacity);
+                            g.strokeStyle = color(o, stroke);
+                            g.lineWidth = lw;
+                            g.strokeText(o.text, x, y);
+                        }
+                    }
+
+                    if (o.angle) g.restore();
+                }
+            }
+
+            function drawAll(pathFunc) {
+                return function (g, scene, bounds) {
+                    drawPathAll(pathFunc, g, scene, bounds);
+                }
+            }
+
+            function drawOne(pathFunc) {
+                return function (g, scene, bounds) {
+                    if (!scene.items.length) return;
+                    if (bounds && !bounds.intersects(scene.items[0].bounds))
+                        return; // bounds check
+                    drawPathOne(pathFunc, g, scene.items[0], scene.items);
+                }
+            }
+
+            function drawGroup(g, scene, bounds) {
+                if (!scene.items.length) return;
+                var items = scene.items, group, axes, legends,
+                    renderer = this, gx, gy, gb, i, n, j, m;
+
+                drawRect(g, scene, bounds);
+
+                for (i = 0, n = items.length; i < n; ++i) {
+                    group = items[i];
+                    axes = group.axisItems || [];
+                    legends = group.legendItems || [];
+                    gx = group.x || 0;
+                    gy = group.y || 0;
+
+                    // render group contents
+                    g.save();
+                    g.translate(gx, gy);
+                    if (group.clip) {
+                        g.beginPath();
+                        g.rect(0, 0, group.width || 0, group.height || 0);
+                        g.clip();
+                    }
+
+                    if (bounds) bounds.translate(-gx, -gy);
+
+                    for (j = 0, m = axes.length; j < m; ++j) {
+                        if (axes[j].def.layer === "back") {
+                            renderer.draw(g, axes[j], bounds);
+                        }
+                    }
+                    for (j = 0, m = group.items.length; j < m; ++j) {
+                        renderer.draw(g, group.items[j], bounds);
+                    }
+                    for (j = 0, m = axes.length; j < m; ++j) {
+                        if (axes[j].def.layer !== "back") {
+                            renderer.draw(g, axes[j], bounds);
+                        }
+                    }
+                    for (j = 0, m = legends.length; j < m; ++j) {
+                        renderer.draw(g, legends[j], bounds);
+                    }
+
+                    if (bounds) bounds.translate(gx, gy);
+                    g.restore();
+                }
+            }
+
+            function color(g, o, value) {
+                return (value.id)
+                    ? gradient(g, value, o.bounds)
+                    : value;
+            }
+
+            function gradient(g, p, b) {
+                var w = b.width(),
+                    h = b.height(),
+                    x1 = b.x1 + p.x1 * w,
+                    y1 = b.y1 + p.y1 * h,
+                    x2 = b.x1 + p.x2 * w,
+                    y2 = b.y1 + p.y2 * h,
+                    grad = g.createLinearGradient(x1, y1, x2, y2),
+                    stop = p.stops,
+                    i, n;
+
+                for (i = 0, n = stop.length; i < n; ++i) {
+                    grad.addColorStop(stop[i].offset, stop[i].color);
+                }
+                return grad;
+            }
+
+            // hit testing
+
+            function pickGroup(g, scene, x, y, gx, gy) {
+                if (scene.items.length === 0 ||
+                    scene.bounds && !scene.bounds.contains(gx, gy)) {
+                    return false;
+                }
+                var items = scene.items, subscene, group, hit, dx, dy,
+                    handler = this, i, j;
+
+                for (i = items.length; --i >= 0;) {
+                    group = items[i];
+                    dx = group.x || 0;
+                    dy = group.y || 0;
+
+                    g.save();
+                    g.translate(dx, dy);
+                    for (j = group.items.length; --j >= 0;) {
+                        subscene = group.items[j];
+                        if (subscene.interactive === false) continue;
+                        hit = handler.pick(subscene, x, y, gx - dx, gy - dy);
+                        if (hit) {
+                            g.restore();
+                            return hit;
+                        }
+                    }
+                    g.restore();
+                }
+
+                return scene.interactive
+                    ? pickAll(hitTests.group, g, scene, x, y, gx, gy)
+                    : false;
+            }
+
+            function pickAll(test, g, scene, x, y, gx, gy) {
+                if (!scene.items.length) return false;
+                var o, b, i;
+
+                if (g._ratio !== 1) {
+                    x *= g._ratio;
+                    y *= g._ratio;
+                }
+
+                for (i = scene.items.length; --i >= 0;) {
+                    o = scene.items[i];
+                    b = o.bounds;
+                    // first hit test against bounding box
+                    if ((b && !b.contains(gx, gy)) || !b) continue;
+                    // if in bounding box, perform more careful test
+                    if (test(g, o, x, y, gx, gy)) return o;
+                }
+                return false;
+            }
+
+            function pickArea(g, scene, x, y, gx, gy) {
+                if (!scene.items.length) return false;
+                var items = scene.items,
+                    o, b, i, di, dd, od, dx, dy;
+
+                b = items[0].bounds;
+                if (b && !b.contains(gx, gy)) return false;
+                if (g._ratio !== 1) {
+                    x *= g._ratio;
+                    y *= g._ratio;
+                }
+                if (!hitTests.area(g, items, x, y)) return false;
+                return items[0];
+            }
+
+            function pickLine(g, scene, x, y, gx, gy) {
+                if (!scene.items.length) return false;
+                var items = scene.items,
+                    o, b, i, di, dd, od, dx, dy;
+
+                b = items[0].bounds;
+                if (b && !b.contains(gx, gy)) return false;
+                if (g._ratio !== 1) {
+                    x *= g._ratio;
+                    y *= g._ratio;
+                }
+                if (!hitTests.line(g, items, x, y)) return false;
+                return items[0];
+            }
+
+            function pick(test) {
+                return function (g, scene, x, y, gx, gy) {
+                    return pickAll(test, g, scene, x, y, gx, gy);
+                };
+            }
+
+            function textHit(g, o, x, y, gx, gy) {
+                if (!o.fontSize) return false;
+                if (!o.angle) return true; // bounds sufficient if no rotation
+
+                var b = vg.scene.bounds.text(o, tmpBounds, true),
+                    a = -o.angle * Math.PI / 180,
+                    cos = Math.cos(a),
+                    sin = Math.sin(a),
+                    x = o.x,
+                    y = o.y,
+                    px = cos * gx - sin * gy + (x - x * cos + y * sin),
+                    py = sin * gx + cos * gy + (y - x * sin - y * cos);
+
+                return b.contains(px, py);
+            }
+
+            var hitTests = {
+                text: textHit,
+                rect: function (g, o, x, y) {
+                    return true;
+                }, // bounds test is sufficient
+                image: function (g, o, x, y) {
+                    return true;
+                }, // bounds test is sufficient
+                group: function (g, o, x, y) {
+                    return o.fill || o.stroke;
+                },
+                rule: function (g, o, x, y) {
+                    if (!g.isPointInStroke) return false;
+                    ruleStroke(g, o);
+                    return g.isPointInStroke(x, y);
+                },
+                line: function (g, s, x, y) {
+                    if (!g.isPointInStroke) return false;
+                    lineStroke(g, s);
+                    return g.isPointInStroke(x, y);
+                },
+                arc: function (g, o, x, y) {
+                    arcPath(g, o);
+                    return g.isPointInPath(x, y);
+                },
+                area: function (g, s, x, y) {
+                    areaPath(g, s);
+                    return g.isPointInPath(x, y);
+                },
+                path: function (g, o, x, y) {
+                    pathPath(g, o);
+                    return g.isPointInPath(x, y);
+                },
+                symbol: function (g, o, x, y) {
+                    symbolPath(g, o);
+                    return g.isPointInPath(x, y);
+                }
+            };
+
+            return {
+                draw: {
+                    group: drawGroup,
+                    area: drawOne(areaPath),
+                    line: drawOne(linePath),
+                    arc: drawAll(arcPath),
+                    path: drawAll(pathPath),
+                    symbol: drawAll(symbolPath),
+                    rect: drawRect,
+                    rule: drawRule,
+                    text: drawText,
+                    image: drawImage,
+                    drawOne: drawOne, // expose for extensibility
+                    drawAll: drawAll  // expose for extensibility
+                },
+                pick: {
+                    group: pickGroup,
+                    area: pickArea,
+                    line: pickLine,
+                    arc: pick(hitTests.arc),
+                    path: pick(hitTests.path),
+                    symbol: pick(hitTests.symbol),
+                    rect: pick(hitTests.rect),
+                    rule: pick(hitTests.rule),
+                    text: pick(hitTests.text),
+                    image: pick(hitTests.image),
+                    pickAll: pickAll  // expose for extensibility
+                }
+            };
+
+        })();
+        vg.canvas.Renderer = (function () {
+            var renderer = function () {
+                this._ctx = null;
+                this._el = null;
+                this._imgload = 0;
+            };
+
+            var prototype = renderer.prototype;
+
+            prototype.initialize = function (el, width, height, pad) {
+                this._el = el;
+
+                if (!el) return this; // early exit if no DOM element
+
+                // select canvas element
+                var canvas = d3.select(el)
+                    .selectAll("canvas.marks")
+                    .data([1]);
+
+                // create new canvas element if needed
+                canvas.enter()
+                    .append("canvas")
+                    .attr("class", "marks");
+
+                // remove extraneous canvas if needed
+                canvas.exit().remove();
+
+                return this.resize(width, height, pad);
+            };
+
+            prototype.resize = function (width, height, pad) {
+                this._width = width;
+                this._height = height;
+                this._padding = pad;
+
+                if (this._el) {
+                    var canvas = d3.select(this._el).select("canvas.marks");
+
+                    // initialize canvas attributes
+                    canvas
+                        .attr("width", width + pad.left + pad.right)
+                        .attr("height", height + pad.top + pad.bottom);
+
+                    // get the canvas graphics context
+                    var s;
+                    this._ctx = canvas.node().getContext("2d");
+                    this._ctx._ratio = (s = scaleCanvas(canvas.node(), this._ctx) || 1);
+                    this._ctx.setTransform(s, 0, 0, s, s * pad.left, s * pad.top);
+                }
+
+                initializeLineDash(this._ctx);
+                return this;
+            };
+
+            function scaleCanvas(canvas, ctx) {
+                // get canvas pixel data
+                var devicePixelRatio = window.devicePixelRatio || 1,
+                    backingStoreRatio = (
+                        ctx.webkitBackingStorePixelRatio ||
+                        ctx.mozBackingStorePixelRatio ||
+                        ctx.msBackingStorePixelRatio ||
+                        ctx.oBackingStorePixelRatio ||
+                        ctx.backingStorePixelRatio) || 1,
+                    ratio = devicePixelRatio / backingStoreRatio;
+
+                if (devicePixelRatio !== backingStoreRatio) {
+                    var w = canvas.width, h = canvas.height;
+                    // set actual and visible canvas size
+                    canvas.setAttribute("width", w * ratio);
+                    canvas.setAttribute("height", h * ratio);
+                    canvas.style.width = w + 'px';
+                    canvas.style.height = h + 'px';
+                }
+                return ratio;
+            }
+
+            function initializeLineDash(ctx) {
+                if (ctx.vgLineDash) return; // already set
+
+                var NODASH = [];
+                if (ctx.setLineDash) {
+                    ctx.vgLineDash = function (dash) {
+                        this.setLineDash(dash || NODASH);
+                    };
+                    ctx.vgLineDashOffset = function (off) {
+                        this.lineDashOffset = off;
+                    };
+                } else if (ctx.webkitLineDash !== undefined) {
+                    ctx.vgLineDash = function (dash) {
+                        this.webkitLineDash = dash || NODASH;
+                    };
+                    ctx.vgLineDashOffset = function (off) {
+                        this.webkitLineDashOffset = off;
+                    };
+                } else if (ctx.mozDash !== undefined) {
+                    ctx.vgLineDash = function (dash) {
+                        this.mozDash = dash;
+                    };
+                    ctx.vgLineDashOffset = function (off) { /* unsupported */
+                    };
+                } else {
+                    ctx.vgLineDash = function (dash) { /* unsupported */
+                    };
+                    ctx.vgLineDashOffset = function (off) { /* unsupported */
+                    };
+                }
+            }
+
+            prototype.context = function (ctx) {
+                if (ctx) {
+                    this._ctx = ctx;
+                    return this;
+                }
+                else return this._ctx;
+            };
+
+            prototype.element = function () {
+                return this._el;
+            };
+
+            prototype.pendingImages = function () {
+                return this._imgload;
+            };
+
+            function translatedBounds(item, bounds) {
+                var b = new vg.Bounds(bounds);
+                while ((item = item.mark.group) != null) {
+                    b.translate(item.x || 0, item.y || 0);
+                }
+                return b;
+            }
+
+            function getBounds(items) {
+                return !items ? null :
+                    vg.array(items).reduce(function (b, item) {
+                        return b.union(translatedBounds(item, item.bounds))
+                            .union(translatedBounds(item, item['bounds:prev']));
+                    }, new vg.Bounds());
+            }
+
+            function setBounds(g, bounds) {
+                var bbox = null;
+                if (bounds) {
+                    bbox = (new vg.Bounds(bounds)).round();
+                    g.beginPath();
+                    g.rect(bbox.x1, bbox.y1, bbox.width(), bbox.height());
+                    g.clip();
+                }
+                return bbox;
+            }
+
+            prototype.render = function (scene, items) {
+                var g = this._ctx,
+                    pad = this._padding,
+                    w = this._width + pad.left + pad.right,
+                    h = this._height + pad.top + pad.bottom,
+                    bb = null, bb2;
+
+                // setup
+                this._scene = scene;
+                g.save();
+                bb = setBounds(g, getBounds(items));
+                g.clearRect(-pad.left, -pad.top, w, h);
+
+                // render
+                this.draw(g, scene, bb);
+
+                // render again to handle possible bounds change
+                if (items) {
+                    g.restore();
+                    g.save();
+                    bb2 = setBounds(g, getBounds(items));
+                    if (!bb.encloses(bb2)) {
+                        g.clearRect(-pad.left, -pad.top, w, h);
+                        this.draw(g, scene, bb2);
+                    }
+                }
+
+                // takedown
+                g.restore();
+                this._scene = null;
+            };
+
+            prototype.draw = function (ctx, scene, bounds) {
+                var marktype = scene.marktype,
+                    renderer = vg.canvas.marks.draw[marktype];
+                renderer.call(this, ctx, scene, bounds);
+            };
+
+            prototype.renderAsync = function (scene) {
+                // TODO make safe for multiple scene rendering?
+                var renderer = this;
+                if (renderer._async_id) {
+                    clearTimeout(renderer._async_id);
+                }
+                renderer._async_id = setTimeout(function () {
+                    renderer.render(scene);
+                    delete renderer._async_id;
+                }, 50);
+            };
+
+            prototype.loadImage = function (uri) {
+                var renderer = this,
+                    scene = renderer._scene,
+                    image = null, url;
+
+                renderer._imgload += 1;
+                if (vg.config.isNode) {
+                    image = new (require("canvas").Image)();
+                    vg.data.load(uri, function (err, data) {
+                        if (err) {
+                            vg.error(err);
+                            return;
+                        }
+                        image.src = data;
+                        image.loaded = true;
+                        renderer._imgload -= 1;
+                    });
+                } else {
+                    image = new Image();
+                    url = vg.config.baseURL + uri;
+                    image.onload = function () {
+                        vg.log("LOAD IMAGE: " + url);
+                        image.loaded = true;
+                        renderer._imgload -= 1;
+                        renderer.renderAsync(scene);
+                    };
+                    image.src = url;
+                }
+
+                return image;
+            };
+
+            return renderer;
+        })();
+        vg.canvas.Handler = (function () {
+            var handler = function (el, model) {
+                this._active = null;
+                this._handlers = {};
+                if (el) this.initialize(el);
+                if (model) this.model(model);
+            };
+
+            var prototype = handler.prototype;
+
+            prototype.initialize = function (el, pad, obj) {
+                this._el = d3.select(el).node();
+                this._canvas = d3.select(el).select("canvas.marks").node();
+                this._padding = pad;
+                this._obj = obj || null;
+
+                // add event listeners
+                var canvas = this._canvas, that = this;
+                events.forEach(function (type) {
+                    canvas.addEventListener(type, function (evt) {
+                        prototype[type].call(that, evt);
+                    });
+                });
+
+                return this;
+            };
+
+            prototype.padding = function (pad) {
+                this._padding = pad;
+                return this;
+            };
+
+            prototype.model = function (model) {
+                if (!arguments.length) return this._model;
+                this._model = model;
+                return this;
+            };
+
+            prototype.handlers = function () {
+                var h = this._handlers;
+                return vg.keys(h).reduce(function (a, k) {
+                    return h[k].reduce(function (a, x) {
+                        return (a.push(x), a);
+                    }, a);
+                }, []);
+            };
+
+            // setup events
+            var events = [
+                "mousedown",
+                "mouseup",
+                "click",
+                "dblclick",
+                "wheel",
+                "keydown",
+                "keypress",
+                "keyup",
+                "mousewheel"
+            ];
+            events.forEach(function (type) {
+                prototype[type] = function (evt) {
+                    this.fire(type, evt);
+                };
+            });
+            events.push("mousemove");
+            events.push("mouseout");
+
+            function eventName(name) {
+                var i = name.indexOf(".");
+                return i < 0 ? name : name.slice(0, i);
+            }
+
+            prototype.mousemove = function (evt) {
+                var pad = this._padding,
+                    b = evt.target.getBoundingClientRect(),
+                    x = evt.clientX - b.left,
+                    y = evt.clientY - b.top,
+                    a = this._active,
+                    p = this.pick(this._model.scene(), x, y, x - pad.left, y - pad.top);
+
+                if (p === a) {
+                    this.fire("mousemove", evt);
+                    return;
+                } else if (a) {
+                    this.fire("mouseout", evt);
+                }
+                this._active = p;
+                if (p) {
+                    this.fire("mouseover", evt);
+                }
+            };
+
+            prototype.mouseout = function (evt) {
+                if (this._active) {
+                    this.fire("mouseout", evt);
+                }
+                this._active = null;
+            };
+
+            // to keep firefox happy
+            prototype.DOMMouseScroll = function (evt) {
+                this.fire("mousewheel", evt);
+            };
+
+            // fire an event
+            prototype.fire = function (type, evt) {
+                var a = this._active,
+                    h = this._handlers[type];
+                if (a && h) {
+                    for (var i = 0, len = h.length; i < len; ++i) {
+                        h[i].handler.call(this._obj, evt, a);
+                    }
+                }
+            };
+
+            // add an event handler
+            prototype.on = function (type, handler) {
+                var name = eventName(type),
+                    h = this._handlers;
+                h = h[name] || (h[name] = []);
+                h.push({
+                    type: type,
+                    handler: handler
+                });
+                return this;
+            };
+
+            // remove an event handler
+            prototype.off = function (type, handler) {
+                var name = eventName(type),
+                    h = this._handlers[name];
+                if (!h) return;
+                for (var i = h.length; --i >= 0;) {
+                    if (h[i].type !== type) continue;
+                    if (!handler || h[i].handler === handler) h.splice(i, 1);
+                }
+                return this;
+            };
+
+            // retrieve the current canvas context
+            prototype.context = function () {
+                return this._canvas.getContext("2d");
+            };
+
+            // find the scenegrap

<TRUNCATED>