import { dispatch } from "d3-dispatch"; import constant from "./constant"; import interpolation from "./interpolation"; import interpolationPivots from "./interpolationPivots"; import neighbourSamplingDistance from "./neighbourSamplingDistance"; export default function (nodes, config) { var hybrid, fullSimulation, SAMPLE_ITERATIONS = config.hasOwnProperty("iteration") ? config.iteration : 300, neighbourSize = config.hasOwnProperty("neighbourSize") ? config.neighbourSize : 6, sampleSize = config.hasOwnProperty("sampleSize") ? config.sampleSize : 3, distanceRange = config.hasOwnProperty("distanceRange") ? config.distanceRange : 10, FULL_ITERATIONS = config.hasOwnProperty("fullIterations") ? config.fullIterations : 20, FullneighbourSize = config.hasOwnProperty("fullNeighbourSize") ? config.fullNeighbourSize : 6, FullsampleSize = config.hasOwnProperty("fullSampleSize") ? config.fullSampleSize : 3, FulldistanceRange = config.hasOwnProperty("fullDistanceRange") ? config.fullDistanceRange : 10, distanceFn = config.hasOwnProperty("distanceFn") ? config.distanceFn : constant(300), PIVOTS = config.hasOwnProperty("pivots") ? config.pivots : false, NUMPIVOTS = config.hasOwnProperty("numPivots") ? config.numPivots : 3, event = d3.dispatch("sampleTick", "fullTick", "startFull", "end"); var sets = sampleFromNodes(nodes, Math.sqrt(nodes.length)); var sample = sets.sample; var remainder = sets.remainder; var sampleSubset = sampleFromNodes(sample, Math.sqrt(sample.length)).sample; var sampleSimulation = d3.forceSimulation(sample) .stop() .alphaDecay(1 - Math.pow(0.001, 1 / SAMPLE_ITERATIONS)) .on("tick", function () { event.call("sampleTick", sampleSimulation); }) .on("end", ended); sampleSimulation.force("forces", neighbourSamplingDistance() .neighbourSize(neighbourSize) .sampleSize(sampleSize) .distanceRange(distanceRange) .distance(distanceFn) ); sampleSimulation.alpha(1).restart(); function ended() { event.call("startFull"); console.log("Ended sample simulation"); /* if (PIVOTS) { interpolationPivots(sample, remainder, interpSubset, NUMPIVOTS, distance); } else { interpolation(sample, remainder, interpSubset, distance); } */ event.call("fullTick"); alert('About to Full run'); if (FULL_ITERATIONS==0) { event.call("end"); return; } fullSimulation = d3.forceSimulation() .stop() .alphaDecay(1 - Math.pow(0.001, 1 / FULL_ITERATIONS)); fullSimulation .force("neighbourSampling", neighbourSamplingDistance() .neighbourSize(FullneighbourSize) .sampleSize(FullsampleSize) .distanceRange(FulldistanceRange) .distance(distanceFn) ) .on("tick", function () { event.call("fullTick", fullSimulation); }) .on("end", function () { event.call("end", fullSimulation); }) .nodes(nodes) .alpha(1).restart(); } return hybrid = { distance: function (_) { return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), hybrid) : distance; }, stop: function () { if (typeof sampleSimulation !== 'undefined') { sampleSimulation.stop(); } if (typeof fullSimulation !== 'undefined') { fullSimulation.stop(); } return hybrid; }, pivots: function (_) { return arguments.length ? (PIVOTS = _, hybrid) : PIVOTS; }, numPivots: function (_) { return arguments.length ? (NUMPIVOTS = +_, hybrid) : NUMPIVOTS; }, multiplier: function (_) { return arguments.length ? (MULTIPLIER = +_, hybrid) : MULTIPLIER; }, sampleIterations: function (_) { return arguments.length ? (SAMPLE_ITERATIONS = +_, hybrid) : SAMPLE_ITERATIONS; }, fullIterations: function (_) { return arguments.length ? (FULL_ITERATIONS = +_, hybrid) : FULL_ITERATIONS; }, neighbourSize: function (_) { return arguments.length ? (neighbourSize = +_, hybrid) : neighbourSize; }, sampleSize: function (_) { return arguments.length ? (sampleSize = +_, hybrid) : sampleSize; }, on: function (name, _) { return arguments.length > 1 ? (event.on(name, _), hybrid) : event.on(name); }, sample: function (_) { return arguments.length ? (sample = _, hybrid) : sample; }, remainder: function (_) { return arguments.length ? (remainder = _, hybrid) : remainder; }, stress: function () { return fullSimulation.force("neighbourSampling").stress(); } }; } function sampleFromNodes(nodes, size) { let randElements = [], max = nodes.length; for (var i = 0; i < size; ++i) { var rand = nodes[Math.floor((Math.random() * max))]; // If the rand is already in random list or in exclude list // ignore it and get a new value. while (randElements.includes(rand)) { rand = nodes[Math.floor((Math.random() * max))]; } randElements.push(rand); } var remainder = nodes.filter(function (node) { return !randElements.includes(node); }); return { sample: randElements, remainder: remainder }; }