Skip to content

Commit 45c8379

Browse files
committed
refactor -- start adding links
1 parent 727f0ba commit 45c8379

File tree

7 files changed

+199
-53
lines changed

7 files changed

+199
-53
lines changed

css/style2.css

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ svg text {
6464
#main svg {
6565
background-color: hsl(40,10%,90%);
6666
}
67+
#main text {
68+
font-family: BrownPro, Brown, futura, helvetica, arial, sans-serif;
69+
text-anchor: middle;
70+
}
6771
.row-drag {
6872
stroke-width:2;
6973
stroke-dasharray: 2,1;
@@ -77,9 +81,7 @@ svg text {
7781
}
7882

7983
.word text {
80-
font-family: BrownPro, Brown, futura, helvetica, arial, sans-serif;
8184
font-size:16px;
82-
text-anchor: middle;
8385
fill:black;
8486
}
8587
.word path {
@@ -96,9 +98,7 @@ svg text {
9698
cursor: text;
9799
}
98100

99-
.word-cluster text {
100-
fill:#a94442;
101-
}
101+
.word-cluster text,
102102
.word .word-tag {
103103
fill:#333;
104104
}
@@ -107,5 +107,15 @@ svg text {
107107
fill: #fff;
108108
}
109109
.editing rect {
110-
fill: rgb(203, 120, 111);
110+
/*fill: rgb(203, 120, 111);*/
111+
fill:#a94442;
112+
}
113+
114+
.link path.polyline {
115+
stroke: #6590b4;
116+
fill: none;
117+
}
118+
.link {
119+
font-size: 12px;
120+
fill:#6590b4;
111121
}

js2/components/link.js

Lines changed: 134 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,164 @@
11
class Link {
2-
constructor(eventId, trigger, args) {
2+
constructor(eventId, trigger, args, reltype) {
33
this.eventId = eventId;
44
this.trigger = trigger;
55
this.arguments = args;
66
this.links = [];
7-
console.log('trigger\t\t', this.val);
8-
console.log.apply(null, args);
7+
this.reltype = reltype;
8+
// console.log('trigger\t\t', this.val);
9+
// console.log.apply(null, args);
10+
11+
if (this.trigger) { this.trigger.links.push(this); }
12+
this.arguments.forEach(arg => arg.anchor.links.push(this));
913

1014
this.mainSVG = null;
1115
this.svg = null;
1216
this.handles = [];
13-
this.lines = [];
17+
this.line = null;
1418
this.svgTexts = [];
1519
}
1620

1721
init(svg) {
18-
// this.mainSVG = svg;
19-
// this.svg = svg.group().addClass('link');
20-
// if (this.trigger) {
21-
// console.log(this.trigger.x, this.trigger.boxWidth, this.trigger.row);
22-
// }
23-
}
24-
25-
/**
26-
* remove reference to a link
27-
* @return array containing the link, or undefined
28-
*/
29-
detachLink(link) {
30-
let i = this.links.indexOf(link);
31-
if (i > -1) {
32-
return this.links.splice(i, 1);
22+
this.mainSVG = svg;
23+
this.svg = svg.group().addClass('link');
24+
25+
// init handles
26+
const s = 4;
27+
if (this.trigger) {
28+
// draw a diamond at the location of the trigger
29+
let x = this.trigger.cx;
30+
let y = this.trigger.absoluteY;
31+
let handle = this.svg.path(`M${s},0L0,${s}L${-s},0L0,${-s}Z`)
32+
.x(x - s)
33+
.y(y);
34+
this.handles.push({ anchor: this.trigger, handle, x, y });
35+
}
36+
this.arguments.forEach(arg => {
37+
// draw a triangle at the location of the argument
38+
let x = arg.anchor.cx;
39+
let y = arg.anchor.absoluteY;
40+
41+
let handle = this.svg.path(`M${[s, -s/2]}L${[-s, -s/2]}L0,${s}`)
42+
.x(x - s)
43+
.y(y);
44+
this.handles.push({ anchor: arg.anchor, handle, x, y });
45+
46+
if (this.trigger) {
47+
let text = this.svg.text(arg.type)
48+
.y(-7)
49+
.addClass('link-text');
50+
this.svgTexts.push(text);
51+
}
52+
});
53+
if (this.reltype) {
54+
let text = this.svg.text(this.reltype)
55+
.y(-7)
56+
.addClass('link-text');
57+
this.svgTexts.push(text);
3358
}
59+
60+
this.line = this.svg.path()
61+
.addClass('polyline');
62+
this.draw();
63+
64+
//TODO: sort links and offset according to # of links the anchor has
65+
}
66+
67+
draw(anchor) {
68+
const s = 4;
69+
this.handles.forEach(h => {
70+
if (anchor === h.anchor) {
71+
h.x = anchor.cx;
72+
h.y = anchor.absoluteY;
73+
h.handle
74+
.x(h.x - s)
75+
.y(h.y);
76+
}
77+
})
78+
if (this.line) {
79+
let d;
80+
if (this.trigger) {
81+
d = this.arguments.map((arg, i) => {
82+
let tx = this.trigger.cx
83+
, ty = this.trigger.absoluteY
84+
, ax = arg.anchor.cx
85+
, ay = arg.anchor.absoluteY;
86+
87+
let dx = (tx < ax) ? 10 : -10;
88+
let dy = ty - ay; // FIXME: this only handles case for trigger.y on lower level than arg.y
89+
90+
// get text position
91+
let len = this.svgTexts[i]
92+
.x((ax + tx) / 2)
93+
.y(arg.anchor.absoluteY - 10 - 7)
94+
.length() / 2;
95+
96+
let cx = (ax - tx) / 2 - dx;
97+
if (cx < 0) { len = -len; }
98+
99+
// get path string
100+
return 'M' + [tx, ty]
101+
+ 'c' + [0, -10 - dy, 0, -10 - dy, dx, -10 - dy]
102+
+ 'l' + [cx - len, 0]
103+
+ 'm' + [len * 2, 0]
104+
+ 'l' + [cx - len, 0]
105+
+ 'c' + [dx, 0, dx, 10, dx, 10];
106+
}).join();
107+
}
108+
else {
109+
let avg = this.arguments.reduce((acc, a) => acc + a.anchor.cx, 0) / this.arguments.length;
110+
this.svgTexts[0].x(avg)
111+
.y(this.arguments[0].anchor.absoluteY - 10 - 7);
112+
d = 'M' + [this.arguments[0].anchor.cx, this.arguments[0].anchor.absoluteY]
113+
+ 'L' + [this.arguments[1].anchor.cx, this.arguments[1].anchor.absoluteY];
114+
}
115+
this.line.plot(d);
116+
}
117+
118+
this.links.forEach(l => l.draw(this));
34119
}
35120

36121
remove() {
37122
this.svg.remove();
38123

124+
let self = this;
125+
// remove reference to a link
126+
function detachLink(anchor) {
127+
let i = anchor.links.indexOf(self);
128+
if (i > -1) {
129+
anchor.links.splice(i, 1);
130+
}
131+
};
132+
39133
// remove references to link from all anchors
40-
if (this.trigger) { this.trigger.detachLink(this); }
41-
this.arguments.forEach(arg => arg.detachLink(this));
134+
if (this.trigger) { detachLink(this.trigger); }
135+
this.arguments.forEach(arg => detachLink(arg.anchor));
42136
}
43137

44138
hasAnchor(a) {
45139
if (this.trigger && a === this.trigger) { return true; }
46140
return this.arguments.find(arg => arg.anchor === a);
47141
}
48142

143+
get cx() {
144+
if (this.trigger) {
145+
// if (this.trigger.links.length > 1) {
146+
// let offset = this.trigger.links.indexOf(this) / (this.trigger.links.length - 1) - 0.5;
147+
// return this.trigger.cx + offset * 200;
148+
// }
149+
return this.trigger.cx;
150+
}
151+
if (this.arguments.length > 0) {
152+
return this.arguments.reduce((acc, arg) => acc + arg.cx, 0) / this.arguments.length;
153+
}
154+
return 0;
155+
}
156+
get absoluteY() {
157+
if (this.trigger) { return this.trigger.absoluteY - 15; }
158+
if (this.arguments[0]) { return this.arguments[0].absoluteY - 15; }
159+
return 0;
160+
}
161+
49162
get val() {
50163
return this.trigger && this.trigger.val;
51164
}

js2/components/tag.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class WordTag {
2626
}
2727
remove() {
2828
this.entity.tag = null;
29-
this.entity.setBoxWidth();
29+
this.entity.calculateBox();
3030
return this.svg.remove();
3131
}
3232
updateWordWidth() {
@@ -92,7 +92,7 @@ class WordTag {
9292
this.remove();
9393
}
9494
else {
95-
this.entity.setBoxWidth();
95+
this.entity.calculateBox();
9696
}
9797
}
9898
// word width

js2/components/word.js

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class Word {
55
this.idx = idx;
66
this.x = 0;
77
this.boxWidth = 0;
8+
this.boxHeight = 0;
89
this.isPunct = (val.length === 1 && val.charCodeAt(0) < 65); // FIXME: doesn't handle fancier unicode punct | should exclude left-punctuation e.g. left-paren or left-quote
910
this.clusters = [];
1011
this.links = [];
@@ -32,7 +33,7 @@ class Word {
3233
else {
3334
this.tag = new WordTag(tag, this);
3435
}
35-
this.setBoxWidth();
36+
this.calculateBox();
3637
}
3738
else {
3839
this.tag = tag;
@@ -58,7 +59,7 @@ class Word {
5859
});
5960

6061
// translate over by half (since the text is centered)
61-
this.setBoxWidth();
62+
this.calculateBox();
6263
this.svg.y(-this.svgText.bbox().y2);
6364

6465
// attach drag listeners
@@ -89,6 +90,10 @@ class Word {
8990
}
9091
}
9192

93+
redrawLinks() {
94+
this.links.forEach(l => l.draw(this));
95+
}
96+
9297
redrawClusters() {
9398
this.clusters.forEach(cluster => {
9499
if (cluster.endpoints.indexOf(this) > -1) {
@@ -101,15 +106,18 @@ class Word {
101106
this.x = x;
102107
this.svg.transform({x: this.boxWidth / 2 + this.x});
103108
this.redrawClusters();
109+
this.redrawLinks();
104110
}
105111

106112
dx(x) {
107113
this.move(this.x + x);
108114
}
109115

110-
setBoxWidth() {
111-
let diff = this.boxWidth - this.minWidth;
116+
calculateBox() {
117+
let minWidth = (this.tag instanceof WordTag) ? Math.max(this.tag.ww, this.ww) : this.ww;
118+
let diff = this.boxWidth - minWidth;
112119
this.boxWidth -= diff;
120+
this.boxHeight = this.svg.bbox().height;
113121
this.dx(diff / 2);
114122
this.mainSVG.fire('word-move', {object: this, x: 0});
115123
}
@@ -119,21 +127,13 @@ class Word {
119127
row.addWord(this, i, ignorePosition);
120128
}
121129

122-
/**
123-
* remove reference to a link
124-
* @return array containing the link, or undefined
125-
*/
126-
detachLink(link) {
127-
let i = this.links.indexOf(link);
128-
if (i > -1) {
129-
return this.links.splice(i, 1);
130-
}
130+
get absoluteY() {
131+
return this.row ? this.row.ry + this.row.rh - this.boxHeight - 5 : 0;
132+
}
133+
get cx() {
134+
return this.x + this.boxWidth / 2;
131135
}
132-
133136
get ww() {
134137
return this.svgText.length();
135138
}
136-
get minWidth() {
137-
return this.tag instanceof WordTag ? Math.max(this.tag.ww, this.ww) : this.ww;
138-
}
139139
}

0 commit comments

Comments
 (0)