-
Notifications
You must be signed in to change notification settings - Fork 5
/
render-scene-graph.js
161 lines (148 loc) · 5.53 KB
/
render-scene-graph.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
renderSceneGraph = function(selector, scene_graph) {
/* Creates a graph visualization.
*
* Args:
* selector: String id of the div where the graph should be displayed.
* scene_graph: JSON representation of the scene graph.
*/
var objects = scene_graph['objects'];
var attributes = scene_graph['attributes'];
var relationships = scene_graph['relationships'];
var obj_type = "object", pred_type = "pred", attr_type = "attr";
var nodes = [], links = [];
var object_pred_map = {};
// these three methods make links and nodes
function makeLink(parentElementID, childElementID) {
return new joint.dia.Link({
source: {id: parentElementID},
target: {id: childElementID},
attrs: {'.marker-target': {stroke:'rgba(68,68,68,0.6)',
fill: 'rgba(68,68,68,0.6)',
d: 'M 4 0 L 0 2 L 4 4 z' },
'.connection':{stroke: 'rgba(68,68,68,0.6)',
'stroke-width': '1px' }},
smooth: true,
});
}
function makeLink2(parentElementID, tx, ty) {
return new joint.dia.Link({
source: {id: parentElementID},
target: {x: tx, y: ty},
attrs: { '.marker-target': {stroke:'rgba(68,68,68,0.6)',
fill: 'rgba(68,68,68,0.6)',
d: 'M 4 0 L 0 2 L 4 4 z' },
'.connection':{stroke: 'rgba(68,68,68,0.6)',
'stroke-width': '1px' }},
smooth: true,
});
}
function makeElement(label, indexID, nodeclass, x, y) {
x = typeof x !== 'undefined' ? x : 0;
y = typeof y !== 'undefined' ? y : 0;
var maxLine = _.max(label.split('\n'), function(l) { return l.length - (l.length - l.replace(/i/g, "").replace(/l/g, "").length); });
var maxLineLength = maxLine.length - 0.62*(maxLine.length - maxLine.replace(/i/g, "").replace(/l/g,"").length);
// Compute width/height of the rectangle based on the number
// of lines in the label and the letter size. 0.6 * letterSize is
// an approximation of the monospace font letter width.
var letterSize = 8;
var width = 5 + (letterSize * (maxLineLength + 1));
var height = 10 + ((label.split('\n').length + 1) * letterSize);
return new joint.shapes.basic.Rect({
id: indexID,
size: { width: width, height: height },
attrs: {
text: { text: label, 'font-size': letterSize },
rect: {
width: width, height: height,
rx: 6, ry: 6,
stroke: '#555'
}
},
position:{x: x, y: y}
});
}
// add all the objects to the nodes
for(var i = 0; i < objects.length; i++) {
var node = {label: objects[i]['name'],
class: obj_type};
nodes.push(node);
object_pred_map[i] = [];
};
// given a list of objects with an attribute of "pred"
// returns the index of the object with the predicate
function findIndexOfPredicate(arr, predicate){
for(var i=0; i<arr.length; i++){
if (arr[i].pred == predicate)
return i;
}
return -1;
};
// for each object, predicate, subject, we make a node
// (if it doesn't already exist)
for(var i = 0; i < relationships.length; i++) {
var t = 0;
var subject = relationships[i]['subject'];
var pred = relationships[i]['predicate'];
var index = findIndexOfPredicate(object_pred_map[subject], pred);
if (index == -1) {
var node = {
label: pred,
class: pred_type
};
nodes.push(node);
object_pred_map[subject].push({pred: pred, index: nodes.length-1});
t = nodes.length-1;
}
else {
t = object_pred_map[subject][index].index;
}
links.push({
source : subject,
target : t,
weight : 1
});
links.push({
source : t,
target : relationships[i]['object'],
weight: 1
});
};
for (var i = 0; i < attributes.length; i++) {
var unary = {label: attributes[i]['attribute'],
class: attr_type};
nodes.push(unary);
links.push({source: attributes[i]['object'],
target: nodes.length - 1,
weight: 1});
}
var num_nodes = nodes.length;
var w = 1200, h = 1000;
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({
el: $(selector),
width: 0,
height: 0,
gridSize: 1,
model: graph,
interactive: false
});
paper.$el.css('pointer-events', 'none');
// Just give the viewport a little padding.
V(paper.viewport).translate(20, 20);
elements = [];
for (var i = 0; i<nodes.length; i++){
elements.push(makeElement(nodes[i].label, String(i), nodes[i].class));
}
for (var i=0; i<links.length; i++){
elements.push(makeLink(String(links[i].source), String(links[i].target)));
}
graph.addCells(elements);
for (var i = 0; i < nodes.length; i++){
V(paper.findViewByModel(String(i)).el).addClass(nodes[i].class)
}
var g2 = joint.layout.DirectedGraph.layout(graph, {setLinkVertices: false,
nodeSep: 10,
rankSep: 20,
rankDir: 'LR'});
paper.setDimensions(g2.width+40,g2.height+40);
};