Files
d3-spring-model/src/hybridSimulation.js
2018-01-16 21:24:47 +00:00

169 lines
5.3 KiB
JavaScript

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
};
}