prototype.interpolate = function(item, values) { var key, curr, next, interp, list = null; for (key in values) { curr = item[key]; next = values[key]; if (curr !== next) { if (skip[key] || curr === undefined) { // skip interpolation for specific keys or undefined start values Tuple.set(item, key, next); } else if (typeof curr === 'number' && !isFinite(curr)) { // for NaN or infinite numeric values, skip to final value Tuple.set(item, key, next); } else { // otherwise lookup interpolator interp = d3.interpolate(curr, next); interp.property = key; (list || (list=[])).push(interp); } } } if (list === null && item.status === Status.EXIT) { list = []; // ensure exiting items are included } if (list != null) { list.item = item; list.ease = item.mark.ease || this.ease; list.next = this.updates.next; this.updates.next = list; } return this; };
prototype.batchTransform = function(input, data) { log.debug(input, ['stacking']); var groupby = this.param('groupby').accessor, sortby = dl.comparator(this.param('sortby').field), field = this.param('field').accessor, offset = this.param('offset'), output = this._output; // partition, sum, and sort the stack groups var groups = partition(data, groupby, sortby, field); // compute stack layouts per group for (var i=0, max=groups.max; i<groups.length; ++i) { var group = groups[i], sum = group.sum, off = offset==='center' ? (max - sum)/2 : 0, scale = offset==='normalize' ? (1/sum) : 1, j, x, a, b = off, v = 0; // set stack coordinates for each datum in group for (j=0; j<group.length; ++j) { x = group[j]; a = b; // use previous value for start point v += field(x); b = scale * v + off; // compute end point Tuple.set(x, output.start, a); Tuple.set(x, output.end, b); Tuple.set(x, output.mid, 0.5 * (a + b)); } } input.fields[output.start] = 1; input.fields[output.end] = 1; input.fields[output.mid] = 1; return input; };
update.encode = function(item, group, trans, db, signals, preds) { var dirty = fn.call(fn, item, group, trans, db, signals, preds), field = (orient==='bottom' || orient==='top') ? 'y' : 'x'; if (titleStyle[field] != null) return dirty; axisBounds.clear() .union(group.items[3].bounds) .union(group.items[4].bounds); var o = trans ? {} : item, method = (orient==='left' || orient==='right') ? 'width' : 'height', sign = (orient==='top' || orient==='left') ? -1 : 1, off = ~~(axisBounds[method]() + item.fontSize/2 + pad); Tuple.set(o, field, sign * Math.min(Math.max(min, off), max)); if (trans) trans.interpolate(item, o); return true; };
prototype.batchTransform = function(input, data) { log.debug(input, ['treeifying']); var fields = this.param('groupby').field, childField = this._output.children, parentField = this._output.parent, summary = [{name:'*', ops: ['values'], as: [childField]}], aggrs = fields.map(function(f) { return dl.groupby(f).summarize(summary); }), prev = this._internal || [], curr = [], i, n; function level(index, node, values) { var vals = aggrs[index].execute(values); node[childField] = vals; vals.forEach(function(n) { n[parentField] = node; curr.push(Tuple.ingest(n)); if (index+1 < fields.length) level(index+1, n, n[childField]); else n[childField].forEach(function(c) { c[parentField] = n; }); }); } var root = Tuple.ingest({}); root[parentField] = null; curr.push(root); level(0, root, data); // update changeset with internal nodes for (i=0, n=curr.length; i<n; ++i) { input.add.push(curr[i]); } for (i=0, n=prev.length; i<n; ++i) { input.rem.push(prev[i]); } this._internal = curr; return input; };
function tuple(gb, gv, ob, ov) { var t = {_imputed: true}, i; for (i=0; i<gv.length; ++i) t[gb[i]] = gv[i]; for (i=0; i<ov.length; ++i) t[ob[i]] = ov[i]; return Tuple.ingest(t); }
function axisUpdate(item, group, trans) { var o = trans ? {} : item, offset = item.mark.def.offset, orient = item.mark.def.orient, width = group.width, height = group.height; // TODO fallback to global w,h? if (dl.isArray(offset)) { var ofx = offset[0], ofy = offset[1]; switch (orient) { case 'left': { Tuple.set(o, 'x', -ofx); Tuple.set(o, 'y', ofy); break; } case 'right': { Tuple.set(o, 'x', width + ofx); Tuple.set(o, 'y', ofy); break; } case 'bottom': { Tuple.set(o, 'x', ofx); Tuple.set(o, 'y', height + ofy); break; } case 'top': { Tuple.set(o, 'x', ofx); Tuple.set(o, 'y', -ofy); break; } default: { Tuple.set(o, 'x', ofx); Tuple.set(o, 'y', ofy); } } } else { if (dl.isObject(offset)) { offset = -group.scale(offset.scale)(offset.value); } switch (orient) { case 'left': { Tuple.set(o, 'x', -offset); Tuple.set(o, 'y', 0); break; } case 'right': { Tuple.set(o, 'x', width + offset); Tuple.set(o, 'y', 0); break; } case 'bottom': { Tuple.set(o, 'x', 0); Tuple.set(o, 'y', height + offset); break; } case 'top': { Tuple.set(o, 'x', 0); Tuple.set(o, 'y', -offset); break; } default: { Tuple.set(o, 'x', 0); Tuple.set(o, 'y', 0); } } } if (trans) trans.interpolate(item, o); return true; }
function set(t) { var path = shape(sourceX(t), sourceY(t), targetX(t), targetY(t), tension); Tuple.set(t, output.path, path); }
vals.forEach(function(n) { n[parentField] = node; curr.push(Tuple.ingest(n)); if (index+1 < fields.length) level(index+1, n, n[childField]); else n[childField].forEach(function(c) { c[parentField] = n; }); });
function set(t) { var ll = [lon(t), lat(t)]; var xy = proj(ll) || [null, null]; Tuple.set(t, output.x, xy[0]); Tuple.set(t, output.y, xy[1]); }
function set(t) { Tuple.set(t, output.path, path(geojson(t))); }