Simplify affinity, strengthen links
This commit is contained in:
10
Layout.js
10
Layout.js
@@ -57,15 +57,17 @@ class Layout {
|
||||
this.groups_ = [];
|
||||
for (let group of this.graph_.groups) {
|
||||
let nodes = this.nodesFromGraphNodes(group.nodes);
|
||||
this.groups_.push(new LayoutGroup(group, this.nodesByPos_, nodes));
|
||||
this.groups_.push(new LayoutGroup(group, this.nodesByPos_, nodes, 'group'));
|
||||
}
|
||||
for (let subgraph of this.graph_.nodesBySubgraph.values()) {
|
||||
let nodes = this.nodesFromGraphNodes(subgraph);
|
||||
this.groups_.push(new LayoutGroup(null, this.nodesByPos_, nodes));
|
||||
this.groups_.push(new LayoutGroup(null, this.nodesByPos_, nodes,
|
||||
'subgraph'));
|
||||
}
|
||||
for (let labelGroup of this.graph_.nodesByLabel.values()) {
|
||||
let nodes = this.nodesFromGraphNodes(labelGroup);
|
||||
this.groups_.push(new LayoutGroup(null, this.nodesByPos_, nodes));
|
||||
this.groups_.push(new LayoutGroup(null, this.nodesByPos_, nodes,
|
||||
'labelgroup'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +225,7 @@ class Layout {
|
||||
|
||||
addGroupPos() {
|
||||
for (let group of this.groups_) {
|
||||
if (!group.hasGraphGroup()) {
|
||||
if (!group.isType('group')) {
|
||||
continue;
|
||||
}
|
||||
let [min, max] = group.getMinMax();
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
class LayoutGroup {
|
||||
constructor(graphGroup, nodesByPos, nodes) {
|
||||
constructor(graphGroup, nodesByPos, nodes, type) {
|
||||
this.graphGroup_ = graphGroup;
|
||||
this.nodesByPos_ = nodesByPos;
|
||||
this.nodes = new Set(nodes);
|
||||
this.type = type;
|
||||
this.tension = 0;
|
||||
|
||||
this.label = this.graphGroup_ ? this.graphGroup_.label : null;
|
||||
@@ -74,10 +75,15 @@ class LayoutGroup {
|
||||
return [min, max];
|
||||
}
|
||||
|
||||
isContained(pos) {
|
||||
// border is [left, right, top, bottom]
|
||||
isContained(pos, border=[0,0,0,0]) {
|
||||
let [min, max] = this.getMinMax();
|
||||
return (pos[0] >= min[0] && pos[0] <= max[0] &&
|
||||
pos[1] >= min[1] && pos[1] <= max[1]);
|
||||
return (pos[0] >= (min[0] - border[0]) && pos[0] <= (max[0] + border[1]) &&
|
||||
pos[1] >= (min[1] - border[2]) && pos[1] <= (max[1] + border[3]));
|
||||
}
|
||||
|
||||
isContainedWithMargin(pos) {
|
||||
return this.isContained(pos, [1, 1, this.label ? 2 : 1, 1]);
|
||||
}
|
||||
|
||||
getSteps() {
|
||||
@@ -106,7 +112,7 @@ class LayoutGroup {
|
||||
return steps;
|
||||
}
|
||||
|
||||
hasGraphGroup() {
|
||||
return this.graphGroup_ != null;
|
||||
isType(type) {
|
||||
return this.type == type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,49 +35,35 @@ class LayoutNode {
|
||||
// Keep unassociated subgroups together
|
||||
this.addAffinity(node, d => d);
|
||||
|
||||
// Keep one space between subgraphs
|
||||
if (this.subgraph != node.subgraph && this.label != node.label) {
|
||||
this.addAffinity(node, d => d <= 2 ? -INF : 0);
|
||||
}
|
||||
|
||||
// Am I in any labeled groups that node is not?
|
||||
// If so, preserve two spaces above the group
|
||||
if (asymDifference(this.labelGroups(this.groups), node.groups).size) {
|
||||
this.addAffinity(node,
|
||||
(d, v) =>
|
||||
(v[0] >= -1 && v[0] <= 1 && v[1] < 0 && v[1] >= -2) ? -INF : 0);
|
||||
}
|
||||
|
||||
// Preserve one space all around the group
|
||||
if (asymDifference(this.graphGroups(this.groups),
|
||||
this.graphGroups(node.groups)).size) {
|
||||
this.addAffinity(node, d => d <= 2 ? -INF : 0);
|
||||
}
|
||||
|
||||
// Try to stack nodes with the same label
|
||||
if (node.label == this.label) {
|
||||
this.addAffinity(node, (d, v) => v[0] == 0 ? 200 : 500);
|
||||
}
|
||||
|
||||
for (let group of this.groups) {
|
||||
// Ensure groups do not overlap
|
||||
if (!group.isType('group') && !group.isType('subgraph')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure groups do not overlap, with border
|
||||
if (group.nodes.has(node)) {
|
||||
continue;
|
||||
}
|
||||
this.addAffinity(node, (d, v, p) => group.isContained(p) ? -INF : 0);
|
||||
this.addAffinity(node,
|
||||
(d, v, p) => group.isContainedWithMargin(p) ? -INF : 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (let link of this.links) {
|
||||
// Stronger affinity for links
|
||||
// Prefer to move toward the target instance
|
||||
this.addAffinity(link.to, d => d <= 2 ? -INF : d * 11);
|
||||
link.to.addAffinity(this, d => d <= 2 ? -INF : d * 9);
|
||||
this.addAffinity(link.to, d => d <= 2 ? -INF : d * 40);
|
||||
link.to.addAffinity(this, d => d <= 2 ? -INF : d * 35);
|
||||
}
|
||||
|
||||
// Affinity for groups
|
||||
// Affinity within groups
|
||||
for (let group of this.groups) {
|
||||
if (!group.hasGraphGroup()) {
|
||||
if (!group.isType('group')) {
|
||||
continue;
|
||||
}
|
||||
for (let node of group.nodes) {
|
||||
@@ -86,14 +72,6 @@ class LayoutNode {
|
||||
}
|
||||
}
|
||||
|
||||
graphGroups(groups) {
|
||||
return new Set(Array.from(groups).filter(g => g.hasGraphGroup()));
|
||||
}
|
||||
|
||||
labelGroups(groups) {
|
||||
return new Set(Array.from(groups).filter(g => !!g.label));
|
||||
}
|
||||
|
||||
addAffinity(node, distanceToWeight) {
|
||||
if (this == node) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user