Skip to content

Commit efb518f

Browse files
committed
modify graphlayout recursive function to avoid self-trees
1 parent f198b98 commit efb518f

File tree

3 files changed

+72
-27
lines changed

3 files changed

+72
-27
lines changed

js/GraphLayout.js

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ const GraphLayout = (function() {
66
// recursively build hierarchy from a root word or link
77
function addNode(node, depth, source) {
88
let incoming = [];
9+
source = source ? source.slice() : [];
10+
let top = source[source.length - 1];
911

1012
let data = {
1113
node,
@@ -14,26 +16,38 @@ const GraphLayout = (function() {
1416
type: node instanceof Word ? 'Word' : 'Link'
1517
};
1618

19+
if (node !== top && source.indexOf(node) > -1) {
20+
return data;
21+
}
22+
else {
23+
source.push(node);
24+
}
25+
1726
if (depth < maxDepth) {
18-
let children = node.parents
19-
.filter(parent => {
27+
let p = node.parents;
28+
let children = p.filter((parent, j) => {
29+
// ignore duplicate children (for self-links)
30+
if (p.indexOf(parent) !== j) { return false; }
31+
2032
// ignore "incoming" links
21-
if (parent !== source && parent instanceof Link) {
33+
if (parent !== top && parent instanceof Link) {
2234
const i = parent.words.indexOf(node);
2335
if (i < 0 || parent.arrowDirections[i] === -1) {
2436
incoming.push(parent);
2537
return false;
2638
}
2739
}
28-
return parent !== source;
40+
return parent !== top;
2941
})
30-
.map((parent) => addNode(parent, depth + 1, node));
42+
.map((parent) => addNode(parent, depth + 1, source));
3143

3244
if (node instanceof Link) {
3345
let anchors = node.words
3446
.map((word, i) => {
35-
if (word !== source) {
36-
const newNode = addNode(word, depth + 1, node);
47+
// ignore duplicate children (for self-links)
48+
if (node.words.indexOf(word) !== i) { return null; }
49+
if (word !== top) {
50+
const newNode = addNode(word, depth + 1, source);
3751

3852
if (node.arrowDirections[i] === -1) {
3953
newNode.receivesArrow = true;
@@ -105,7 +119,7 @@ const GraphLayout = (function() {
105119

106120
// selected words to generate graph around
107121
this.words = [];
108-
this.maxDepth = 20; // default value for max dist from root
122+
this.maxDepth = 8; // default value for max dist from root
109123
}
110124
resize() {
111125
this.bounds = this.div.getBoundingClientRect();

js/annotate.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,22 +231,15 @@ function determineSide(link) {
231231
//TODO - should there be a global strategy for each class of link types? for the different styles of links? for each parent word/link? or for every single individual link??? E.g., could a word support links with different strategies, or would that become cluttered??
232232
function calcAttachPoints(link, strategy) {
233233

234-
//link.leftWord.nr += 1;
235-
//link.rightWord.nl += 1;
236-
237234
//console.log("" + link.id + " strategy = CLOSEST");
238235

239236
if (determineSide(link) == swapside.YES) {
240237
//console.log("rootS < rootE (" +rootS +" < " + rootE +")");
241-
link.leftWord.nr += 1;
242-
link.rightWord.nl += 1;
243238
link.leftAttach = sides.RIGHT;
244239
link.rightAttach = sides.LEFT;
245240
} else {
246241
//console.log("rootS >= rootE (" +rootS +" >= " + rootE +")");
247242

248-
link.leftWord.nl += 1;
249-
link.rightWord.nr += 1;
250243
link.leftAttach = sides.LEFT;
251244
link.rightAttach = sides.RIGHT;
252245

js/wordcollapser.js

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const WordCollapser = (function() {
22

3-
let div;
3+
let div = {};
44
let selecting;
55
let leftWord;
66

@@ -20,20 +20,20 @@ const WordCollapser = (function() {
2020
div.className = null;
2121
}
2222

23+
document.addEventListener('keydown', function(e) {
24+
let c = e.keyCode;
25+
if (c === 65) { // A
26+
listenForLeftWord();
27+
}
28+
else {
29+
cancel();
30+
}
31+
});
32+
2333
class WordCollapser {
2434

2535
constructor() {
2636
div = document.getElementById('drawing');
27-
28-
document.addEventListener('keydown', function(e) {
29-
let c = e.keyCode;
30-
if (c === 65) { // A
31-
listenForLeftWord();
32-
}
33-
else {
34-
cancel();
35-
}
36-
});
3737
}
3838

3939
setClick(word) {
@@ -75,10 +75,48 @@ const WordCollapser = (function() {
7575
let removedWords = wordObjs.splice(lIndex, numberToSplice, phrase);
7676
row.words.splice(row.words.indexOf(leftWord), numberToSplice, phrase);
7777

78+
79+
removedWords.forEach(word => {
80+
81+
// replace backreferences of word in link with phrase
82+
function replaceLinkWordObject(link) {
83+
['leftWord', 'rightWord', 'nearestConnectedMaxWord', 'nearestConnectedMinWord', 'rootMaxWord', 'rootMinWord'].forEach(prop => {
84+
if (link[prop] === word) {
85+
link[prop] = phrase;
86+
}
87+
let idx = link.words.indexOf(word);
88+
if (idx > -1) {
89+
link.words[idx] = phrase;
90+
}
91+
});
92+
93+
link.parents.forEach(replaceLinkWordObject);
94+
}
95+
96+
// relink word links to phrase
97+
['parentsL', 'parentsC', 'parentsR'].forEach(prop => {
98+
phrase[prop] = phrase[prop].concat(word[prop]);
99+
});
100+
['slotsL', 'slotsR'].forEach(prop => {
101+
word[prop].forEach(slot => {
102+
if (phrase[prop].indexOf(slot) < 0) {
103+
phrase[prop].push(slot);
104+
}
105+
});
106+
})
107+
108+
// recurse through word's ancestor links
109+
word.parents.forEach(replaceLinkWordObject);
110+
111+
// make svg invisible
112+
word.svg.hide();
113+
114+
});
115+
78116
phrase.leftX = leftWord.leftX;
79117
phrase.row = row;
80118
phrase.draw();
81-
removedWords.forEach(word => word.svg.hide());
119+
redrawLinks(true);
82120
cancel();
83121
}
84122
}

0 commit comments

Comments
 (0)