StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
StackGenVis/frontend/node_modules/vega-scenegraph/build/vega-scenegraph.js

5039 lines
130 KiB

4 years ago
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vega-util'), require('vega-canvas'), require('vega-loader'), require('d3-shape'), require('d3-path')) :
typeof define === 'function' && define.amd ? define(['exports', 'vega-util', 'vega-canvas', 'vega-loader', 'd3-shape', 'd3-path'], factory) :
(global = global || self, factory(global.vega = {}, global.vega, global.vega, global.vega, global.d3, global.d3));
}(this, (function (exports, vegaUtil, vegaCanvas, vegaLoader, d3Shape, d3Path) { 'use strict';
function Bounds(b) {
this.clear();
if (b) this.union(b);
}
var prototype = Bounds.prototype;
prototype.clone = function() {
return new Bounds(this);
};
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.empty = function() {
return (
this.x1 === +Number.MAX_VALUE &&
this.y1 === +Number.MAX_VALUE &&
this.x2 === -Number.MAX_VALUE &&
this.y2 === -Number.MAX_VALUE
);
};
prototype.equals = function(b) {
return (
this.x1 === b.x1 &&
this.y1 === b.y1 &&
this.x2 === b.x2 &&
this.y2 === b.y2
);
};
prototype.set = function(x1, y1, x2, y2) {
if (x2 < x1) {
this.x2 = x1;
this.x1 = x2;
} else {
this.x1 = x1;
this.x2 = x2;
}
if (y2 < y1) {
this.y2 = y1;
this.y1 = y2;
} else {
this.y1 = y1;
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) {
const p = this.rotatedPoints(angle, x, y);
return this.clear()
.add(p[0], p[1])
.add(p[2], p[3])
.add(p[4], p[5])
.add(p[6], p[7]);
};
prototype.rotatedPoints = function(angle, x, y) {
var {x1, y1, x2, y2} = this,
cos = Math.cos(angle),
sin = Math.sin(angle),
cx = x - x*cos + y*sin,
cy = y - x*sin - y*cos;
return [
cos*x1 - sin*y1 + cx, sin*x1 + cos*y1 + cy,
cos*x1 - sin*y2 + cx, sin*x1 + cos*y2 + cy,
cos*x2 - sin*y1 + cx, sin*x2 + cos*y1 + cy,
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.intersect = 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.alignsWith = 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;
};
var gradient_id = 0;
const patternPrefix = 'p_';
function isGradient(value) {
return value && value.gradient;
}
function gradientRef(g, defs, base) {
let id = g.id,
type = g.gradient,
prefix = type === 'radial' ? patternPrefix : '';
// check id, assign default values as needed
if (!id) {
id = g.id = 'gradient_' + (gradient_id++);
if (type === 'radial') {
g.x1 = get(g.x1, 0.5);
g.y1 = get(g.y1, 0.5);
g.r1 = get(g.r1, 0);
g.x2 = get(g.x2, 0.5);
g.y2 = get(g.y2, 0.5);
g.r2 = get(g.r2, 0.5);
prefix = patternPrefix;
} else {
g.x1 = get(g.x1, 0);
g.y1 = get(g.y1, 0);
g.x2 = get(g.x2, 1);
g.y2 = get(g.y2, 0);
}
}
// register definition
defs[id] = g;
// return url reference
return 'url(' + (base || '') + '#' + prefix + id + ')';
}
function get(val, def) {
return val != null ? val : def;
}
function Gradient(p0, p1) {
var stops = [], gradient;
return gradient = {
gradient: 'linear',
x1: p0 ? p0[0] : 0,
y1: p0 ? p0[1] : 0,
x2: p1 ? p1[0] : 1,
y2: p1 ? p1[1] : 0,
stops: stops,
stop: function(offset, color) {
stops.push({offset: offset, color: color});
return gradient;
}
};
}
function Item(mark) {
this.mark = mark;
this.bounds = (this.bounds || new Bounds());
}
function GroupItem(mark) {
Item.call(this, mark);
this.items = (this.items || []);
}
vegaUtil.inherits(GroupItem, Item);
function ResourceLoader(customLoader) {
this._pending = 0;
this._loader = customLoader || vegaLoader.loader();
}
var prototype$1 = ResourceLoader.prototype;
prototype$1.pending = function() {
return this._pending;
};
function increment(loader) {
loader._pending += 1;
}
function decrement(loader) {
loader._pending -= 1;
}
prototype$1.sanitizeURL = function(uri) {
var loader = this;
increment(loader);
return loader._loader.sanitize(uri, {context:'href'})
.then(function(opt) {
decrement(loader);
return opt;
})
.catch(function() {
decrement(loader);
return null;
});
};
prototype$1.loadImage = function(uri) {
var loader = this,
Image = vegaCanvas.image();
increment(loader);
return loader._loader
.sanitize(uri, {context: 'image'})
.then(function(opt) {
var url = opt.href;
if (!url || !Image) throw {url: url};
var img = new Image();
img.onload = function() {
decrement(loader);
};
img.onerror = function() {
decrement(loader);
};
img.src = url;
return img;
})
.catch(function(e) {
decrement(loader);
return {complete: false, width: 0, height: 0, src: e && e.url || ''};
});
};
prototype$1.ready = function() {
var loader = this;
return new Promise(function(accept) {
function poll(value) {
if (!loader.pending()) accept(value);
else setTimeout(function() { poll(true); }, 10);
}
poll(false);
});
};
var lookup = {
'basis': {
curve: d3Shape.curveBasis
},
'basis-closed': {
curve: d3Shape.curveBasisClosed
},
'basis-open': {
curve: d3Shape.curveBasisOpen
},
'bundle': {
curve: d3Shape.curveBundle,
tension: 'beta',
value: 0.85
},
'cardinal': {
curve: d3Shape.curveCardinal,
tension: 'tension',
value: 0
},
'cardinal-open': {
curve: d3Shape.curveCardinalOpen,
tension: 'tension',
value: 0
},
'cardinal-closed': {
curve: d3Shape.curveCardinalClosed,
tension: 'tension',
value: 0
},
'catmull-rom': {
curve: d3Shape.curveCatmullRom,
tension: 'alpha',
value: 0.5
},
'catmull-rom-closed': {
curve: d3Shape.curveCatmullRomClosed,
tension: 'alpha',
value: 0.5
},
'catmull-rom-open': {
curve: d3Shape.curveCatmullRomOpen,
tension: 'alpha',
value: 0.5
},
'linear': {
curve: d3Shape.curveLinear
},
'linear-closed': {
curve: d3Shape.curveLinearClosed
},
'monotone': {
horizontal: d3Shape.curveMonotoneY,
vertical: d3Shape.curveMonotoneX
},
'natural': {
curve: d3Shape.curveNatural
},
'step': {
curve: d3Shape.curveStep
},
'step-after': {
curve: d3Shape.curveStepAfter
},
'step-before': {
curve: d3Shape.curveStepBefore
}
};
function curves(type, orientation, tension) {
var entry = vegaUtil.hasOwnProperty(lookup, type) && lookup[type],
curve = null;
if (entry) {
curve = entry.curve || entry[orientation || 'vertical'];
if (entry.tension && tension != null) {
curve = curve[entry.tension](tension);
}
}
return curve;
}
// Path parsing and rendering code adapted from fabric.js -- Thanks!
var cmdlen = { m:2, l:2, h:1, v:1, c:6, s:4, q:4, t:2, a:7 },
regexp = [/([MLHVCSQTAZmlhvcsqtaz])/g, /###/, /(\d)([-+])/g, /\s|,|###/];
function pathParse(pathstr) {
var result = [],
path,
curr,
chunks,
parsed, param,
cmd, len, i, j, n, m;
// First, break path into command sequence
path = pathstr
.slice()
.replace(regexp[0], '###$1')
.split(regexp[1])
.slice(1);
// Next, parse each command in turn
for (i=0, n=path.length; i<n; ++i) {
curr = path[i];
chunks = curr
.slice(1)
.trim()
.replace(regexp[2],'$1###$2')
.split(regexp[3]);
cmd = curr.charAt(0);
parsed = [cmd];
for (j=0, m=chunks.length; j<m; ++j) {
if ((param = +chunks[j]) === param) { // not NaN
parsed.push(param);
}
}
len = cmdlen[cmd.toLowerCase()];
if (parsed.length-1 > len) {
for (j=1, m=parsed.length; j<m; j+=len) {
result.push([cmd].concat(parsed.slice(j, j+len)));
}
}
else {
result.push(parsed);
}
}
return result;
}
const DegToRad = Math.PI / 180;
const Epsilon = 1e-14;
const HalfPi = Math.PI / 2;
const Tau = Math.PI * 2;
const HalfSqrt3 = Math.sqrt(3) / 2;
var segmentCache = {};
var bezierCache = {};
var join = [].join;
// Copied from Inkscape svgtopdf, thanks!
function segments(x, y, rx, ry, large, sweep, rotateX, ox, oy) {
var key = join.call(arguments);
if (segmentCache[key]) {
return segmentCache[key];
}
var th = rotateX * DegToRad;
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 += Tau;
} else if (th_arc > 0 && sweep === 0) {
th_arc -= Tau;
}
var segs = Math.ceil(Math.abs(th_arc / (HalfPi + 0.001)));
var result = [];
for (var i=0; i<segs; ++i) {
var th2 = th0 + i * th_arc / segs;
var th3 = th0 + (i+1) * th_arc / segs;
result[i] = [xc, yc, th2, th3, rx, ry, sin_th, cos_th];
}
return (segmentCache[key] = result);
}
function bezier(params) {
var key = join.call(params);
if (bezierCache[key]) {
return bezierCache[key];
}
var cx = params[0],
cy = params[1],
th0 = params[2],
th1 = params[3],
rx = params[4],
ry = params[5],
sin_th = params[6],
cos_th = params[7];
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 (bezierCache[key] = [
a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
a00 * x3 + a01 * y3, a10 * x3 + a11 * y3
]);
}
var temp = ['l', 0, 0, 0, 0, 0, 0, 0];
function scale(current, sX, sY) {
var c = (temp[0] = current[0]);
if (c === 'a' || c === 'A') {
temp[1] = sX * current[1];
temp[2] = sY * current[2];
temp[3] = current[3];
temp[4] = current[4];
temp[5] = current[5];
temp[6] = sX * current[6];
temp[7] = sY * current[7];
} else if (c === 'h' || c === 'H') {
temp[1] = sX * current[1];
} else if (c === 'v' || c === 'V') {
temp[1] = sY * current[1];
} else {
for (var i=1, n=current.length; i<n; ++i) {
temp[i] = (i % 2 == 1 ? sX : sY) * current[i];
}
}
return temp;
}
function pathRender(context, path, l, t, sX, sY) {
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;
if (l == null) l = 0;
if (t == null) t = 0;
if (sX == null) sX = 1;
if (sY == null) sY = sX;
if (context.beginPath) context.beginPath();
for (var i=0, len=path.length; i<len; ++i) {
current = path[i];
if (sX !== 1 || sY !== 1) {
current = scale(current, sX, sY);
}
switch (current[0]) { // first letter
case 'l': // lineto, relative
x += current[1];
y += current[2];
context.lineTo(x + l, y + t);
break;
case 'L': // lineto, absolute
x = current[1];
y = current[2];
context.lineTo(x + l, y + t);
break;
case 'h': // horizontal lineto, relative
x += current[1];
context.lineTo(x + l, y + t);
break;
case 'H': // horizontal lineto, absolute
x = current[1];
context.lineTo(x + l, y + t);
break;
case 'v': // vertical lineto, relative
y += current[1];
context.lineTo(x + l, y + t);
break;
case 'V': // verical lineto, absolute
y = current[1];
context.lineTo(x + l, y + t);
break;
case 'm': // moveTo, relative
x += current[1];
y += current[2];
context.moveTo(x + l, y + t);
break;
case 'M': // moveTo, absolute
x = current[1];
y = current[2];
context.moveTo(x + l, y + t);
break;
case 'c': // bezierCurveTo, relative
tempX = x + current[5];
tempY = y + current[6];
controlX = x + current[3];
controlY = y + current[4];
context.bezierCurveTo(
x + current[1] + l, // x1
y + current[2] + t, // y1
controlX + l, // x2
controlY + t, // y2
tempX + l,
tempY + t
);
x = tempX;
y = tempY;
break;
case 'C': // bezierCurveTo, absolute
x = current[5];
y = current[6];
controlX = current[3];
controlY = current[4];
context.bezierCurveTo(
current[1] + l,
current[2] + t,
controlX + l,
controlY + t,
x + l,
y + t
);
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;
context.bezierCurveTo(
controlX + l,
controlY + t,
x + current[1] + l,
y + current[2] + t,
tempX + l,
tempY + t
);
// 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;
context.bezierCurveTo(
controlX + l,
controlY + t,
current[1] + l,
current[2] + t,
tempX + l,
tempY + t
);
x = tempX;
y = 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];
context.quadraticCurveTo(
controlX + l,
controlY + t,
tempX + l,
tempY + t
);
x = tempX;
y = tempY;
break;
case 'Q': // quadraticCurveTo, absolute
tempX = current[3];
tempY = current[4];
context.quadraticCurveTo(
current[1] + l,
current[2] + t,
tempX + l,
tempY + t
);
x = tempX;
y = tempY;
controlX = current[1];
controlY = current[2];
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;
context.quadraticCurveTo(
controlX + l,
controlY + t,
tempX + l,
tempY + t
);
x = tempX;
y = tempY;
controlX = x + current[1];
controlY = y + current[2];
break;
case 'T':
tempX = current[1];
tempY = current[2];
// calculate reflection of previous control points
controlX = 2 * x - controlX;
controlY = 2 * y - controlY;
context.quadraticCurveTo(
controlX + l,
controlY + t,
tempX + l,
tempY + t
);
x = tempX;
y = tempY;
break;
case 'a':
drawArc(context, x + l, y + t, [
current[1],
current[2],
current[3],
current[4],
current[5],
current[6] + x + l,
current[7] + y + t
]);
x += current[6];
y += current[7];
break;
case 'A':
drawArc(context, x + l, y + t, [
current[1],
current[2],
current[3],
current[4],
current[5],
current[6] + l,
current[7] + t
]);
x = current[6];
y = current[7];
break;
case 'z':
case 'Z':
context.closePath();
break;
}
previous = current;
}
}
function drawArc(context, x, y, coords) {
var seg = segments(
coords[5], // end x
coords[6], // end y
coords[0], // radius x
coords[1], // radius y
coords[3], // large flag
coords[4], // sweep flag
coords[2], // rotation
x, y
);
for (var i=0; i<seg.length; ++i) {
var bez = bezier(seg[i]);
context.bezierCurveTo(bez[0], bez[1], bez[2], bez[3], bez[4], bez[5]);
}
}
var Tan30 = 0.5773502691896257;
var builtins = {
'circle': {
draw: function(context, size) {
var r = Math.sqrt(size) / 2;
context.moveTo(r, 0);
context.arc(0, 0, r, 0, Tau);
}
},
'cross': {
draw: function(context, size) {
var r = Math.sqrt(size) / 2,
s = r / 2.5;
context.moveTo(-r, -s);
context.lineTo(-r, s);
context.lineTo(-s, s);
context.lineTo(-s, r);
context.lineTo(s, r);
context.lineTo(s, s);
context.lineTo(r, s);
context.lineTo(r, -s);
context.lineTo(s, -s);
context.lineTo(s, -r);
context.lineTo(-s, -r);
context.lineTo(-s, -s);
context.closePath();
}
},
'diamond': {
draw: function(context, size) {
var r = Math.sqrt(size) / 2;
context.moveTo(-r, 0);
context.lineTo(0, -r);
context.lineTo(r, 0);
context.lineTo(0, r);
context.closePath();
}
},
'square': {
draw: function(context, size) {
var w = Math.sqrt(size),
x = -w / 2;
context.rect(x, x, w, w);
}
},
'arrow': {
draw: function(context, size) {
var r = Math.sqrt(size) / 2,
s = r / 7,
t = r / 2.5,
v = r / 8;
context.moveTo(-s, r);
context.lineTo(s, r);
context.lineTo(s, -v);
context.lineTo(t, -v);
context.lineTo(0, -r);
context.lineTo(-t, -v);
context.lineTo(-s, -v);
context.closePath();
}
},
'wedge': {
draw: function(context, size) {
var r = Math.sqrt(size) / 2,
h = HalfSqrt3 * r,
o = (h - r * Tan30),
b = r / 4;
context.moveTo(0, -h - o);
context.lineTo(-b, h - o);
context.lineTo(b, h - o);
context.closePath();
}
},
'triangle': {
draw: function(context, size) {
var r = Math.sqrt(size) / 2,
h = HalfSqrt3 * r,
o = (h - r * Tan30);
context.moveTo(0, -h - o);
context.lineTo(-r, h - o);
context.lineTo(r, h - o);
context.closePath();
}
},
'triangle-up': {
draw: function(context, size) {
var r = Math.sqrt(size) / 2,
h = HalfSqrt3 * r;
context.moveTo(0, -h);
context.lineTo(-r, h);
context.lineTo(r, h);
context.closePath();
}
},
'triangle-down': {
draw: function(context, size) {
var r = Math.sqrt(size) / 2,
h = HalfSqrt3 * r;
context.moveTo(0, h);
context.lineTo(-r, -h);
context.lineTo(r, -h);
context.closePath();
}
},
'triangle-right': {
draw: function(context, size) {
var r = Math.sqrt(size) / 2,
h = HalfSqrt3 * r;
context.moveTo(h, 0);
context.lineTo(-h, -r);
context.lineTo(-h, r);
context.closePath();
}
},
'triangle-left': {
draw: function(context, size) {
var r = Math.sqrt(size) / 2,
h = HalfSqrt3 * r;
context.moveTo(-h, 0);
context.lineTo(h, -r);
context.lineTo(h, r);
context.closePath();
}
},
'stroke': {
draw: function(context, size) {
var r = Math.sqrt(size) / 2;
context.moveTo(-r, 0);
context.lineTo(r, 0);
}
}
};
function symbols(_) {
return vegaUtil.hasOwnProperty(builtins, _) ? builtins[_] : customSymbol(_);
}
var custom = {};
function customSymbol(path) {
if (!vegaUtil.hasOwnProperty(custom, path)) {
var parsed = pathParse(path);
custom[path] = {
draw: function(context, size) {
pathRender(context, parsed, 0, 0, Math.sqrt(size) / 2);
}
};
}
return custom[path];
}
// See http://spencermortensen.com/articles/bezier-circle/
const C = 0.448084975506; // C = 1 - c
function rectangleX(d) {
return d.x;
}
function rectangleY(d) {
return d.y;
}
function rectangleWidth(d) {
return d.width;
}
function rectangleHeight(d) {
return d.height;
}
function number(_) {
return typeof _ === 'function' ? _ : () => +_;
}
function clamp(value, min, max) {
return Math.max(min, Math.min(value, max));
}
function vg_rect() {
var x = rectangleX,
y = rectangleY,
width = rectangleWidth,
height = rectangleHeight,
crTL = number(0),
crTR = crTL,
crBL = crTL,
crBR = crTL,
context = null;
function rectangle(_, x0, y0) {
var buffer,
x1 = x0 != null ? x0 : +x.call(this, _),
y1 = y0 != null ? y0 : +y.call(this, _),
w = +width.call(this, _),
h = +height.call(this, _),
s = Math.min(w, h) / 2,
tl = clamp(+crTL.call(this, _), 0, s),
tr = clamp(+crTR.call(this, _), 0, s),
bl = clamp(+crBL.call(this, _), 0, s),
br = clamp(+crBR.call(this, _), 0, s);
if (!context) context = buffer = d3Path.path();
if (tl <= 0 && tr <= 0 && bl <= 0 && br <= 0) {
context.rect(x1, y1, w, h);
} else {
var x2 = x1 + w,
y2 = y1 + h;
context.moveTo(x1 + tl, y1);
context.lineTo(x2 - tr, y1);
context.bezierCurveTo(x2 - C * tr, y1, x2, y1 + C * tr, x2, y1 + tr);
context.lineTo(x2, y2 - br);
context.bezierCurveTo(x2, y2 - C * br, x2 - C * br, y2, x2 - br, y2);
context.lineTo(x1 + bl, y2);
context.bezierCurveTo(x1 + C * bl, y2, x1, y2 - C * bl, x1, y2 - bl);
context.lineTo(x1, y1 + tl);
context.bezierCurveTo(x1, y1 + C * tl, x1 + C * tl, y1, x1 + tl, y1);
context.closePath();
}
if (buffer) {
context = null;
return buffer + '' || null;
}
}
rectangle.x = function(_) {
if (arguments.length) {
x = number(_);
return rectangle;
} else {
return x;
}
};
rectangle.y = function(_) {
if (arguments.length) {
y = number(_);
return rectangle;
} else {
return y;
}
};
rectangle.width = function(_) {
if (arguments.length) {
width = number(_);
return rectangle;
} else {
return width;
}
};
rectangle.height = function(_) {
if (arguments.length) {
height = number(_);
return rectangle;
} else {
return height;
}
};
rectangle.cornerRadius = function(tl, tr, br, bl) {
if (arguments.length) {
crTL = number(tl);
crTR = tr != null ? number(tr) : crTL;
crBR = br != null ? number(br) : crTL;
crBL = bl != null ? number(bl) : crTR;
return rectangle;
} else {
return crTL;
}
};
rectangle.context = function(_) {
if (arguments.length) {
context = _ == null ? null : _;
return rectangle;
} else {
return context;
}
};
return rectangle;
}
function vg_trail() {
var x,
y,
size,
defined,
context = null,
ready, x1, y1, r1;
function point(x2, y2, w2) {
var r2 = w2 / 2;
if (ready) {
var ux = y1 - y2,
uy = x2 - x1;
if (ux || uy) {
// get normal vector
var ud = Math.sqrt(ux * ux + uy * uy),
rx = (ux /= ud) * r1,
ry = (uy /= ud) * r1,
t = Math.atan2(uy, ux);
// draw segment
context.moveTo(x1 - rx, y1 - ry);
context.lineTo(x2 - ux * r2, y2 - uy * r2);
context.arc(x2, y2, r2, t - Math.PI, t);
context.lineTo(x1 + rx, y1 + ry);
context.arc(x1, y1, r1, t, t + Math.PI);
} else {
context.arc(x2, y2, r2, 0, Tau);
}
context.closePath();
} else {
ready = 1;
}
x1 = x2;
y1 = y2;
r1 = r2;
}
function trail(data) {
var i,
n = data.length,
d,
defined0 = false,
buffer;
if (context == null) context = buffer = d3Path.path();
for (i = 0; i <= n; ++i) {
if (!(i < n && defined(d = data[i], i, data)) === defined0) {
if (defined0 = !defined0) ready = 0;
}
if (defined0) point(+x(d, i, data), +y(d, i, data), +size(d, i, data));
}
if (buffer) {
context = null;
return buffer + '' || null;
}
}
trail.x = function(_) {
if (arguments.length) {
x = _;
return trail;
} else {
return x;
}
};
trail.y = function(_) {
if (arguments.length) {
y = _;
return trail;
} else {
return y;
}
};
trail.size = function(_) {
if (arguments.length) {
size = _;
return trail;
} else {
return size;
}
};
trail.defined = function(_) {
if (arguments.length) {
defined = _;
return trail;
} else {
return defined;
}
};
trail.context = function(_) {
if (arguments.length) {
if (_ == null) {
context = null;
} else {
context = _;
}
return trail;
} else {
return context;
}
};
return trail;
}
function value(a, b) {
return a != null ? a : b;
}
const x = item => item.x || 0,
y = item => item.y || 0,
w = item => item.width || 0,
h = item => item.height || 0,
xw = item => (item.x || 0) + (item.width || 0),
yh = item => (item.y || 0) + (item.height || 0),
sa = item => item.startAngle || 0,
ea = item => item.endAngle || 0,
pa = item => item.padAngle || 0,
ir = item => item.innerRadius || 0,
or = item => item.outerRadius || 0,
cr = item => item.cornerRadius || 0,
tl = item => value(item.cornerRadiusTopLeft, item.cornerRadius) || 0,
tr = item => value(item.cornerRadiusTopRight, item.cornerRadius) || 0,
br = item => value(item.cornerRadiusBottomRight, item.cornerRadius) || 0,
bl = item => value(item.cornerRadiusBottomLeft, item.cornerRadius) || 0,
sz = item => value(item.size, 64),
ts = item => item.size || 1,
def = item => !(item.defined === false),
type = item => symbols(item.shape || 'circle');
const arcShape = d3Shape.arc().startAngle(sa).endAngle(ea).padAngle(pa)
.innerRadius(ir).outerRadius(or).cornerRadius(cr),
areavShape = d3Shape.area().x(x).y1(y).y0(yh).defined(def),
areahShape = d3Shape.area().y(y).x1(x).x0(xw).defined(def),
lineShape = d3Shape.line().x(x).y(y).defined(def),
rectShape = vg_rect().x(x).y(y).width(w).height(h)
.cornerRadius(tl, tr, br, bl),
symbolShape = d3Shape.symbol().type(type).size(sz),
trailShape = vg_trail().x(x).y(y).defined(def).size(ts);
function hasCornerRadius(item) {
return item.cornerRadius
|| item.cornerRadiusTopLeft
|| item.cornerRadiusTopRight
|| item.cornerRadiusBottomRight
|| item.cornerRadiusBottomLeft;
}
function arc(context, item) {
return arcShape.context(context)(item);
}
function area(context, items) {
var item = items[0],
interp = item.interpolate || 'linear';
return (item.orient === 'horizontal' ? areahShape : areavShape)
.curve(curves(interp, item.orient, item.tension))
.context(context)(items);
}
function line(context, items) {
var item = items[0],
interp = item.interpolate || 'linear';
return lineShape.curve(curves(interp, item.orient, item.tension))
.context(context)(items);
}
function rectangle(context, item, x, y) {
return rectShape.context(context)(item, x, y);
}
function shape(context, item) {
return (item.mark.shape || item.shape)
.context(context)(item);
}
function symbol(context, item) {
return symbolShape.context(context)(item);
}
function trail(context, items) {
return trailShape.context(context)(items);
}
function boundStroke(bounds, item, miter) {
if (item.stroke && item.opacity !== 0 && item.strokeOpacity !== 0) {
const sw = item.strokeWidth != null ? +item.strokeWidth : 1;
bounds.expand(sw + (miter ? miterAdjustment(item, sw) : 0));
}
return bounds;
}
function miterAdjustment(item, strokeWidth) {
// TODO: more sophisticated adjustment? Or miter support in boundContext?
return item.strokeJoin && item.strokeJoin !== 'miter' ? 0 : strokeWidth;
}
var bounds, lx, ly,
circleThreshold = Tau - 1e-8;
function context(_) {
bounds = _;
return context;
}
function noop() {}
function add(x, y) { bounds.add(x, y); }
function addL(x, y) { add(lx = x, ly = y); }
function addX(x) { add(x, bounds.y1); }
function addY(y) { add(bounds.x1, y); }
context.beginPath = noop;
context.closePath = noop;
context.moveTo = addL;
context.lineTo = addL;
context.rect = function(x, y, w, h) {
add(x + w, y + h);
addL(x, y);
};
context.quadraticCurveTo = function(x1, y1, x2, y2) {
quadExtrema(lx, x1, x2, addX);
quadExtrema(ly, y1, y2, addY);
addL(x2, y2);
};
function quadExtrema(x0, x1, x2, cb) {
const t = (x0 - x1) / (x0 + x2 - 2 * x1);
if (0 < t && t < 1) cb(x0 + (x1 - x0) * t);
}
context.bezierCurveTo = function(x1, y1, x2, y2, x3, y3) {
cubicExtrema(lx, x1, x2, x3, addX);
cubicExtrema(ly, y1, y2, y3, addY);
addL(x3, y3);
};
function cubicExtrema(x0, x1, x2, x3, cb) {
const a = x3 - x0 + 3 * x1 - 3 * x2,
b = x0 + x2 - 2 * x1,
c = x0 - x1;
let t0 = 0, t1 = 0, r;
// solve for parameter t
if (Math.abs(a) > Epsilon) {
// quadratic equation
r = b * b + c * a;
if (r >= 0) {
r = Math.sqrt(r);
t0 = (-b + r) / a;
t1 = (-b - r) / a;
}
} else {
// linear equation
t0 = 0.5 * c / b;
}
// calculate position
if (0 < t0 && t0 < 1) cb(cubic(t0, x0, x1, x2, x3));
if (0 < t1 && t1 < 1) cb(cubic(t1, x0, x1, x2, x3));
}
function cubic(t, x0, x1, x2, x3) {
const s = 1 - t, s2 = s * s, t2 = t * t;
return (s2 * s * x0) + (3 * s2 * t * x1) + (3 * s * t2 * x2) + (t2 * t * x3);
}
context.arc = function(cx, cy, r, sa, ea, ccw) {
// store last point on path
lx = r * Math.cos(ea) + cx;
ly = r * Math.sin(ea) + cy;
if (Math.abs(ea - sa) > circleThreshold) {
// treat as full circle
add(cx - r, cy - r);
add(cx + r, cy + r);
} else {
const update = a => add(r * Math.cos(a) + cx, r * Math.sin(a) + cy);
let s, i;
// sample end points
update(sa);
update(ea);
// sample interior points aligned with 90 degrees
if (ea !== sa) {
sa = sa % Tau; if (sa < 0) sa += Tau;
ea = ea % Tau; if (ea < 0) ea += Tau;
if (ea < sa) {
ccw = !ccw; // flip direction
s = sa; sa = ea; ea = s; // swap end-points
}
if (ccw) {
ea -= Tau;
s = sa - (sa % HalfPi);
for (i=0; i<4 && s>ea; ++i, s-=HalfPi) update(s);
} else {
s = sa - (sa % HalfPi) + HalfPi;
for (i=0; i<4 && s<ea; ++i, s=s+HalfPi) update(s);
}
}
}
};
var context$1 = (context$1 = vegaCanvas.canvas(1,1))
? context$1.getContext('2d')
: null;
const b = new Bounds();
function intersectPath(draw) {
return function(item, brush) {
// rely on (inaccurate) bounds intersection if no context
if (!context$1) return true;
// add path to offscreen graphics context
draw(context$1, item);
// get bounds intersection region
b.clear().union(item.bounds).intersect(brush).round();
const {x1, y1, x2, y2} = b;
// iterate over intersection region
// perform fine grained inclusion test
for (let y = y1; y <= y2; ++y) {
for (let x = x1; x <= x2; ++x) {
if (context$1.isPointInPath(x, y)) {
return true;
}
}
}
// false if no hits in intersection region
return false;
}
}
function intersectPoint(item, box) {
return box.contains(item.x || 0, item.y || 0);
}
function intersectRect(item, box) {
const x = item.x || 0,
y = item.y || 0,
w = item.width || 0,
h = item.height || 0;
return box.intersects(b.set(x, y, x + w, y + h));
}
function intersectRule(item, box) {
const x = item.x || 0,
y = item.y || 0,
x2 = item.x2 != null ? item.x2 : x,
y2 = item.y2 != null ? item.y2 : y;
return intersectBoxLine(box, x, y, x2, y2);
}
function intersectBoxLine(box, x, y, u, v) {
const {x1, y1, x2, y2} = box,
dx = u - x,
dy = v - y;
let t0 = 0, t1 = 1, p, q, r, e;
for (e=0; e<4; ++e) {
if (e === 0) { p = -dx; q = -(x1 - x); }
if (e === 1) { p = dx; q = (x2 - x); }
if (e === 2) { p = -dy; q = -(y1 - y); }
if (e === 3) { p = dy; q = (y2 - y); }
if (Math.abs(p) < 1e-10 && q < 0) return false;
r = q / p;
if (p < 0) {
if (r > t1) return false;
else if (r > t0) t0 = r;
} else if (p > 0) {
if (r < t0) return false;
else if (r < t1) t1 = r;
}
}
return true;
}
function gradient(context, gradient, bounds) {
const w = bounds.width(),
h = bounds.height(),
stop = gradient.stops,
n = stop.length;
const canvasGradient = gradient.gradient === 'radial'
? context.createRadialGradient(
bounds.x1 + v(gradient.x1, 0.5) * w,
bounds.y1 + v(gradient.y1, 0.5) * h,
Math.max(w, h) * v(gradient.r1, 0),
bounds.x1 + v(gradient.x2, 0.5) * w,
bounds.y1 + v(gradient.y2, 0.5) * h,
Math.max(w, h) * v(gradient.r2, 0.5)
)
: context.createLinearGradient(
bounds.x1 + v(gradient.x1, 0) * w,
bounds.y1 + v(gradient.y1, 0) * h,
bounds.x1 + v(gradient.x2, 1) * w,
bounds.y1 + v(gradient.y2, 0) * h
);
for (let i=0; i<n; ++i) {
canvasGradient.addColorStop(stop[i].offset, stop[i].color);
}
return canvasGradient;
}
function v(value, dflt) {
return value == null ? dflt : value;
}
function color(context, item, value) {
return isGradient(value) ?
gradient(context, value, item.bounds) :
value;
}
function fill(context, item, opacity) {
opacity *= (item.fillOpacity==null ? 1 : item.fillOpacity);
if (opacity > 0) {
context.globalAlpha = opacity;
context.fillStyle = color(context, item, item.fill);
return true;
} else {
return false;
}
}
var Empty = [];
function stroke(context, item, opacity) {
var lw = (lw = item.strokeWidth) != null ? lw : 1;
if (lw <= 0) return false;
opacity *= (item.strokeOpacity==null ? 1 : item.strokeOpacity);
if (opacity > 0) {
context.globalAlpha = opacity;
context.strokeStyle = color(context, item, item.stroke);
context.lineWidth = lw;
context.lineCap = item.strokeCap || 'butt';
context.lineJoin = item.strokeJoin || 'miter';
context.miterLimit = item.strokeMiterLimit || 10;
if (context.setLineDash) {
context.setLineDash(item.strokeDash || Empty);
context.lineDashOffset = item.strokeDashOffset || 0;
}
return true;
} else {
return false;
}
}
function compare(a, b) {
return a.zindex - b.zindex || a.index - b.index;
}
function zorder(scene) {
if (!scene.zdirty) return scene.zitems;
var items = scene.items,
output = [], item, i, n;
for (i=0, n=items.length; i<n; ++i) {
item = items[i];
item.index = i;
if (item.zindex) output.push(item);
}
scene.zdirty = false;
return scene.zitems = output.sort(compare);
}
function visit(scene, visitor) {
var items = scene.items, i, n;
if (!items || !items.length) return;
var zitems = zorder(scene);
if (zitems && zitems.length) {
for (i=0, n=items.length; i<n; ++i) {
if (!items[i].zindex) visitor(items[i]);
}
items = zitems;
}
for (i=0, n=items.length; i<n; ++i) {
visitor(items[i]);
}
}
function pickVisit(scene, visitor) {
var items = scene.items, hit, i;
if (!items || !items.length) return null;
var zitems = zorder(scene);
if (zitems && zitems.length) items = zitems;
for (i=items.length; --i >= 0;) {
if (hit = visitor(items[i])) return hit;
}
if (items === zitems) {
for (items=scene.items, i=items.length; --i >= 0;) {
if (!items[i].zindex) {
if (hit = visitor(items[i])) return hit;
}
}
}
return null;
}
function drawAll(path) {
return function(context, scene, bounds) {
visit(scene, function(item) {
if (!bounds || bounds.intersects(item.bounds)) {
drawPath(path, context, item, item);
}
});
};
}
function drawOne(path) {
return function(context, scene, bounds) {
if (scene.items.length && (!bounds || bounds.intersects(scene.bounds))) {
drawPath(path, context, scene.items[0], scene.items);
}
};
}
function drawPath(path, context, item, items) {
var opacity = item.opacity == null ? 1 : item.opacity;
if (opacity === 0) return;
if (path(context, items)) return;
if (item.fill && fill(context, item, opacity)) {
context.fill();
}
if (item.stroke && stroke(context, item, opacity)) {
context.stroke();
}
}
function pick(test) {
test = test || vegaUtil.truthy;
return function(context, scene, x, y, gx, gy) {
x *= context.pixelRatio;
y *= context.pixelRatio;
return pickVisit(scene, function(item) {
var b = item.bounds;
// first hit test against bounding box
if ((b && !b.contains(gx, gy)) || !b) return;
// if in bounding box, perform more careful test
if (test(context, item, x, y, gx, gy)) return item;
});
};
}
function hitPath(path, filled) {
return function(context, o, x, y) {
var item = Array.isArray(o) ? o[0] : o,
fill = (filled == null) ? item.fill : filled,
stroke = item.stroke && context.isPointInStroke, lw, lc;
if (stroke) {
lw = item.strokeWidth;
lc = item.strokeCap;
context.lineWidth = lw != null ? lw : 1;
context.lineCap = lc != null ? lc : 'butt';
}
return path(context, o) ? false :
(fill && context.isPointInPath(x, y)) ||
(stroke && context.isPointInStroke(x, y));
};
}
function pickPath(path) {
return pick(hitPath(path));
}
function translate(x, y) {
return 'translate(' + x + ',' + y + ')';
}
function rotate(a) {
return 'rotate(' + a + ')';
}
function scale$1(scaleX, scaleY){
return 'scale('+ scaleX + ',' + scaleY+')';
}
function translateItem(item) {
return translate(item.x || 0, item.y || 0);
}
function transformItem(item) {
return translate(item.x || 0, item.y || 0)
+ (item.angle ? ' ' + rotate(item.angle) : '')
+ (item.scaleX || item.scaleY ? ' ' + scale$1(item.scaleX || 1, item.scaleY || 1) : '');
}
function markItemPath(type, shape, isect) {
function attr(emit, item) {
emit('transform', transformItem(item));
emit('d', shape(null, item));
}
function bound(bounds, item) {
var x = item.x || 0,
y = item.y || 0;
shape(context(bounds), item);
boundStroke(bounds, item).translate(x, y);
if (item.angle) {
bounds.rotate(item.angle * DegToRad, x, y);
}
return bounds;
}
function draw(context, item) {
var x = item.x || 0,
y = item.y || 0,
a = item.angle || 0;
context.translate(x, y);
if (a) context.rotate(a *= DegToRad);
context.beginPath();
shape(context, item);
if (a) context.rotate(-a);
context.translate(-x, -y);
}
return {
type: type,
tag: 'path',
nested: false,
attr: attr,
bound: bound,
draw: drawAll(draw),
pick: pickPath(draw),
isect: isect || intersectPath(draw)
};
}
var arc$1 = markItemPath('arc', arc);
function pickArea(a, p) {
var v = a[0].orient === 'horizontal' ? p[1] : p[0],
z = a[0].orient === 'horizontal' ? 'y' : 'x',
i = a.length,
min = +Infinity, hit, d;
while (--i >= 0) {
if (a[i].defined === false) continue;
d = Math.abs(a[i][z] - v);
if (d < min) {
min = d;
hit = a[i];
}
}
return hit;
}
function pickLine(a, p) {
var t = Math.pow(a[0].strokeWidth || 1, 2),
i = a.length, dx, dy, dd;
while (--i >= 0) {
if (a[i].defined === false) continue;
dx = a[i].x - p[0];
dy = a[i].y - p[1];
dd = dx * dx + dy * dy;
if (dd < t) return a[i];
}
return null;
}
function pickTrail(a, p) {
var i = a.length, dx, dy, dd;
while (--i >= 0) {
if (a[i].defined === false) continue;
dx = a[i].x - p[0];
dy = a[i].y - p[1];
dd = dx * dx + dy * dy;
dx = a[i].size || 1;
if (dd < dx*dx) return a[i];
}
return null;
}
function markMultiItemPath(type, shape, tip) {
function attr(emit, item) {
var items = item.mark.items;
if (items.length) emit('d', shape(null, items));
}
function bound(bounds, mark) {
var items = mark.items;
if (items.length === 0) {
return bounds;
} else {
shape(context(bounds), items);
return boundStroke(bounds, items[0]);
}
}
function draw(context, items) {
context.beginPath();
shape(context, items);
}
var hit = hitPath(draw);
function pick(context, scene, x, y, gx, gy) {
var items = scene.items,
b = scene.bounds;
if (!items || !items.length || b && !b.contains(gx, gy)) {
return null;
}
x *= context.pixelRatio;
y *= context.pixelRatio;
return hit(context, items, x, y) ? items[0] : null;
}
return {
type: type,
tag: 'path',
nested: true,
attr: attr,
bound: bound,
draw: drawOne(draw),
pick: pick,
isect: intersectPoint,
tip: tip
};
}
var area$1 = markMultiItemPath('area', area, pickArea);
function clip(context, scene) {
var clip = scene.clip;
context.save();
if (vegaUtil.isFunction(clip)) {
context.beginPath();
clip(context);
context.clip();
} else {
clipGroup(context, scene.group);
}
}
function clipGroup(context, group) {
context.beginPath();
hasCornerRadius(group)
? rectangle(context, group, 0, 0)
: context.rect(0, 0, group.width || 0, group.height || 0);
context.clip();
}
var clip_id = 1;
function resetSVGClipId() {
clip_id = 1;
}
function clip$1(renderer, item, size) {
var clip = item.clip,
defs = renderer._defs,
id = item.clip_id || (item.clip_id = 'clip' + clip_id++),
c = defs.clipping[id] || (defs.clipping[id] = {id: id});
if (vegaUtil.isFunction(clip)) {
c.path = clip(null);
} else if (hasCornerRadius(size)) {
c.path = rectangle(null, size, 0, 0);
} else {
c.width = size.width || 0;
c.height = size.height || 0;
}
return 'url(#' + id + ')';
}
function offset(item) {
var sw = (sw = item.strokeWidth) != null ? sw : 1;
return item.strokeOffset != null ? item.strokeOffset
: item.stroke && sw > 0.5 && sw < 1.5 ? 0.5 - Math.abs(sw - 1)
: 0;
}
function attr(emit, item) {
emit('transform', translateItem(item));
}
function emitRectangle(emit, item) {
var off = offset(item);
emit('d', rectangle(null, item, off, off));
}
function background(emit, item) {
emit('class', 'background');
emitRectangle(emit, item);
}
function foreground(emit, item) {
emit('class', 'foreground');
if (item.strokeForeground) {
emitRectangle(emit, item);
} else {
emit('d', '');
}
}
function content(emit, item, renderer) {
var url = item.clip ? clip$1(renderer, item, item) : null;
emit('clip-path', url);
}
function bound(bounds, group) {
if (!group.clip && group.items) {
var items = group.items;
for (var j=0, m=items.length; j<m; ++j) {
bounds.union(items[j].bounds);
}
}
if ((group.clip || group.width || group.height) && !group.noBound) {
bounds.add(0, 0).add(group.width || 0, group.height || 0);
}
boundStroke(bounds, group);
return bounds.translate(group.x || 0, group.y || 0);
}
function rectanglePath(context, group, x, y) {
var off = offset(group);
context.beginPath();
rectangle(context, group, (x || 0) + off, (y || 0) + off);
}
var hitBackground = hitPath(rectanglePath);
var hitForeground = hitPath(rectanglePath, false);
function draw(context, scene, bounds) {
var renderer = this;
visit(scene, function(group) {
var gx = group.x || 0,
gy = group.y || 0,
fore = group.strokeForeground,
opacity = group.opacity == null ? 1 : group.opacity;
// draw group background
if ((group.stroke || group.fill) && opacity) {
rectanglePath(context, group, gx, gy);
if (group.fill && fill(context, group, opacity)) {
context.fill();
}
if (group.stroke && !fore && stroke(context, group, opacity)) {
context.stroke();
}
}
// setup graphics context, set clip and bounds
context.save();
context.translate(gx, gy);
if (group.clip) clipGroup(context, group);
if (bounds) bounds.translate(-gx, -gy);
// draw group contents
visit(group, function(item) {
renderer.draw(context, item, bounds);
});
// restore graphics context
if (bounds) bounds.translate(gx, gy);
context.restore();
// draw group foreground
if (fore && group.stroke && opacity) {
rectanglePath(context, group, gx, gy);
if (stroke(context, group, opacity)) {
context.stroke();
}
}
});
}
function pick$1(context, scene, x, y, gx, gy) {
if (scene.bounds && !scene.bounds.contains(gx, gy) || !scene.items) {
return null;
}
var handler = this,
cx = x * context.pixelRatio,
cy = y * context.pixelRatio;
return pickVisit(scene, function(group) {
var hit, fore, ix, dx, dy, dw, dh, b, c;
// first hit test bounding box
b = group.bounds;
if (b && !b.contains(gx, gy)) return;
// passed bounds check, test rectangular clip
dx = group.x || 0;
dy = group.y || 0;
dw = dx + (group.width || 0);
dh = dy + (group.height || 0);
c = group.clip;
if (c && (gx < dx || gx > dw || gy < dx || gy > dh)) return;
// adjust coordinate system
context.save();
context.translate(dx, dy);
dx = gx - dx;
dy = gy - dy;
// test background for rounded corner clip
if (c && hasCornerRadius(group) && !hitBackground(context, group, cx, cy)) {
context.restore();
return null;
}
fore = group.strokeForeground;
ix = scene.interactive !== false;
// hit test against group foreground
if (ix && fore && group.stroke
&& hitForeground(context, group, cx, cy)) {
context.restore();
return group;
}
// hit test against contained marks
hit = pickVisit(group, function(mark) {
return pickMark(mark, dx, dy)
? handler.pick(mark, x, y, dx, dy)
: null;
});
// hit test against group background
if (!hit && ix && (group.fill || (!fore && group.stroke))
&& hitBackground(context, group, cx, cy)) {
hit = group;
}
// restore state and return
context.restore();
return hit || null;
});
}
function pickMark(mark, x, y) {
return (mark.interactive !== false || mark.marktype === 'group')
&& mark.bounds && mark.bounds.contains(x, y);
}
var group = {
type: 'group',
tag: 'g',
nested: false,
attr: attr,
bound: bound,
draw: draw,
pick: pick$1,
isect: intersectRect,
content: content,
background: background,
foreground: foreground
};
function getImage(item, renderer) {
var image = item.image;
if (!image || item.url && item.url !== image.url) {
image = {complete: false, width: 0, height: 0};
renderer.loadImage(item.url).then(image => {
item.image = image;
item.image.url = item.url;
});
}
return image;
}
function imageWidth(item, image) {
return item.width != null ? item.width
: !image || !image.width ? 0
: item.aspect !== false && item.height ? item.height * image.width / image.height
: image.width;
}
function imageHeight(item, image) {
return item.height != null ? item.height
: !image || !image.height ? 0
: item.aspect !== false && item.width ? item.width * image.height / image.width
: image.height;
}
function imageXOffset(align, w) {
return align === 'center' ? w / 2 : align === 'right' ? w : 0;
}
function imageYOffset(baseline, h) {
return baseline === 'middle' ? h / 2 : baseline === 'bottom' ? h : 0;
}
function attr$1(emit, item, renderer) {
var image = getImage(item, renderer),
x = item.x || 0,
y = item.y || 0,
w = imageWidth(item, image),
h = imageHeight(item, image),
a = item.aspect === false ? 'none' : 'xMidYMid';
x -= imageXOffset(item.align, w);
y -= imageYOffset(item.baseline, h);
if (!image.src && image.toDataURL) {
emit('href', image.toDataURL(), 'http://www.w3.org/1999/xlink', 'xlink:href');
} else {
emit('href', image.src || '', 'http://www.w3.org/1999/xlink', 'xlink:href');
}
emit('transform', translate(x, y));
emit('width', w);
emit('height', h);
emit('preserveAspectRatio', a);
}
function bound$1(bounds, item) {
var image = item.image,
x = item.x || 0,
y = item.y || 0,
w = imageWidth(item, image),
h = imageHeight(item, image);
x -= imageXOffset(item.align, w);
y -= imageYOffset(item.baseline, h);
return bounds.set(x, y, x + w, y + h);
}
function draw$1(context, scene, bounds) {
var renderer = this;
visit(scene, function(item) {
if (bounds && !bounds.intersects(item.bounds)) return; // bounds check
var image = getImage(item, renderer),
x = item.x || 0,
y = item.y || 0,
w = imageWidth(item, image),
h = imageHeight(item, image),
opacity, ar0, ar1, t;
x -= imageXOffset(item.align, w);
y -= imageYOffset(item.baseline, h);
if (item.aspect !== false) {
ar0 = image.width / image.height;
ar1 = item.width / item.height;
if (ar0 === ar0 && ar1 === ar1 && ar0 !== ar1) {
if (ar1 < ar0) {
t = w / ar0;
y += (h - t) / 2;
h = t;
} else {
t = h * ar0;
x += (w - t) / 2;
w = t;
}
}
}
if (image.complete || image.toDataURL) {
context.globalAlpha = (opacity = item.opacity) != null ? opacity : 1;
context.imageSmoothingEnabled = item.smooth !== false;
context.drawImage(image, x, y, w, h);
}
});
}
var image = {
type: 'image',
tag: 'image',
nested: false,
attr: attr$1,
bound: bound$1,
draw: draw$1,
pick: pick(),
isect: vegaUtil.truthy, // bounds check is sufficient
get: getImage,
xOffset: imageXOffset,
yOffset: imageYOffset
};
var line$1 = markMultiItemPath('line', line, pickLine);
function attr$2(emit, item) {
var sx = item.scaleX || 1,
sy = item.scaleY || 1;
if (sx !== 1 || sy !== 1) {
emit('vector-effect', 'non-scaling-stroke');
}
emit('transform', transformItem(item));
emit('d', item.path);
}
function path(context, item) {
var path = item.path;
if (path == null) return true;
var x = item.x || 0,
y = item.y || 0,
sx = item.scaleX || 1,
sy = item.scaleY || 1,
a = (item.angle || 0) * DegToRad,
cache = item.pathCache;
if (!cache || cache.path !== path) {
(item.pathCache = cache = pathParse(path)).path = path;
}
if (a && context.rotate && context.translate) {
context.translate(x, y);
context.rotate(a);
pathRender(context, cache, 0, 0, sx, sy);
context.rotate(-a);
context.translate(-x, -y);
} else {
pathRender(context, cache, x, y, sx, sy);
}
}
function bound$2(bounds, item) {
path(context(bounds), item)
? bounds.set(0, 0, 0, 0)
: boundStroke(bounds, item, true);
if (item.angle) {
bounds.rotate(item.angle * DegToRad, item.x || 0, item.y || 0);
}
return bounds;
}
var path$1 = {
type: 'path',
tag: 'path',
nested: false,
attr: attr$2,
bound: bound$2,
draw: drawAll(path),
pick: pickPath(path),
isect: intersectPath(path)
};
function attr$3(emit, item) {
emit('d', rectangle(null, item));
}
function bound$3(bounds, item) {
var x, y;
return boundStroke(bounds.set(
x = item.x || 0,
y = item.y || 0,
(x + item.width) || 0,
(y + item.height) || 0
), item);
}
function draw$2(context, item) {
context.beginPath();
rectangle(context, item);
}
var rect = {
type: 'rect',
tag: 'path',
nested: false,
attr: attr$3,
bound: bound$3,
draw: drawAll(draw$2),
pick: pickPath(draw$2),
isect: intersectRect
};
function attr$4(emit, item) {
emit('transform', translateItem(item));
emit('x2', item.x2 != null ? item.x2 - (item.x || 0) : 0);
emit('y2', item.y2 != null ? item.y2 - (item.y || 0) : 0);
}
function bound$4(bounds, item) {
var x1, y1;
return boundStroke(bounds.set(
x1 = item.x || 0,
y1 = item.y || 0,
item.x2 != null ? item.x2 : x1,
item.y2 != null ? item.y2 : y1
), item);
}
function path$2(context, item, opacity) {
var x1, y1, x2, y2;
if (item.stroke && stroke(context, item, opacity)) {
x1 = item.x || 0;
y1 = item.y || 0;
x2 = item.x2 != null ? item.x2 : x1;
y2 = item.y2 != null ? item.y2 : y1;
context.beginPath();
context.moveTo(x1, y1);
context.lineTo(x2, y2);
return true;
}
return false;
}
function draw$3(context, scene, bounds) {
visit(scene, function(item) {
if (bounds && !bounds.intersects(item.bounds)) return; // bounds check
var opacity = item.opacity == null ? 1 : item.opacity;
if (opacity && path$2(context, item, opacity)) {
context.stroke();
}
});
}
function hit(context, item, x, y) {
if (!context.isPointInStroke) return false;
return path$2(context, item, 1) && context.isPointInStroke(x, y);
}
var rule = {
type: 'rule',
tag: 'line',
nested: false,
attr: attr$4,
bound: bound$4,
draw: draw$3,
pick: pick(hit),
isect: intersectRule
};
var shape$1 = markItemPath('shape', shape);
var symbol$1 = markItemPath('symbol', symbol, intersectPoint);
var currFontHeight;
var textMetrics = {
height: fontSize,
measureWidth: measureWidth,
estimateWidth: estimateWidth,
width: estimateWidth,
canvas: useCanvas
};
useCanvas(true);
// make dumb, simple estimate if no canvas is available
function estimateWidth(item, text) {
currFontHeight = fontSize(item);
return estimate(textValue(item, text));
}
function estimate(text) {
return ~~(0.8 * text.length * currFontHeight);
}
// measure text width if canvas is available
function measureWidth(item, text) {
return fontSize(item) <= 0 ? 0
: (context$1.font = font(item), measure(textValue(item, text)));
}
function measure(text) {
return context$1.measureText(text).width;
}
function fontSize(item) {
return item.fontSize != null ? item.fontSize : 11;
}
function useCanvas(use) {
textMetrics.width = (use && context$1) ? measureWidth : estimateWidth;
}
function lineHeight(item) {
return item.lineHeight != null ? item.lineHeight : (fontSize(item) + 2);
}
function lineArray(_) {
return vegaUtil.isArray(_) ? _.length > 1 ? _ : _[0] : _;
}
function textLines(item) {
return lineArray(
item.lineBreak && item.text && !vegaUtil.isArray(item.text)
? item.text.split(item.lineBreak)
: item.text
);
}
function multiLineOffset(item) {
const tl = textLines(item);
return (vegaUtil.isArray(tl) ? (tl.length - 1) : 0) * lineHeight(item);
}
function textValue(item, line) {
return line == null ? ''
: item.limit > 0 ? truncate(item, line)
: line + '';
}
function truncate(item, line) {
var limit = +item.limit,
text = line + '',
width;
if (textMetrics.width === measureWidth) {
// we are using canvas
context$1.font = font(item);
width = measure;
} else {
// we are relying on estimates
currFontHeight = fontSize(item);
width = estimate;
}
if (width(text) < limit) return text;
var ellipsis = item.ellipsis || '\u2026',
rtl = item.dir === 'rtl',
lo = 0,
hi = text.length, mid;
limit -= width(ellipsis);
if (rtl) {
while (lo < hi) {
mid = (lo + hi >>> 1);
if (width(text.slice(mid)) > limit) lo = mid + 1;
else hi = mid;
}
return ellipsis + text.slice(lo);
} else {
while (lo < hi) {
mid = 1 + (lo + hi >>> 1);
if (width(text.slice(0, mid)) < limit) lo = mid;
else hi = mid - 1;
}
return text.slice(0, lo) + ellipsis;
}
}
function fontFamily(item, quote) {
var font = item.font;
return (quote && font
? String(font).replace(/"/g, '\'')
: font) || 'sans-serif';
}
function font(item, quote) {
return '' +
(item.fontStyle ? item.fontStyle + ' ' : '') +
(item.fontVariant ? item.fontVariant + ' ' : '') +
(item.fontWeight ? item.fontWeight + ' ' : '') +
fontSize(item) + 'px ' +
fontFamily(item, quote);
}
function offset$1(item) {
// perform our own font baseline calculation
// why? not all browsers support SVG 1.1 'alignment-baseline' :(
var baseline = item.baseline,
h = fontSize(item);
return Math.round(
baseline === 'top' ? 0.79*h :
baseline === 'middle' ? 0.30*h :
baseline === 'bottom' ? -0.21*h : 0
);
}
var textAlign = {
'left': 'start',
'center': 'middle',
'right': 'end'
};
var tempBounds = new Bounds();
function anchorPoint(item) {
var x = item.x || 0,
y = item.y || 0,
r = item.radius || 0, t;
if (r) {
t = (item.theta || 0) - HalfPi;
x += r * Math.cos(t);
y += r * Math.sin(t);
}
tempBounds.x1 = x;
tempBounds.y1 = y;
return tempBounds;
}
function attr$5(emit, item) {
var dx = item.dx || 0,
dy = (item.dy || 0) + offset$1(item),
p = anchorPoint(item),
x = p.x1,
y = p.y1,
a = item.angle || 0, t;
emit('text-anchor', textAlign[item.align] || 'start');
if (a) {
t = translate(x, y) + ' ' + rotate(a);
if (dx || dy) t += ' ' + translate(dx, dy);
} else {
t = translate(x + dx, y + dy);
}
emit('transform', t);
}
function bound$5(bounds, item, mode) {
var h = textMetrics.height(item),
a = item.align,
p = anchorPoint(item),
x = p.x1,
y = p.y1,
dx = item.dx || 0,
dy = (item.dy || 0) + offset$1(item) - Math.round(0.8*h), // use 4/5 offset
tl = textLines(item),
w;
// get dimensions
if (vegaUtil.isArray(tl)) {
// multi-line text
h += lineHeight(item) * (tl.length - 1);
w = tl.reduce((w, t) => Math.max(w, textMetrics.width(item, t)), 0);
} else {
// single-line text
w = textMetrics.width(item, tl);
}
// horizontal alignment
if (a === 'center') {
dx -= (w / 2);
} else if (a === 'right') {
dx -= w;
}
bounds.set(dx+=x, dy+=y, dx+w, dy+h);
if (item.angle && !mode) {
bounds.rotate(item.angle * DegToRad, x, y);
} else if (mode === 2) {
return bounds.rotatedPoints(item.angle * DegToRad, x, y);
}
return bounds;
}
function draw$4(context, scene, bounds) {
visit(scene, function(item) {
var opacity = item.opacity == null ? 1 : item.opacity,
p, x, y, i, lh, tl, str;
if (bounds && !bounds.intersects(item.bounds) || // bounds check
opacity === 0 || item.fontSize <= 0 ||
item.text == null || item.text.length === 0) return;
context.font = font(item);
context.textAlign = item.align || 'left';
p = anchorPoint(item);
x = p.x1,
y = p.y1;
if (item.angle) {
context.save();
context.translate(x, y);
context.rotate(item.angle * DegToRad);
x = y = 0; // reset x, y
}
x += (item.dx || 0);
y += (item.dy || 0) + offset$1(item);
tl = textLines(item);
if (vegaUtil.isArray(tl)) {
lh = lineHeight(item);
for (i=0; i<tl.length; ++i) {
str = textValue(item, tl[i]);
if (item.fill && fill(context, item, opacity)) {
context.fillText(str, x, y);
}
if (item.stroke && stroke(context, item, opacity)) {
context.strokeText(str, x, y);
}
y += lh;
}
} else {
str = textValue(item, tl);
if (item.fill && fill(context, item, opacity)) {
context.fillText(str, x, y);
}
if (item.stroke && stroke(context, item, opacity)) {
context.strokeText(str, x, y);
}
}
if (item.angle) context.restore();
});
}
function hit$1(context, item, x, y, gx, gy) {
if (item.fontSize <= 0) return false;
if (!item.angle) return true; // bounds sufficient if no rotation
// project point into space of unrotated bounds
var p = anchorPoint(item),
ax = p.x1,
ay = p.y1,
b = bound$5(tempBounds, item, 1),
a = -item.angle * DegToRad,
cos = Math.cos(a),
sin = Math.sin(a),
px = cos * gx - sin * gy + (ax - cos * ax + sin * ay),
py = sin * gx + cos * gy + (ay - sin * ax - cos * ay);
return b.contains(px, py);
}
function intersectText(item, box) {
var p = bound$5(tempBounds, item, 2);
return intersectBoxLine(box, p[0], p[1], p[2], p[3])
|| intersectBoxLine(box, p[0], p[1], p[4], p[5])
|| intersectBoxLine(box, p[4], p[5], p[6], p[7])
|| intersectBoxLine(box, p[2], p[3], p[6], p[7]);
}
var text = {
type: 'text',
tag: 'text',
nested: false,
attr: attr$5,
bound: bound$5,
draw: draw$4,
pick: pick(hit$1),
isect: intersectText
};
var trail$1 = markMultiItemPath('trail', trail, pickTrail);
var Marks = {
arc: arc$1,
area: area$1,
group: group,
image: image,
line: line$1,
path: path$1,
rect: rect,
rule: rule,
shape: shape$1,
symbol: symbol$1,
text: text,
trail: trail$1
};
function boundItem(item, func, opt) {
var type = Marks[item.mark.marktype],
bound = func || type.bound;
if (type.nested) item = item.mark;
return bound(item.bounds || (item.bounds = new Bounds()), item, opt);
}
var DUMMY = {mark: null};
function boundMark(mark, bounds, opt) {
var type = Marks[mark.marktype],
bound = type.bound,
items = mark.items,
hasItems = items && items.length,
i, n, item, b;
if (type.nested) {
if (hasItems) {
item = items[0];
} else {
// no items, fake it
DUMMY.mark = mark;
item = DUMMY;
}
b = boundItem(item, bound, opt);
bounds = bounds && bounds.union(b) || b;
return bounds;
}
bounds = bounds
|| mark.bounds && mark.bounds.clear()
|| new Bounds();
if (hasItems) {
for (i=0, n=items.length; i<n; ++i) {
bounds.union(boundItem(items[i], bound, opt));
}
}
return mark.bounds = bounds;
}
var keys = [
'marktype', 'name', 'role', 'interactive', 'clip', 'items', 'zindex',
'x', 'y', 'width', 'height', 'align', 'baseline', // layout
'fill', 'fillOpacity', 'opacity', // fill
'stroke', 'strokeOpacity', 'strokeWidth', 'strokeCap', // stroke
'strokeDash', 'strokeDashOffset', // stroke dash
'strokeForeground', 'strokeOffset', // group
'startAngle', 'endAngle', 'innerRadius', 'outerRadius', // arc
'cornerRadius', 'padAngle', // arc, rect
'cornerRadiusTopLeft', 'cornerRadiusTopRight', // rect, group
'cornerRadiusBottomLeft', 'cornerRadiusBottomRight',
'interpolate', 'tension', 'orient', 'defined', // area, line
'url', 'aspect', 'smooth', // image
'path', 'scaleX', 'scaleY', // path
'x2', 'y2', // rule
'size', 'shape', // symbol
'text', 'angle', 'theta', 'radius', 'dir', 'dx', 'dy', // text
'ellipsis', 'limit', 'lineBreak', 'lineHeight',
'font', 'fontSize', 'fontWeight', 'fontStyle', 'fontVariant' // font
];
function sceneToJSON(scene, indent) {
return JSON.stringify(scene, keys, indent);
}
function sceneFromJSON(json) {
var scene = (typeof json === 'string' ? JSON.parse(json) : json);
return initialize(scene);
}
function initialize(scene) {
var type = scene.marktype,
items = scene.items,
parent, i, n;
if (items) {
for (i=0, n=items.length; i<n; ++i) {
parent = type ? 'mark' : 'group';
items[i][parent] = scene;
if (items[i].zindex) items[i][parent].zdirty = true;
if ('group' === (type || parent)) initialize(items[i]);
}
}
if (type) boundMark(scene);
return scene;
}
function Scenegraph(scene) {
if (arguments.length) {
this.root = sceneFromJSON(scene);
} else {
this.root = createMark({
marktype: 'group',
name: 'root',
role: 'frame'
});
this.root.items = [new GroupItem(this.root)];
}
}
var prototype$2 = Scenegraph.prototype;
prototype$2.toJSON = function(indent) {
return sceneToJSON(this.root, indent || 0);
};
prototype$2.mark = function(markdef, group, index) {
group = group || this.root.items[0];
var mark = createMark(markdef, group);
group.items[index] = mark;
if (mark.zindex) mark.group.zdirty = true;
return mark;
};
function createMark(def, group) {
return {
bounds: new Bounds(),
clip: !!def.clip,
group: group,
interactive: def.interactive === false ? false : true,
items: [],
marktype: def.marktype,
name: def.name || undefined,
role: def.role || undefined,
zindex: def.zindex || 0
};
}
// create a new DOM element
function domCreate(doc, tag, ns) {
if (!doc && typeof document !== 'undefined' && document.createElement) {
doc = document;
}
return doc
? (ns ? doc.createElementNS(ns, tag) : doc.createElement(tag))
: null;
}
// find first child element with matching tag
function domFind(el, tag) {
tag = tag.toLowerCase();
var nodes = el.childNodes, i = 0, n = nodes.length;
for (; i<n; ++i) if (nodes[i].tagName.toLowerCase() === tag) {
return nodes[i];
}
}
// retrieve child element at given index
// create & insert if doesn't exist or if tags do not match
function domChild(el, index, tag, ns) {
var a = el.childNodes[index], b;
if (!a || a.tagName.toLowerCase() !== tag.toLowerCase()) {
b = a || null;
a = domCreate(el.ownerDocument, tag, ns);
el.insertBefore(a, b);
}
return a;
}
// remove all child elements at or above the given index
function domClear(el, index) {
var nodes = el.childNodes,
curr = nodes.length;
while (curr > index) el.removeChild(nodes[--curr]);
return el;
}
// generate css class name for mark
function cssClass(mark) {
return 'mark-' + mark.marktype
+ (mark.role ? ' role-' + mark.role : '')
+ (mark.name ? ' ' + mark.name : '');
}
function point(event, el) {
var rect = el.getBoundingClientRect();
return [
event.clientX - rect.left - (el.clientLeft || 0),
event.clientY - rect.top - (el.clientTop || 0)
];
}
function resolveItem(item, event, el, origin) {
var mark = item && item.mark,
mdef, p;
if (mark && (mdef = Marks[mark.marktype]).tip) {
p = point(event, el);
p[0] -= origin[0];
p[1] -= origin[1];
while (item = item.mark.group) {
p[0] -= item.x || 0;
p[1] -= item.y || 0;
}
item = mdef.tip(mark.items, p);
}
return item;
}
/**
* Create a new Handler instance.
* @param {object} [customLoader] - Optional loader instance for
* href URL sanitization. If not specified, a standard loader
* instance will be generated.
* @param {function} [customTooltip] - Optional tooltip handler
* function for custom tooltip display.
* @constructor
*/
function Handler(customLoader, customTooltip) {
this._active = null;
this._handlers = {};
this._loader = customLoader || vegaLoader.loader();
this._tooltip = customTooltip || defaultTooltip;
}
// The default tooltip display handler.
// Sets the HTML title attribute on the visualization container.
function defaultTooltip(handler, event, item, value) {
handler.element().setAttribute('title', value || '');
}
var prototype$3 = Handler.prototype;
/**
* Initialize a new Handler instance.
* @param {DOMElement} el - The containing DOM element for the display.
* @param {Array<number>} origin - The origin of the display, in pixels.
* The coordinate system will be translated to this point.
* @param {object} [obj] - Optional context object that should serve as
* the "this" context for event callbacks.
* @return {Handler} - This handler instance.
*/
prototype$3.initialize = function(el, origin, obj) {
this._el = el;
this._obj = obj || null;
return this.origin(origin);
};
/**
* Returns the parent container element for a visualization.
* @return {DOMElement} - The containing DOM element.
*/
prototype$3.element = function() {
return this._el;
};
/**
* Returns the scene element (e.g., canvas or SVG) of the visualization
* Subclasses must override if the first child is not the scene element.
* @return {DOMElement} - The scene (e.g., canvas or SVG) element.
*/
prototype$3.canvas = function() {
return this._el && this._el.firstChild;
};
/**
* Get / set the origin coordinates of the visualization.
*/
prototype$3.origin = function(origin) {
if (arguments.length) {
this._origin = origin || [0, 0];
return this;
} else {
return this._origin.slice();
}
};
/**
* Get / set the scenegraph root.
*/
prototype$3.scene = function(scene) {
if (!arguments.length) return this._scene;
this._scene = scene;
return this;
};
/**
* Add an event handler. Subclasses should override this method.
*/
prototype$3.on = function(/*type, handler*/) {};
/**
* Remove an event handler. Subclasses should override this method.
*/
prototype$3.off = function(/*type, handler*/) {};
/**
* Utility method for finding the array index of an event handler.
* @param {Array} h - An array of registered event handlers.
* @param {string} type - The event type.
* @param {function} handler - The event handler instance to find.
* @return {number} - The handler's array index or -1 if not registered.
*/
prototype$3._handlerIndex = function(h, type, handler) {
for (var i = h ? h.length : 0; --i>=0;) {
if (h[i].type === type && (!handler || h[i].handler === handler)) {
return i;
}
}
return -1;
};
/**
* Returns an array with registered event handlers.
* @param {string} [type] - The event type to query. Any annotations
* are ignored; for example, for the argument "click.foo", ".foo" will
* be ignored and the method returns all "click" handlers. If type is
* null or unspecified, this method returns handlers for all types.
* @return {Array} - A new array containing all registered event handlers.
*/
prototype$3.handlers = function(type) {
var h = this._handlers, a = [], k;
if (type) {
a.push.apply(a, h[this.eventName(type)]);
} else {
for (k in h) { a.push.apply(a, h[k]); }
}
return a;
};
/**
* Parses an event name string to return the specific event type.
* For example, given "click.foo" returns "click"
* @param {string} name - The input event type string.
* @return {string} - A string with the event type only.
*/
prototype$3.eventName = function(name) {
var i = name.indexOf('.');
return i < 0 ? name : name.slice(0,i);
};
/**
* Handle hyperlink navigation in response to an item.href value.
* @param {Event} event - The event triggering hyperlink navigation.
* @param {Item} item - The scenegraph item.
* @param {string} href - The URL to navigate to.
*/
prototype$3.handleHref = function(event, item, href) {
this._loader
.sanitize(href, {context:'href'})
.then(function(opt) {
var e = new MouseEvent(event.type, event),
a = domCreate(null, 'a');
for (var name in opt) a.setAttribute(name, opt[name]);
a.dispatchEvent(e);
})
.catch(function() { /* do nothing */ });
};
/**
* Handle tooltip display in response to an item.tooltip value.
* @param {Event} event - The event triggering tooltip display.
* @param {Item} item - The scenegraph item.
* @param {boolean} show - A boolean flag indicating whether
* to show or hide a tooltip for the given item.
*/
prototype$3.handleTooltip = function(event, item, show) {
if (item && item.tooltip != null) {
item = resolveItem(item, event, this.canvas(), this._origin);
var value = (show && item && item.tooltip) || null;
this._tooltip.call(this._obj, this, event, item, value);
}
};
/**
* Returns the size of a scenegraph item and its position relative
* to the viewport.
* @param {Item} item - The scenegraph item.
* @return {object} - A bounding box object (compatible with the
* DOMRect type) consisting of x, y, width, heigh, top, left,
* right, and bottom properties.
*/
prototype$3.getItemBoundingClientRect = function(item) {
if (!(el = this.canvas())) return;
var el, rect = el.getBoundingClientRect(),
origin = this._origin,
itemBounds = item.bounds,
x = itemBounds.x1 + origin[0] + rect.left,
y = itemBounds.y1 + origin[1] + rect.top,
w = itemBounds.width(),
h = itemBounds.height();
// translate coordinate for each parent group
while (item.mark && (item = item.mark.group)) {
x += item.x || 0;
y += item.y || 0;
}
// return DOMRect-compatible bounding box
return {
x: x,
y: y,
width: w,
height: h,
left: x,
top: y,
right: x + w,
bottom: y + h
};
};
/**
* Create a new Renderer instance.
* @param {object} [loader] - Optional loader instance for
* image and href URL sanitization. If not specified, a
* standard loader instance will be generated.
* @constructor
*/
function Renderer(loader) {
this._el = null;
this._bgcolor = null;
this._loader = new ResourceLoader(loader);
}
var prototype$4 = Renderer.prototype;
/**
* Initialize a new Renderer instance.
* @param {DOMElement} el - The containing DOM element for the display.
* @param {number} width - The coordinate width of the display, in pixels.
* @param {number} height - The coordinate height of the display, in pixels.
* @param {Array<number>} origin - The origin of the display, in pixels.
* The coordinate system will be translated to this point.
* @param {number} [scaleFactor=1] - Optional scaleFactor by which to multiply
* the width and height to determine the final pixel size.
* @return {Renderer} - This renderer instance.
*/
prototype$4.initialize = function(el, width, height, origin, scaleFactor) {
this._el = el;
return this.resize(width, height, origin, scaleFactor);
};
/**
* Returns the parent container element for a visualization.
* @return {DOMElement} - The containing DOM element.
*/
prototype$4.element = function() {
return this._el;
};
/**
* Returns the scene element (e.g., canvas or SVG) of the visualization
* Subclasses must override if the first child is not the scene element.
* @return {DOMElement} - The scene (e.g., canvas or SVG) element.
*/
prototype$4.canvas = function() {
return this._el && this._el.firstChild;
};
/**
* Get / set the background color.
*/
prototype$4.background = function(bgcolor) {
if (arguments.length === 0) return this._bgcolor;
this._bgcolor = bgcolor;
return this;
};
/**
* Resize the display.
* @param {number} width - The new coordinate width of the display, in pixels.
* @param {number} height - The new coordinate height of the display, in pixels.
* @param {Array<number>} origin - The new origin of the display, in pixels.
* The coordinate system will be translated to this point.
* @param {number} [scaleFactor=1] - Optional scaleFactor by which to multiply
* the width and height to determine the final pixel size.
* @return {Renderer} - This renderer instance;
*/
prototype$4.resize = function(width, height, origin, scaleFactor) {
this._width = width;
this._height = height;
this._origin = origin || [0, 0];
this._scale = scaleFactor || 1;
return this;
};
/**
* Report a dirty item whose bounds should be redrawn.
* This base class method does nothing. Subclasses that perform
* incremental should implement this method.
* @param {Item} item - The dirty item whose bounds should be redrawn.
*/
prototype$4.dirty = function(/*item*/) {
};
/**
* Render an input scenegraph, potentially with a set of dirty items.
* This method will perform an immediate rendering with available resources.
* The renderer may also need to perform image loading to perform a complete
* render. This process can lead to asynchronous re-rendering of the scene
* after this method returns. To receive notification when rendering is
* complete, use the renderAsync method instead.
* @param {object} scene - The root mark of a scenegraph to render.
* @return {Renderer} - This renderer instance.
*/
prototype$4.render = function(scene) {
var r = this;
// bind arguments into a render call, and cache it
// this function may be subsequently called for async redraw
r._call = function() { r._render(scene); };
// invoke the renderer
r._call();
// clear the cached call for garbage collection
// async redraws will stash their own copy
r._call = null;
return r;
};
/**
* Internal rendering method. Renderer subclasses should override this
* method to actually perform rendering.
* @param {object} scene - The root mark of a scenegraph to render.
*/
prototype$4._render = function(/*scene*/) {
// subclasses to override
};
/**
* Asynchronous rendering method. Similar to render, but returns a Promise
* that resolves when all rendering is completed. Sometimes a renderer must
* perform image loading to get a complete rendering. The returned
* Promise will not resolve until this process completes.
* @param {object} scene - The root mark of a scenegraph to render.
* @return {Promise} - A Promise that resolves when rendering is complete.
*/
prototype$4.renderAsync = function(scene) {
var r = this.render(scene);
return this._ready
? this._ready.then(function() { return r; })
: Promise.resolve(r);
};
/**
* Internal method for asynchronous resource loading.
* Proxies method calls to the ImageLoader, and tracks loading
* progress to invoke a re-render once complete.
* @param {string} method - The method name to invoke on the ImageLoader.
* @param {string} uri - The URI for the requested resource.
* @return {Promise} - A Promise that resolves to the requested resource.
*/
prototype$4._load = function(method, uri) {
var r = this,
p = r._loader[method](uri);
if (!r._ready) {
// re-render the scene when loading completes
var call = r._call;
r._ready = r._loader.ready()
.then(function(redraw) {
if (redraw) call();
r._ready = null;
});
}
return p;
};
/**
* Sanitize a URL to include as a hyperlink in the rendered scene.
* This method proxies a call to ImageLoader.sanitizeURL, but also tracks
* image loading progress and invokes a re-render once complete.
* @param {string} uri - The URI string to sanitize.
* @return {Promise} - A Promise that resolves to the sanitized URL.
*/
prototype$4.sanitizeURL = function(uri) {
return this._load('sanitizeURL', uri);
};
/**
* Requests an image to include in the rendered scene.
* This method proxies a call to ImageLoader.loadImage, but also tracks
* image loading progress and invokes a re-render once complete.
* @param {string} uri - The URI string of the image.
* @return {Promise} - A Promise that resolves to the loaded Image.
*/
prototype$4.loadImage = function(uri) {
return this._load('loadImage', uri);
};
var Events = [
'keydown',
'keypress',
'keyup',
'dragenter',
'dragleave',
'dragover',
'mousedown',
'mouseup',
'mousemove',
'mouseout',
'mouseover',
'click',
'dblclick',
'wheel',
'mousewheel',
'touchstart',
'touchmove',
'touchend'
];
var TooltipShowEvent = 'mousemove';
var TooltipHideEvent = 'mouseout';
var HrefEvent = 'click';
function CanvasHandler(loader, tooltip) {
Handler.call(this, loader, tooltip);
this._down = null;
this._touch = null;
this._first = true;
}
var prototype$5 = vegaUtil.inherits(CanvasHandler, Handler);
prototype$5.initialize = function(el, origin, obj) {
// add event listeners
var canvas = this._canvas = el && domFind(el, 'canvas');
if (canvas) {
var that = this;
this.events.forEach(function(type) {
canvas.addEventListener(type, function(evt) {
if (prototype$5[type]) {
prototype$5[type].call(that, evt);
} else {
that.fire(type, evt);
}
});
});
}
return Handler.prototype.initialize.call(this, el, origin, obj);
};
// return the backing canvas instance
prototype$5.canvas = function() {
return this._canvas;
};
// retrieve the current canvas context
prototype$5.context = function() {
return this._canvas.getContext('2d');
};
// supported events
prototype$5.events = Events;
// to keep old versions of firefox happy
prototype$5.DOMMouseScroll = function(evt) {
this.fire('mousewheel', evt);
};
function move(moveEvent, overEvent, outEvent) {
return function(evt) {
var a = this._active,
p = this.pickEvent(evt);
if (p === a) {
// active item and picked item are the same
this.fire(moveEvent, evt); // fire move
} else {
// active item and picked item are different
if (!a || !a.exit) {
// fire out for prior active item
// suppress if active item was removed from scene
this.fire(outEvent, evt);
}
this._active = p; // set new active item
this.fire(overEvent, evt); // fire over for new active item
this.fire(moveEvent, evt); // fire move for new active item
}
};
}
function inactive(type) {
return function(evt) {
this.fire(type, evt);
this._active = null;
};
}
prototype$5.mousemove = move('mousemove', 'mouseover', 'mouseout');
prototype$5.dragover = move('dragover', 'dragenter', 'dragleave');
prototype$5.mouseout = inactive('mouseout');
prototype$5.dragleave = inactive('dragleave');
prototype$5.mousedown = function(evt) {
this._down = this._active;
this.fire('mousedown', evt);
};
prototype$5.click = function(evt) {
if (this._down === this._active) {
this.fire('click', evt);
this._down = null;
}
};
prototype$5.touchstart = function(evt) {
this._touch = this.pickEvent(evt.changedTouches[0]);
if (this._first) {
this._active = this._touch;
this._first = false;
}
this.fire('touchstart', evt, true);
};
prototype$5.touchmove = function(evt) {
this.fire('touchmove', evt, true);
};
prototype$5.touchend = function(evt) {
this.fire('touchend', evt, true);
this._touch = null;
};
// fire an event
prototype$5.fire = function(type, evt, touch) {
var a = touch ? this._touch : this._active,
h = this._handlers[type], i, len;
// set event type relative to scenegraph items
evt.vegaType = type;
// handle hyperlinks and tooltips first
if (type === HrefEvent && a && a.href) {
this.handleHref(evt, a, a.href);
} else if (type === TooltipShowEvent || type === TooltipHideEvent) {
this.handleTooltip(evt, a, type !== TooltipHideEvent);
}
// invoke all registered handlers
if (h) {
for (i=0, len=h.length; i<len; ++i) {
h[i].handler.call(this._obj, evt, a);
}
}
};
// add an event handler
prototype$5.on = function(type, handler) {
var name = this.eventName(type),
h = this._handlers,
i = this._handlerIndex(h[name], type, handler);
if (i < 0) {
(h[name] || (h[name] = [])).push({
type: type,
handler: handler
});
}
return this;
};
// remove an event handler
prototype$5.off = function(type, handler) {
var name = this.eventName(type),
h = this._handlers[name],
i = this._handlerIndex(h, type, handler);
if (i >= 0) {
h.splice(i, 1);
}
return this;
};
prototype$5.pickEvent = function(evt) {
var p = point(evt, this._canvas),
o = this._origin;
return this.pick(this._scene, p[0], p[1], p[0] - o[0], p[1] - o[1]);
};
// find the scenegraph item at the current mouse position
// x, y -- the absolute x, y mouse coordinates on the canvas element
// gx, gy -- the relative coordinates within the current group
prototype$5.pick = function(scene, x, y, gx, gy) {
var g = this.context(),
mark = Marks[scene.marktype];
return mark.pick.call(this, g, scene, x, y, gx, gy);
};
function devicePixelRatio() {
return typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1;
}
var pixelRatio = devicePixelRatio();
function resize(canvas, width, height, origin, scaleFactor, opt) {
var inDOM = typeof HTMLElement !== 'undefined'
&& canvas instanceof HTMLElement
&& canvas.parentNode != null;
var context = canvas.getContext('2d'),
ratio = inDOM ? pixelRatio : scaleFactor,
key;
canvas.width = width * ratio;
canvas.height = height * ratio;
for (key in opt) {
context[key] = opt[key];
}
if (inDOM && ratio !== 1) {
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
}
context.pixelRatio = ratio;
context.setTransform(
ratio, 0, 0, ratio,
ratio * origin[0],
ratio * origin[1]
);
return canvas;
}
function CanvasRenderer(loader) {
Renderer.call(this, loader);
this._redraw = false;
this._dirty = new Bounds();
}
var prototype$6 = vegaUtil.inherits(CanvasRenderer, Renderer),
base = Renderer.prototype,
tempBounds$1 = new Bounds();
prototype$6.initialize = function(el, width, height, origin, scaleFactor, options) {
this._options = options;
this._canvas = vegaCanvas.canvas(1, 1, options && options.type); // instantiate a small canvas
if (el) {
domClear(el, 0).appendChild(this._canvas);
this._canvas.setAttribute('class', 'marks');
}
// this method will invoke resize to size the canvas appropriately
return base.initialize.call(this, el, width, height, origin, scaleFactor);
};
prototype$6.resize = function(width, height, origin, scaleFactor) {
base.resize.call(this, width, height, origin, scaleFactor);
resize(this._canvas, this._width, this._height,
this._origin, this._scale, this._options && this._options.context);
this._redraw = true;
return this;
};
prototype$6.canvas = function() {
return this._canvas;
};
prototype$6.context = function() {
return this._canvas ? this._canvas.getContext('2d') : null;
};
prototype$6.dirty = function(item) {
var b = translate$1(item.bounds, item.mark.group);
this._dirty.union(b);
};
function clipToBounds(g, b, origin) {
// expand bounds by 1 pixel, then round to pixel boundaries
b.expand(1).round();
// to avoid artifacts translate if origin has fractional pixels
b.translate(-(origin[0] % 1), -(origin[1] % 1));
// set clipping path
g.beginPath();
g.rect(b.x1, b.y1, b.width(), b.height());
g.clip();
return b;
}
function viewBounds(origin, width, height) {
return tempBounds$1
.set(0, 0, width, height)
.translate(-origin[0], -origin[1]);
}
function translate$1(bounds, group) {
if (group == null) return bounds;
var b = tempBounds$1.clear().union(bounds);
for (; group != null; group = group.mark.group) {
b.translate(group.x || 0, group.y || 0);
}
return b;
}
prototype$6._render = function(scene) {
var g = this.context(),
o = this._origin,
w = this._width,
h = this._height,
b = this._dirty;
// setup
g.save();
if (this._redraw || b.empty()) {
this._redraw = false;
b = viewBounds(o, w, h).expand(1);
} else {
b = clipToBounds(g, b.intersect(viewBounds(o, w, h)), o);
}
this.clear(-o[0], -o[1], w, h);
// render
this.draw(g, scene, b);
// takedown
g.restore();
this._dirty.clear();
return this;
};
prototype$6.draw = function(ctx, scene, bounds) {
var mark = Marks[scene.marktype];
if (scene.clip) clip(ctx, scene);
mark.draw.call(this, ctx, scene, bounds);
if (scene.clip) ctx.restore();
};
prototype$6.clear = function(x, y, w, h) {
var g = this.context();
g.clearRect(x, y, w, h);
if (this._bgcolor != null) {
g.fillStyle = this._bgcolor;
g.fillRect(x, y, w, h);
}
};
function SVGHandler(loader, tooltip) {
Handler.call(this, loader, tooltip);
var h = this;
h._hrefHandler = listener(h, function(evt, item) {
if (item && item.href) h.handleHref(evt, item, item.href);
});
h._tooltipHandler = listener(h, function(evt, item) {
h.handleTooltip(evt, item, evt.type !== TooltipHideEvent);
});
}
var prototype$7 = vegaUtil.inherits(SVGHandler, Handler);
prototype$7.initialize = function(el, origin, obj) {
var svg = this._svg;
if (svg) {
svg.removeEventListener(HrefEvent, this._hrefHandler);
svg.removeEventListener(TooltipShowEvent, this._tooltipHandler);
svg.removeEventListener(TooltipHideEvent, this._tooltipHandler);
}
this._svg = svg = el && domFind(el, 'svg');
if (svg) {
svg.addEventListener(HrefEvent, this._hrefHandler);
svg.addEventListener(TooltipShowEvent, this._tooltipHandler);
svg.addEventListener(TooltipHideEvent, this._tooltipHandler);
}
return Handler.prototype.initialize.call(this, el, origin, obj);
};
prototype$7.canvas = function() {
return this._svg;
};
// wrap an event listener for the SVG DOM
function listener(context, handler) {
return function(evt) {
var target = evt.target,
item = target.__data__;
evt.vegaType = evt.type;
item = Array.isArray(item) ? item[0] : item;
handler.call(context._obj, evt, item);
};
}
// add an event handler
prototype$7.on = function(type, handler) {
var name = this.eventName(type),
h = this._handlers,
i = this._handlerIndex(h[name], type, handler);
if (i < 0) {
var x = {
type: type,
handler: handler,
listener: listener(this, handler)
};
(h[name] || (h[name] = [])).push(x);
if (this._svg) {
this._svg.addEventListener(name, x.listener);
}
}
return this;
};
// remove an event handler
prototype$7.off = function(type, handler) {
var name = this.eventName(type),
h = this._handlers[name],
i = this._handlerIndex(h, type, handler);
if (i >= 0) {
if (this._svg) {
this._svg.removeEventListener(name, h[i].listener);
}
h.splice(i, 1);
}
return this;
};
// generate string for an opening xml tag
// tag: the name of the xml tag
// attr: hash of attribute name-value pairs to include
// raw: additional raw string to include in tag markup
function openTag(tag, attr, raw) {
var s = '<' + tag, key, val;
if (attr) {
for (key in attr) {
val = attr[key];
if (val != null) {
s += ' ' + key + '="' + val + '"';
}
}
}
if (raw) s += ' ' + raw;
return s + '>';
}
// generate string for closing xml tag
// tag: the name of the xml tag
function closeTag(tag) {
return '</' + tag + '>';
}
var metadata = {
'version': '1.1',
'xmlns': 'http://www.w3.org/2000/svg',
'xmlns:xlink': 'http://www.w3.org/1999/xlink'
};
var styles = {
'fill': 'fill',
'fillOpacity': 'fill-opacity',
'stroke': 'stroke',
'strokeOpacity': 'stroke-opacity',
'strokeWidth': 'stroke-width',
'strokeCap': 'stroke-linecap',
'strokeJoin': 'stroke-linejoin',
'strokeDash': 'stroke-dasharray',
'strokeDashOffset': 'stroke-dashoffset',
'strokeMiterLimit': 'stroke-miterlimit',
'opacity': 'opacity'
};
var styleProperties = Object.keys(styles);
var ns = metadata.xmlns;
function SVGRenderer(loader) {
Renderer.call(this, loader);
this._dirtyID = 0;
this._dirty = [];
this._svg = null;
this._root = null;
this._defs = null;
}
var prototype$8 = vegaUtil.inherits(SVGRenderer, Renderer);
var base$1 = Renderer.prototype;
prototype$8.initialize = function(el, width, height, padding) {
if (el) {
this._svg = domChild(el, 0, 'svg', ns);
this._svg.setAttribute('class', 'marks');
domClear(el, 1);
// set the svg root group
this._root = domChild(this._svg, 0, 'g', ns);
domClear(this._svg, 1);
}
// create the svg definitions cache
this._defs = {
gradient: {},
clipping: {}
};
// set background color if defined
this.background(this._bgcolor);
return base$1.initialize.call(this, el, width, height, padding);
};
prototype$8.background = function(bgcolor) {
if (arguments.length && this._svg) {
this._svg.style.setProperty('background-color', bgcolor);
}
return base$1.background.apply(this, arguments);
};
prototype$8.resize = function(width, height, origin, scaleFactor) {
base$1.resize.call(this, width, height, origin, scaleFactor);
if (this._svg) {
this._svg.setAttribute('width', this._width * this._scale);
this._svg.setAttribute('height', this._height * this._scale);
this._svg.setAttribute('viewBox', '0 0 ' + this._width + ' ' + this._height);
this._root.setAttribute('transform', 'translate(' + this._origin + ')');
}
this._dirty = [];
return this;
};
prototype$8.canvas = function() {
return this._svg;
};
prototype$8.svg = function() {
if (!this._svg) return null;
var attr = {
class: 'marks',
width: this._width * this._scale,
height: this._height * this._scale,
viewBox: '0 0 ' + this._width + ' ' + this._height
};
for (var key in metadata) {
attr[key] = metadata[key];
}
var bg = !this._bgcolor ? ''
: (openTag('rect', {
width: this._width,
height: this._height,
style: 'fill: ' + this._bgcolor + ';'
}) + closeTag('rect'));
return openTag('svg', attr) + bg + this._svg.innerHTML + closeTag('svg');
};
// -- Render entry point --
prototype$8._render = function(scene) {
// perform spot updates and re-render markup
if (this._dirtyCheck()) {
if (this._dirtyAll) this._resetDefs();
this.draw(this._root, scene);
domClear(this._root, 1);
}
this.updateDefs();
this._dirty = [];
++this._dirtyID;
return this;
};
// -- Manage SVG definitions ('defs') block --
prototype$8.updateDefs = function() {
var svg = this._svg,
defs = this._defs,
el = defs.el,
index = 0, id;
for (id in defs.gradient) {
if (!el) defs.el = (el = domChild(svg, 0, 'defs', ns));
index = updateGradient(el, defs.gradient[id], index);
}
for (id in defs.clipping) {
if (!el) defs.el = (el = domChild(svg, 0, 'defs', ns));
index = updateClipping(el, defs.clipping[id], index);
}
// clean-up
if (el) {
if (index === 0) {
svg.removeChild(el);
defs.el = null;
} else {
domClear(el, index);
}
}
};
function updateGradient(el, grad, index) {
var i, n, stop;
if (grad.gradient === 'radial') {
// SVG radial gradients automatically transform to normalized bbox
// coordinates, in a way that is cumbersome to replicate in canvas.
// So we wrap the radial gradient in a pattern element, allowing us
// to mantain a circular gradient that matches what canvas provides.
var pt = domChild(el, index++, 'pattern', ns);
pt.setAttribute('id', patternPrefix + grad.id);
pt.setAttribute('viewBox', '0,0,1,1');
pt.setAttribute('width', '100%');
pt.setAttribute('height', '100%');
pt.setAttribute('preserveAspectRatio', 'xMidYMid slice');
pt = domChild(pt, 0, 'rect', ns);
pt.setAttribute('width', '1');
pt.setAttribute('height', '1');
pt.setAttribute('fill', 'url(' + href() + '#' + grad.id + ')');
el = domChild(el, index++, 'radialGradient', ns);
el.setAttribute('id', grad.id);
el.setAttribute('fx', grad.x1);
el.setAttribute('fy', grad.y1);
el.setAttribute('fr', grad.r1);
el.setAttribute('cx', grad.x2);
el.setAttribute('cy', grad.y2);
el.setAttribute( 'r', grad.r2);
} else {
el = domChild(el, index++, 'linearGradient', ns);
el.setAttribute('id', grad.id);
el.setAttribute('x1', grad.x1);
el.setAttribute('x2', grad.x2);
el.setAttribute('y1', grad.y1);
el.setAttribute('y2', grad.y2);
}
for (i=0, n=grad.stops.length; i<n; ++i) {
stop = domChild(el, i, 'stop', ns);
stop.setAttribute('offset', grad.stops[i].offset);
stop.setAttribute('stop-color', grad.stops[i].color);
}
domClear(el, i);
return index;
}
function updateClipping(el, clip, index) {
var mask;
el = domChild(el, index, 'clipPath', ns);
el.setAttribute('id', clip.id);
if (clip.path) {
mask = domChild(el, 0, 'path', ns);
mask.setAttribute('d', clip.path);
} else {
mask = domChild(el, 0, 'rect', ns);
mask.setAttribute('x', 0);
mask.setAttribute('y', 0);
mask.setAttribute('width', clip.width);
mask.setAttribute('height', clip.height);
}
domClear(el, 1);
return index + 1;
}
prototype$8._resetDefs = function() {
var def = this._defs;
def.gradient = {};
def.clipping = {};
};
// -- Manage rendering of items marked as dirty --
prototype$8.dirty = function(item) {
if (item.dirty !== this._dirtyID) {
item.dirty = this._dirtyID;
this._dirty.push(item);
}
};
prototype$8.isDirty = function(item) {
return this._dirtyAll
|| !item._svg
|| item.dirty === this._dirtyID;
};
prototype$8._dirtyCheck = function() {
this._dirtyAll = true;
var items = this._dirty;
if (!items.length || !this._dirtyID) return true;
var id = ++this._dirtyID,
item, mark, type, mdef, i, n, o;
for (i=0, n=items.length; i<n; ++i) {
item = items[i];
mark = item.mark;
if (mark.marktype !== type) {
// memoize mark instance lookup
type = mark.marktype;
mdef = Marks[type];
}
if (mark.zdirty && mark.dirty !== id) {
this._dirtyAll = false;
dirtyParents(item, id);
mark.items.forEach(function(i) { i.dirty = id; });
}
if (mark.zdirty) continue; // handle in standard drawing pass
if (item.exit) { // EXIT
if (mdef.nested && mark.items.length) {
// if nested mark with remaining points, update instead
o = mark.items[0];
if (o._svg) this._update(mdef, o._svg, o);
} else if (item._svg) {
// otherwise remove from DOM
o = item._svg.parentNode;
if (o) o.removeChild(item._svg);
}
item._svg = null;
continue;
}
item = (mdef.nested ? mark.items[0] : item);
if (item._update === id) continue; // already visited
if (!item._svg || !item._svg.ownerSVGElement) {
// ENTER
this._dirtyAll = false;
dirtyParents(item, id);
} else {
// IN-PLACE UPDATE
this._update(mdef, item._svg, item);
}
item._update = id;
}
return !this._dirtyAll;
};
function dirtyParents(item, id) {
for (; item && item.dirty !== id; item=item.mark.group) {
item.dirty = id;
if (item.mark && item.mark.dirty !== id) {
item.mark.dirty = id;
} else return;
}
}
// -- Construct & maintain scenegraph to SVG mapping ---
// Draw a mark container.
prototype$8.draw = function(el, scene, prev) {
if (!this.isDirty(scene)) return scene._svg;
var renderer = this,
svg = this._svg,
mdef = Marks[scene.marktype],
events = scene.interactive === false ? 'none' : null,
isGroup = mdef.tag === 'g',
sibling = null,
i = 0,
parent;
parent = bind(scene, el, prev, 'g', svg);
parent.setAttribute('class', cssClass(scene));
if (!isGroup) {
parent.style.setProperty('pointer-events', events);
}
if (scene.clip) {
parent.setAttribute('clip-path', clip$1(renderer, scene, scene.group));
} else {
parent.removeAttribute('clip-path');
}
function process(item) {
var dirty = renderer.isDirty(item),
node = bind(item, parent, sibling, mdef.tag, svg);
if (dirty) {
renderer._update(mdef, node, item);
if (isGroup) recurse(renderer, node, item);
}
sibling = node;
++i;
}
if (mdef.nested) {
if (scene.items.length) process(scene.items[0]);
} else {
visit(scene, process);
}
domClear(parent, i);
return parent;
};
// Recursively process group contents.
function recurse(renderer, el, group) {
el = el.lastChild.previousSibling;
var prev, idx = 0;
visit(group, function(item) {
prev = renderer.draw(el, item, prev);
++idx;
});
// remove any extraneous DOM elements
domClear(el, 1 + idx);
}
// Bind a scenegraph item to an SVG DOM element.
// Create new SVG elements as needed.
function bind(item, el, sibling, tag, svg) {
var node = item._svg, doc;
// create a new dom node if needed
if (!node) {
doc = el.ownerDocument;
node = domCreate(doc, tag, ns);
item._svg = node;
if (item.mark) {
node.__data__ = item;
node.__values__ = {fill: 'default'};
// if group, create background, content, and foreground elements
if (tag === 'g') {
var bg = domCreate(doc, 'path', ns);
node.appendChild(bg);
bg.__data__ = item;
var cg = domCreate(doc, 'g', ns);
node.appendChild(cg);
cg.__data__ = item;
var fg = domCreate(doc, 'path', ns);
node.appendChild(fg);
fg.__data__ = item;
fg.__values__ = {fill: 'default'};
}
}
}
// (re-)insert if (a) not contained in SVG or (b) sibling order has changed
if (node.ownerSVGElement !== svg || siblingCheck(node, sibling)) {
el.insertBefore(node, sibling ? sibling.nextSibling : el.firstChild);
}
return node;
}
function siblingCheck(node, sibling) {
return node.parentNode
&& node.parentNode.childNodes.length > 1
&& node.previousSibling != sibling; // treat null/undefined the same
}
// -- Set attributes & styles on SVG elements ---
var element = null, // temp var for current SVG element
values = null; // temp var for current values hash
// Extra configuration for certain mark types
var mark_extras = {
group: function(mdef, el, item) {
var fg, bg;
element = fg = el.childNodes[2];
values = fg.__values__;
mdef.foreground(emit, item, this);
values = el.__values__; // use parent's values hash
element = el.childNodes[1];
mdef.content(emit, item, this);
element = bg = el.childNodes[0];
mdef.background(emit, item, this);
var value = item.mark.interactive === false ? 'none' : null;
if (value !== values.events) {
fg.style.setProperty('pointer-events', value);
bg.style.setProperty('pointer-events', value);
values.events = value;
}
if (item.strokeForeground && item.stroke) {
const fill = item.fill;
fg.style.removeProperty('display');
// set style of background
this.style(bg, item);
bg.style.removeProperty('stroke');
// set style of foreground
if (fill) item.fill = null;
values = fg.__values__;
this.style(fg, item);
if (fill) item.fill = fill;
// leave element null to prevent downstream styling
element = null;
} else {
// ensure foreground is ignored
fg.style.setProperty('display', 'none');
fg.style.setProperty('fill', 'none');
}
},
image: function(mdef, el, item) {
if (item.smooth === false) {
setStyle(el, 'image-rendering', 'optimizeSpeed');
setStyle(el, 'image-rendering', 'pixelated');
} else {
setStyle(el, 'image-rendering', null);
}
},
text: function(mdef, el, item) {
var tl = textLines(item),
key, value, doc, lh;
if (vegaUtil.isArray(tl)) {
// multi-line text
value = tl.map(_ => textValue(item, _));
key = value.join('\n'); // content cache key
if (key !== values.text) {
domClear(el, 0);
doc = el.ownerDocument;
lh = lineHeight(item);
value.forEach((t, i) => {
const ts = domCreate(doc, 'tspan', ns);
ts.__data__ = item; // data binding
ts.textContent = t;
if (i) {
ts.setAttribute('x', 0);
ts.setAttribute('dy', lh);
}
el.appendChild(ts);
});
values.text = key;
}
} else {
// single-line text
value = textValue(item, tl);
if (value !== values.text) {
el.textContent = value;
values.text = value;
}
}
setStyle(el, 'font-family', fontFamily(item));
setStyle(el, 'font-size', fontSize(item) + 'px');
setStyle(el, 'font-style', item.fontStyle);
setStyle(el, 'font-variant', item.fontVariant);
setStyle(el, 'font-weight', item.fontWeight);
}
};
function setStyle(el, name, value) {
if (value !== values[name]) {
if (value == null) {
el.style.removeProperty(name);
} else {
el.style.setProperty(name, value + '');
}
values[name] = value;
}
}
prototype$8._update = function(mdef, el, item) {
// set dom element and values cache
// provides access to emit method
element = el;
values = el.__values__;
// apply svg attributes
mdef.attr(emit, item, this);
// some marks need special treatment
var extra = mark_extras[mdef.type];
if (extra) extra.call(this, mdef, el, item);
// apply svg css styles
// note: element may be modified by 'extra' method
if (element) this.style(element, item);
};
function emit(name, value, ns) {
// early exit if value is unchanged
if (value === values[name]) return;
if (value != null) {
// if value is provided, update DOM attribute
if (ns) {
element.setAttributeNS(ns, name, value);
} else {
element.setAttribute(name, value);
}
} else {
// else remove DOM attribute
if (ns) {
element.removeAttributeNS(ns, name);
} else {
element.removeAttribute(name);
}
}
// note current value for future comparison
values[name] = value;
}
prototype$8.style = function(el, o) {
if (o == null) return;
var i, n, prop, name, value;
for (i=0, n=styleProperties.length; i<n; ++i) {
prop = styleProperties[i];
value = o[prop];
if (prop === 'font') {
value = fontFamily(o);
}
if (value === values[prop]) continue;
name = styles[prop];
if (value == null) {
if (name === 'fill') {
el.style.setProperty(name, 'none');
} else {
el.style.removeProperty(name);
}
} else {
if (isGradient(value)) {
value = gradientRef(value, this._defs.gradient, href());
}
el.style.setProperty(name, value + '');
}
values[prop] = value;
}
};
function href() {
var loc;
return typeof window === 'undefined' ? ''
: (loc = window.location).hash ? loc.href.slice(0, -loc.hash.length)
: loc.href;
}
function SVGStringRenderer(loader) {
Renderer.call(this, loader);
this._text = {
head: '',
bg: '',
root: '',
foot: '',
defs: '',
body: ''
};
this._defs = {
gradient: {},
clipping: {}
};
}
var prototype$9 = vegaUtil.inherits(SVGStringRenderer, Renderer);
var base$2 = Renderer.prototype;
prototype$9.resize = function(width, height, origin, scaleFactor) {
base$2.resize.call(this, width, height, origin, scaleFactor);
var o = this._origin,
t = this._text;
var attr = {
class: 'marks',
width: this._width * this._scale,
height: this._height * this._scale,
viewBox: '0 0 ' + this._width + ' ' + this._height
};
for (var key in metadata) {
attr[key] = metadata[key];
}
t.head = openTag('svg', attr);
var bg = this._bgcolor;
if (bg === 'transparent' || bg === 'none') bg = null;
if (bg) {
t.bg = openTag('rect', {
width: this._width,
height: this._height,
style: 'fill: ' + bg + ';'
}) + closeTag('rect');
} else {
t.bg = '';
}
t.root = openTag('g', {
transform: 'translate(' + o + ')'
});
t.foot = closeTag('g') + closeTag('svg');
return this;
};
prototype$9.background = function() {
var rv = base$2.background.apply(this, arguments);
if (arguments.length && this._text.head) {
this.resize(this._width, this._height, this._origin, this._scale);
}
return rv;
};
prototype$9.svg = function() {
var t = this._text;
return t.head + t.bg + t.defs + t.root + t.body + t.foot;
};
prototype$9._render = function(scene) {
this._text.body = this.mark(scene);
this._text.defs = this.buildDefs();
return this;
};
prototype$9.buildDefs = function() {
var all = this._defs,
defs = '',
i, id, def, tag, stops;
for (id in all.gradient) {
def = all.gradient[id];
stops = def.stops;
if (def.gradient === 'radial') {
// SVG radial gradients automatically transform to normalized bbox
// coordinates, in a way that is cumbersome to replicate in canvas.
// So we wrap the radial gradient in a pattern element, allowing us
// to mantain a circular gradient that matches what canvas provides.
defs += openTag(tag = 'pattern', {
id: patternPrefix + id,
viewBox: '0,0,1,1',
width: '100%',
height: '100%',
preserveAspectRatio: 'xMidYMid slice'
});
defs += openTag('rect', {
width: '1',
height: '1',
fill: 'url(#' + id + ')'
}) + closeTag('rect');
defs += closeTag(tag);
defs += openTag(tag = 'radialGradient', {
id: id,
fx: def.x1,
fy: def.y1,
fr: def.r1,
cx: def.x2,
cy: def.y2,
r: def.r2
});
} else {
defs += openTag(tag = 'linearGradient', {
id: id,
x1: def.x1,
x2: def.x2,
y1: def.y1,
y2: def.y2
});
}
for (i=0; i<stops.length; ++i) {
defs += openTag('stop', {
offset: stops[i].offset,
'stop-color': stops[i].color
}) + closeTag('stop');
}
defs += closeTag(tag);
}
for (id in all.clipping) {
def = all.clipping[id];
defs += openTag('clipPath', {id: id});
if (def.path) {
defs += openTag('path', {
d: def.path
}) + closeTag('path');
} else {
defs += openTag('rect', {
x: 0,
y: 0,
width: def.width,
height: def.height
}) + closeTag('rect');
}
defs += closeTag('clipPath');
}
return (defs.length > 0) ? openTag('defs') + defs + closeTag('defs') : '';
};
var object;
function emit$1(name, value, ns, prefixed) {
object[prefixed || name] = value;
}
prototype$9.attributes = function(attr, item) {
object = {};
attr(emit$1, item, this);
return object;
};
prototype$9.href = function(item) {
var that = this,
href = item.href,
attr;
if (href) {
if (attr = that._hrefs && that._hrefs[href]) {
return attr;
} else {
that.sanitizeURL(href).then(function(attr) {
// rewrite to use xlink namespace
// note that this will be deprecated in SVG 2.0
attr['xlink:href'] = attr.href;
attr.href = null;
(that._hrefs || (that._hrefs = {}))[href] = attr;
});
}
}
return null;
};
prototype$9.mark = function(scene) {
var renderer = this,
mdef = Marks[scene.marktype],
tag = mdef.tag,
defs = this._defs,
str = '',
style;
if (tag !== 'g' && scene.interactive === false) {
style = 'style="pointer-events: none;"';
}
// render opening group tag
str += openTag('g', {
'class': cssClass(scene),
'clip-path': scene.clip ? clip$1(renderer, scene, scene.group) : null
}, style);
// render contained elements
function process(item) {
var href = renderer.href(item);
if (href) str += openTag('a', href);
style = (tag !== 'g') ? applyStyles(item, scene, tag, defs) : null;
str += openTag(tag, renderer.attributes(mdef.attr, item), style);
if (tag === 'text') {
const tl = textLines(item);
if (vegaUtil.isArray(tl)) {
// multi-line text
const attrs = {x: 0, dy: lineHeight(item)};
for (let i=0; i<tl.length; ++i) {
str += openTag('tspan', i ? attrs: null)
+ escape_text(textValue(item, tl[i]))
+ closeTag('tspan');
}
} else {
// single-line text
str += escape_text(textValue(item, tl));
}
} else if (tag === 'g') {
const fore = item.strokeForeground,
fill = item.fill,
stroke = item.stroke;
if (fore && stroke) {
item.stroke = null;
}
str += openTag('path', renderer.attributes(mdef.background, item),
applyStyles(item, scene, 'bgrect', defs)) + closeTag('path');
str += openTag('g', renderer.attributes(mdef.content, item))
+ renderer.markGroup(item)
+ closeTag('g');
if (fore && stroke) {
if (fill) item.fill = null;
item.stroke = stroke;
str += openTag('path', renderer.attributes(mdef.foreground, item),
applyStyles(item, scene, 'bgrect', defs)) + closeTag('path');
if (fill) item.fill = fill;
} else {
str += openTag('path', renderer.attributes(mdef.foreground, item),
applyStyles({}, scene, 'bgfore', defs)) + closeTag('path');
}
}
str += closeTag(tag);
if (href) str += closeTag('a');
}
if (mdef.nested) {
if (scene.items && scene.items.length) process(scene.items[0]);
} else {
visit(scene, process);
}
// render closing group tag
return str + closeTag('g');
};
prototype$9.markGroup = function(scene) {
var renderer = this,
str = '';
visit(scene, function(item) {
str += renderer.mark(item);
});
return str;
};
function applyStyles(o, mark, tag, defs) {
if (o == null) return '';
var i, n, prop, name, value, s = '';
if (tag === 'bgrect' && mark.interactive === false) {
s += 'pointer-events: none; ';
}
if (tag === 'bgfore') {
if (mark.interactive === false) {
s += 'pointer-events: none; ';
}
s += 'display: none; ';
}
if (tag === 'image') {
if (o.smooth === false) {
s += 'image-rendering: optimizeSpeed; image-rendering: pixelated; ';
}
}
if (tag === 'text') {
s += 'font-family: ' + fontFamily(o) + '; ';
s += 'font-size: ' + fontSize(o) + 'px; ';
if (o.fontStyle) s += 'font-style: ' + o.fontStyle + '; ';
if (o.fontVariant) s += 'font-variant: ' + o.fontVariant + '; ';
if (o.fontWeight) s += 'font-weight: ' + o.fontWeight + '; ';
}
for (i=0, n=styleProperties.length; i<n; ++i) {
prop = styleProperties[i];
name = styles[prop];
value = o[prop];
if (value == null) {
if (name === 'fill') {
s += 'fill: none; ';
}
} else if (value === 'transparent' && (name === 'fill' || name === 'stroke')) {
// transparent is not a legal SVG value, so map to none instead
s += name + ': none; ';
} else {
if (isGradient(value)) {
value = gradientRef(value, defs.gradient, '');
}
s += name + ': ' + value + '; ';
}
}
return s ? 'style="' + s.trim() + '"' : null;
}
function escape_text(s) {
return s.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}
var Canvas = 'canvas';
var PNG = 'png';
var SVG = 'svg';
var None = 'none';
var RenderType = {
Canvas: Canvas,
PNG: PNG,
SVG: SVG,
None: None
};
var modules = {};
modules[Canvas] = modules[PNG] = {
renderer: CanvasRenderer,
headless: CanvasRenderer,
handler: CanvasHandler
};
modules[SVG] = {
renderer: SVGRenderer,
headless: SVGStringRenderer,
handler: SVGHandler
};
modules[None] = {};
function renderModule(name, _) {
name = String(name || '').toLowerCase();
if (arguments.length > 1) {
modules[name] = _;
return this;
} else {
return modules[name];
}
}
function intersect(scene, bounds, filter) {
const hits = [], // intersection results
box = new Bounds().union(bounds), // defensive copy
type = scene.marktype;
return type ? intersectMark(scene, box, filter, hits)
: type === 'group' ? intersectGroup(scene, box, filter, hits)
: vegaUtil.error('Intersect scene must be mark node or group item.');
}
function intersectMark(mark, box, filter, hits) {
if (visitMark(mark, box, filter)) {
const items = mark.items,
type = mark.marktype,
n = items.length;
let i = 0;
if (type === 'group') {
for (; i<n; ++i) {
intersectGroup(items[i], box, filter, hits);
}
} else {
for (const test = Marks[type].isect; i<n; ++i) {
let item = items[i];
if (intersectItem(item, box, test)) hits.push(item);
}
}
}
return hits;
}
function visitMark(mark, box, filter) {
// process if bounds intersect and if
// (1) mark is a group mark (so we must recurse), or
// (2) mark is interactive and passes filter
return mark.bounds && box.intersects(mark.bounds) && (
mark.marktype === 'group' ||
mark.interactive !== false && (!filter || filter(mark))
);
}
function intersectGroup(group, box, filter, hits) {
// test intersect against group
// skip groups by default unless filter says otherwise
if ((filter && filter(group.mark)) &&
intersectItem(group, box, Marks.group.isect)) {
hits.push(group);
}
// recursively test children marks
// translate box to group coordinate space
const marks = group.items,
n = marks && marks.length;
if (n) {
const x = group.x || 0,
y = group.y || 0;
box.translate(-x, -y);
for (let i=0; i<n; ++i) {
intersectMark(marks[i], box, filter, hits);
}
box.translate(x, y);
}
return hits;
}
function intersectItem(item, box, test) {
// test bounds enclosure, bounds intersection, then detailed test
const bounds = item.bounds;
return box.encloses(bounds) || (box.intersects(bounds) && test(item, box));
}
var clipBounds = new Bounds();
function boundClip(mark) {
var clip = mark.clip;
if (vegaUtil.isFunction(clip)) {
clip(context(clipBounds.clear()));
} else if (clip) {
clipBounds.set(0, 0, mark.group.width, mark.group.height);
} else return;
mark.bounds.intersect(clipBounds);
}
var TOLERANCE = 1e-9;
function sceneEqual(a, b, key) {
return (a === b) ? true
: (key === 'path') ? pathEqual(a, b)
: (a instanceof Date && b instanceof Date) ? +a === +b
: (vegaUtil.isNumber(a) && vegaUtil.isNumber(b)) ? Math.abs(a - b) <= TOLERANCE
: (!a || !b || !vegaUtil.isObject(a) && !vegaUtil.isObject(b)) ? a == b
: (a == null || b == null) ? false
: objectEqual(a, b);
}
function pathEqual(a, b) {
return sceneEqual(pathParse(a), pathParse(b));
}
function objectEqual(a, b) {
var ka = Object.keys(a),
kb = Object.keys(b),
key, i;
if (ka.length !== kb.length) return false;
ka.sort();
kb.sort();
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] != kb[i]) return false;
}
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!sceneEqual(a[key], b[key], key)) return false;
}
return typeof a === typeof b;
}
exports.Bounds = Bounds;
exports.CanvasHandler = CanvasHandler;
exports.CanvasRenderer = CanvasRenderer;
exports.Gradient = Gradient;
exports.GroupItem = GroupItem;
exports.Handler = Handler;
exports.Item = Item;
exports.Marks = Marks;
exports.RenderType = RenderType;
exports.Renderer = Renderer;
exports.ResourceLoader = ResourceLoader;
exports.SVGHandler = SVGHandler;
exports.SVGRenderer = SVGRenderer;
exports.SVGStringRenderer = SVGStringRenderer;
exports.Scenegraph = Scenegraph;
exports.boundClip = boundClip;
exports.boundContext = context;
exports.boundItem = boundItem;
exports.boundMark = boundMark;
exports.boundStroke = boundStroke;
exports.closeTag = closeTag;
exports.domChild = domChild;
exports.domClear = domClear;
exports.domCreate = domCreate;
exports.domFind = domFind;
exports.font = font;
exports.fontFamily = fontFamily;
exports.fontSize = fontSize;
exports.intersect = intersect;
exports.intersectBoxLine = intersectBoxLine;
exports.intersectPath = intersectPath;
exports.intersectPoint = intersectPoint;
exports.intersectRule = intersectRule;
exports.lineHeight = lineHeight;
exports.multiLineOffset = multiLineOffset;
exports.openTag = openTag;
exports.pathCurves = curves;
exports.pathEqual = pathEqual;
exports.pathParse = pathParse;
exports.pathRectangle = vg_rect;
exports.pathRender = pathRender;
exports.pathSymbols = symbols;
exports.pathTrail = vg_trail;
exports.point = point;
exports.renderModule = renderModule;
exports.resetSVGClipId = resetSVGClipId;
exports.sceneEqual = sceneEqual;
exports.sceneFromJSON = sceneFromJSON;
exports.scenePickVisit = pickVisit;
exports.sceneToJSON = sceneToJSON;
exports.sceneVisit = visit;
exports.sceneZOrder = zorder;
exports.textMetrics = textMetrics;
Object.defineProperty(exports, '__esModule', { value: true });
})));