Socket
Socket
Sign inDemoInstall

vega

Package Overview
Dependencies
Maintainers
2
Versions
181
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

vega - npm Package Compare versions

Comparing version 2.3.1 to 2.4.0

src/transforms/Hierarchy.js

1

index.js

@@ -18,3 +18,4 @@ module.exports = {

util: require('datalib'),
logging: require('vega-logging'),
debug: require('vega-logging').debug
};

17

package.json
{
"name": "vega",
"version": "2.3.1",
"version": "2.4.0",
"description": "The Vega visualization grammar.",

@@ -35,13 +35,16 @@ "keywords": [

"dependencies": {
"d3": "^3.5.6",
"d3": "^3.5.9",
"d3-geo-projection": "^0.2.15",
"d3-cloud": "^1.2.0",
"datalib": "^1.4.6",
"d3-cloud": "^1.2.1",
"datalib": "^1.4.12",
"topojson": "^1.6.19",
"vega-dataflow": "^1.2.5",
"vega-dataflow": "^1.3.2",
"vega-expression": "^1.0.3",
"vega-logging": "^1.0.1",
"vega-scenegraph": "^1.0.11",
"yargs": "^3.15.0"
"vega-scenegraph": "^1.0.15",
"yargs": "^3.30.0"
},
"optionalDependencies": {
"canvas": "^1.3.4"
},
"devDependencies": {

@@ -48,0 +51,0 @@ "browserify": "^10.2.6",

@@ -29,2 +29,13 @@ var d3 = require('d3'),

// root scenegraph group
config.scene = {
fill: undefined,
fillOpacity: undefined,
stroke: undefined,
strokeOpacity: undefined,
strokeWidth: undefined,
strokeDash: undefined,
strokeDashOffset: undefined
};
// default axis properties

@@ -36,2 +47,3 @@ config.axis = {

axisColor: '#000',
axisWidth: 1,
gridColor: '#000',

@@ -41,3 +53,2 @@ gridOpacity: 0.15,

tickLabelColor: '#000',
axisWidth: 1,
tickWidth: 1,

@@ -51,3 +62,6 @@ tickSize: 6,

titleFontWeight: 'bold',
titleOffset: 35
titleOffset: 'auto',
titleOffsetAutoMin: 30,
titleOffsetAutoMax: Infinity,
titleOffsetAutoMargin: 4
};

@@ -59,3 +73,4 @@

offset: 20,
padding: 3,
padding: 3, // padding between legend items and border
margin: 2, // extra margin between two consecutive legends
gradientStrokeColor: '#888',

@@ -62,0 +77,0 @@ gradientStrokeWidth: 1,

@@ -7,3 +7,3 @@ var sg = require('vega-scenegraph').render,

function HeadlessView(width, height, model) {
View.call(null, width, height, model);
View.call(this, width, height, model);
this._type = 'canvas';

@@ -26,3 +26,3 @@ this._renderers = {canvas: canvas, svg: svg};

var r = this._renderer, view = this;
function wait() {

@@ -46,3 +46,3 @@ if (r.pendingImages() === 0) {

prototype.initialize = function() {
prototype.initialize = function() {
var w = this._width,

@@ -62,3 +62,3 @@ h = this._height,

.background(bg);
return this;

@@ -65,0 +65,0 @@ };

@@ -13,6 +13,8 @@ var dl = require('datalib'),

this._predicates = {};
this._scene = null;
this._scene = null; // Root scenegraph node.
this._groups = null; // Index of group items.
this._node = null;
this._builder = null; // Top-level scenegraph builder
this._builder = null; // Top-level scenegraph builder.

@@ -99,10 +101,33 @@ this._reset = {axes: false, legends: false};

if (!arguments.length) return this._scene;
if (this._builder) this.node().removeListener(this._builder.disconnect());
this._builder = new GroupBuilder(this, this._defs.marks, this._scene={});
this.node().addListener(this._builder.connect());
var p = this._builder.pipeline();
p[p.length-1].addListener(renderer);
if (this._builder) {
this.node().removeListener(this._builder);
this._builder._groupBuilder.disconnect();
}
var m = this,
b = this._builder = new Node(this);
b.evaluate = function(input) {
if (b._groupBuilder) return input;
var gb = b._groupBuilder = new GroupBuilder(m, m._defs.marks, m._scene={}),
p = gb.pipeline();
m._groups = {};
this.addListener(gb.connect());
p[p.length-1].addListener(renderer);
return input;
};
this.addListener(b);
return this;
};
prototype.group = function(id, item) {
var groups = this._groups;
if (arguments.length === 1) return groups[id];
return (groups[id] = item, this);
};
prototype.reset = function() {

@@ -129,3 +154,3 @@ if (this._scene && this._reset.axes) {

prototype.removeListener = function(l) {
this.node().removeListener(l);
this.node().removeListener(l);
};

@@ -132,0 +157,0 @@

@@ -17,3 +17,3 @@ var dl = require('datalib'),

// Compile if we're not loading the schema from a URL.
// Compile if we're not loading the schema from a URL.
// Load from a URL to extend the existing base schema.

@@ -26,4 +26,4 @@ if (opt.url) {

"title": "Vega Visualization Specification Language",
"defs": {},
"refs": {},
"defs": {},
"refs": {},
"$ref": "#/defs/spec"

@@ -48,2 +48,2 @@ };

return schema;
};
};

@@ -14,3 +14,3 @@ var d3 = require('d3'),

this._model = null;
this._width = this.__width = width || 500;
this._width = this.__width = width || 500;
this._height = this.__height = height || 300;

@@ -54,3 +54,3 @@ this._bgcolor = null;

// If we have it stashed, don't create a new closure.
// If we have it stashed, don't create a new closure.
if (this._api[src]) return this._api[src];

@@ -77,3 +77,3 @@

api.values = function() { return ds.values(); };
api.values = function() { return ds.values(); };

@@ -96,7 +96,7 @@ return (this._api[src] = api);

var VIEW_SIGNALS = dl.toMap(['width', 'height', 'padding']);
prototype.signal = function(name, value, propagate) {
var m = this._model,
cs = this._changeset,
streamer = this._streamer,
batch;
var m = this._model,
key, values;

@@ -114,18 +114,25 @@ // Getter. Returns the value for the specified signal, or

if (dl.isObject(name)) {
batch = name;
values = name;
propagate = value;
} else {
batch = {};
batch[name] = value;
values = {};
values[name] = value;
}
dl.keys(batch).forEach(function(k) {
streamer.addListener(m.signal(k).value(batch[k]));
if (propagate !== false) cs.signals[k] = 1;
cs.reflow = true;
});
for (key in values) {
if (VIEW_SIGNALS[key]) {
this[key](values[key]);
} else {
setSignal.call(this, key, values[key], propagate);
}
}
return this;
};
function setSignal(name, value, propagate) {
var cs = this._changeset;
this._streamer.addListener(this._model.signal(name).value(value));
if (propagate !== false) cs.signals[name] = 1;
cs.reflow = true;
}
prototype.width = function(width) {

@@ -138,2 +145,3 @@ if (!arguments.length) return this.__width;

if (this._strict) this._autopad = 1;
setSignal.call(this, 'width', width);
}

@@ -150,2 +158,3 @@ return this;

if (this._strict) this._autopad = 1;
setSignal.call(this, 'height', height);
}

@@ -176,4 +185,5 @@ return this;

}
if (this._renderer) this._renderer.resize(this._width, this._height, pad);
if (this._handler) this._handler.padding(pad);
if (this._renderer) this._renderer.resize(this._width, this._height, this._padding);
if (this._handler) this._handler.padding(this._padding);
setSignal.call(this, 'padding', this._padding);
}

@@ -203,7 +213,8 @@ return (this._repaint = true, this);

this._model.width(this._width)
.height(this._height).reset();
this._model.width(this._width).height(this._height).reset();
setSignal.call(this, 'width', this._width);
setSignal.call(this, 'height', this._height);
setSignal.call(this, 'padding', pad);
this.initialize()
.update({props:'enter'}).update({props:'update'});
this.initialize().update({props:'enter'}).update({props:'update'});
} else {

@@ -251,3 +262,3 @@ this.padding(pad).update(opt);

d3.select(el).select('div.vega').remove();
// add div container

@@ -271,3 +282,3 @@ this._el = el = d3.select(el)

.background(bg);
// input handler

@@ -286,3 +297,3 @@ prevHandler = v._handler;

}
return (this._repaint = true, this);

@@ -322,8 +333,6 @@ };

// For all updated datasources, clear their previous values.
for (var d in input.data) { v._model.data(d).synchronize(); }
return input;
};
return (v._model.scene(v._renderNode), true);
return (v._model.scene(v._renderNode), true);
}

@@ -334,5 +343,7 @@

var v = this,
model = this._model,
streamer = this._streamer,
cs = this._changeset,
trans = opt.duration ? new Transition(opt.duration, opt.ease) : null;
var cs = v._changeset;
if (trans) cs.trans = trans;

@@ -356,11 +367,13 @@ if (opt.props !== undefined) {

// Else-If there are streaming updates, perform a targeted propagation.
// Otherwise, reevaluate the entire model (datasources + scene).
if (opt.items && built) {
Encoder.update(this._model, opt.trans, opt.props, opt.items, cs.dirty);
// Otherwise, re-evaluate the entire model (datasources + scene).
if (opt.items && built) {
Encoder.update(model, opt.trans, opt.props, opt.items, cs.dirty);
v._renderNode.evaluate(cs);
} else if (v._streamer.listeners().length && built) {
v._model.propagate(cs, v._streamer);
v._streamer.disconnect();
} else if (streamer.listeners().length && built) {
// Include re-evaluation entire model when repaint flag is set
if (this._repaint) streamer.addListener(model.node());
model.propagate(cs, streamer);
streamer.disconnect();
} else {
v._model.fire(cs);
model.fire(cs);
}

@@ -459,7 +472,7 @@

}
return v;
};
};
};
module.exports = View;

@@ -100,3 +100,3 @@ var dl = require('datalib'),

"values": {
"type": "array",
"type": "array",
"items": {"type": ["string", "number"]}

@@ -103,0 +103,0 @@ },

@@ -7,3 +7,3 @@ var d3 = require('d3');

// run through d3 rgb to sanity check
return d3.rgb(bg) + "";
return d3.rgb(bg) + '';
}

@@ -10,0 +10,0 @@

@@ -10,10 +10,20 @@ var dl = require('datalib'),

