1
0
mirror of https://github.com/yldio/copilot.git synced 2024-11-15 15:50:06 +02:00
copilot/packages/ui-toolkit/src/topology/simulation.js

131 lines
3.2 KiB
JavaScript
Raw Normal View History

import { forceSimulation, forceLink, forceCollide, forceCenter } from 'd3';
import Constants from './constants';
2017-02-14 13:30:57 +02:00
const hypotenuse = (a, b) => Math.sqrt(a * a + b * b);
2017-02-14 13:30:57 +02:00
const rectRadius = ({ width, height }) =>
Math.round(hypotenuse(width, height) / 2);
2017-02-14 13:30:57 +02:00
2017-04-27 14:49:52 +03:00
const forcePlayAnimation = (simulation, animationTicks) => {
const n =
Math.ceil(
Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())
) - animationTicks;
for (let i = 0; i < n; ++i) {
2017-04-27 14:49:52 +03:00
simulation.tick();
}
};
const createLinks = services =>
services.reduce(
(acc, service, index) =>
service.connections
? acc.concat(
service.connections.map((connection, index) => ({
source: service.uuid,
target: connection
}))
)
: acc,
[]
);
const createSimulation = (services, svgSize, animationTicks = 0) => {
2017-02-14 13:30:57 +02:00
// This is not going to work given that as well as the d3 layout stuff, other things might be at play too
// We should pass two objects to the components - one for positioning and one for data
const nodes = services.map((service, index) => ({
2017-04-27 14:49:52 +03:00
uuid: service.uuid,
index
2017-02-14 13:30:57 +02:00
}));
const links = createLinks(services);
2017-02-14 13:30:57 +02:00
const { width, height } = svgSize;
2017-02-14 13:30:57 +02:00
const nodeRadius = rectRadius(Constants.nodeSizeWithChildren);
2017-02-14 13:30:57 +02:00
2017-04-27 14:49:52 +03:00
const simulation = forceSimulation(nodes)
.force('link', forceLink(links).id(d => d.uuid))
.force('collide', forceCollide(nodeRadius))
.force('center', forceCenter(width / 2, height / 2));
2017-04-27 14:49:52 +03:00
forcePlayAnimation(simulation, animationTicks);
return {
2017-04-27 14:49:52 +03:00
nodes,
links,
simulation
};
2017-02-14 13:30:57 +02:00
};
// TODO we need to kill the previous simulation
2017-02-14 13:30:57 +02:00
const updateSimulation = (
simulation,
services,
simNodes,
simLinks,
2017-02-14 13:30:57 +02:00
svgSize,
onTick,
onEnd
) => {
const nodes = services.map((service, index) => {
const simNode = simNodes.reduce((acc, n, i) => {
return service.uuid === n.id ? n : acc;
}, null);
return simNode
? {
id: simNode.id,
// Fx: simNode.x,
// fy: simNode.y,
index
}
: {
id: service.uuid,
index
};
2017-02-14 13:30:57 +02:00
});
const links = createLinks(services);
2017-02-14 13:30:57 +02:00
const { width, height } = svgSize;
2017-02-14 13:30:57 +02:00
const nodeRadius = rectRadius(Constants.nodeSizeWithChildren);
2017-02-14 13:30:57 +02:00
return {
simulation: forceSimulation(nodes)
.force('link', forceLink(links).id(d => d.id))
.force('collide', forceCollide(nodeRadius))
.force('center', forceCenter(width / 2, height / 2))
.on('tick', onTick)
.on('end', onEnd),
nodes,
links
};
2017-02-14 13:30:57 +02:00
};
export { createSimulation, updateSimulation };
2017-02-14 13:30:57 +02:00
/*
Const simulation = forceSimulation(dataNodes)
2017-02-14 13:30:57 +02:00
// .alpha(1).alphaDecay(0.1)
// .force('charge', forceManyBody())
.force('link', forceLink(dataLinks)
2017-02-14 13:30:57 +02:00
//.distance(() => linkDistance)
.id(d => d.id))
.force('collide', forceCollide(nodeRadius))
.force('center', forceCenter(1024/2, 860/2))
2017-02-14 13:30:57 +02:00
.on('tick', () => {
console.log('SIMULATION TICK');
console.log('tickCounter = ', tickCounter);
tickCounter++;
this.forceUpdate();
})
.on('end', () => {
console.log('SIMULATION END');
console.log('tickCounter = ', tickCounter);
// this.forceUpdate();
})
*/