(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vega-dataflow'), require('vega-util'), require('d3-force')) : typeof define === 'function' && define.amd ? define(['exports', 'vega-dataflow', 'vega-util', 'd3-force'], factory) : (global = global || self, factory((global.vega = global.vega || {}, global.vega.transforms = {}), global.vega, global.vega, global.d3)); }(this, function (exports, vegaDataflow, vegaUtil, d3Force) { 'use strict'; var ForceMap = { center: d3Force.forceCenter, collide: d3Force.forceCollide, nbody: d3Force.forceManyBody, link: d3Force.forceLink, x: d3Force.forceX, y: d3Force.forceY }; var Forces = 'forces', ForceParams = [ 'alpha', 'alphaMin', 'alphaTarget', 'velocityDecay', 'forces' ], ForceConfig = ['static', 'iterations'], ForceOutput = ['x', 'y', 'vx', 'vy']; /** * Force simulation layout. * @constructor * @param {object} params - The parameters for this operator. * @param {Array} params.forces - The forces to apply. */ function Force(params) { vegaDataflow.Transform.call(this, null, params); } Force.Definition = { "type": "Force", "metadata": {"modifies": true}, "params": [ { "name": "static", "type": "boolean", "default": false }, { "name": "restart", "type": "boolean", "default": false }, { "name": "iterations", "type": "number", "default": 300 }, { "name": "alpha", "type": "number", "default": 1 }, { "name": "alphaMin", "type": "number", "default": 0.001 }, { "name": "alphaTarget", "type": "number", "default": 0 }, { "name": "velocityDecay", "type": "number", "default": 0.4 }, { "name": "forces", "type": "param", "array": true, "params": [ { "key": {"force": "center"}, "params": [ { "name": "x", "type": "number", "default": 0 }, { "name": "y", "type": "number", "default": 0 } ] }, { "key": {"force": "collide"}, "params": [ { "name": "radius", "type": "number", "expr": true }, { "name": "strength", "type": "number", "default": 0.7 }, { "name": "iterations", "type": "number", "default": 1 } ] }, { "key": {"force": "nbody"}, "params": [ { "name": "strength", "type": "number", "default": -30 }, { "name": "theta", "type": "number", "default": 0.9 }, { "name": "distanceMin", "type": "number", "default": 1 }, { "name": "distanceMax", "type": "number" } ] }, { "key": {"force": "link"}, "params": [ { "name": "links", "type": "data" }, { "name": "id", "type": "field" }, { "name": "distance", "type": "number", "default": 30, "expr": true }, { "name": "strength", "type": "number", "expr": true }, { "name": "iterations", "type": "number", "default": 1 } ] }, { "key": {"force": "x"}, "params": [ { "name": "strength", "type": "number", "default": 0.1 }, { "name": "x", "type": "field" } ] }, { "key": {"force": "y"}, "params": [ { "name": "strength", "type": "number", "default": 0.1 }, { "name": "y", "type": "field" } ] } ] }, { "name": "as", "type": "string", "array": true, "modify": false, "default": ForceOutput } ] }; var prototype = vegaUtil.inherits(Force, vegaDataflow.Transform); prototype.transform = function(_, pulse) { var sim = this.value, change = pulse.changed(pulse.ADD_REM), params = _.modified(ForceParams), iters = _.iterations || 300; // configure simulation if (!sim) { this.value = sim = simulation(pulse.source, _); sim.on('tick', rerun(pulse.dataflow, this)); if (!_.static) { change = true; sim.tick(); // ensure we run on init } pulse.modifies('index'); } else { if (change) { pulse.modifies('index'); sim.nodes(pulse.source); } if (params || pulse.changed(pulse.MOD)) { setup(sim, _, 0, pulse); } } // run simulation if (params || change || _.modified(ForceConfig) || (pulse.changed() && _.restart)) { sim.alpha(Math.max(sim.alpha(), _.alpha || 1)) .alphaDecay(1 - Math.pow(sim.alphaMin(), 1 / iters)); if (_.static) { for (sim.stop(); --iters >= 0;) sim.tick(); } else { if (sim.stopped()) sim.restart(); if (!change) return pulse.StopPropagation; // defer to sim ticks } } return this.finish(_, pulse); }; prototype.finish = function(_, pulse) { var dataflow = pulse.dataflow; // inspect dependencies, touch link source data for (var args=this._argops, j=0, m=args.length, arg; j