function loaded(d) {
function onError(error, d) {
log.error('PARSE DATA FAILED: ' + d.name + ' ' + error);
count = -1;
callback(error);
}
function onLoad(d) {
return function(error, data) {
if (error) {
log.error('LOADING FAILED: ' + d.url + ' ' + error);
} else {
model.data(d.name).values(dl.read(data, d.format));
onError(error, d);
} else if (count > 0) {
try {
model.data(d.name).values(dl.read(data, d.format));
if (--count === 0) callback();
} catch (err) {
onError(err, d);
}
}
if (--count === 0) callback();
};

@@ -26,5 +36,9 @@ }

count += 1;
dl.load(dl.extend({url: d.url}, config.load), loaded(d));
dl.load(dl.extend({url: d.url}, config.load), onLoad(d));
}
parseData.datasource(model, d);
try {
parseData.datasource(model, d);
} catch (err) {
onError(err, d);
}
});

@@ -38,3 +52,3 @@

var transform = (d.transform || []).map(function(t) {
return parseTransforms(model, t);
return parseTransforms(model, t);
}),

@@ -50,7 +64,7 @@ mod = (d.modify || []).map(function(m) {

// Derived ds will be pulsed by its src rather than the model.
ds.source(d.source).addListener(ds);
model.removeListener(ds.pipeline()[0]);
ds.source(d.source).addListener(ds);
model.removeListener(ds.pipeline()[0]);
}
return ds;
return ds;
};

@@ -57,0 +71,0 @@

module.exports = {
axes: require('./axes'),
axes: require('./axes'),
background: require('./background'),
data: require('./data'),
events: require('./events'),
expr: require('./expr'),
legends: require('./legends'),
mark: require('./mark'),
marks: require('./marks'),
modify: require('./modify'),
padding: require('./padding'),
data: require('./data'),
events: require('./events'),
expr: require('./expr'),
legends: require('./legends'),
mark: require('./mark'),
marks: require('./marks'),
modify: require('./modify'),
padding: require('./padding'),
predicates: require('./predicates'),
properties: require('./properties'),
signals: require('./signals'),
spec: require('./spec'),
streams: require('./streams'),
signals: require('./signals'),
spec: require('./spec'),
streams: require('./streams'),
transforms: require('./transforms')
};
};

@@ -62,10 +62,10 @@ var dl = require('datalib'),

}
}
}
}
function ns(n, s) {
function ns(n, s) {
if (dl.isString(s)) {
return s + "_" + n;
} else {
dl.keys(s).forEach(function(x) {
dl.keys(s).forEach(function(x) {
var regex = new RegExp('\\b'+x+'\\b', "g");

@@ -104,4 +104,4 @@ n = n.replace(regex, s[x]);

});
return predicates;
});
return predicates;
}

@@ -118,7 +118,7 @@

function nsMarks(name, marks) {
(marks || []).forEach(function(m) {
(marks || []).forEach(function(m) {
nsProperties(m.properties.enter);
nsProperties(m.properties.update);
nsProperties(m.properties.exit);
mk[ns(m.name, name)] = m;
mk[ns(m.name, name)] = m;
});

@@ -132,5 +132,5 @@ }

else if (p.rule) {
p.rule.forEach(function(r) {
p.rule.forEach(function(r) {
if (r.signal) r.signal = ns(r.signal, sg);
if (r.predicate) nsOperand(r);
if (r.predicate) nsOperand(r);
});

@@ -167,2 +167,2 @@ }

}
};
};

@@ -22,3 +22,3 @@ var dl = require('datalib'),

}
return mark;

@@ -37,3 +37,3 @@ }

"key": {"type": "string"},
"type": {"enum": ["rect", "symbol", "path", "arc",
"type": {"enum": ["rect", "symbol", "path", "arc",
"area", "line", "rule", "image", "text", "group"]},

@@ -53,3 +53,3 @@

"ease": {
"enum": ["linear", "quad", "cubic", "sin",
"enum": ["linear", "quad", "cubic", "sin",
"exp", "circle", "bounce"].reduce(function(acc, e) {

@@ -56,0 +56,0 @@ ["in", "out", "in-out", "out-in"].forEach(function(m) {

@@ -1,15 +0,40 @@

var parseMark = require('./mark');
var parseMark = require('./mark'),
parseProperties = require('./properties');
function parseRootMark(model, spec, width, height) {
return {
type: "group",
width: width,
height: height,
scales: spec.scales || [],
axes: spec.axes || [],
legends: spec.legends || [],
marks: (spec.marks || []).map(function(m) { return parseMark(model, m); })
type: 'group',
width: width,
height: height,
properties: defaults(spec.scene || {}, model),
scales: spec.scales || [],
axes: spec.axes || [],
legends: spec.legends || [],
marks: (spec.marks || []).map(function(m) { return parseMark(model, m); })
};
}
var PROPERTIES = [
'fill', 'fillOpacity', 'stroke', 'strokeOpacity',
'strokeWidth', 'strokeDash', 'strokeDashOffset'
];
function defaults(spec, model) {
var config = model.config().scene,
props = {}, i, n, m, p, s;
for (i=0, n=m=PROPERTIES.length; i<n; ++i) {
p = PROPERTIES[i];
if ((s=spec[p]) !== undefined) {
props[p] = s.signal ? s : {value: s};
} else if (config[p]) {
props[p] = {value: config[p]};
} else {
--m;
}
}
return m ? {update: parseProperties(model, 'group', props)} : {};
}
module.exports = parseRootMark;

@@ -22,2 +47,31 @@

"properties": {
"scene": {
"type": "object",
"properties": {
"fill": {
"oneOf": [{"type": "string"}, {"$ref": "#/refs/signal"}]
},
"fillOpacity": {
"oneOf": [{"type": "number"}, {"$ref": "#/refs/signal"}]
},
"stroke": {
"oneOf": [{"type": "string"}, {"$ref": "#/refs/signal"}]
},
"strokeOpacity": {
"oneOf": [{"type": "number"}, {"$ref": "#/refs/signal"}]
},
"strokeWidth": {
"oneOf": [{"type": "number"}, {"$ref": "#/refs/signal"}]
},
"strokeDash": {
"oneOf": [
{"type": "array", "items": {"type": "number"}},
{"$ref": "#/refs/signal"}
]
},
"strokeDashOffset": {
"oneOf": [{"type": "number"}, {"$ref": "#/refs/signal"}]
},
}
},
"scales": {

@@ -60,5 +114,5 @@ "type": "array",

{"$ref": "#/defs/mark"}
]
]
}
}
};

@@ -25,7 +25,8 @@ var dl = require('datalib'),

function parseModify(model, def, ds) {
var signal = def.signal ? dl.field(def.signal) : null,
var signal = def.signal ? dl.field(def.signal) : null,
signalName = signal ? signal[0] : null,
predicate = def.predicate ? model.predicate(def.predicate.name || def.predicate) : null,
reeval = (predicate === null),
node = new Node(model).router(def.type === Types.CLEAR);
isClear = def.type === Types.CLEAR,
node = new Node(model).router(isClear);

@@ -40,5 +41,5 @@ node.evaluate = function(input) {

log.debug(input, [def.type+"ing", reeval]);
if (!reeval) return input;
if (!reeval || (!isClear && !input.signals[signalName])) return input;
var datum = {},
var datum = {},
value = signal ? model.signalRef(def.signal) : null,

@@ -52,3 +53,3 @@ d = model.data(ds.name),

// our dynamic data. W/o modifying ds._data, only the output
// collector will contain dynamic tuples.
// collector will contain dynamic tuples.
if (def.type === Types.INSERT) {

@@ -79,3 +80,3 @@ t = Tuple.ingest(datum);

d._data = [];
}
}

@@ -87,3 +88,3 @@ input.fields[def.field] = 1;

if (signalName) node.dependency(Deps.SIGNALS, signalName);
if (predicate) {

@@ -93,3 +94,3 @@ node.dependency(Deps.DATA, predicate.data);

}
return node;

@@ -122,2 +123,2 @@ }

}
};
};
var dl = require('datalib');
function parsePadding(pad) {
if (pad == null) return "auto";
else if (dl.isString(pad)) return pad==="strict" ? "strict" : "auto";
else if (dl.isObject(pad)) return pad;
var p = dl.isNumber(pad) ? pad : 20;
return {top:p, left:p, right:p, bottom:p};
return pad == null ? 'auto' :
dl.isObject(pad) ? pad :
dl.isNumber(pad) ? {top:pad, left:pad, right:pad, bottom:pad} :
pad === 'strict' ? pad : 'auto';
}

@@ -31,2 +30,2 @@

}
};
};

@@ -24,3 +24,3 @@ var dl = require('datalib');

var parse = types[s.type](model, s);
/* jshint evil:true */

@@ -84,4 +84,4 @@ var pred = Function("args", "db", "signals", "predicates", parse.code);

def += ", ";
});
}
});
}

@@ -155,3 +155,3 @@ def += p+".call("+p+", args, db, signals, predicates)";

code += "return ordSet !== null ? ordSet.indexOf(o0) !== -1 :\n" +
code += "return ordSet !== null ? ordSet.indexOf(o0) !== -1 :\n" +
" o1 < o2 ? o1 <= o0 && o0 <= o2 : o2 <= o0 && o0 <= o1;";

@@ -161,4 +161,4 @@ }

return {
code: code,
signals: ops.signals,
code: code,
signals: ops.signals,
data: ops.data.concat(spec.data ? [spec.data] : [])

@@ -168,5 +168,5 @@ };

// Populate ops such that ultimate scale/inversion function will be in `scale` var.
// Populate ops such that ultimate scale/inversion function will be in `scale` var.
function parseScale(spec, ops) {
var code = "var scale = ",
var code = "var scale = ",
idx = ops.length;

@@ -291,2 +291,2 @@

}
};
};

@@ -607,3 +607,3 @@ var d3 = require('d3'),

"align": valueSchema(["left", "right", "center"]),
"baseline": valueSchema(["top", "middle", "bottom"]),
"baseline": valueSchema(["top", "middle", "bottom", "alphabetic"]),

@@ -610,0 +610,0 @@ // Text-mark properties

@@ -5,3 +5,3 @@ var dl = require('datalib'),

var RESERVED = ['datum', 'event', 'signals']
var RESERVED = ['datum', 'event', 'signals', 'width', 'height', 'padding']
.concat(dl.keys(expr.codegen.functions));

@@ -34,3 +34,3 @@

}
return sg[s.name] ? input : model.doNotPropagate;
return sg[s.name] ? input : model.doNotPropagate;
};

@@ -71,2 +71,7 @@ signal.dependency(SIGNALS, s.expr.globals);

// Verify scope is valid
if (model.group(scope._id) !== scope) {
throw new Error('Scope for scale "'+name+'" is not a valid group item.');
}
var s = scope.scale(name);

@@ -131,2 +136,2 @@ return !s ? value : (def.invert ? s.invert(value) : s(value));

}
};
};

@@ -6,30 +6,71 @@ var dl = require('datalib'),

