Layout tweaks

This commit is contained in:
futpib 2018-11-17 16:49:43 +03:00
parent 6659fc9e96
commit 3dff4b5d51
2 changed files with 106 additions and 23 deletions

View File

@ -1,21 +1,34 @@
const {
filter,
} = require('ramda');
const { size } = require('../../constants/view');
const plusMinus = require('../../utils/plus-minus');
const margin = size / 10;
const step = size + (2 * margin);
function nodesIntersect(a, b) {
if (a.x === undefined || a.y === undefined || b.x === undefined || b.y === undefined) {
return undefined;
}
const offsetY = 1080 / 2;
return (((a.x - size - margin) < b.x) && (b.x < (a.x + size + margin))) &&
(((a.y - size - margin) < b.y) && (b.y < (a.y + size + margin)));
}
const centerColumnsCount = 5;
module.exports = class LayoutEngine {
constructor(graphViewProps) {
this.graphViewProps = graphViewProps;
constructor() {
Object.assign(this, {
size,
margin,
});
}
nodesIntersect(a, b) {
if (a.x === undefined || a.y === undefined || b.x === undefined || b.y === undefined) {
return undefined;
}
return (((a.x - size - margin) < b.x) && (b.x < (a.x + size + margin))) &&
(((a.y - size - margin) < b.y) && (b.y < (a.y + size + margin)));
}
calculatePosition(node) {
@ -23,36 +36,76 @@ module.exports = class LayoutEngine {
}
adjustNodes(nodes) {
nodes.forEach(node => {
const targetClientsColumnHeight = Math.round(filter(
x => x.type === 'sink' || x.type === 'source',
nodes,
).length * 0.75);
const estimatedColumnHeights = {
total: 0,
get(k) {
return this[k] || 0;
},
inc(k) {
this[k] = this[k] || 0;
this[k] += 1;
this.total += 1;
return this[k];
},
};
const nodeColumn = node => Math.round(node.x / step) - 2;
const unpositionedNodes = nodes.filter(node => {
if (node.type === 'satellite') {
return;
return false;
}
if (node.x !== undefined) {
return;
estimatedColumnHeights.inc(nodeColumn(node));
return false;
}
return true;
});
unpositionedNodes.forEach(node => {
if (node.type === 'source') {
node.x = 0 * step;
} else if (node.type === 'sink') {
node.x = 8 * step;
} else {
node.x = (2 * step) + ((node.index % 5) * step);
let targetCol = node.index % centerColumnsCount;
if (estimatedColumnHeights.get(2) < targetClientsColumnHeight) {
targetCol = 2;
}
node.x = (2 * step) + (targetCol * step);
}
node.y = 0;
const columnHeight = estimatedColumnHeights.inc(nodeColumn(node));
for (const otherNode of nodes) {
if (otherNode.type === 'satellite') {
continue;
}
const direction = Math.sign(plusMinus(node.index));
if (otherNode === node) {
continue;
}
node.y = offsetY + (direction * (Math.floor(columnHeight / 2) - 1) * (size + margin));
if (nodesIntersect(node, otherNode)) {
node.y += size + margin;
let intersected = true;
while (intersected) {
intersected = false;
for (const otherNode of nodes) {
if (otherNode.type === 'satellite') {
continue;
}
if (otherNode === node) {
continue;
}
if (this.nodesIntersect(node, otherNode)) {
node.y += direction * (size + margin);
intersected = true;
}
}
}
});

View File

@ -0,0 +1,30 @@
import test from 'ava';
import LayoutEngine from './layout-engine';
const n = (x, y) => ({ x, y });
test('nodesIntersect', t => {
const l = new LayoutEngine();
const { size, margin } = l;
const true_ = (x1, y1, x2, y2) => t.true(l.nodesIntersect(n(x1, y1), n(x2, y2)));
const false_ = (x1, y1, x2, y2) => t.false(l.nodesIntersect(n(x1, y1), n(x2, y2)));
[
[ 0, 0 ],
[ 500, 500 ],
[ -500, -500 ],
].forEach(([ x0, y0 ]) => {
true_(x0, y0, x0, y0);
false_(x0, y0, x0 + size + margin, y0);
false_(x0, y0, x0, y0 + size + margin);
true_(x0, y0, x0 + size + margin - 1, y0);
true_(x0, y0, x0, y0 + size + margin - 1);
true_(x0, y0, x0 + size + margin - 1, y0 + size + margin - 1);
});
});