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:15:04 UTC
[32/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_Count/Member_Count/js/vega.js
----------------------------------------------------------------------
diff --git a/extensions/das/metering-service/capps/stratos-metering-service/Gadget_Member_Count/Member_Count/js/vega.js b/extensions/das/metering-service/capps/stratos-metering-service/Gadget_Member_Count/Member_Count/js/vega.js
new file mode 100644
index 0000000..019e421
--- /dev/null
+++ b/extensions/das/metering-service/capps/stratos-metering-service/Gadget_Member_Count/Member_Count/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 scenegraph item at the current mouse position
+
<TRUNCATED>