function parseSpec(spec, callback) {
var vf = arguments[arguments.length-1],
viewFactory = arguments.length > 2 && dl.isFunction(vf) ? vf : View.factory,
config = arguments[2] !== viewFactory ? arguments[2] : {},
model = new Model(config);
/**
* Parse graph specification
* @param spec (object)
* @param config (optional object)
* @param viewFactory (optional function)
* @param callback (error, model)
*/
function parseSpec(spec /*, [config,] [viewFactory,] callback */) {
// do not assign any values to callback, as it will change arguments
var arglen = arguments.length,
argidx = 2,
cb = arguments[arglen-1],
model = new Model(),
viewFactory = View.factory;
if (arglen > argidx && dl.isFunction(arguments[arglen - argidx])) {
viewFactory = arguments[arglen - argidx];
++argidx;
}
if (arglen > argidx && dl.isObject(arguments[arglen - argidx])) {
model.config(arguments[arglen - argidx]);
}
function onDone(err, value) {
if (cb) {
if (cb.length > 1) cb(err, value);
else if (!err) cb(value);
cb = null;
}
}
function onError(err) {
log.error(err);
onDone(err);
}
function onCreate(err) {
if (err) onError(err);
else onDone(null, viewFactory(model));
}
function parse(spec) {
// protect against subsequent spec modification
spec = dl.duplicate(spec);
try {
// protect against subsequent spec modification
spec = dl.duplicate(spec);
var parsers = require('./'),
width = spec.width || 500,
height = spec.height || 500,
viewport = spec.viewport || null;
var parsers = require('./'),
width = spec.width || 500,
height = spec.height || 500,
padding = parsers.padding(spec.padding);
model.defs({
width: width,
height: height,
viewport: viewport,
background: parsers.background(spec.background),
padding: parsers.padding(spec.padding),
signals: parsers.signals(model, spec.signals),
predicates: parsers.predicates(model, spec.predicates),
marks: parsers.marks(model, spec, width, height),
data: parsers.data(model, spec.data, function() {
callback(viewFactory(model));
})
});
// create signals for width, height and padding
model.signal('width', width);
model.signal('height', height);
model.signal('padding', padding);
// initialize model
model.defs({
width: width,
height: height,
padding: padding,
viewport: spec.viewport || null,
background: parsers.background(spec.background),
signals: parsers.signals(model, spec.signals),
predicates: parsers.predicates(model, spec.predicates),
marks: parsers.marks(model, spec, width, height),
data: parsers.data(model, spec.data, onCreate)
});
} catch (err) { onError(err); }
}

@@ -41,15 +82,8 @@

var opts = dl.extend({url: spec}, model.config().load);
dl.load(opts, function(err, data) {
if (err) {
log.error('LOADING SPECIFICATION FAILED: ' + err.statusText);
} else {
try {
parse(JSON.parse(data));
} catch (e) {
log.error('INVALID SPECIFICATION: Must be a valid JSON object. '+e);
}
}
dl.json(opts, function(err, spec) {
if (err) onError('SPECIFICATION LOAD FAILED: ' + err);
else parse(spec);
});
} else {
log.error('INVALID SPECIFICATION: Must be a valid JSON object or URL.');
onError('INVALID SPECIFICATION: Must be a valid JSON object or URL.');
}

@@ -59,2 +93,3 @@ }

module.exports = parseSpec;
parseSpec.schema = {

@@ -97,2 +132,2 @@ "defs": {

}
};
};

@@ -48,3 +48,3 @@ var d3 = require('d3'),

// signals are registered on the same event, they will receive the
// new value on the same pulse.
// new value on the same pulse.
dl.keys(internal.handlers).forEach(function(type) {

@@ -137,3 +137,3 @@ view.on(type, function(evt, item) {

if (filtered) continue;
val = h.exp.fn(datum, evt, model.values(SIGNALS, h.exp.globals));

@@ -201,6 +201,6 @@ if (h.spec.scale) {

input.signals[sig.name()] = 1;
input.reflow = true;
input.reflow = true;
}
return input;
return input;
};

@@ -213,5 +213,5 @@ n.dependency(df.Dependencies.SIGNALS, selector.signal);

function orderedStream(sig, selector, exp, spec) {
var name = sig.name(),
gk = name + GATEKEEPER,
trueFn = expr('true'),
var name = sig.name(),
gk = name + GATEKEEPER,
trueFn = expr('true'),
falseFn = expr('false'),

@@ -223,4 +223,4 @@ middle = selector.middle,

// Register an anonymous signal to act as a gatekeeper. Its value is
// true or false depending on whether the start or end streams occur.
// The middle signal then simply filters for the gatekeeper's value.
// true or false depending on whether the start or end streams occur.
// The middle signal then simply filters for the gatekeeper's value.
mergedStream(gatekeeper, [selector.start], trueFn, {});

@@ -253,2 +253,2 @@ mergedStream(gatekeeper, [selector.end], falseFn, {});

}
};
};

@@ -6,3 +6,3 @@ var dl = require('datalib'),

var tx = new transforms[def.type](model);
// We want to rename output fields before setting any other properties,

@@ -34,4 +34,4 @@ // as subsequent properties may require output to be set (e.g. group by).

"items": {
"oneOf": keys.map(function(k) {
return {"$ref": "#/defs/"+k+"Transform"};
"oneOf": keys.map(function(k) {
return {"$ref": "#/defs/"+k+"Transform"};
})

@@ -41,2 +41,2 @@ }

})
};
};

@@ -5,2 +5,4 @@ var dl = require('datalib'),

var axisBounds = new (require('vega-scenegraph').Bounds)();
var TIME = 'time',

@@ -14,6 +16,6 @@ UTC = 'utc',

var scale,
config = model.config(),
orient = config.axis.orient,
config = model.config().axis,
orient = config.orient,
offset = 0,
titleOffset = config.axis.titleOffset,
titleOffset = config.titleOffset,
axisDef = {},

@@ -23,6 +25,6 @@ layer = 'front',

title = null,
tickMajorSize = config.axis.tickSize,
tickMinorSize = config.axis.tickSize,
tickEndSize = config.axis.tickSize,
tickPadding = config.axis.padding,
tickMajorSize = config.tickSize,
tickMinorSize = config.tickSize,
tickEndSize = config.tickSize,
tickPadding = config.padding,
tickValues = null,

@@ -32,3 +34,3 @@ tickFormatString = null,

tickSubdivide = 0,
tickCount = config.axis.ticks,
tickCount = config.ticks,
gridLineStyle = {},

