(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