dc.graph
Version:
Graph visualizations integrated with crossfilter and dc.js
104 lines (101 loc) • 3.63 kB
JavaScript
var _workers = {};
var NUMBER_RESULTS = 3;
function create_worker(layoutAlgorithm) {
if(!_workers[layoutAlgorithm]) {
var worker = _workers[layoutAlgorithm] = {
worker: new Worker(script_path() + 'dc.graph.' + layoutAlgorithm + '.worker.js'),
layouts: {}
};
worker.worker.onmessage = function(e) {
var layoutId = e.data.layoutId;
if(!worker.layouts[layoutId])
throw new Error('layoutId "' + layoutId + '" unknown!');
var engine = worker.layouts[layoutId].getEngine();
if(e.data.args.length > NUMBER_RESULTS && engine.processExtraWorkerResults)
engine.processExtraWorkerResults.apply(engine, e.data.args.slice(NUMBER_RESULTS));
worker.layouts[layoutId].dispatch()[e.data.response].apply(null, e.data.args);
};
}
return _workers[layoutAlgorithm];
}
dc_graph.webworker_layout = function(layoutEngine) {
var _tick, _done, _dispatch = d3.dispatch('init', 'start', 'tick', 'end');
var _worker = create_worker(layoutEngine.layoutAlgorithm());
var engine = {};
_worker.layouts[layoutEngine.layoutId()] = engine;
engine.parent = function(parent) {
if(layoutEngine.parent)
layoutEngine.parent(parent);
};
engine.init = function(options) {
options = layoutEngine.optionNames().reduce(
function(options, option) {
options[option] = layoutEngine[option]();
return options;
}, options);
if(layoutEngine.propagateOptions)
layoutEngine.propagateOptions(options);
_worker.worker.postMessage({
command: 'init',
args: {
layoutId: layoutEngine.layoutId(),
options: options
}
});
return this;
};
engine.data = function(graph, nodes, edges, clusters, constraints) {
_worker.worker.postMessage({
command: 'data',
args: {
layoutId: layoutEngine.layoutId(),
graph: graph,
nodes: nodes,
edges: edges,
clusters: clusters,
constraints: constraints
}
});
};
engine.start = function() {
_worker.worker.postMessage({
command: 'start',
args: {
layoutId: layoutEngine.layoutId()
}
});
};
engine.stop = function() {
_worker.worker.postMessage({
command: 'stop',
args: {
layoutId: layoutEngine.layoutId()
}
});
return this;
};
// stopgap while layout options are still on diagram
engine.getEngine = function() {
return layoutEngine;
};
// somewhat sketchy - do we want this object to be transparent or not?
var passthroughs = ['layoutAlgorithm', 'populateLayoutNode', 'populateLayoutEdge',
'rankdir', 'ranksep'];
passthroughs.concat(layoutEngine.optionNames(),
layoutEngine.passThru ? layoutEngine.passThru() : []).forEach(function(name) {
engine[name] = function() {
var ret = layoutEngine[name].apply(layoutEngine, arguments);
return arguments.length ? this : ret;
};
});
engine.on = function(event, f) {
if(arguments.length === 1)
return _dispatch.on(event);
_dispatch.on(event, f);
return this;
};
engine.dispatch = function() {
return _dispatch;
};
return engine;
};