@@ -109,3 +111,3 @@ tickLabelStyle = {},

}
function getTicks(format) {

@@ -133,2 +135,3 @@ var major = tickValues || (scale.ticks ? scale.ticks(tickCount) : scale.domain()),

axisDef.layer = layer;
if (titleOffset === 'auto') titleAutoOffset(axisDef);

@@ -138,2 +141,32 @@ return axisDef;

function titleAutoOffset(axisDef) {
var orient = axisDef.orient,
update = axisDef.marks[5].properties.update,
fn = update.encode,
min = config.titleOffsetAutoMin,
max = config.titleOffsetAutoMax,
pad = config.titleOffsetAutoMargin;
// Offset axis title using bounding box of axis domain and labels
// Assumes other components are **encoded and bounded** beforehand
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;
};
}
function axis_def(scale) {

@@ -158,4 +191,4 @@ // setup scale mapping

dl.extend(m.title, axisTitle(config));
m.gridLines.properties.enter.stroke = {value: config.axis.gridColor};
m.gridLines.properties.enter.strokeOpacity = {value: config.axis.gridOpacity};
m.gridLines.properties.enter.stroke = {value: config.gridColor};
m.gridLines.properties.enter.strokeOpacity = {value: config.gridOpacity};

@@ -169,4 +202,4 @@ // extend axis marks based on axis orientation

axisDomainExtend(orient, m.domain, range, tickEndSize);
axisTitleExtend(orient, m.title, range, titleOffset); // TODO get offset
axisTitleExtend(orient, m.title, range, +titleOffset || -1);
// add / override custom style properties

@@ -184,3 +217,3 @@ dl.extend(m.gridLines.properties.update, gridLineStyle);

interactive: false,
properties: {
properties: {
enter: {

@@ -211,3 +244,3 @@ encode: axisUpdate,

if (orient !== x) {
orient = x in axisOrients ? x + '' : config.axis.orient;
orient = x in axisOrients ? x + '' : config.orient;
reset();

@@ -278,3 +311,3 @@ }

};
axis.offset = function(x) {

@@ -294,3 +327,3 @@ if (!arguments.length) return offset;

if (!arguments.length) return titleOffset;
if (titleOffset !== +x) { titleOffset = +x; reset(); }
if (titleOffset !== x) { titleOffset = x; reset(); }
return axis;

@@ -346,6 +379,6 @@ };

};
axis.reset = function() {
reset();
return axis;
axis.reset = function() {
reset();
return axis;
};

@@ -410,3 +443,3 @@

size *= -1;
}
}
if (orient === 'top' || orient === 'bottom') {

@@ -459,3 +492,3 @@ dl.extend(labels.properties.enter, {

x: newScale,
});
});
} else {

@@ -479,17 +512,14 @@ dl.extend(ticks.properties.enter, {

function axisTitleExtend(orient, title, range, offset) {
var mid = ~~((range[0] + range[1]) / 2),
var update = title.properties.update,
mid = ~~((range[0] + range[1]) / 2),
sign = (orient === 'top' || orient === 'left') ? -1 : 1;
if (orient === 'bottom' || orient === 'top') {
dl.extend(title.properties.update, {
x: {value: mid},
y: {value: sign*offset},
angle: {value: 0}
});
update.x = {value: mid};
update.angle = {value: 0};
if (offset >= 0) update.y = sign * offset;
} else {
dl.extend(title.properties.update, {
x: {value: sign*offset},
y: {value: mid},
angle: {value: orient === 'left' ? -90 : 90}
});
update.y = {value: mid};
update.angle = {value: orient === 'left' ? -90 : 90};
if (offset >= 0) update.x = sign * offset;
}

@@ -554,4 +584,4 @@ }

enter: {
stroke: {value: config.axis.tickColor},
strokeWidth: {value: config.axis.tickWidth},
stroke: {value: config.tickColor},
strokeWidth: {value: config.tickWidth},
opacity: {value: 1e-6}

@@ -572,5 +602,5 @@ },

enter: {
fill: {value: config.axis.tickLabelColor},
font: {value: config.axis.tickLabelFont},
fontSize: {value: config.axis.tickLabelFontSize},
fill: {value: config.tickLabelColor},
font: {value: config.tickLabelFont},
fontSize: {value: config.tickLabelFontSize},
opacity: {value: 1e-6},

@@ -591,6 +621,6 @@ text: {field: 'label'}

enter: {
font: {value: config.axis.titleFont},
fontSize: {value: config.axis.titleFontSize},
fontWeight: {value: config.axis.titleFontWeight},
fill: {value: config.axis.titleColor},
font: {value: config.titleFont},
fontSize: {value: config.titleFontSize},
fontWeight: {value: config.titleFontWeight},
fill: {value: config.titleColor},
align: {value: 'center'},

@@ -613,4 +643,4 @@ baseline: {value: 'middle'},

y: {value: 0.5},
stroke: {value: config.axis.axisColor},
strokeWidth: {value: config.axis.axisWidth}
stroke: {value: config.axisColor},
strokeWidth: {value: config.axisWidth}
},

@@ -617,0 +647,0 @@ update: {}

@@ -21,12 +21,18 @@ var dl = require('datalib'),

var type = this._mark.marktype,
var mark = this._mark,
type = mark.marktype,
isGrp = type === 'group',
items = this._mark.items,
hasLegends = dl.array(this._mark.def.legends).length > 0,
i, ilen, j, jlen, group, legend;
items = mark.items,
group = items.length && (isGrp ? items[0] : items[0].mark.group),
axis = group && group.mark.axis,
signals = input.signals,
hasLegends = dl.array(mark.def.legends).length > 0,
i, ilen, j, jlen, legend;
if (input.add.length || input.rem.length || !items.length ||
if (input.add.length || input.rem.length || !items.length ||
input.mod.length === items.length ||
type === 'area' || type === 'line') {
bound.mark(this._mark, null, isGrp && !hasLegends);
type === 'area' || type === 'line' ||
signals.width || signals.height || signals.padding ||
(axis && input.scales[axis.scale().scaleName])) {
bound.mark(mark, null, isGrp && !hasLegends);
} else {

@@ -42,3 +48,3 @@ input.mod.forEach(function(item) { bound.item(item); });

legend = group.legendItems[j];
Encoder.update(this._graph, input.trans, 'vg_legendPosition', legend.items, input.dirty);
Encoder.update(this._graph, input.trans, 'legendPosition', legend.items, input.dirty);
bound.mark(legend, null, false);

@@ -48,3 +54,3 @@ }

bound.mark(this._mark, null, true);
bound.mark(mark, null, true);
}

@@ -55,2 +61,2 @@

module.exports = Bounder;
module.exports = Bounder;

@@ -14,3 +14,3 @@ var dl = require('datalib'),

function Builder() {
function Builder() {
return arguments.length ? this.init.apply(this, arguments) : this;

@@ -54,5 +54,5 @@ }

// Non-group mark builders are super nodes. Encoder and Bounder remain
// Non-group mark builders are super nodes. Encoder and Bounder remain
// separate operators but are embedded and called by Builder.evaluate.
this._isSuper = (this._def.type !== 'group');
this._isSuper = (this._def.type !== 'group');
this._encoder = new Encoder(this._graph, this._mark, this);

@@ -73,4 +73,4 @@ this._bounder = new Bounder(this._graph, this._mark);

// Reactive geometry and mark-level transformations are handled here
// because they need their group's data-joined context.
// Reactive geometry and mark-level transformations are handled here
// because they need their group's data-joined context.
function inlineDs() {

@@ -85,3 +85,3 @@ var from = this._def.from,

name: name,
transform: from.transform,
transform: from.transform,
modify: from.modify

@@ -119,3 +119,3 @@ };

// At this point, we have a new datasource but it is empty as
// the propagation cycle has already crossed the datasources.
// the propagation cycle has already crossed the datasources.
// So, we repulse just this datasource. This should be safe

@@ -171,3 +171,3 @@ // as the ds isn't connected to the scenegraph yet.

disconnectScales(dl.keys(this._mark._scaleRefs));
return (this._status = DISCONNECTED, this);

@@ -187,3 +187,3 @@ };

update = props.update || {},
output = ChangeSet.create(input),
output = ChangeSet.create(input),
fullUpdate, fcs, data, name;

@@ -254,3 +254,3 @@

// Only mark rems as exiting. Due to keyf, there may be an add/mod
// Only mark rems as exiting. Due to keyf, there may be an add/mod
// tuple that replaces it.

@@ -257,0 +257,0 @@ for (i=0, len=rem.length; i<len; ++i) {

@@ -25,3 +25,3 @@ var dl = require('datalib'),

// we still want scales in 'enter' and 'exit' to be evaluated
// before the encoder.
// before the encoder.
if (enter) s.push.apply(s, enter.scales);

@@ -79,3 +79,3 @@

item = input.rem[i];
if (exit) encode.call(this, exit, item, input.trans, db, sg, preds, dirty);
if (exit) encode.call(this, exit, item, input.trans, db, sg, preds, dirty);
if (input.trans && !exit) input.trans.interpolate(item, EMPTY);

@@ -110,3 +110,3 @@ else if (!input.trans) items.pop();

if ((p=props.exit) && (x=p[type]).length && input.rem.length) {
o = graph.values(type, x, (o=o||{}));
o = graph.values(type, x, (o=o||{}));
}

@@ -128,3 +128,3 @@ if ((p=props.update) && (x=p[type]).length && (add || input.mod.length)) {

// If a specified property set called, or update property set
// If a specified property set called, or update property set
// uses nested fieldrefs, reevaluate all items.

@@ -134,3 +134,3 @@ proto.reevaluate = function(pulse) {

props = def.properties || {},
reeval = dl.isFunction(def.from) || def.orient || pulse.request ||
reeval = dl.isFunction(def.from) || def.orient || pulse.request ||
Node.prototype.reevaluate.call(this, pulse);

@@ -174,3 +174,3 @@

items = dl.array(items);
var preds = graph.predicates(),
var preds = graph.predicates(),
db = graph.values(Deps.DATA),

@@ -192,2 +192,2 @@ sg = graph.values(Deps.SIGNALS),

module.exports = Encoder;
module.exports = Encoder;

@@ -63,6 +63,8 @@ var dl = require('datalib'),

proto.evaluate = function() {
var output = Builder.prototype.evaluate.apply(this, arguments),
var output = Builder.prototype.evaluate.apply(this, arguments),
model = this._graph,
builder = this;
output.add.forEach(function(group) { buildGroup.call(builder, output, group); });
output.rem.forEach(function(group) { model.group(group._id, null); });
return output;

@@ -125,6 +127,6 @@ };

// This new child needs to be built during this propagation cycle.
// We could add its builder as a listener off the _recursor node,
// We could add its builder as a listener off the _recursor node,
// but try to inline it if we can to minimize graph dispatches.
inline = (def.type !== Types.GROUP);
inline = inline && (this._graph.data(c.from) !== undefined);
inline = inline && (this._graph.data(c.from) !== undefined);
inline = inline && (pipeline[pipeline.length-1].listeners().length === 1); // Reactive geom source

@@ -146,3 +148,3 @@ inline = inline && (def.from && !def.from.mark); // Reactive geom target

function updateAxis(a) {
function updateAxis(a) {
var scale = a.scale();

@@ -152,4 +154,4 @@ if (!input.scales[scale.scaleName]) return;

}
function updateLegend(l) {
function updateLegend(l) {
var scale = l.size() || l.shape() || l.fill() || l.stroke();

@@ -173,5 +175,5 @@ if (!input.scales[scale.scaleName]) return;

function disconnectChildren(c) {
function disconnectChildren(c) {
builder._recursor.removeListener(c.builder);
c.builder.disconnect();
c.builder.disconnect();
}

@@ -203,3 +205,3 @@

group._scales = group._scales || {};
group._scales = group._scales || {};
group.scale = scale.bind(group);

@@ -215,2 +217,5 @@

group.legendItems = group.legendItems || [];
// Index group by ID to enable safe scoped scale lookups.
this._graph.group(group._id, group);
}

@@ -230,6 +235,6 @@

b.init(this._graph, mark, group.items[i], this, group._id, inherit);
this._children[group._id].push({
builder: b,
from: from.data || (from.mark ? ("vg_" + group._id + "_" + from.mark) : inherit),
type: Types.MARK
this._children[group._id].push({
builder: b,
from: from.data || (from.mark ? ("vg_" + group._id + "_" + from.mark) : inherit),
type: Types.MARK
});

@@ -250,3 +255,3 @@ }

axisItems[i] = {group: group, axis: true, layer: def.layer};
axisItems[i] = {group: group, axis: a, layer: def.layer};
b = (def.type === Types.GROUP) ? new GroupBuilder() : new Builder();

@@ -270,3 +275,3 @@ b.init(builder._graph, def, axisItems[i], builder)

legendItems[i] = {group: group, legend: true};
legendItems[i] = {group: group, legend: l};
b = (def.type === Types.GROUP) ? new GroupBuilder() : new Builder();

@@ -273,0 +278,0 @@ b.init(builder._graph, def, legendItems[i], builder)

@@ -16,7 +16,7 @@ var d3 = require('d3'),

formatString = null,
config = model.config(),
config = model.config().legend,
title,
orient = 'right',
offset = config.legend.offset,
padding = config.legend.padding,
orient = config.orient,
offset = config.offset,
padding = config.padding,
tickArguments = [5],

@@ -43,9 +43,9 @@ legendStyle = {},

var scale = size || shape || fill || stroke;
format = !formatString ? null : ((scale.type === 'time') ?
dl.format.time(formatString) : dl.format.number(formatString));
if (!legendDef.type) {
legendDef = (scale===fill || scale===stroke) && !discrete(scale.type) ?
quantDef(scale) : ordinalDef(scale);
quantDef(scale) : ordinalDef(scale);
}

@@ -55,2 +55,3 @@ legendDef.orient = orient;

legendDef.padding = padding;
legendDef.margin = config.margin;
return legendDef;

@@ -72,3 +73,3 @@ };

var fmt = format==null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : String) : format;
// determine spacing between legend entries

@@ -83,6 +84,6 @@ var fs, range, offset, pad=5, domain = d3.range(data.length);

} else {
offset = Math.round(Math.sqrt(config.legend.symbolSize));
offset = Math.round(Math.sqrt(config.symbolSize));
range = spacing ||
(fs = labelStyle.fontSize) && (fs.value + pad) ||
(config.legend.labelFontSize + pad);
(config.labelFontSize + pad);
range = domain.map(function(d,i) {

@@ -97,8 +98,9 @@ return Math.round(offset/2 + i*range);

ts = titleStyle.fontSize;
sz += 5 + ((ts && ts.value) || config.legend.titleFontSize);
sz += 5 + ((ts && ts.value) || config.titleFontSize);
}
for (var i=0, n=range.length; i<n; ++i) range[i] += sz;
// build scale for label layout
var scaleSpec = {
def.scales = def.scales || [{}];
dl.extend(def.scales[0], {
name: 'legend',

@@ -109,4 +111,4 @@ type: 'ordinal',

range: range
};
});
// update legend def

@@ -118,3 +120,2 @@ var tdata = (title ? [title] : []).map(ingest);

});
def.scales = [ scaleSpec ];
def.marks[0].from = function() { return tdata; };

@@ -129,9 +130,9 @@ def.marks[1].from = function() { return data; };

// setup legend marks
var titles = dl.extend(m.titles, vg_legendTitle(config)),
symbols = dl.extend(m.symbols, vg_legendSymbols(config)),
labels = dl.extend(m.labels, vg_vLegendLabels(config));
var titles = dl.extend(m.titles, legendTitle(config)),
symbols = dl.extend(m.symbols, legendSymbols(config)),
labels = dl.extend(m.labels, vLegendLabels(config));
// extend legend marks
vg_legendSymbolExtend(symbols, size, shape, fill, stroke);
legendSymbolExtend(symbols, size, shape, fill, stroke);
// add / override custom style properties

@@ -155,4 +156,4 @@ dl.extend(titles.properties.update, titleStyle);

enter: parseProperties(model, 'group', legendStyle),
vg_legendPosition: {
encode: vg_legendPosition,
legendPosition: {
encode: legendPosition,
signals: [], scales:[], data: [], fields: []

@@ -171,7 +172,8 @@ }

data = (values == null ? dom : values).map(ingest),
width = (gradientStyle.width && gradientStyle.width.value) || config.legend.gradientWidth,
width = (gradientStyle.width && gradientStyle.width.value) || config.gradientWidth,
fmt = format==null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : String) : format;
// build scale for label layout
var layoutSpec = {
def.scales = def.scales || [{}];
var layoutSpec = dl.extend(def.scales[0], {
name: 'legend',

@@ -183,5 +185,5 @@ type: scale.type,

range: [padding, width+padding]
};
});
if (scale.type==='pow') layoutSpec.exponent = scale.exponent();
// update legend def

@@ -193,3 +195,3 @@ var tdata = (title ? [title] : []).map(ingest);

});
def.scales = [ layoutSpec ];
def.marks[0].from = function() { return tdata; };

@@ -200,8 +202,8 @@ def.marks[1].from = function() { return [1]; };

}
function q_legend_def(scale) {
// setup legend marks
var titles = dl.extend(m.titles, vg_legendTitle(config)),
gradient = dl.extend(m.gradient, vg_legendGradient(config)),
labels = dl.extend(m.labels, vg_hLegendLabels(config)),
var titles = dl.extend(m.titles, legendTitle(config)),
gradient = dl.extend(m.gradient, legendGradient(config)),
labels = dl.extend(m.labels, hLegendLabels(config)),
grad = new Gradient();

@@ -214,3 +216,3 @@

f = scale.copy().domain([min, max]).range([0,1]);
var stops = (scale.type !== 'linear' && scale.ticks) ?

@@ -246,3 +248,3 @@ scale.ticks.call(scale, 15) : dom;

}
// padding from legend border

@@ -263,4 +265,4 @@ titles.properties.enter.x.value += padding;

enter: parseProperties(model, 'group', legendStyle),
vg_legendPosition: {
encode: vg_legendPosition,
legendPosition: {
encode: legendPosition,
signals: [], scales: [], data: [], fields: []

@@ -292,3 +294,3 @@ }

};
legend.stroke = function(x) {

@@ -323,3 +325,3 @@ if (!arguments.length) return stroke;

if (!arguments.length) return orient;
orient = x in vg_legendOrients ? x + '' : config.legend.orient;
orient = x in LEGEND_ORIENT ? x + '' : config.orient;
return legend;

@@ -363,3 +365,3 @@ };

};
legend.titleProperties = function(x) {

@@ -371,4 +373,4 @@ if (!arguments.length) return titleStyle;

legend.reset = function() {
reset();
legend.reset = function() {
reset();
return legend;

@@ -380,12 +382,13 @@ };

var vg_legendOrients = {right: 1, left: 1};
var LEGEND_ORIENT = {right: 1, left: 1};
function vg_legendPosition(item, group, trans, db, signals, predicates) {
var o = trans ? {} : item, gx,
offset = item.mark.def.offset,
orient = item.mark.def.orient,
pad = item.mark.def.padding * 2,
function legendPosition(item, group, trans, db, signals, predicates) {
var o = trans ? {} : item, i, aw = 0,
def = item.mark.def,
offset = def.offset,
orient = def.orient,
pad = def.padding * 2,
lw = ~~item.bounds.width() + (item.width ? 0 : pad),
lh = ~~item.bounds.height() + (item.height ? 0 : pad),
pos = group._legendPositions ||
pos = group._legendPositions ||
(group._legendPositions = {right: 0.5, left: 0.5});

@@ -396,22 +399,16 @@

o.y = pos[orient];
pos[orient] += (o.height = lh);
pos[orient] += (o.height = lh) + def.margin;
// HACK: use to estimate group bounds during animated transition
if (!trans && group.bounds) {
group.bounds.delta = group.bounds.x2 - group.width;
for (i=0; i<group.axes.length; ++i) {
if (group.axes[i].orient() === orient) {
aw = Math.max(aw, group.axisItems[i].bounds.width());
}
}
switch (orient) {
case 'left': {
gx = group.bounds ? group.bounds.x1 : 0;
o.x += gx - offset - lw;
break;
}
case 'right': {
gx = group.width + (group.bounds && trans ? group.bounds.delta : 0);
o.x += gx + offset;
break;
}
if (orient === 'left') {
o.x -= aw + offset + lw;
} else {
o.x += group.width + aw + offset;
}
if (trans) trans.interpolate(item, o);

@@ -423,3 +420,3 @@ var enc = item.mark.def.properties.enter.encode;

function vg_legendSymbolExtend(mark, size, shape, fill, stroke) {
function legendSymbolExtend(mark, size, shape, fill, stroke) {
var e = mark.properties.enter,

@@ -433,4 +430,3 @@ u = mark.properties.update;

function vg_legendTitle(config) {
var cfg = config.legend;
function legendTitle(config) {
return {

@@ -444,6 +440,6 @@ type: 'text',

y: {value: 0},
fill: {value: cfg.titleColor},
font: {value: cfg.titleFont},
fontSize: {value: cfg.titleFontSize},
fontWeight: {value: cfg.titleFontWeight},
fill: {value: config.titleColor},
font: {value: config.titleFont},
fontSize: {value: config.titleFontSize},
fontWeight: {value: config.titleFontWeight},
baseline: {value: 'top'},

@@ -459,4 +455,3 @@ text: {field: 'data'},

function vg_legendSymbols(config) {
var cfg = config.legend;
function legendSymbols(config) {
return {

@@ -470,6 +465,6 @@ type: 'symbol',

y: {scale: 'legend', field: 'index'},
shape: {value: cfg.symbolShape},
size: {value: cfg.symbolSize},
stroke: {value: cfg.symbolColor},
strokeWidth: {value: cfg.symbolStrokeWidth},
shape: {value: config.symbolShape},
size: {value: config.symbolSize},
stroke: {value: config.symbolColor},
strokeWidth: {value: config.symbolStrokeWidth},
opacity: {value: 1e-6}

@@ -487,4 +482,3 @@ },

function vg_vLegendLabels(config) {
var cfg = config.legend;
function vLegendLabels(config) {
return {

@@ -498,7 +492,7 @@ type: 'text',

y: {scale: 'legend', field: 'index'},
fill: {value: cfg.labelColor},
font: {value: cfg.labelFont},
fontSize: {value: cfg.labelFontSize},
align: {value: cfg.labelAlign},
baseline: {value: cfg.labelBaseline},
fill: {value: config.labelColor},
font: {value: config.labelFont},
fontSize: {value: config.labelFontSize},
align: {value: config.labelAlign},
baseline: {value: config.labelBaseline},
text: {field: 'label'},

@@ -517,4 +511,3 @@ opacity: {value: 1e-6}

function vg_legendGradient(config) {
var cfg = config.legend;
function legendGradient(config) {
return {

@@ -527,6 +520,6 @@ type: 'rect',

y: {value: 0},
width: {value: cfg.gradientWidth},
height: {value: cfg.gradientHeight},
stroke: {value: cfg.gradientStrokeColor},
strokeWidth: {value: cfg.gradientStrokeWidth},
width: {value: config.gradientWidth},
height: {value: config.gradientHeight},
stroke: {value: config.gradientStrokeColor},
strokeWidth: {value: config.gradientStrokeWidth},
opacity: {value: 1e-6}

@@ -544,4 +537,3 @@ },

function vg_hLegendLabels(config) {
var cfg = config.legend;
function hLegendLabels(config) {
return {

@@ -556,5 +548,5 @@ type: 'text',

dy: {value: 2},
fill: {value: cfg.labelColor},
font: {value: cfg.labelFont},
fontSize: {value: cfg.labelFontSize},
fill: {value: config.labelColor},
font: {value: config.labelFont},
fontSize: {value: config.labelFontSize},
align: {field: 'align'},

@@ -561,0 +553,0 @@ baseline: {value: 'top'},

@@ -60,7 +60,7 @@ var d3 = require('d3'),

// reflow pulse. Thus, if multiple scales update in the parent group, we don't
// reevaluate child marks multiple times.
// reevaluate child marks multiple times.
if (this._updated) {
input.scales[this._def.name] = 1;
log.debug(input, ["scale", this._def.name]);
}
log.debug(input, ["scale", this._def.name]);
}
return df.ChangeSet.create(input, true);

@@ -120,3 +120,3 @@ };

domain, str, spatial=true;
// range pre-processing for data-driven ranges

@@ -127,3 +127,3 @@ if (dl.isObject(def.range) && !dl.isArray(def.range)) {

}
// domain

@@ -135,3 +135,3 @@ domain = dataRef.call(this, DataRef.DOMAIN, def.domain, scale, group);

this._updated = true;
}
}

@@ -177,3 +177,3 @@ // range

// "Polyfill" ordinal scale inversion. Currently, only ordinal scales
// with ordered numeric ranges are supported.
// with ordered numeric ranges are supported.
var bisect = d3.bisector(dl.numcmp).right,

@@ -231,3 +231,3 @@ findAsc = function(a, x) { return bisect(a,x) - 1; },

this._updated = true;
}
}

@@ -258,7 +258,7 @@ // range

function isUniques(scale) {
return scale.type === Types.ORDINAL || scale.type === Types.QUANTILE;
function isUniques(scale) {
return scale.type === Types.ORDINAL || scale.type === Types.QUANTILE;
}
function getRefs(def) {
function getRefs(def) {
return def.fields || dl.array(def);

@@ -284,6 +284,6 @@ }

// Scale datarefs can be computed over multiple schema types.
// Scale datarefs can be computed over multiple schema types.
// This function determines the type of aggregator created, and
// what data is sent to it: values, tuples, or multi-tuples that must
// be standardized into a consistent schema.
// be standardized into a consistent schema.
function aggrType(def, scale) {

@@ -322,3 +322,3 @@ var refs = getRefs(def);

// If a scale's dataref doesn't inherit data from the group, we can
// store the dataref aggregator at the Scale (dataflow node) level.
// store the dataref aggregator at the Scale (dataflow node) level.
if (inherit) {

@@ -343,3 +343,3 @@ scale[ck] = cache;

groupby = DataRef.GROUPBY;
summarize = [{ field: DataRef.VALUE, ops: [sort.op] }];
summarize = [{ field: DataRef.VALUE, ops: [sort.op] }];
}

@@ -373,3 +373,3 @@ } else {

uniques = isUniques(scale),
i, rlen, j, flen, ref, fields, field, data, from, so, cmp;
i, rlen, j, flen, ref, fields, field, data, from, cmp;

@@ -410,4 +410,3 @@ function addDep(s) {

if (dl.isObject(sort)) {
cmp = (so = sort.order) && so.signal ? graph.signalRef(so.signal) : so;
cmp = (cmp == DataRef.DESC ? '-' : '+') + sort.op + '_' + DataRef.VALUE;
cmp = sort.op + '_' + DataRef.VALUE;
cmp = dl.comparator(cmp);

@@ -509,3 +508,3 @@ } else if (sort === true) {

}
if (def.reverse !== undefined) {

@@ -518,3 +517,3 @@ var rev = signal.call(this, def.reverse);

}
return rng;

@@ -585,4 +584,3 @@ }

"field": {"type": "string"},
"op": {"enum": require('../transforms/Aggregate').VALID_OPS},
"order": {"enum": [DataRef.ASC, DataRef.DESC]}
"op": {"enum": require('../transforms/Aggregate').VALID_OPS}
}

@@ -606,3 +604,3 @@ }]

"type": {
"enum": [Types.LINEAR, Types.ORDINAL, Types.TIME, Types.TIME_UTC, Types.LOG,
"enum": [Types.LINEAR, Types.ORDINAL, Types.TIME, Types.TIME_UTC, Types.LOG,
Types.POWER, Types.SQRT, Types.QUANTILE, Types.QUANTIZE, Types.THRESHOLD],

@@ -618,4 +616,4 @@ "default": Types.LINEAR

"oneOf": [
{"type":"string"},
{"type": "number"},
{"type":"string"},
{"type": "number"},
{"$ref": "#/refs/signal"}

@@ -647,4 +645,4 @@ ]

"oneOf": [
{"type":"string"},
{"type": "number"},
{"type":"string"},
{"type": "number"},
{"$ref": "#/refs/signal"}

@@ -656,4 +654,4 @@ ]

"oneOf": [
{"type":"string"},
{"type": "number"},
{"type":"string"},
{"type": "number"},
{"$ref": "#/refs/signal"}

@@ -693,3 +691,3 @@ ]

"clamp": {"oneOf": [{"type": "boolean"}, {"$ref": "#/refs/signal"}]},
"nice": {"oneOf": [{"enum": ["second", "minute", "hour",
"nice": {"oneOf": [{"enum": ["second", "minute", "hour",
"day", "week", "month", "year"]}, {"$ref": "#/refs/signal"}]}

@@ -701,3 +699,3 @@ },

"properties": {
"type": {"enum": [Types.LINEAR, Types.LOG, Types.POWER, Types.SQRT,
"type": {"enum": [Types.LINEAR, Types.LOG, Types.POWER, Types.SQRT,
Types.QUANTILE, Types.QUANTIZE, Types.THRESHOLD], "default": Types.LINEAR},

@@ -704,0 +702,0 @@ "range": {"oneOf": rangeDef},

@@ -24,3 +24,3 @@ var d3 = require('d3'),

curr = item[key];
next = values[key];
next = values[key];
if (curr !== next) {

@@ -104,2 +104,2 @@ if (skip[key] || curr === undefined) {

module.exports = Transition;
module.exports = Transition;

@@ -13,2 +13,2 @@ module.exports = function visit(node, func) {

}
};
};

@@ -16,3 +16,3 @@ var dl = require('datalib'),

summarize: {
type: 'custom',
type: 'custom',
set: function(summarize) {

@@ -54,3 +54,3 @@ var signalDeps = {},

this._type = TYPES.TUPLE;
this._type = TYPES.TUPLE;
this._acc = {groupby: dl.true, value: dl.true};

@@ -65,4 +65,4 @@

var TYPES = Aggregate.TYPES = {
VALUE: 1,
TUPLE: 2,
VALUE: 1,
TUPLE: 2,
MULTI: 3

@@ -72,10 +72,10 @@ };

Aggregate.VALID_OPS = [
'values', 'count', 'valid', 'missing', 'distinct',
'sum', 'mean', 'average', 'variance', 'variancep', 'stdev',
'stdevp', 'median', 'q1', 'q3', 'modeskew', 'min', 'max',
'values', 'count', 'valid', 'missing', 'distinct',
'sum', 'mean', 'average', 'variance', 'variancep', 'stdev',
'stdevp', 'median', 'q1', 'q3', 'modeskew', 'min', 'max',
'argmin', 'argmax'
];
prototype.type = function(type) {
return (this._type = type, this);
prototype.type = function(type) {
return (this._type = type, this);
};

@@ -166,3 +166,3 @@

p = Tuple.prev,
add, rem, mod, i;
add, rem, mod, mark, i;

@@ -179,5 +179,6 @@ // Upon reset, retract prior tuples and re-initialize.

if (this._type === TYPES.TUPLE) {
add = function(x) { aggr._add(x); Tuple.prev_init(x); };
rem = function(x) { aggr._rem(p(x)); };
mod = function(x) { aggr._mod(x, p(x)); };
add = function(x) { aggr._add(x); Tuple.prev_init(x); };
rem = function(x) { aggr._rem(p(x)); };
mod = function(x) { aggr._mod(x, p(x)); };
mark = function(x) { aggr._markMod(x, p(x)); };
} else {

@@ -189,5 +190,6 @@ var gby = this._acc.groupby,

};
add = function(x) { aggr._add(get(x)); Tuple.prev_init(x); };
rem = function(x) { aggr._rem(get(p(x))); };
mod = function(x) { aggr._mod(get(x), get(p(x))); };
add = function(x) { aggr._add(get(x)); Tuple.prev_init(x); };
rem = function(x) { aggr._rem(get(p(x))); };
mod = function(x) { aggr._mod(get(x), get(p(x))); };
mark = function(x) { aggr._mark(get(x), get(p(x))); };
}

@@ -207,3 +209,3 @@

}
if (reeval) input.mod.forEach(mod);
input.mod.forEach(reeval ? mod : mark);
}

@@ -210,0 +212,0 @@

var Base = require('./Transform').prototype;
function BatchTransform() {
// Nearest appropriate collector.
// Nearest appropriate collector.
// Set by the dataflow Graph during connection.
this._collector = null;
this._collector = null;
}

@@ -17,9 +17,9 @@

prototype.transform = function(input) {
return this.batchTransform(input, this._collector.data());
prototype.transform = function(input, reset) {
return this.batchTransform(input, this._collector.data(), reset);
};
prototype.batchTransform = function(/* input, data */) {
prototype.batchTransform = function(/* input, data, reset */) {
};
module.exports = BatchTransform;

@@ -23,3 +23,4 @@ var dl = require('datalib'),

start: 'bin_start',
end: 'bin_end'
end: 'bin_end',
mid: 'bin_mid'
};

@@ -63,3 +64,4 @@ return this.mutates(true);

if (minstep) opt.minstep = minstep;
var b = dl.bins(opt);
var b = dl.bins(opt),
s = b.step;

@@ -69,5 +71,6 @@ function update(d) {

v = v == null ? null
: b.start + b.step * ~~((v - b.start) / b.step);
: b.start + s * ~~((v - b.start) / s);
Tuple.set(d, output.start, v);
Tuple.set(d, output.end, v + b.step);
Tuple.set(d, output.end, v + s);
Tuple.set(d, output.mid, v + s/2);
}

@@ -80,2 +83,3 @@ input.add.forEach(update);

input.fields[output.end] = 1;
input.fields[output.mid] = 1;
return input;

@@ -149,3 +153,4 @@ };

"start": {"type": "string", "default": "bin_start"},
"end": {"type": "string", "default": "bin_end"}
"end": {"type": "string", "default": "bin_end"},
"mid": {"type": "string", "default": "bin_mid"}
},

@@ -152,0 +157,0 @@ "additionalProperties": false

@@ -1,2 +0,3 @@

var df = require('vega-dataflow'),
var dl = require('datalib'),
df = require('vega-dataflow'),
ChangeSet = df.ChangeSet,

@@ -18,6 +19,5 @@ Tuple = df.Tuple,

this._output = {'left': 'a', 'right': 'b'};
this._lastRem = null; // Most recent stamp that rem occured.
this._lastWith = null; // Last time we crossed w/withds.
this._ids = {};
this._cache = {};
this._lastWith = null; // Last time we crossed w/with-ds.
this._cids = {};
this._cache = {};

@@ -30,69 +30,148 @@ return this.router(true).produces(true);

// Each cached incoming tuple also has a stamp to track if we need to do
// lazy filtering of removed tuples.
function cache(x, t) {
var c = this._cache[x._id] = this._cache[x._id] || {c: [], s: this._stamp};
c.c.push(t);
// Each cached incoming tuple also has a flag to determine whether
// any tuples were filtered.
function _cache(x, t) {
var c = this._cache,
cross = c[x._id] || (c[x._id] = {c: [], f: false});
cross.c.push(t);
}
function add(output, left, data, diag, test, x) {
var i = 0, len = data.length, t = {}, y, id;
function _cid(left, x, y) {
return left ? x._id+'_'+y._id : y._id+'_'+x._id;
}
function add(output, left, data, diag, test, mids, x) {
var as = this._output,
cache = this._cache,
cids = this._cids,
oadd = output.add,
fltrd = false,
i = 0, len = data.length,
t = {}, y, cid;
for (; i<len; ++i) {
y = data[i];
id = left ? x._id+'_'+y._id : y._id+'_'+x._id;
if (this._ids[id]) continue;
if (x._id == y._id && !diag) continue;
cid = _cid(left, x, y);
if (cids[cid]) continue;
if (x._id === y._id && !diag) continue;
t[this._output.left] = left ? x : y;
t[this._output.right] = left ? y : x;
Tuple.set(t, as.left, left ? x : y);
Tuple.set(t, as.right, left ? y : x);
// Only ingest a tuple if we keep it around.
// Only ingest a tuple if we keep it around. Otherwise, flag the
// caches as filtered.
if (!test || test(t)) {
output.add.push(t=Tuple.ingest(t));
cache.call(this, x, t);
cache.call(this, y, t);
this._ids[id] = 1;
oadd.push(t=Tuple.ingest(t));
_cache.call(this, x, t);
if (x._id !== y._id) _cache.call(this, y, t);
mids[t._id] = 1;
cids[cid] = true;
t = {};
}
} else {
if (cache[y._id]) cache[y._id].f = true;
fltrd = true;
}
}
if (cache[x._id]) cache[x._id].f = fltrd;
}
function mod(output, left, x) {
var cross = this,
c = this._cache[x._id];
function mod(output, left, data, diag, test, mids, rids, x) {
var as = this._output,
cache = this._cache,
cids = this._cids,
cross = cache[x._id],
tpls = cross && cross.c,
fltrd = !cross || cross.f,
omod = output.mod,
orem = output.rem,
i, t, y, l, cid;
if (this._lastRem > c.s) { // Removed tuples haven't been filtered yet
c.c = c.c.filter(function(y) {
var t = y[cross._output[left ? 'right' : 'left']];
return cross._cache[t._id] !== null;
});
c.s = this._lastRem;
// If we have cached values, iterate through them for lazy
// removal, and to re-run the filter.
if (tpls) {
for (i=tpls.length-1; i>=0; --i) {
t = tpls[i];
l = x === t[as.left]; // Cache has tpls w/x both on left & right.
y = l ? t[as.right] : t[as.left];
cid = _cid(l, x, y);
// Lazy removal: y was previously rem'd, so clean up the cache.
if (!cache[y._id]) {
cids[cid] = false;
tpls.splice(i, 1);
continue;
}
if (!test || test(t)) {
if (mids[t._id]) continue;
omod.push(t);
mids[t._id] = 1;
} else {
if (!rids[t._id]) orem.push.apply(orem, tpls.splice(i, 1));
rids[t._id] = 1;
cids[cid] = false;
cross.f = true;
}
}
}
output.mod.push.apply(output.mod, c.c);
// If we have a filter param, call add to catch any tuples that may
// have previously been filtered.
if (test && fltrd) add.call(this, output, left, data, diag, test, mids, x);
}
function rem(output, x) {
output.rem.push.apply(output.rem, this._cache[x._id].c);
function rem(output, left, rids, x) {
var as = this._output,
cross = this._cache[x._id],
cids = this._cids,
orem = output.rem,
i, len, t, y, l;
if (!cross) return;
for (i=0, len=cross.c.length; i<len; ++i) {
t = cross.c[i];
l = x === t[as.left];
y = l ? t[as.right] : t[as.left];
cids[_cid(l, x, y)] = false;
if (!rids[t._id]) {
orem.push(t);
rids[t._id] = 1;
}
}
this._cache[x._id] = null;
this._lastRem = this._stamp;
}
function upFields(input, output) {
if (input.add.length || input.rem.length) {
output.fields[this._output.left] = 1;
output.fields[this._output.right] = 1;
function purge(output, rids) {
var cache = this._cache,
keys = dl.keys(cache),
rem = output.rem,
i, len, j, jlen, cross, t;
for (i=0, len=keys.length; i<len; ++i) {
cross = cache[keys[i]];
for (j=0, jlen=cross.c.length; j<jlen; ++j) {
t = cross.c[j];
if (rids[t._id]) continue;
rem.push(t);
rids[t._id] = 1;
}
}
this._cache = {};
this._cids = {};
this._lastWith = null;
}
prototype.batchTransform = function(input, data) {
prototype.batchTransform = function(input, data, reset) {
log.debug(input, ['crossing']);
var w = this.param('with'),
var g = this._graph,
w = this.param('with'),
f = this.param('filter'),
diag = this.param('diagonal'),
graph = this._graph,
signals = graph.values(SIGNALS, this.dependency(SIGNALS)),
test = f ? function(x) {return f(x, null, signals); } : null,
as = this._output,
sg = g.values(SIGNALS, this.dependency(SIGNALS)),
test = f ? function(x) {return f(x, null, sg); } : null,
selfCross = (!w.name),

@@ -102,19 +181,27 @@ woutput = selfCross ? input : w.source.last(),

output = ChangeSet.create(input),
r = rem.bind(this, output);
mids = {}, rids = {}; // Track IDs to prevent dupe mod/rem tuples.
input.rem.forEach(r);
input.add.forEach(add.bind(this, output, true, wdata, diag, test));
// If signal values (for diag or test) have changed, purge the cache
// and re-run cross in batch mode. Otherwise stream cross values.
if (reset) {
purge.call(this, output, rids);
data.forEach(add.bind(this, output, true, wdata, diag, test, mids));
this._lastWith = woutput.stamp;
} else {
input.rem.forEach(rem.bind(this, output, true, rids));
input.add.forEach(add.bind(this, output, true, wdata, diag, test, mids));
if (!selfCross && woutput.stamp > this._lastWith) {
woutput.rem.forEach(r);
woutput.add.forEach(add.bind(this, output, false, data, diag, test));
woutput.mod.forEach(mod.bind(this, output, false));
upFields.call(this, woutput, output);
this._lastWith = woutput.stamp;
if (woutput.stamp > this._lastWith) {
woutput.rem.forEach(rem.bind(this, output, false, rids));
woutput.add.forEach(add.bind(this, output, false, data, diag, test, mids));
woutput.mod.forEach(mod.bind(this, output, false, data, diag, test, mids, rids));
this._lastWith = woutput.stamp;
}
// Mods need to come after all removals have been run.
input.mod.forEach(mod.bind(this, output, true, wdata, diag, test, mids, rids));
}
// Mods need to come after all removals have been run.
input.mod.forEach(mod.bind(this, output, true));
upFields.call(this, input, output);
output.fields[as.left] = 1;
output.fields[as.right] = 1;
return output;

@@ -134,3 +221,3 @@ };

"type": "string",
"description": "The name of the secondary data set to cross with the primary data. " +
"description": "The name of the secondary data set to cross with the primary data. " +
"If unspecified, the primary data is crossed with itself."

@@ -137,0 +224,0 @@ },

@@ -17,3 +17,3 @@ var Transform = require('./Transform'),

});
}
}
}

@@ -33,2 +33,16 @@ });

prototype.transform = function(input, reset) {
var output = Aggregate.prototype.transform.call(this, input, reset);
// New facet cells should trigger a re-ranking of the dataflow graph.
// This ensures facet datasources are computed before scenegraph nodes.
// We rerank the Facet's first listener, which is the next node in the
// datasource's pipeline.
if (input.add.length) {
this.listeners()[0].rerank();
}
return output;
};
module.exports = Facet;

@@ -35,0 +49,0 @@

@@ -22,3 +22,3 @@ var dl = require('datalib'),

prototype._ingest = function(t) {
prototype._ingest = function(t) {
return Tuple.ingest(t, null);

@@ -25,0 +25,0 @@ };

@@ -9,3 +9,3 @@ var df = require('vega-dataflow'),

Transform.addParameters(this, {
fields: {type: 'array<field>'}
fields: {type: 'array<field>'}
});

@@ -22,3 +22,3 @@

prototype._reset = function(input, output) {
prototype._reset = function(input, output) {
for (var id in this._cache) {

@@ -40,7 +40,7 @@ output.rem.push.apply(output.rem, this._cache[id]);

for (j=0, m=on.field.length; j<m; ++j) {
t = this._tuple(d, j, m);
t = this._tuple(d, j, m);
Tuple.set(t, this._output.key, on.field[j]);
Tuple.set(t, this._output.value, on.accessor[j](d));
out.push(t);
}
}
}

@@ -66,3 +66,3 @@ };

// If we're only propagating values, don't mark key/value as updated.
if (input.add.length || input.rem.length ||
if (input.add.length || input.rem.length ||
on.field.some(function(f) { return !!input.fields[f]; })) {

@@ -69,0 +69,0 @@ output.fields[this._output.key] = 1;

@@ -19,3 +19,3 @@ var d3 = require('d3'),

Transform.addParameters(this, {
size: {type: 'array<value>', default: [500, 500]},
size: {type: 'array<value>', default: require('./screen').size},
bound: {type: 'value', default: true},

@@ -37,3 +37,3 @@ links: {type: 'data'},

interactive: {type: 'value', default: this._interactive},
interactive: {type: 'value', default: this._interactive},
active: {type: 'value', default: this._prev},

@@ -71,3 +71,3 @@ fixed: {type: 'data'}

this.configure(nodeInput, linkInput, interactive, reset);
// run batch layout

@@ -88,3 +88,3 @@ if (!interactive) {

// update active node status,
// update active node status,
if (active !== this._prev) {

@@ -294,2 +294,2 @@ this._prev = active;

"required": ["type", "links"]
};
};

@@ -33,3 +33,3 @@ var df = require('vega-dataflow'),

input.add.forEach(set);
if (this.reevaluate(input)) {

@@ -36,0 +36,0 @@ input.mod.forEach(set);

@@ -25,3 +25,3 @@ var d3 = require('d3'),

center: {type: 'array<value>'},
translate: {type: 'array<value>'},
translate: {type: 'array<value>', default: require('./screen').center},
rotate: {type: 'array<value>'},

@@ -106,3 +106,3 @@ scale: {type: 'value'},

{"$ref": "#/refs/signal"}
]
]
},

@@ -119,3 +119,3 @@ "translate": {

{"$ref": "#/refs/signal"}
]
]
},

@@ -172,1 +172,2 @@ "rotate": {

};

@@ -69,3 +69,2 @@ var dl = require('datalib'),

log.debug(input, ['imputing2']);
return input;

@@ -72,0 +71,0 @@ };

@@ -14,2 +14,3 @@ module.exports = {

geopath: require('./GeoPath'),
hierarchy: require('./Hierarchy'),
impute: require('./Impute'),

@@ -20,2 +21,3 @@ lookup: require('./Lookup'),

stack: require('./Stack'),
treeify: require('./Treeify'),
treemap: require('./Treemap'),

@@ -22,0 +24,0 @@ voronoi: require('./Voronoi'),

@@ -39,2 +39,24 @@ var Tuple = require('vega-dataflow').Tuple,

function cornerX(sx, sy, tx, ty) {
return 'M' + sx + ',' + sy +
'V' + ty + 'H' + tx;
}
function cornerY(sx, sy, tx, ty) {
return 'M' + sx + ',' + sy +
'H' + tx + 'V' + ty;
}
function cornerR(sa, sr, ta, tr) {
var sc = Math.cos(sa),
ss = Math.sin(sa),
tc = Math.cos(ta),
ts = Math.sin(ta),
sf = Math.abs(ta - sa) > Math.PI ? ta <= sa : ta > sa;
return 'M' + (sr*sc) + ',' + (sr*ss) +
'A' + sr + ',' + sr + ' 0 0,' + (sf?1:0) +
' ' + (sr*tc) + ',' + (sr*ts) +
'L' + (tr*tc) + ',' + (tr*ts);
}
function diagonalX(sx, sy, tx, ty) {

@@ -56,8 +78,23 @@ var m = (sx + tx) / 2;

function diagonalR(sa, sr, ta, tr) {
var sc = Math.cos(sa),
ss = Math.sin(sa),
tc = Math.cos(ta),
ts = Math.sin(ta),
mr = (sr + tr) / 2;
return 'M' + (sr*sc) + ',' + (sr*ss) +
'C' + (mr*sc) + ',' + (mr*ss) +
' ' + (mr*tc) + ',' + (mr*ts) +
' ' + (tr*tc) + ',' + (tr*ts);
}
var shapes = {
line: line,
curve: curve,
diagonal: diagonalX,
cornerX: cornerX,
cornerY: cornerY,
cornerR: cornerR,
diagonalX: diagonalX,
diagonalY: diagonalY
diagonalY: diagonalY,
diagonalR: diagonalR
};

@@ -135,3 +172,3 @@

"oneOf": [
{"enum": ["line", "curve", "diagonal", "diagonalX", "diagonalY"]},
{"enum": ["line", "curve", "cornerX", "cornerY", "cornerR", "diagonalX", "diagonalY", "diagonalR"]},
{"$ref": "#/refs/signal"}

@@ -138,0 +175,0 @@ ],

@@ -64,3 +64,3 @@ var Tuple = require('vega-dataflow').Tuple,

input.mod.forEach(set);
input.rem.forEach(set);
input.rem.forEach(set);
}

@@ -106,2 +106,2 @@

"additionalProperties": false
};
};

@@ -21,3 +21,3 @@ var dl = require('datalib'),

this._resolution = false;
this._signals = {};
this._signals = [];
}

@@ -44,6 +44,6 @@

prototype.get = function() {
var graph = this._transform._graph,
var graph = this._transform._graph,
isData = dataType.test(this._type),
isField = fieldType.test(this._type),
s, idx, val;
i, n, sig, idx, val;

@@ -58,8 +58,9 @@ // If we don't require resolution, return the value immediately.

for (s in this._signals) {
idx = this._signals[s];
val = graph.signalRef(s);
for (i=0, n=this._signals.length; i<n; ++i) {
sig = this._signals[i];
idx = sig.index;
val = sig.value(graph);
if (isField) {
this._accessors[idx] = this._value[idx] != val ?
this._accessors[idx] = this._value[idx] != val ?
dl.accessor(val) : this._accessors[idx];

@@ -80,6 +81,8 @@ }

p._signals = [];
this._value = dl.array(value).map(function(v, i) {
var e;
if (dl.isString(v)) {
if (isExpr) {
var e = expr(v);
e = expr(v);
p._transform.dependency(Deps.FIELDS, e.fields);

@@ -104,5 +107,19 @@ p._transform.dependency(Deps.SIGNALS, e.globals);

p._resolution = true;
p._signals[v.signal] = i;
p._transform.dependency(Deps.SIGNALS, v.signal);
p._signals.push({
index: i,
value: function(graph) { return graph.signalRef(v.signal); }
});
return v.signal;
} else if (v.expr !== undefined) {
p._resolution = true;
e = expr(v.expr);
p._transform.dependency(Deps.SIGNALS, e.globals);
p._signals.push({
index: i,
value: function(graph) {
return e.fn(null, null, graph.values(Deps.SIGNALS, e.globals));
}
});
return v.expr;
}

@@ -116,2 +133,14 @@

module.exports = Parameter;
module.exports = Parameter;
// Schema for field|value-type parameters.
Parameter.schema = {
"type": "object",
"oneOf": [{
"properties": {"field": {"type": "string"}},
"required": ["field"]
}, {
"properties": {"value": {"type": "string"}},
"required": ["value"]
}]
};

@@ -76,3 +76,3 @@ var dl = require('datalib'),

"oneOf": [{"type": "string"}, {"$ref": "#/refs/signal"}],
"description": "The data values to encode as angular spans. " +
"description": "The data values to encode as angular spans. " +
"If this property is omitted, all pie slices will have equal spans."

@@ -86,3 +86,3 @@ },

"maximum": 2 * Math.PI
},
},
{"$ref": "#/refs/signal"}

@@ -98,3 +98,3 @@ ],

"maximum": 2 * Math.PI
},
},
{"$ref": "#/refs/signal"}

@@ -120,2 +120,2 @@ ],

"required": ["type"]
};
};

@@ -43,3 +43,3 @@ var df = require('vega-dataflow'),

// Many transforms store caches that must be invalidated if
// a signal value has changed.
// a signal value has changed.
var reset = this._stamp < input.stamp &&

@@ -46,0 +46,0 @@ this.dependency(Deps.SIGNALS).reduce(function(c, s) {

@@ -16,5 +16,6 @@ var d3 = require('d3'),

children: {type: 'field', default: 'children'},
parent: {type: 'field', default: 'parent'},
field: {type: 'field', default: 'value'},
// treemap parameters
size: {type: 'array<value>', default: [500, 500]},
size: {type: 'array<value>', default: require('./screen').size},
round: {type: 'value', default: true},

@@ -47,4 +48,11 @@ sticky: {type: 'value', default: false},

var layout = this._layout,
output = this._output;
output = this._output,
sticky = this.param('sticky'),
parent = this.param('parent').accessor,
root = data.filter(function(d) { return parent(d) === null; })[0];
// layout.sticky resets state _regardless_ of input value
// so, we perform out own check first
if (layout.sticky() !== sticky) { layout.sticky(sticky); }
// configure layout

@@ -57,7 +65,6 @@ layout

.round(this.param('round'))
.sticky(this.param('sticky'))
.ratio(this.param('ratio'))
.padding(this.param('padding'))
.mode(this.param('mode'))
.nodes(data[0]);
.nodes(root);

@@ -78,2 +85,3 @@ // copy layout values to nodes

input.fields[output.height] = 1;
input.fields[output.depth] = 1;
return input;

@@ -102,5 +110,11 @@ };

"children": {
"description": "A data field that represents the children array",
"oneOf": [{"type": "string"}, {"$ref": "#/refs/signal"}]
"description": "The data field for the children node array",
"oneOf": [{"type": "string"}, {"$ref": "#/refs/signal"}],
"default": "children"
},
"parent": {
"description": "The data field for the parent node",
"oneOf": [{"type": "string"}, {"$ref": "#/refs/signal"}],
"default": "parent"
},
"field": {

@@ -110,2 +124,10 @@ "description": "The values to use to determine the area of each leaf-level treemap cell.",

},
"mode": {
"description": "The treemap layout algorithm to use.",
"oneOf": [
{"enum": ["squarify", "slice", "dice", "slice-dice"]},
{"$ref": "#/refs/signal"}
],
"default": "squarify"
},
"size": {

@@ -143,3 +165,3 @@ "description": "The dimensions of the treemap layout",

{
"type": "array",
"type": "array",
"items": {"oneOf": [{"type": "number"}, {"$ref": "#/refs/signal"}]},

@@ -146,0 +168,0 @@ "minItems": 4,

@@ -10,3 +10,3 @@ var d3 = require('d3'),

Transform.addParameters(this, {
clipExtent: {type: 'array<value>', default: [[-1e5,-1e5],[1e5,1e5]]},
clipExtent: {type: 'array<value>', default: require('./screen').extent},
x: {type: 'field', default: 'layout_x'},

@@ -13,0 +13,0 @@ y: {type: 'field', default: 'layout_y'}

@@ -8,3 +8,4 @@ var dl = require('datalib'),

Transform = require('./Transform'),
BatchTransform = require('./BatchTransform');
BatchTransform = require('./BatchTransform'),
Parameter = require('./Parameter');

@@ -14,3 +15,3 @@ function Wordcloud(graph) {

Transform.addParameters(this, {
size: {type: 'array<value>', default: [900, 500]},
size: {type: 'array<value>', default: require('./screen').size},
text: {type: 'field', default: 'data'},

@@ -65,3 +66,3 @@ rotate: {type: 'field|value', default: 0},

fontSize = fontSize.accessor || d3.functor(fontSize);
// create font size scaling function as needed

@@ -135,3 +136,3 @@ if (range.length) {

"description": "The font face to use for a word.",
"oneOf": [{"type": "string"}, {"$ref": "#/refs/signal"}],
"oneOf": [{"type": "string"}, Parameter.schema, {"$ref": "#/refs/signal"}],
"default": "sans-serif"

@@ -141,3 +142,3 @@ },

"description": "The font style to use for a word.",
"oneOf": [{"type": "string"}, {"$ref": "#/refs/signal"}],
"oneOf": [{"type": "string"}, Parameter.schema, {"$ref": "#/refs/signal"}],
"default": "normal"

@@ -147,3 +148,3 @@ },

"description": "The font weight to use for a word.",
"oneOf": [{"type": "string"}, {"$ref": "#/refs/signal"}],
"oneOf": [{"type": "string"}, Parameter.schema, {"$ref": "#/refs/signal"}],
"default": "normal"

@@ -153,3 +154,3 @@ },

"description": "The font size to use for a word.",
"oneOf": [{"type": "number"}, {"type": "string"}, {"$ref": "#/refs/signal"}],
"oneOf": [{"type": "number"}, Parameter.schema, {"type": "string"}, {"$ref": "#/refs/signal"}],
"default": 14

@@ -161,3 +162,3 @@ },

{ "type": "null" },
{
{
"type": "array",

@@ -173,3 +174,6 @@ "minItems": 2,

"description": "The field or number to set the roration angle (in degrees).",
"oneOf": [{"type": "number"}, {"type": "string"}, {"$ref": "#/refs/signal"}],
"oneOf": [
{"type": "number"}, {"type": "string"},
Parameter.schema, {"$ref": "#/refs/signal"}
],
"default": 0

@@ -179,3 +183,3 @@ },

"description": "The field containing the text to use for each word.",
"oneOf": [{"type": "string"}, {"$ref": "#/refs/signal"}],
"oneOf": [{"type": "string"}, Parameter.schema, {"$ref": "#/refs/signal"}],
"default": 'data'

@@ -185,3 +189,3 @@ },

"description": "The type of spiral used for positioning words, either 'archimedean' or 'rectangular'.",
"oneOf": [{"enum": ["archimedean", "rectangular"]}, {"$ref": "#/refs/signal"}],
"oneOf": [{"enum": ["archimedean", "rectangular"]}, Parameter.schema, {"$ref": "#/refs/signal"}],
"default": "archimedean"

@@ -191,3 +195,3 @@ },

"description": "The padding around each word.",
"oneOf": [{"type": "number"}, {"$ref": "#/refs/signal"}],
"oneOf": [{"type": "number"}, Parameter.schema, {"$ref": "#/refs/signal"}],
"default": 1

@@ -194,0 +198,0 @@ },

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc