Committed by
Gerrit Code Review
GUI -- deleted old files.
Change-Id: I3a504fe7e0597ae1d1bb1f659cd70b0611cadda4
Showing
32 changed files
with
0 additions
and
3786 deletions
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | - | ||
17 | -/* | ||
18 | - Geometry library - based on work by Mike Bostock. | ||
19 | - */ | ||
20 | - | ||
21 | -(function() { | ||
22 | - | ||
23 | - if (typeof geo == 'undefined') { | ||
24 | - geo = {}; | ||
25 | - } | ||
26 | - | ||
27 | - var tolerance = 1e-10; | ||
28 | - | ||
29 | - function eq(a, b) { | ||
30 | - return (Math.abs(a - b) < tolerance); | ||
31 | - } | ||
32 | - | ||
33 | - function gt(a, b) { | ||
34 | - return (a - b > -tolerance); | ||
35 | - } | ||
36 | - | ||
37 | - function lt(a, b) { | ||
38 | - return gt(b, a); | ||
39 | - } | ||
40 | - | ||
41 | - geo.eq = eq; | ||
42 | - geo.gt = gt; | ||
43 | - geo.lt = lt; | ||
44 | - | ||
45 | - geo.LineSegment = function(x1, y1, x2, y2) { | ||
46 | - this.x1 = x1; | ||
47 | - this.y1 = y1; | ||
48 | - this.x2 = x2; | ||
49 | - this.y2 = y2; | ||
50 | - | ||
51 | - // Ax + By = C | ||
52 | - this.a = y2 - y1; | ||
53 | - this.b = x1 - x2; | ||
54 | - this.c = x1 * this.a + y1 * this.b; | ||
55 | - | ||
56 | - if (eq(this.a, 0) && eq(this.b, 0)) { | ||
57 | - throw new Error( | ||
58 | - 'Cannot construct a LineSegment with two equal endpoints.'); | ||
59 | - } | ||
60 | - }; | ||
61 | - | ||
62 | - geo.LineSegment.prototype.intersect = function(that) { | ||
63 | - var d = (this.x1 - this.x2) * (that.y1 - that.y2) - | ||
64 | - (this.y1 - this.y2) * (that.x1 - that.x2); | ||
65 | - | ||
66 | - if (eq(d, 0)) { | ||
67 | - // The two lines are parallel or very close. | ||
68 | - return { | ||
69 | - x : NaN, | ||
70 | - y : NaN | ||
71 | - }; | ||
72 | - } | ||
73 | - | ||
74 | - var t1 = this.x1 * this.y2 - this.y1 * this.x2, | ||
75 | - t2 = that.x1 * that.y2 - that.y1 * that.x2, | ||
76 | - x = (t1 * (that.x1 - that.x2) - t2 * (this.x1 - this.x2)) / d, | ||
77 | - y = (t1 * (that.y1 - that.y2) - t2 * (this.y1 - this.y2)) / d, | ||
78 | - in1 = (gt(x, Math.min(this.x1, this.x2)) && lt(x, Math.max(this.x1, this.x2)) && | ||
79 | - gt(y, Math.min(this.y1, this.y2)) && lt(y, Math.max(this.y1, this.y2))), | ||
80 | - in2 = (gt(x, Math.min(that.x1, that.x2)) && lt(x, Math.max(that.x1, that.x2)) && | ||
81 | - gt(y, Math.min(that.y1, that.y2)) && lt(y, Math.max(that.y1, that.y2))); | ||
82 | - | ||
83 | - return { | ||
84 | - x : x, | ||
85 | - y : y, | ||
86 | - in1 : in1, | ||
87 | - in2 : in2 | ||
88 | - }; | ||
89 | - }; | ||
90 | - | ||
91 | - geo.LineSegment.prototype.x = function(y) { | ||
92 | - // x = (C - By) / a; | ||
93 | - if (this.a) { | ||
94 | - return (this.c - this.b * y) / this.a; | ||
95 | - } else { | ||
96 | - // a == 0 -> horizontal line | ||
97 | - return NaN; | ||
98 | - } | ||
99 | - }; | ||
100 | - | ||
101 | - geo.LineSegment.prototype.y = function(x) { | ||
102 | - // y = (C - Ax) / b; | ||
103 | - if (this.b) { | ||
104 | - return (this.c - this.a * x) / this.b; | ||
105 | - } else { | ||
106 | - // b == 0 -> vertical line | ||
107 | - return NaN; | ||
108 | - } | ||
109 | - }; | ||
110 | - | ||
111 | - geo.LineSegment.prototype.length = function() { | ||
112 | - return Math.sqrt( | ||
113 | - (this.y2 - this.y1) * (this.y2 - this.y1) + | ||
114 | - (this.x2 - this.x1) * (this.x2 - this.x1)); | ||
115 | - }; | ||
116 | - | ||
117 | - geo.LineSegment.prototype.offset = function(x, y) { | ||
118 | - return new geo.LineSegment( | ||
119 | - this.x1 + x, this.y1 + y, | ||
120 | - this.x2 + x, this.y2 + y); | ||
121 | - }; | ||
122 | - | ||
123 | -})(); |
1 | -<!DOCTYPE html> | ||
2 | -<!-- | ||
3 | - ~ Copyright 2014 Open Networking Laboratory | ||
4 | - ~ | ||
5 | - ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | - ~ you may not use this file except in compliance with the License. | ||
7 | - ~ You may obtain a copy of the License at | ||
8 | - ~ | ||
9 | - ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | - ~ | ||
11 | - ~ Unless required by applicable law or agreed to in writing, software | ||
12 | - ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | - ~ See the License for the specific language governing permissions and | ||
15 | - ~ limitations under the License. | ||
16 | - --> | ||
17 | - | ||
18 | -<!-- | ||
19 | - ONOS UI - single page web app | ||
20 | - | ||
21 | - @author Simon Hunt | ||
22 | - --> | ||
23 | -<html> | ||
24 | -<head> | ||
25 | - <meta charset="utf-8"> | ||
26 | - <title>ONOS GUI</title> | ||
27 | - | ||
28 | - <!--TODO: use the minified version of d3, once debugging is complete --> | ||
29 | - <script src="../tp/d3.js"></script> | ||
30 | - <script src="../tp/jquery-2.1.1.min.js"></script> | ||
31 | - | ||
32 | - <link rel="stylesheet" href="../base.css"> | ||
33 | - <link rel="stylesheet" href="onos.css"> | ||
34 | - | ||
35 | - <script src="../geometry.js"></script> | ||
36 | - <script src="onos.js"></script> | ||
37 | - | ||
38 | -</head> | ||
39 | -<body> | ||
40 | - <div id="frame"> | ||
41 | - <div id="mast"> | ||
42 | - <img id="logo" src="../img/onos-logo.png"> | ||
43 | - <span class="title">Open Network Operating System</span> | ||
44 | - <span id="displayModes" class="right"> | ||
45 | - <span id="showAll" class="radio active">All Layers</span> | ||
46 | - <span id="showPkt" class="radio">Packet Only</span> | ||
47 | - <span id="showOpt" class="radio">Optical Only</span> | ||
48 | - </span> | ||
49 | - </div> | ||
50 | - <div id="view"> | ||
51 | - <!-- NOTE: svg layer injected here --> | ||
52 | - </div> | ||
53 | - <div id="flyout"></div> | ||
54 | - </div> | ||
55 | - | ||
56 | - <!-- Initialize the UI...--> | ||
57 | - <script type="text/javascript"> | ||
58 | - var ONOS = $.onos({note: "config, if needed"}); | ||
59 | - </script> | ||
60 | - | ||
61 | - <!-- include module files--> | ||
62 | - <!-- + mast.js--> | ||
63 | - <!-- + nav.js--> | ||
64 | - <!-- + .... application views--> | ||
65 | - | ||
66 | - <!-- for now, we are just bootstrapping the network visualization--> | ||
67 | - <script src="network.js" type="text/javascript"></script> | ||
68 | - | ||
69 | - <!-- finally, build the UI--> | ||
70 | - <script type="text/javascript"> | ||
71 | - $(ONOS.buildUi); | ||
72 | - </script> | ||
73 | - | ||
74 | -</body> | ||
75 | -</html> |
1 | -{ | ||
2 | - "meta": { | ||
3 | - "comments": [ | ||
4 | - "This is sample data for developing the ONOS UI (network view)", | ||
5 | - " in a standalone mode (no server required).", | ||
6 | - " Eventually, we will wire this up to live data", | ||
7 | - " from the server, via a websocket.", | ||
8 | - "", | ||
9 | - "Note that this is just a first-draft of the data --", | ||
10 | - " additional fields will be added when they are needed." | ||
11 | - ], | ||
12 | - "otherMetaData": "can go here..." | ||
13 | - }, | ||
14 | - "devices": [ | ||
15 | - { | ||
16 | - "id": "of:0000000000000001", | ||
17 | - "labels": ["00:00:00:00:00:00:00:01", "SFO-W10", "opt-1"], | ||
18 | - "type": "roadm" | ||
19 | - }, | ||
20 | - { | ||
21 | - "id": "of:0000000000000002", | ||
22 | - "labels": ["00:00:00:00:00:00:00:02", "SJC-W10", "opt-2"], | ||
23 | - "type": "roadm" | ||
24 | - }, | ||
25 | - { | ||
26 | - "id": "of:0000000000000003", | ||
27 | - "labels": ["00:00:00:00:00:00:00:03", "LAX-W10", "opt-3"], | ||
28 | - "type": "roadm" | ||
29 | - }, | ||
30 | - { | ||
31 | - "id": "of:0000000000000004", | ||
32 | - "labels": ["00:00:00:00:00:00:00:04", "SDG-W10", "opt-4"], | ||
33 | - "type": "roadm" | ||
34 | - }, | ||
35 | - { | ||
36 | - "id": "of:0000000000000011", | ||
37 | - "labels": ["00:00:00:00:00:00:00:11", "SFO-pkt", "pkt-11"], | ||
38 | - "type": "switch" | ||
39 | - }, | ||
40 | - { | ||
41 | - "id": "of:0000000000000012", | ||
42 | - "labels": ["00:00:00:00:00:00:00:12", "SJC-pkt", "pkt-12"], | ||
43 | - "type": "switch" | ||
44 | - }, | ||
45 | - { | ||
46 | - "id": "of:0000000000000013", | ||
47 | - "labels": ["00:00:00:00:00:00:00:13", "LAX-pkt", "pkt-13"], | ||
48 | - "type": "switch" | ||
49 | - } | ||
50 | - ], | ||
51 | - "linkNotes": [ | ||
52 | - "even though we have 'directionality' (src/dst), each link is", | ||
53 | - " considered to be bi-directional. Note that links between hosts", | ||
54 | - " and edge switches are inferred from host information, and not", | ||
55 | - " explicitly represented here." | ||
56 | - ], | ||
57 | - "links": [ | ||
58 | - { | ||
59 | - "src": "of:0000000000000001", | ||
60 | - "dst": "of:0000000000000002", | ||
61 | - "type": "optical", | ||
62 | - "srcPort": 1, | ||
63 | - "dstPort": 2, | ||
64 | - "linkWidth": 1.5 | ||
65 | - }, | ||
66 | - { | ||
67 | - "src": "of:0000000000000001", | ||
68 | - "dst": "of:0000000000000003", | ||
69 | - "type": "optical", | ||
70 | - "srcPort": 2, | ||
71 | - "dstPort": 5, | ||
72 | - "linkWidth": 1.5 | ||
73 | - }, | ||
74 | - { | ||
75 | - "src": "of:0000000000000001", | ||
76 | - "dst": "of:0000000000000004", | ||
77 | - "type": "optical", | ||
78 | - "srcPort": 3, | ||
79 | - "dstPort": 2, | ||
80 | - "linkWidth": 1.5 | ||
81 | - }, | ||
82 | - { | ||
83 | - "src": "of:0000000000000002", | ||
84 | - "dst": "of:0000000000000003", | ||
85 | - "type": "optical", | ||
86 | - "srcPort": 3, | ||
87 | - "dstPort": 4, | ||
88 | - "linkWidth": 1.5 | ||
89 | - }, | ||
90 | - { | ||
91 | - "src": "of:0000000000000002", | ||
92 | - "dst": "of:0000000000000004", | ||
93 | - "type": "optical", | ||
94 | - "srcPort": 4, | ||
95 | - "dstPort": 1, | ||
96 | - "linkWidth": 1.5 | ||
97 | - }, | ||
98 | - { | ||
99 | - "src": "of:0000000000000003", | ||
100 | - "dst": "of:0000000000000004", | ||
101 | - "type": "optical", | ||
102 | - "srcPort": 3, | ||
103 | - "dstPort": 3, | ||
104 | - "linkWidth": 1.5 | ||
105 | - }, | ||
106 | - { | ||
107 | - "src": "of:0000000000000013", | ||
108 | - "dst": "of:0000000000000003", | ||
109 | - "type": "direct", | ||
110 | - "srcPort": 1, | ||
111 | - "dstPort": 7, | ||
112 | - "linkWidth": 1.0 | ||
113 | - }, | ||
114 | - { | ||
115 | - "src": "of:0000000000000012", | ||
116 | - "dst": "of:0000000000000002", | ||
117 | - "type": "direct", | ||
118 | - "srcPort": 1, | ||
119 | - "dstPort": 9, | ||
120 | - "linkWidth": 1.0 | ||
121 | - }, | ||
122 | - { | ||
123 | - "src": "of:0000000000000011", | ||
124 | - "dst": "of:0000000000000001", | ||
125 | - "type": "direct", | ||
126 | - "srcPort": 1, | ||
127 | - "dstPort": 6, | ||
128 | - "linkWidth": 1.0 | ||
129 | - } | ||
130 | - ], | ||
131 | - "hosts": [ | ||
132 | - { | ||
133 | - "id": "00:60:d3:00:11:01/7", | ||
134 | - "labels": ["00:60:d3:00:11:01/7", "Host-11-A"], | ||
135 | - "cp" : { | ||
136 | - "device": "of:0000000000000011", | ||
137 | - "port": 6 | ||
138 | - } | ||
139 | - }, | ||
140 | - { | ||
141 | - "id": "00:60:d3:00:11:02/7", | ||
142 | - "labels": ["00:60:d3:00:11:02/7", "Host-11-B"], | ||
143 | - "cp" : { | ||
144 | - "device": "of:0000000000000011", | ||
145 | - "port": 8 | ||
146 | - } | ||
147 | - }, | ||
148 | - { | ||
149 | - "id": "00:60:d3:00:12:01/4", | ||
150 | - "labels": ["00:60:d3:00:12:01/4", "Host-12-C"], | ||
151 | - "cp" : { | ||
152 | - "device": "of:0000000000000012", | ||
153 | - "port": 12 | ||
154 | - } | ||
155 | - }, | ||
156 | - { | ||
157 | - "id": "00:60:d3:00:12:02/4", | ||
158 | - "labels": ["00:60:d3:00:12:02/4", "Host-12-D"], | ||
159 | - "cp" : { | ||
160 | - "device": "of:0000000000000012", | ||
161 | - "port": 13 | ||
162 | - } | ||
163 | - }, | ||
164 | - { | ||
165 | - "id": "00:60:d3:00:13:01/19", | ||
166 | - "labels": ["00:60:d3:00:13:01/19", "Host-13-E"], | ||
167 | - "cp" : { | ||
168 | - "device": "of:0000000000000013", | ||
169 | - "port": 7 | ||
170 | - } | ||
171 | - }, | ||
172 | - { | ||
173 | - "id": "00:60:d3:00:13:02/19", | ||
174 | - "labels": ["00:60:d3:00:13:02/19", "Host-13-F"], | ||
175 | - "cp" : { | ||
176 | - "device": "of:0000000000000013", | ||
177 | - "port": 8 | ||
178 | - } | ||
179 | - } | ||
180 | - ] | ||
181 | -} |
1 | -{ | ||
2 | - "devices": [ | ||
3 | - { | ||
4 | - "id": "of:0000ffffffffff08", | ||
5 | - "type": "roadm", | ||
6 | - "online": false, | ||
7 | - "labels": [ | ||
8 | - "0000ffffffffff08", | ||
9 | - "FF:FF:FF:FF:FF:08", | ||
10 | - "?" | ||
11 | - ] | ||
12 | - }, | ||
13 | - { | ||
14 | - "id": "of:0000ffffffffff03", | ||
15 | - "type": "roadm", | ||
16 | - "online": false, | ||
17 | - "labels": [ | ||
18 | - "0000ffffffffff03", | ||
19 | - "FF:FF:FF:FF:FF:03", | ||
20 | - "?" | ||
21 | - ] | ||
22 | - }, | ||
23 | - { | ||
24 | - "id": "of:0000ffffffffff02", | ||
25 | - "type": "roadm", | ||
26 | - "online": false, | ||
27 | - "labels": [ | ||
28 | - "0000ffffffffff02", | ||
29 | - "FF:FF:FF:FF:FF:02", | ||
30 | - "?" | ||
31 | - ] | ||
32 | - }, | ||
33 | - { | ||
34 | - "id": "of:0000ffffffff0003", | ||
35 | - "type": "switch", | ||
36 | - "online": false, | ||
37 | - "labels": [ | ||
38 | - "0000ffffffff0003", | ||
39 | - "FF:FF:FF:FF:00:03", | ||
40 | - "?" | ||
41 | - ] | ||
42 | - }, | ||
43 | - { | ||
44 | - "id": "of:0000ffffffffff07", | ||
45 | - "type": "roadm", | ||
46 | - "online": false, | ||
47 | - "labels": [ | ||
48 | - "0000ffffffffff07", | ||
49 | - "FF:FF:FF:FF:FF:07", | ||
50 | - "?" | ||
51 | - ] | ||
52 | - }, | ||
53 | - { | ||
54 | - "id": "of:0000ffffffffff06", | ||
55 | - "type": "roadm", | ||
56 | - "online": false, | ||
57 | - "labels": [ | ||
58 | - "0000ffffffffff06", | ||
59 | - "FF:FF:FF:FF:FF:06", | ||
60 | - "?" | ||
61 | - ] | ||
62 | - }, | ||
63 | - { | ||
64 | - "id": "of:0000ffffffff0007", | ||
65 | - "type": "switch", | ||
66 | - "online": false, | ||
67 | - "labels": [ | ||
68 | - "0000ffffffff0007", | ||
69 | - "FF:FF:FF:FF:00:07", | ||
70 | - "?" | ||
71 | - ] | ||
72 | - }, | ||
73 | - { | ||
74 | - "id": "of:0000ffffffffff05", | ||
75 | - "type": "roadm", | ||
76 | - "online": false, | ||
77 | - "labels": [ | ||
78 | - "0000ffffffffff05", | ||
79 | - "FF:FF:FF:FF:FF:05", | ||
80 | - "?" | ||
81 | - ] | ||
82 | - }, | ||
83 | - { | ||
84 | - "id": "of:0000ffffffff0009", | ||
85 | - "type": "switch", | ||
86 | - "online": false, | ||
87 | - "labels": [ | ||
88 | - "0000ffffffff0009", | ||
89 | - "FF:FF:FF:FF:00:09", | ||
90 | - "?" | ||
91 | - ] | ||
92 | - }, | ||
93 | - { | ||
94 | - "id": "of:0000ffffffffff04", | ||
95 | - "type": "roadm", | ||
96 | - "online": false, | ||
97 | - "labels": [ | ||
98 | - "0000ffffffffff04", | ||
99 | - "FF:FF:FF:FF:FF:04", | ||
100 | - "?" | ||
101 | - ] | ||
102 | - }, | ||
103 | - { | ||
104 | - "id": "of:0000ffffffff000A", | ||
105 | - "type": "switch", | ||
106 | - "online": false, | ||
107 | - "labels": [ | ||
108 | - "0000ffffffff000A", | ||
109 | - "FF:FF:FF:FF:00:0A", | ||
110 | - "?" | ||
111 | - ] | ||
112 | - }, | ||
113 | - { | ||
114 | - "id": "of:0000ffffffff0001", | ||
115 | - "type": "switch", | ||
116 | - "online": false, | ||
117 | - "labels": [ | ||
118 | - "0000ffffffff0001", | ||
119 | - "FF:FF:FF:FF:00:01", | ||
120 | - "?" | ||
121 | - ] | ||
122 | - }, | ||
123 | - { | ||
124 | - "id": "of:0000ffffffffff01", | ||
125 | - "type": "roadm", | ||
126 | - "online": false, | ||
127 | - "labels": [ | ||
128 | - "0000ffffffffff01", | ||
129 | - "FF:FF:FF:FF:FF:01", | ||
130 | - "?" | ||
131 | - ] | ||
132 | - }, | ||
133 | - { | ||
134 | - "id": "of:0000ffffffff0004", | ||
135 | - "type": "switch", | ||
136 | - "online": false, | ||
137 | - "labels": [ | ||
138 | - "0000ffffffff0004", | ||
139 | - "FF:FF:FF:FF:00:04", | ||
140 | - "?" | ||
141 | - ] | ||
142 | - }, | ||
143 | - { | ||
144 | - "id": "of:0000ffffffffff0A", | ||
145 | - "type": "roadm", | ||
146 | - "online": false, | ||
147 | - "labels": [ | ||
148 | - "0000ffffffffff0A", | ||
149 | - "FF:FF:FF:FF:FF:0A", | ||
150 | - "?" | ||
151 | - ] | ||
152 | - }, | ||
153 | - { | ||
154 | - "id": "of:0000ffffffffff09", | ||
155 | - "type": "roadm", | ||
156 | - "online": false, | ||
157 | - "labels": [ | ||
158 | - "0000ffffffffff09", | ||
159 | - "FF:FF:FF:FF:FF:09", | ||
160 | - "?" | ||
161 | - ] | ||
162 | - } | ||
163 | - ], | ||
164 | - "links": [ | ||
165 | - { | ||
166 | - "src": "of:0000ffffffffff02", | ||
167 | - "srcPort": "20", | ||
168 | - "dst": "of:0000ffffffffff05", | ||
169 | - "dstPort": "10", | ||
170 | - "type": "optical", | ||
171 | - "linkWidth": 2 | ||
172 | - }, | ||
173 | - { | ||
174 | - "src": "of:0000ffffffff000A", | ||
175 | - "srcPort": "2", | ||
176 | - "dst": "of:0000ffffffffff0A", | ||
177 | - "dstPort": "1", | ||
178 | - "type": "optical", | ||
179 | - "linkWidth": 2 | ||
180 | - }, | ||
181 | - { | ||
182 | - "src": "of:0000ffffffffff03", | ||
183 | - "srcPort": "10", | ||
184 | - "dst": "of:0000ffffffffff02", | ||
185 | - "dstPort": "10", | ||
186 | - "type": "optical", | ||
187 | - "linkWidth": 2 | ||
188 | - }, | ||
189 | - { | ||
190 | - "src": "of:0000ffffffffff07", | ||
191 | - "srcPort": "21", | ||
192 | - "dst": "of:0000ffffffffff05", | ||
193 | - "dstPort": "20", | ||
194 | - "type": "optical", | ||
195 | - "linkWidth": 2 | ||
196 | - }, | ||
197 | - { | ||
198 | - "src": "of:0000ffffffff0001", | ||
199 | - "srcPort": "2", | ||
200 | - "dst": "of:0000ffffffffff01", | ||
201 | - "dstPort": "1", | ||
202 | - "type": "optical", | ||
203 | - "linkWidth": 2 | ||
204 | - }, | ||
205 | - { | ||
206 | - "src": "of:0000ffffffffff09", | ||
207 | - "srcPort": "20", | ||
208 | - "dst": "of:0000ffffffffff0A", | ||
209 | - "dstPort": "20", | ||
210 | - "type": "optical", | ||
211 | - "linkWidth": 2 | ||
212 | - }, | ||
213 | - { | ||
214 | - "src": "of:0000ffffffffff06", | ||
215 | - "srcPort": "20", | ||
216 | - "dst": "of:0000ffffffffff05", | ||
217 | - "dstPort": "30", | ||
218 | - "type": "optical", | ||
219 | - "linkWidth": 2 | ||
220 | - }, | ||
221 | - { | ||
222 | - "src": "of:0000ffffffffff07", | ||
223 | - "srcPort": "30", | ||
224 | - "dst": "of:0000ffffffffff08", | ||
225 | - "dstPort": "20", | ||
226 | - "type": "optical", | ||
227 | - "linkWidth": 2 | ||
228 | - }, | ||
229 | - { | ||
230 | - "src": "of:0000ffffffffff03", | ||
231 | - "srcPort": "20", | ||
232 | - "dst": "of:0000ffffffffff06", | ||
233 | - "dstPort": "10", | ||
234 | - "type": "optical", | ||
235 | - "linkWidth": 2 | ||
236 | - }, | ||
237 | - { | ||
238 | - "src": "of:0000ffffffffff02", | ||
239 | - "srcPort": "10", | ||
240 | - "dst": "of:0000ffffffffff01", | ||
241 | - "dstPort": "10", | ||
242 | - "type": "optical", | ||
243 | - "linkWidth": 2 | ||
244 | - }, | ||
245 | - { | ||
246 | - "src": "of:0000ffffffffff09", | ||
247 | - "srcPort": "1", | ||
248 | - "dst": "of:0000ffffffff0009", | ||
249 | - "dstPort": "2", | ||
250 | - "type": "optical", | ||
251 | - "linkWidth": 2 | ||
252 | - }, | ||
253 | - { | ||
254 | - "src": "of:0000ffffffffff03", | ||
255 | - "srcPort": "30", | ||
256 | - "dst": "of:0000ffffffffff04", | ||
257 | - "dstPort": "10", | ||
258 | - "type": "optical", | ||
259 | - "linkWidth": 2 | ||
260 | - }, | ||
261 | - { | ||
262 | - "src": "of:0000ffffffffff07", | ||
263 | - "srcPort": "20", | ||
264 | - "dst": "of:0000ffffffffff09", | ||
265 | - "dstPort": "10", | ||
266 | - "type": "optical", | ||
267 | - "linkWidth": 2 | ||
268 | - }, | ||
269 | - { | ||
270 | - "src": "of:0000ffffffffff0A", | ||
271 | - "srcPort": "10", | ||
272 | - "dst": "of:0000ffffffffff08", | ||
273 | - "dstPort": "30", | ||
274 | - "type": "optical", | ||
275 | - "linkWidth": 2 | ||
276 | - }, | ||
277 | - { | ||
278 | - "src": "of:0000ffffffff0004", | ||
279 | - "srcPort": "2", | ||
280 | - "dst": "of:0000ffffffffff04", | ||
281 | - "dstPort": "1", | ||
282 | - "type": "optical", | ||
283 | - "linkWidth": 2 | ||
284 | - }, | ||
285 | - { | ||
286 | - "src": "of:0000ffffffffff07", | ||
287 | - "srcPort": "1", | ||
288 | - "dst": "of:0000ffffffff0007", | ||
289 | - "dstPort": "2", | ||
290 | - "type": "optical", | ||
291 | - "linkWidth": 2 | ||
292 | - }, | ||
293 | - { | ||
294 | - "src": "of:0000ffffffff0003", | ||
295 | - "srcPort": "2", | ||
296 | - "dst": "of:0000ffffffffff03", | ||
297 | - "dstPort": "1", | ||
298 | - "type": "optical", | ||
299 | - "linkWidth": 2 | ||
300 | - }, | ||
301 | - { | ||
302 | - "src": "of:0000ffffffffff06", | ||
303 | - "srcPort": "30", | ||
304 | - "dst": "of:0000ffffffffff08", | ||
305 | - "dstPort": "10", | ||
306 | - "type": "optical", | ||
307 | - "linkWidth": 2 | ||
308 | - } | ||
309 | - ], | ||
310 | - "hosts": [ | ||
311 | - { | ||
312 | - "id": "00:00:00:00:00:03/-1", | ||
313 | - "cp": { | ||
314 | - "device": "of:0000ffffffff0003", | ||
315 | - "port": 1 | ||
316 | - }, | ||
317 | - "labels": [ | ||
318 | - "10.0.0.3", | ||
319 | - "00:00:00:00:00:03" | ||
320 | - ] | ||
321 | - }, | ||
322 | - { | ||
323 | - "id": "00:00:00:00:00:04/-1", | ||
324 | - "cp": { | ||
325 | - "device": "of:0000ffffffff0004", | ||
326 | - "port": 1 | ||
327 | - }, | ||
328 | - "labels": [ | ||
329 | - "10.0.0.4", | ||
330 | - "00:00:00:00:00:04" | ||
331 | - ] | ||
332 | - }, | ||
333 | - { | ||
334 | - "id": "00:00:00:00:00:0A/-1", | ||
335 | - "cp": { | ||
336 | - "device": "of:0000ffffffff000A", | ||
337 | - "port": 1 | ||
338 | - }, | ||
339 | - "labels": [ | ||
340 | - "10.0.0.10", | ||
341 | - "00:00:00:00:00:0A" | ||
342 | - ] | ||
343 | - }, | ||
344 | - { | ||
345 | - "id": "00:00:00:00:00:09/-1", | ||
346 | - "cp": { | ||
347 | - "device": "of:0000ffffffff0009", | ||
348 | - "port": 1 | ||
349 | - }, | ||
350 | - "labels": [ | ||
351 | - "10.0.0.9", | ||
352 | - "00:00:00:00:00:09" | ||
353 | - ] | ||
354 | - }, | ||
355 | - { | ||
356 | - "id": "00:00:00:00:00:07/-1", | ||
357 | - "cp": { | ||
358 | - "device": "of:0000ffffffff0007", | ||
359 | - "port": 1 | ||
360 | - }, | ||
361 | - "labels": [ | ||
362 | - "10.0.0.7", | ||
363 | - "00:00:00:00:00:07" | ||
364 | - ] | ||
365 | - }, | ||
366 | - { | ||
367 | - "id": "00:00:00:00:00:01/-1", | ||
368 | - "cp": { | ||
369 | - "device": "of:0000ffffffff0001", | ||
370 | - "port": 1 | ||
371 | - }, | ||
372 | - "labels": [ | ||
373 | - "10.0.0.1", | ||
374 | - "00:00:00:00:00:01" | ||
375 | - ] | ||
376 | - } | ||
377 | - ] | ||
378 | -} |
1 | -{ | ||
2 | - "comment": "sample device properties", | ||
3 | - "id": "of:0000000000000001", | ||
4 | - "type": "roadm", | ||
5 | - "propOrder": [ "name", "type", "-", "dpid", "latitude", "longitude", "allowed" ], | ||
6 | - "location": { | ||
7 | - "type": "latlng", | ||
8 | - "lat": 37.6, | ||
9 | - "lng": 122.3 | ||
10 | - }, | ||
11 | - "props": { | ||
12 | - "allowed": true, | ||
13 | - "latitude": 37.6, | ||
14 | - "longitude": 122.3, | ||
15 | - "name": "SFO-W10", | ||
16 | - "dpid": "00:00:00:00:00:00:00:01" | ||
17 | - } | ||
18 | -} |
1 | -{ | ||
2 | - "comment": "sample device properties", | ||
3 | - "id": "of:0000000000000002", | ||
4 | - "type": "switch", | ||
5 | - "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ], | ||
6 | - "location": { | ||
7 | - "type": "latlng", | ||
8 | - "lat": 37.6, | ||
9 | - "lng": 122.3 | ||
10 | - }, | ||
11 | - "props": { | ||
12 | - "allowed": true, | ||
13 | - "latitude": 37.3, | ||
14 | - "longitude": 121.9, | ||
15 | - "name": "SJC-W10", | ||
16 | - "dpid": "00:00:00:00:00:00:00:02", | ||
17 | - "type": "Roadm" | ||
18 | - } | ||
19 | -} |
1 | -{ | ||
2 | - "comment": "sample device properties", | ||
3 | - "id": "of:0000000000000003", | ||
4 | - "type": "switch", | ||
5 | - "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ], | ||
6 | - "location": { | ||
7 | - "type": "latlng", | ||
8 | - "lat": 33.9, | ||
9 | - "lng": 118.4 | ||
10 | - }, | ||
11 | - "props": { | ||
12 | - "allowed": true, | ||
13 | - "latitude": 33.9, | ||
14 | - "longitude": 118.4, | ||
15 | - "name": "LAX-W10", | ||
16 | - "dpid": "00:00:00:00:00:00:00:03", | ||
17 | - "type": "Roadm" | ||
18 | - } | ||
19 | -} |
1 | -{ | ||
2 | - "comment": "sample device properties", | ||
3 | - "id": "of:0000000000000004", | ||
4 | - "type": "switch", | ||
5 | - "propOrder": [ "name", "type", "dpid", "latitude", "longitude", "allowed" ], | ||
6 | - "location": { | ||
7 | - "type": "latlng", | ||
8 | - "lat": 32.8, | ||
9 | - "lng": 117.1 | ||
10 | - }, | ||
11 | - "props": { | ||
12 | - "allowed": true, | ||
13 | - "latitude": 32.8, | ||
14 | - "longitude": 117.1, | ||
15 | - "name": "SDG-W10", | ||
16 | - "dpid": "00:00:00:00:00:00:00:04", | ||
17 | - "type": "Roadm" | ||
18 | - } | ||
19 | -} |
1 | -{ | ||
2 | - "id": "of:0000ffffffff0007", | ||
3 | - "type": "switch", | ||
4 | - "propOrder": [ | ||
5 | - "Name", | ||
6 | - "Vendor", | ||
7 | - "H/W Version", | ||
8 | - "S/W Version", | ||
9 | - "S/W Version", | ||
10 | - "-", | ||
11 | - "Latitude", | ||
12 | - "Longitude", | ||
13 | - "Ports" | ||
14 | - ], | ||
15 | - "props": { | ||
16 | - "Name": null, | ||
17 | - "Vendor": "Linc", | ||
18 | - "H/W Version": "PK", | ||
19 | - "S/W Version": "?", | ||
20 | - "-": "", | ||
21 | - "Latitude": "41.8", | ||
22 | - "Longitude": "120.1", | ||
23 | - "Ports": "2" | ||
24 | - } | ||
25 | -} |
1 | -{ | ||
2 | - "id": "of:0000ffffffff0009", | ||
3 | - "type": "switch", | ||
4 | - "propOrder": [ | ||
5 | - "Name", | ||
6 | - "Vendor", | ||
7 | - "H/W Version", | ||
8 | - "S/W Version", | ||
9 | - "S/W Version", | ||
10 | - "-", | ||
11 | - "Latitude", | ||
12 | - "Longitude", | ||
13 | - "Ports" | ||
14 | - ], | ||
15 | - "props": { | ||
16 | - "Name": null, | ||
17 | - "Vendor": "Linc", | ||
18 | - "H/W Version": "PK", | ||
19 | - "S/W Version": "?", | ||
20 | - "-": "", | ||
21 | - "Latitude": "40.8", | ||
22 | - "Longitude": "73.1", | ||
23 | - "Ports": "2" | ||
24 | - } | ||
25 | -} |
1 | -{ | ||
2 | - "id": "of:0000ffffffffff07", | ||
3 | - "type": "roadm", | ||
4 | - "propOrder": [ | ||
5 | - "Name", | ||
6 | - "Vendor", | ||
7 | - "H/W Version", | ||
8 | - "S/W Version", | ||
9 | - "S/W Version", | ||
10 | - "-", | ||
11 | - "Latitude", | ||
12 | - "Longitude", | ||
13 | - "Ports" | ||
14 | - ], | ||
15 | - "props": { | ||
16 | - "Name": null, | ||
17 | - "Vendor": "Linc", | ||
18 | - "H/W Version": "OE", | ||
19 | - "S/W Version": "?", | ||
20 | - "-": "", | ||
21 | - "Latitude": "41.8", | ||
22 | - "Longitude": "120.1", | ||
23 | - "Ports": "2" | ||
24 | - } | ||
25 | -} |
1 | -{ | ||
2 | - "id": "of:0000ffffffffff09", | ||
3 | - "type": "roadm", | ||
4 | - "propOrder": [ | ||
5 | - "Name", | ||
6 | - "Vendor", | ||
7 | - "H/W Version", | ||
8 | - "S/W Version", | ||
9 | - "S/W Version", | ||
10 | - "-", | ||
11 | - "Latitude", | ||
12 | - "Longitude", | ||
13 | - "Ports" | ||
14 | - ], | ||
15 | - "props": { | ||
16 | - "Name": null, | ||
17 | - "Vendor": "Linc", | ||
18 | - "H/W Version": "OE", | ||
19 | - "S/W Version": "?", | ||
20 | - "-": "", | ||
21 | - "Latitude": "40.8", | ||
22 | - "Longitude": "73.1", | ||
23 | - "Ports": "2" | ||
24 | - } | ||
25 | -} |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | - | ||
17 | -/* | ||
18 | - ONOS network topology viewer - PoC version 1.0 | ||
19 | - | ||
20 | - @author Simon Hunt | ||
21 | - */ | ||
22 | - | ||
23 | -(function (onos) { | ||
24 | - 'use strict'; | ||
25 | - | ||
26 | - // reference to the framework api | ||
27 | - var api = onos.api; | ||
28 | - | ||
29 | - // configuration data | ||
30 | - var config = { | ||
31 | - useLiveData: false, | ||
32 | - debugOn: false, | ||
33 | - debug: { | ||
34 | - showNodeXY: false, | ||
35 | - showKeyHandler: true | ||
36 | - }, | ||
37 | - options: { | ||
38 | - layering: true, | ||
39 | - collisionPrevention: true, | ||
40 | - loadBackground: true | ||
41 | - }, | ||
42 | - backgroundUrl: 'img/us-map.png', | ||
43 | - data: { | ||
44 | - live: { | ||
45 | - jsonUrl: 'rs/topology/graph', | ||
46 | - detailPrefix: 'rs/topology/graph/', | ||
47 | - detailSuffix: '' | ||
48 | - }, | ||
49 | - fake: { | ||
50 | - jsonUrl: 'json/network2.json', | ||
51 | - detailPrefix: 'json/', | ||
52 | - detailSuffix: '.json' | ||
53 | - } | ||
54 | - }, | ||
55 | - iconUrl: { | ||
56 | - device: 'img/device.png', | ||
57 | - host: 'img/host.png', | ||
58 | - pkt: 'img/pkt.png', | ||
59 | - opt: 'img/opt.png' | ||
60 | - }, | ||
61 | - mastHeight: 36, | ||
62 | - force: { | ||
63 | - note: 'node.class or link.class is used to differentiate', | ||
64 | - linkDistance: { | ||
65 | - infra: 200, | ||
66 | - host: 40 | ||
67 | - }, | ||
68 | - linkStrength: { | ||
69 | - infra: 1.0, | ||
70 | - host: 1.0 | ||
71 | - }, | ||
72 | - charge: { | ||
73 | - device: -800, | ||
74 | - host: -1000 | ||
75 | - }, | ||
76 | - ticksWithoutCollisions: 50, | ||
77 | - marginLR: 20, | ||
78 | - marginTB: 20, | ||
79 | - translate: function() { | ||
80 | - return 'translate(' + | ||
81 | - config.force.marginLR + ',' + | ||
82 | - config.force.marginTB + ')'; | ||
83 | - } | ||
84 | - }, | ||
85 | - labels: { | ||
86 | - imgPad: 16, | ||
87 | - padLR: 8, | ||
88 | - padTB: 6, | ||
89 | - marginLR: 3, | ||
90 | - marginTB: 2, | ||
91 | - port: { | ||
92 | - gap: 3, | ||
93 | - width: 18, | ||
94 | - height: 14 | ||
95 | - } | ||
96 | - }, | ||
97 | - icons: { | ||
98 | - w: 32, | ||
99 | - h: 32, | ||
100 | - xoff: -12, | ||
101 | - yoff: -8 | ||
102 | - }, | ||
103 | - constraints: { | ||
104 | - ypos: { | ||
105 | - host: 0.05, | ||
106 | - switch: 0.3, | ||
107 | - roadm: 0.7 | ||
108 | - } | ||
109 | - }, | ||
110 | - hostLinkWidth: 1.0, | ||
111 | - hostRadius: 7, | ||
112 | - mouseOutTimerDelayMs: 120 | ||
113 | - }; | ||
114 | - | ||
115 | - // state variables | ||
116 | - var view = {}, | ||
117 | - network = {}, | ||
118 | - selected = {}, | ||
119 | - highlighted = null, | ||
120 | - hovered = null, | ||
121 | - viewMode = 'showAll', | ||
122 | - portLabelsOn = false; | ||
123 | - | ||
124 | - | ||
125 | - function debug(what) { | ||
126 | - return config.debugOn && config.debug[what]; | ||
127 | - } | ||
128 | - | ||
129 | - function urlData() { | ||
130 | - return config.data[config.useLiveData ? 'live' : 'fake']; | ||
131 | - } | ||
132 | - | ||
133 | - function networkJsonUrl() { | ||
134 | - return urlData().jsonUrl; | ||
135 | - } | ||
136 | - | ||
137 | - function safeId(id) { | ||
138 | - return id.replace(/[^a-z0-9]/gi, '_'); | ||
139 | - } | ||
140 | - | ||
141 | - function detailJsonUrl(id) { | ||
142 | - var u = urlData(), | ||
143 | - encId = config.useLiveData ? encodeURIComponent(id) : safeId(id); | ||
144 | - return u.detailPrefix + encId + u.detailSuffix; | ||
145 | - } | ||
146 | - | ||
147 | - | ||
148 | - // load the topology view of the network | ||
149 | - function loadNetworkView() { | ||
150 | - // Hey, here I am, calling something on the ONOS api: | ||
151 | - api.printTime(); | ||
152 | - | ||
153 | - resize(); | ||
154 | - | ||
155 | - // go get our network data from the server... | ||
156 | - var url = networkJsonUrl(); | ||
157 | - d3.json(url , function (err, data) { | ||
158 | - if (err) { | ||
159 | - alert('Oops! Error reading JSON...\n\n' + | ||
160 | - 'URL: ' + url + '\n\n' + | ||
161 | - 'Error: ' + err.message); | ||
162 | - return; | ||
163 | - } | ||
164 | -// console.log("here is the JSON data..."); | ||
165 | -// console.log(data); | ||
166 | - | ||
167 | - network.data = data; | ||
168 | - drawNetwork(); | ||
169 | - }); | ||
170 | - | ||
171 | - // while we wait for the data, set up the handlers... | ||
172 | - setUpClickHandler(); | ||
173 | - setUpRadioButtonHandler(); | ||
174 | - setUpKeyHandler(); | ||
175 | - $(window).on('resize', resize); | ||
176 | - } | ||
177 | - | ||
178 | - function setUpClickHandler() { | ||
179 | - // click handler for "selectable" objects | ||
180 | - $(document).on('click', '.select-object', function () { | ||
181 | - // when any object of class "select-object" is clicked... | ||
182 | - var obj = network.lookup[$(this).data('id')]; | ||
183 | - if (obj) { | ||
184 | - selectObject(obj); | ||
185 | - } | ||
186 | - // stop propagation of event (I think) ... | ||
187 | - return false; | ||
188 | - }); | ||
189 | - } | ||
190 | - | ||
191 | - function setUpRadioButtonHandler() { | ||
192 | - d3.selectAll('#displayModes .radio').on('click', function () { | ||
193 | - var id = d3.select(this).attr('id'); | ||
194 | - if (id !== viewMode) { | ||
195 | - radioButton('displayModes', id); | ||
196 | - viewMode = id; | ||
197 | - doRadioAction(id); | ||
198 | - } | ||
199 | - }); | ||
200 | - } | ||
201 | - | ||
202 | - function doRadioAction(id) { | ||
203 | - showAllLayers(); | ||
204 | - if (id === 'showPkt') { | ||
205 | - showPacketLayer(); | ||
206 | - } else if (id === 'showOpt') { | ||
207 | - showOpticalLayer(); | ||
208 | - } | ||
209 | - } | ||
210 | - | ||
211 | - function showAllLayers() { | ||
212 | - network.node.classed('inactive', false); | ||
213 | - network.link.classed('inactive', false); | ||
214 | - d3.selectAll('svg .port').classed('inactive', false) | ||
215 | - d3.selectAll('svg .portText').classed('inactive', false) | ||
216 | - } | ||
217 | - | ||
218 | - function showPacketLayer() { | ||
219 | - network.node.each(function(d) { | ||
220 | - // deactivate nodes that are not hosts or switches | ||
221 | - if (d.class === 'device' && d.type !== 'switch') { | ||
222 | - d3.select(this).classed('inactive', true); | ||
223 | - } | ||
224 | - }); | ||
225 | - | ||
226 | - network.link.each(function(lnk) { | ||
227 | - // deactivate infrastructure links that have opt's as endpoints | ||
228 | - if (lnk.source.type === 'roadm' || lnk.target.type === 'roadm') { | ||
229 | - d3.select(this).classed('inactive', true); | ||
230 | - } | ||
231 | - }); | ||
232 | - | ||
233 | - // deactivate non-packet ports | ||
234 | - d3.selectAll('svg .optPort').classed('inactive', true) | ||
235 | - } | ||
236 | - | ||
237 | - function showOpticalLayer() { | ||
238 | - network.node.each(function(d) { | ||
239 | - // deactivate nodes that are not optical devices | ||
240 | - if (d.type !== 'roadm') { | ||
241 | - d3.select(this).classed('inactive', true); | ||
242 | - } | ||
243 | - }); | ||
244 | - | ||
245 | - network.link.each(function(lnk) { | ||
246 | - // deactivate infrastructure links that have opt's as endpoints | ||
247 | - if (lnk.source.type !== 'roadm' || lnk.target.type !== 'roadm') { | ||
248 | - d3.select(this).classed('inactive', true); | ||
249 | - } | ||
250 | - }); | ||
251 | - | ||
252 | - // deactivate non-packet ports | ||
253 | - d3.selectAll('svg .pktPort').classed('inactive', true) | ||
254 | - } | ||
255 | - | ||
256 | - function setUpKeyHandler() { | ||
257 | - d3.select('body') | ||
258 | - .on('keydown', function () { | ||
259 | - processKeyEvent(); | ||
260 | - if (debug('showKeyHandler')) { | ||
261 | - network.svg.append('text') | ||
262 | - .attr('x', 5) | ||
263 | - .attr('y', 15) | ||
264 | - .style('font-size', '20pt') | ||
265 | - .text('keyCode: ' + d3.event.keyCode + | ||
266 | - ' applied to : ' + contextLabel()) | ||
267 | - .transition().duration(2000) | ||
268 | - .style('font-size', '2pt') | ||
269 | - .style('fill-opacity', 0.01) | ||
270 | - .remove(); | ||
271 | - } | ||
272 | - }); | ||
273 | - } | ||
274 | - | ||
275 | - function contextLabel() { | ||
276 | - return hovered === null ? "(nothing)" : hovered.id; | ||
277 | - } | ||
278 | - | ||
279 | - function radioButton(group, id) { | ||
280 | - d3.selectAll("#" + group + " .radio").classed("active", false); | ||
281 | - d3.select("#" + group + " #" + id).classed("active", true); | ||
282 | - } | ||
283 | - | ||
284 | - function processKeyEvent() { | ||
285 | - var code = d3.event.keyCode; | ||
286 | - switch (code) { | ||
287 | - case 66: // B | ||
288 | - toggleBackground(); | ||
289 | - break; | ||
290 | - case 71: // G | ||
291 | - cycleLayout(); | ||
292 | - break; | ||
293 | - case 76: // L | ||
294 | - cycleLabels(); | ||
295 | - break; | ||
296 | - case 80: // P | ||
297 | - togglePorts(); | ||
298 | - break; | ||
299 | - case 85: // U | ||
300 | - unpin(); | ||
301 | - break; | ||
302 | - } | ||
303 | - | ||
304 | - } | ||
305 | - | ||
306 | - function toggleBackground() { | ||
307 | - var bg = d3.select('#bg'), | ||
308 | - vis = bg.style('visibility'), | ||
309 | - newvis = (vis === 'hidden') ? 'visible' : 'hidden'; | ||
310 | - bg.style('visibility', newvis); | ||
311 | - } | ||
312 | - | ||
313 | - function cycleLayout() { | ||
314 | - config.options.layering = !config.options.layering; | ||
315 | - network.force.resume(); | ||
316 | - } | ||
317 | - | ||
318 | - function cycleLabels() { | ||
319 | - console.log('Cycle Labels - context = ' + contextLabel()); | ||
320 | - } | ||
321 | - | ||
322 | - function togglePorts() { | ||
323 | - portLabelsOn = !portLabelsOn; | ||
324 | - var portVis = portLabelsOn ? 'visible' : 'hidden'; | ||
325 | - d3.selectAll('.port').style('visibility', portVis); | ||
326 | - d3.selectAll('.portText').style('visibility', portVis); | ||
327 | - } | ||
328 | - | ||
329 | - function unpin() { | ||
330 | - if (hovered) { | ||
331 | - hovered.fixed = false; | ||
332 | - findNodeFromData(hovered).classed('fixed', false); | ||
333 | - network.force.resume(); | ||
334 | - } | ||
335 | - console.log('Unpin - context = ' + contextLabel()); | ||
336 | - } | ||
337 | - | ||
338 | - | ||
339 | - // ======================================================== | ||
340 | - | ||
341 | - function drawNetwork() { | ||
342 | - $('#view').empty(); | ||
343 | - | ||
344 | - prepareNodesAndLinks(); | ||
345 | - createLayout(); | ||
346 | - console.log("\n\nHere is the augmented network object..."); | ||
347 | - console.log(network); | ||
348 | - } | ||
349 | - | ||
350 | - function prepareNodesAndLinks() { | ||
351 | - network.lookup = {}; | ||
352 | - network.nodes = []; | ||
353 | - network.links = []; | ||
354 | - | ||
355 | - var nw = network.forceWidth, | ||
356 | - nh = network.forceHeight; | ||
357 | - | ||
358 | - function yPosConstraintForNode(n) { | ||
359 | - return config.constraints.ypos[n.type || 'host']; | ||
360 | - } | ||
361 | - | ||
362 | - // Note that both 'devices' and 'hosts' get mapped into the nodes array | ||
363 | - | ||
364 | - // first, the devices... | ||
365 | - network.data.devices.forEach(function(n) { | ||
366 | - var ypc = yPosConstraintForNode(n), | ||
367 | - ix = Math.random() * 0.6 * nw + 0.2 * nw, | ||
368 | - iy = ypc * nh, | ||
369 | - node = { | ||
370 | - id: n.id, | ||
371 | - labels: n.labels, | ||
372 | - class: 'device', | ||
373 | - icon: 'device', | ||
374 | - type: n.type, | ||
375 | - x: ix, | ||
376 | - y: iy, | ||
377 | - constraint: { | ||
378 | - weight: 0.7, | ||
379 | - y: iy | ||
380 | - } | ||
381 | - }; | ||
382 | - network.lookup[n.id] = node; | ||
383 | - network.nodes.push(node); | ||
384 | - }); | ||
385 | - | ||
386 | - // then, the hosts... | ||
387 | - network.data.hosts.forEach(function(n) { | ||
388 | - var ypc = yPosConstraintForNode(n), | ||
389 | - ix = Math.random() * 0.6 * nw + 0.2 * nw, | ||
390 | - iy = ypc * nh, | ||
391 | - node = { | ||
392 | - id: n.id, | ||
393 | - labels: n.labels, | ||
394 | - class: 'host', | ||
395 | - icon: 'host', | ||
396 | - type: n.type, | ||
397 | - x: ix, | ||
398 | - y: iy, | ||
399 | - constraint: { | ||
400 | - weight: 0.7, | ||
401 | - y: iy | ||
402 | - } | ||
403 | - }; | ||
404 | - network.lookup[n.id] = node; | ||
405 | - network.nodes.push(node); | ||
406 | - }); | ||
407 | - | ||
408 | - | ||
409 | - // now, process the explicit links... | ||
410 | - network.data.links.forEach(function(lnk) { | ||
411 | - var src = network.lookup[lnk.src], | ||
412 | - dst = network.lookup[lnk.dst], | ||
413 | - id = src.id + "-" + dst.id; | ||
414 | - | ||
415 | - var link = { | ||
416 | - class: 'infra', | ||
417 | - id: id, | ||
418 | - type: lnk.type, | ||
419 | - width: lnk.linkWidth, | ||
420 | - source: src, | ||
421 | - srcPort: lnk.srcPort, | ||
422 | - target: dst, | ||
423 | - tgtPort: lnk.dstPort, | ||
424 | - strength: config.force.linkStrength.infra | ||
425 | - }; | ||
426 | - network.links.push(link); | ||
427 | - }); | ||
428 | - | ||
429 | - // finally, infer host links... | ||
430 | - network.data.hosts.forEach(function(n) { | ||
431 | - var src = network.lookup[n.id], | ||
432 | - dst = network.lookup[n.cp.device], | ||
433 | - id = src.id + "-" + dst.id; | ||
434 | - | ||
435 | - var link = { | ||
436 | - class: 'host', | ||
437 | - id: id, | ||
438 | - type: 'hostLink', | ||
439 | - width: config.hostLinkWidth, | ||
440 | - source: src, | ||
441 | - target: dst, | ||
442 | - strength: config.force.linkStrength.host | ||
443 | - }; | ||
444 | - network.links.push(link); | ||
445 | - }); | ||
446 | - } | ||
447 | - | ||
448 | - function createLayout() { | ||
449 | - | ||
450 | - var cfg = config.force; | ||
451 | - | ||
452 | - network.force = d3.layout.force() | ||
453 | - .size([network.forceWidth, network.forceHeight]) | ||
454 | - .nodes(network.nodes) | ||
455 | - .links(network.links) | ||
456 | - .linkStrength(function(d) { return cfg.linkStrength[d.class]; }) | ||
457 | - .linkDistance(function(d) { return cfg.linkDistance[d.class]; }) | ||
458 | - .charge(function(d) { return cfg.charge[d.class]; }) | ||
459 | - .on('tick', tick); | ||
460 | - | ||
461 | - network.svg = d3.select('#view').append('svg') | ||
462 | - .attr('width', view.width) | ||
463 | - .attr('height', view.height) | ||
464 | - .append('g') | ||
465 | - .attr('transform', config.force.translate()); | ||
466 | -// .attr('id', 'zoomable') | ||
467 | -// .call(d3.behavior.zoom().on("zoom", zoomRedraw)); | ||
468 | - | ||
469 | - network.svg.append('svg:image') | ||
470 | - .attr({ | ||
471 | - id: 'bg', | ||
472 | - width: view.width, | ||
473 | - height: view.height, | ||
474 | - 'xlink:href': config.backgroundUrl | ||
475 | - }) | ||
476 | - .style('visibility', | ||
477 | - config.options.loadBackground ? 'visible' : 'hidden'); | ||
478 | - | ||
479 | -// function zoomRedraw() { | ||
480 | -// d3.select("#zoomable").attr("transform", | ||
481 | -// "translate(" + d3.event.translate + ")" | ||
482 | -// + " scale(" + d3.event.scale + ")"); | ||
483 | -// } | ||
484 | - | ||
485 | - // TODO: move glow/blur stuff to util script | ||
486 | - var glow = network.svg.append('filter') | ||
487 | - .attr('x', '-50%') | ||
488 | - .attr('y', '-50%') | ||
489 | - .attr('width', '200%') | ||
490 | - .attr('height', '200%') | ||
491 | - .attr('id', 'blue-glow'); | ||
492 | - | ||
493 | - glow.append('feColorMatrix') | ||
494 | - .attr('type', 'matrix') | ||
495 | - .attr('values', '0 0 0 0 0 ' + | ||
496 | - '0 0 0 0 0 ' + | ||
497 | - '0 0 0 0 .7 ' + | ||
498 | - '0 0 0 1 0 '); | ||
499 | - | ||
500 | - glow.append('feGaussianBlur') | ||
501 | - .attr('stdDeviation', 3) | ||
502 | - .attr('result', 'coloredBlur'); | ||
503 | - | ||
504 | - glow.append('feMerge').selectAll('feMergeNode') | ||
505 | - .data(['coloredBlur', 'SourceGraphic']) | ||
506 | - .enter().append('feMergeNode') | ||
507 | - .attr('in', String); | ||
508 | - | ||
509 | - // TODO: legend (and auto adjust on scroll) | ||
510 | -// $('#view').on('scroll', function() { | ||
511 | -// | ||
512 | -// }); | ||
513 | - | ||
514 | - | ||
515 | - // TODO: move drag behavior into separate method. | ||
516 | - // == define node drag behavior... | ||
517 | - network.draggedThreshold = d3.scale.linear() | ||
518 | - .domain([0, 0.1]) | ||
519 | - .range([5, 20]) | ||
520 | - .clamp(true); | ||
521 | - | ||
522 | - function dragged(d) { | ||
523 | - var threshold = network.draggedThreshold(network.force.alpha()), | ||
524 | - dx = d.oldX - d.px, | ||
525 | - dy = d.oldY - d.py; | ||
526 | - if (Math.abs(dx) >= threshold || Math.abs(dy) >= threshold) { | ||
527 | - d.dragged = true; | ||
528 | - } | ||
529 | - return d.dragged; | ||
530 | - } | ||
531 | - | ||
532 | - network.drag = d3.behavior.drag() | ||
533 | - .origin(function(d) { return d; }) | ||
534 | - .on('dragstart', function(d) { | ||
535 | - d.oldX = d.x; | ||
536 | - d.oldY = d.y; | ||
537 | - d.dragged = false; | ||
538 | - d.fixed |= 2; | ||
539 | - }) | ||
540 | - .on('drag', function(d) { | ||
541 | - d.px = d3.event.x; | ||
542 | - d.py = d3.event.y; | ||
543 | - if (dragged(d)) { | ||
544 | - if (!network.force.alpha()) { | ||
545 | - network.force.alpha(.025); | ||
546 | - } | ||
547 | - } | ||
548 | - }) | ||
549 | - .on('dragend', function(d) { | ||
550 | - if (!dragged(d)) { | ||
551 | - selectObject(d, this); | ||
552 | - } | ||
553 | - d.fixed &= ~6; | ||
554 | - | ||
555 | - // once we've finished moving, pin the node in position, | ||
556 | - // if it is a device (not a host) | ||
557 | - if (d.class === 'device') { | ||
558 | - d.fixed = true; | ||
559 | - d3.select(this).classed('fixed', true) | ||
560 | - } | ||
561 | - }); | ||
562 | - | ||
563 | - $('#view').on('click', function(e) { | ||
564 | - if (!$(e.target).closest('.node').length) { | ||
565 | - deselectObject(); | ||
566 | - } | ||
567 | - }); | ||
568 | - | ||
569 | - // ............................................................... | ||
570 | - | ||
571 | - // add links to the display | ||
572 | - network.link = network.svg.append('g').attr('id', 'links') | ||
573 | - .selectAll('.link') | ||
574 | - .data(network.force.links(), function(d) {return d.id}) | ||
575 | - .enter().append('line') | ||
576 | - .attr('class', function(d) {return 'link ' + d.class}); | ||
577 | - | ||
578 | - network.linkSrcPort = network.svg.append('g') | ||
579 | - .attr({ | ||
580 | - id: 'srcPorts', | ||
581 | - class: 'portLayer' | ||
582 | - }); | ||
583 | - network.linkTgtPort = network.svg.append('g') | ||
584 | - .attr({ | ||
585 | - id: 'tgtPorts', | ||
586 | - class: 'portLayer' | ||
587 | - }); | ||
588 | - | ||
589 | - var portVis = portLabelsOn ? 'visible' : 'hidden', | ||
590 | - pw = config.labels.port.width, | ||
591 | - ph = config.labels.port.height; | ||
592 | - | ||
593 | - network.link.filter('.infra').each(function(d) { | ||
594 | - var srcType = d.source.type === 'roadm' ? 'optPort' : 'pktPort', | ||
595 | - tgtType = d.target.type === 'roadm' ? 'optPort' : 'pktPort'; | ||
596 | - | ||
597 | - if (d.source.type) | ||
598 | - | ||
599 | - network.linkSrcPort.append('rect').attr({ | ||
600 | - id: 'srcPort-' + safeId(d.id), | ||
601 | - class: 'port ' + srcType, | ||
602 | - width: pw, | ||
603 | - height: ph, | ||
604 | - rx: 4, | ||
605 | - ry: 4 | ||
606 | - }).style('visibility', portVis); | ||
607 | - | ||
608 | - network.linkTgtPort.append('rect').attr({ | ||
609 | - id: 'tgtPort-' + safeId(d.id), | ||
610 | - class: 'port ' + tgtType, | ||
611 | - width: pw, | ||
612 | - height: ph, | ||
613 | - rx: 4, | ||
614 | - ry: 4 | ||
615 | - }).style('visibility', portVis); | ||
616 | - | ||
617 | - network.linkSrcPort.append('text').attr({ | ||
618 | - id: 'srcText-' + safeId(d.id), | ||
619 | - class: 'portText ' + srcType | ||
620 | - }).text(d.srcPort) | ||
621 | - .style('visibility', portVis); | ||
622 | - | ||
623 | - network.linkTgtPort.append('text').attr({ | ||
624 | - id: 'tgtText-' + safeId(d.id), | ||
625 | - class: 'portText ' + tgtType | ||
626 | - }).text(d.tgtPort) | ||
627 | - .style('visibility', portVis); | ||
628 | - }); | ||
629 | - | ||
630 | - // ............................................................... | ||
631 | - | ||
632 | - // add nodes to the display | ||
633 | - network.node = network.svg.selectAll('.node') | ||
634 | - .data(network.force.nodes(), function(d) {return d.id}) | ||
635 | - .enter().append('g') | ||
636 | - .attr('class', function(d) { | ||
637 | - var cls = 'node ' + d.class; | ||
638 | - if (d.type) { | ||
639 | - cls += ' ' + d.type; | ||
640 | - } | ||
641 | - return cls; | ||
642 | - }) | ||
643 | - .attr('transform', function(d) { | ||
644 | - return translate(d.x, d.y); | ||
645 | - }) | ||
646 | - .call(network.drag) | ||
647 | - .on('mouseover', function(d) { | ||
648 | - // TODO: show tooltip | ||
649 | - if (network.mouseoutTimeout) { | ||
650 | - clearTimeout(network.mouseoutTimeout); | ||
651 | - network.mouseoutTimeout = null; | ||
652 | - } | ||
653 | - hoverObject(d); | ||
654 | - }) | ||
655 | - .on('mouseout', function(d) { | ||
656 | - // TODO: hide tooltip | ||
657 | - if (network.mouseoutTimeout) { | ||
658 | - clearTimeout(network.mouseoutTimeout); | ||
659 | - network.mouseoutTimeout = null; | ||
660 | - } | ||
661 | - network.mouseoutTimeout = setTimeout(function() { | ||
662 | - hoverObject(null); | ||
663 | - }, config.mouseOutTimerDelayMs); | ||
664 | - }); | ||
665 | - | ||
666 | - | ||
667 | - // deal with device nodes first | ||
668 | - network.nodeRect = network.node.filter('.device') | ||
669 | - .append('rect') | ||
670 | - .attr({ | ||
671 | - rx: 5, | ||
672 | - ry: 5, | ||
673 | - width: 100, | ||
674 | - height: 12 | ||
675 | - }); | ||
676 | - // note that width/height are adjusted to fit the label text | ||
677 | - // then padded, and space made for the icon. | ||
678 | - | ||
679 | - network.node.filter('.device').each(function(d) { | ||
680 | - var node = d3.select(this), | ||
681 | - icon = iconUrl(d); | ||
682 | - | ||
683 | - node.append('text') | ||
684 | - // TODO: add label cycle behavior | ||
685 | - .text(d.id) | ||
686 | - .attr('dy', '1.1em'); | ||
687 | - | ||
688 | - if (icon) { | ||
689 | - var cfg = config.icons; | ||
690 | - node.append('svg:image') | ||
691 | - .attr({ | ||
692 | - width: cfg.w, | ||
693 | - height: cfg.h, | ||
694 | - 'xlink:href': icon | ||
695 | - }); | ||
696 | - // note, icon relative positioning (x,y) is done after we have | ||
697 | - // adjusted the bounds of the rectangle... | ||
698 | - } | ||
699 | - | ||
700 | - // debug function to show the modelled x,y coordinates of nodes... | ||
701 | - if (debug('showNodeXY')) { | ||
702 | - node.select('rect').attr('fill-opacity', 0.5); | ||
703 | - node.append('circle') | ||
704 | - .attr({ | ||
705 | - class: 'debug', | ||
706 | - cx: 0, | ||
707 | - cy: 0, | ||
708 | - r: '3px' | ||
709 | - }); | ||
710 | - } | ||
711 | - }); | ||
712 | - | ||
713 | - // now process host nodes | ||
714 | - network.nodeCircle = network.node.filter('.host') | ||
715 | - .append('circle') | ||
716 | - .attr({ | ||
717 | - r: config.hostRadius | ||
718 | - }); | ||
719 | - | ||
720 | - network.node.filter('.host').each(function(d) { | ||
721 | - var node = d3.select(this), | ||
722 | - icon = iconUrl(d); | ||
723 | - | ||
724 | - // debug function to show the modelled x,y coordinates of nodes... | ||
725 | - if (debug('showNodeXY')) { | ||
726 | - node.select('circle').attr('fill-opacity', 0.5); | ||
727 | - node.append('circle') | ||
728 | - .attr({ | ||
729 | - class: 'debug', | ||
730 | - cx: 0, | ||
731 | - cy: 0, | ||
732 | - r: '3px' | ||
733 | - }); | ||
734 | - } | ||
735 | - }); | ||
736 | - | ||
737 | - // this function is scheduled to happen soon after the given thread ends | ||
738 | - setTimeout(function() { | ||
739 | - var lab = config.labels, | ||
740 | - portGap = lab.port.gap, | ||
741 | - midW = portGap + lab.port.width/ 2, | ||
742 | - midH = portGap + lab.port.height / 2; | ||
743 | - | ||
744 | - // post process the device nodes, to pad their size to fit the | ||
745 | - // label text and attach the icon to the right location. | ||
746 | - network.node.filter('.device').each(function(d) { | ||
747 | - // for every node, recompute size, padding, etc. so text fits | ||
748 | - var node = d3.select(this), | ||
749 | - text = node.select('text'), | ||
750 | - box = adjustRectToFitText(node); | ||
751 | - | ||
752 | - // now make the computed adjustment | ||
753 | - node.select('rect') | ||
754 | - .attr(box); | ||
755 | - | ||
756 | - node.select('image') | ||
757 | - .attr('x', box.x + config.icons.xoff) | ||
758 | - .attr('y', box.y + config.icons.yoff); | ||
759 | - | ||
760 | - var bounds = boundsFromBox(box), | ||
761 | - portBounds = { | ||
762 | - x1: bounds.x1 - midW, | ||
763 | - x2: bounds.x2 + midW, | ||
764 | - y1: bounds.y1 - midH, | ||
765 | - y2: bounds.y2 + midH | ||
766 | - }; | ||
767 | - | ||
768 | - // todo: clean up extent and edge work.. | ||
769 | - d.extent = { | ||
770 | - left: bounds.x1 - lab.marginLR, | ||
771 | - right: bounds.x2 + lab.marginLR, | ||
772 | - top: bounds.y1 - lab.marginTB, | ||
773 | - bottom: bounds.y2 + lab.marginTB | ||
774 | - }; | ||
775 | - | ||
776 | - d.edge = { | ||
777 | - left : new geo.LineSegment(bounds.x1, bounds.y1, bounds.x1, bounds.y2), | ||
778 | - right : new geo.LineSegment(bounds.x2, bounds.y1, bounds.x2, bounds.y2), | ||
779 | - top : new geo.LineSegment(bounds.x1, bounds.y1, bounds.x2, bounds.y1), | ||
780 | - bottom : new geo.LineSegment(bounds.x1, bounds.y2, bounds.x2, bounds.y2) | ||
781 | - }; | ||
782 | - | ||
783 | - d.portEdge = { | ||
784 | - left : new geo.LineSegment( | ||
785 | - portBounds.x1, portBounds.y1, portBounds.x1, portBounds.y2 | ||
786 | - ), | ||
787 | - right : new geo.LineSegment( | ||
788 | - portBounds.x2, portBounds.y1, portBounds.x2, portBounds.y2 | ||
789 | - ), | ||
790 | - top : new geo.LineSegment( | ||
791 | - portBounds.x1, portBounds.y1, portBounds.x2, portBounds.y1 | ||
792 | - ), | ||
793 | - bottom : new geo.LineSegment( | ||
794 | - portBounds.x1, portBounds.y2, portBounds.x2, portBounds.y2 | ||
795 | - ) | ||
796 | - }; | ||
797 | - | ||
798 | - }); | ||
799 | - | ||
800 | - network.numTicks = 0; | ||
801 | - network.preventCollisions = false; | ||
802 | - network.force.start(); | ||
803 | - for (var i = 0; i < config.force.ticksWithoutCollisions; i++) { | ||
804 | - network.force.tick(); | ||
805 | - } | ||
806 | - network.preventCollisions = true; | ||
807 | - $('#view').css('visibility', 'visible'); | ||
808 | - }); | ||
809 | - | ||
810 | - | ||
811 | - // returns the newly computed bounding box of the rectangle | ||
812 | - function adjustRectToFitText(n) { | ||
813 | - var text = n.select('text'), | ||
814 | - box = text.node().getBBox(), | ||
815 | - lab = config.labels; | ||
816 | - | ||
817 | - // not sure why n.data() returns an array of 1 element... | ||
818 | - var data = n.data()[0]; | ||
819 | - | ||
820 | - text.attr('text-anchor', 'middle') | ||
821 | - .attr('y', '-0.8em') | ||
822 | - .attr('x', lab.imgPad/2) | ||
823 | - ; | ||
824 | - | ||
825 | - // translate the bbox so that it is centered on [x,y] | ||
826 | - box.x = -box.width / 2; | ||
827 | - box.y = -box.height / 2; | ||
828 | - | ||
829 | - // add padding | ||
830 | - box.x -= (lab.padLR + lab.imgPad/2); | ||
831 | - box.width += lab.padLR * 2 + lab.imgPad; | ||
832 | - box.y -= lab.padTB; | ||
833 | - box.height += lab.padTB * 2; | ||
834 | - | ||
835 | - return box; | ||
836 | - } | ||
837 | - | ||
838 | - function boundsFromBox(box) { | ||
839 | - return { | ||
840 | - x1: box.x, | ||
841 | - y1: box.y, | ||
842 | - x2: box.x + box.width, | ||
843 | - y2: box.y + box.height | ||
844 | - }; | ||
845 | - } | ||
846 | - | ||
847 | - } | ||
848 | - | ||
849 | - function iconUrl(d) { | ||
850 | - return 'img/' + d.type + '.png'; | ||
851 | -// return config.iconUrl[d.icon]; | ||
852 | - } | ||
853 | - | ||
854 | - function translate(x, y) { | ||
855 | - return 'translate(' + x + ',' + y + ')'; | ||
856 | - } | ||
857 | - | ||
858 | - // prevents collisions amongst device nodes | ||
859 | - function preventCollisions() { | ||
860 | - var quadtree = d3.geom.quadtree(network.nodes), | ||
861 | - hrad = config.hostRadius; | ||
862 | - | ||
863 | - network.nodes.forEach(function(n) { | ||
864 | - var nx1, nx2, ny1, ny2; | ||
865 | - | ||
866 | - if (n.class === 'device') { | ||
867 | - nx1 = n.x + n.extent.left; | ||
868 | - nx2 = n.x + n.extent.right; | ||
869 | - ny1 = n.y + n.extent.top; | ||
870 | - ny2 = n.y + n.extent.bottom; | ||
871 | - | ||
872 | - } else { | ||
873 | - nx1 = n.x - hrad; | ||
874 | - nx2 = n.x + hrad; | ||
875 | - ny1 = n.y - hrad; | ||
876 | - ny2 = n.y + hrad; | ||
877 | - } | ||
878 | - | ||
879 | - quadtree.visit(function(quad, x1, y1, x2, y2) { | ||
880 | - if (quad.point && quad.point !== n) { | ||
881 | - // check if the rectangles/circles intersect | ||
882 | - var p = quad.point, | ||
883 | - px1, px2, py1, py2, ix; | ||
884 | - | ||
885 | - if (p.class === 'device') { | ||
886 | - px1 = p.x + p.extent.left; | ||
887 | - px2 = p.x + p.extent.right; | ||
888 | - py1 = p.y + p.extent.top; | ||
889 | - py2 = p.y + p.extent.bottom; | ||
890 | - | ||
891 | - } else { | ||
892 | - px1 = p.x - hrad; | ||
893 | - px2 = p.x + hrad; | ||
894 | - py1 = p.y - hrad; | ||
895 | - py2 = p.y + hrad; | ||
896 | - } | ||
897 | - | ||
898 | - ix = (px1 <= nx2 && nx1 <= px2 && py1 <= ny2 && ny1 <= py2); | ||
899 | - | ||
900 | - if (ix) { | ||
901 | - var xa1 = nx2 - px1, // shift n left , p right | ||
902 | - xa2 = px2 - nx1, // shift n right, p left | ||
903 | - ya1 = ny2 - py1, // shift n up , p down | ||
904 | - ya2 = py2 - ny1, // shift n down , p up | ||
905 | - adj = Math.min(xa1, xa2, ya1, ya2); | ||
906 | - | ||
907 | - if (adj == xa1) { | ||
908 | - n.x -= adj / 2; | ||
909 | - p.x += adj / 2; | ||
910 | - } else if (adj == xa2) { | ||
911 | - n.x += adj / 2; | ||
912 | - p.x -= adj / 2; | ||
913 | - } else if (adj == ya1) { | ||
914 | - n.y -= adj / 2; | ||
915 | - p.y += adj / 2; | ||
916 | - } else if (adj == ya2) { | ||
917 | - n.y += adj / 2; | ||
918 | - p.y -= adj / 2; | ||
919 | - } | ||
920 | - } | ||
921 | - return ix; | ||
922 | - } | ||
923 | - }); | ||
924 | - | ||
925 | - }); | ||
926 | - } | ||
927 | - | ||
928 | - function tick(e) { | ||
929 | - network.numTicks++; | ||
930 | - | ||
931 | - if (config.options.layering) { | ||
932 | - // adjust the y-coord of each node, based on y-pos constraints | ||
933 | - network.nodes.forEach(function (n) { | ||
934 | - var z = e.alpha * n.constraint.weight; | ||
935 | - if (!isNaN(n.constraint.y)) { | ||
936 | - n.y = (n.constraint.y * z + n.y * (1 - z)); | ||
937 | - } | ||
938 | - }); | ||
939 | - } | ||
940 | - | ||
941 | - if (config.options.collisionPrevention && network.preventCollisions) { | ||
942 | - preventCollisions(); | ||
943 | - } | ||
944 | - | ||
945 | - var portHalfW = config.labels.port.width / 2, | ||
946 | - portHalfH = config.labels.port.height / 2; | ||
947 | - | ||
948 | - // clip visualization of links at bounds of nodes... | ||
949 | - network.link.each(function(d) { | ||
950 | - var xs = d.source.x, | ||
951 | - ys = d.source.y, | ||
952 | - xt = d.target.x, | ||
953 | - yt = d.target.y, | ||
954 | - line = new geo.LineSegment(xs, ys, xt, yt), | ||
955 | - e, ix, | ||
956 | - exs, eys, ext, eyt, | ||
957 | - pxs, pys, pxt, pyt; | ||
958 | - | ||
959 | - if (d.class === 'host') { | ||
960 | - // no adjustment for source end of link, since hosts are dots | ||
961 | - exs = xs; | ||
962 | - eys = ys; | ||
963 | - | ||
964 | - } else { | ||
965 | - for (e in d.source.edge) { | ||
966 | - ix = line.intersect(d.source.edge[e].offset(xs, ys)); | ||
967 | - if (ix.in1 && ix.in2) { | ||
968 | - exs = ix.x; | ||
969 | - eys = ix.y; | ||
970 | - | ||
971 | - // also pick off the port label intersection | ||
972 | - ix = line.intersect(d.source.portEdge[e].offset(xs, ys)); | ||
973 | - pxs = ix.x; | ||
974 | - pys = ix.y; | ||
975 | - break; | ||
976 | - } | ||
977 | - } | ||
978 | - } | ||
979 | - | ||
980 | - for (e in d.target.edge) { | ||
981 | - ix = line.intersect(d.target.edge[e].offset(xt, yt)); | ||
982 | - if (ix.in1 && ix.in2) { | ||
983 | - ext = ix.x; | ||
984 | - eyt = ix.y; | ||
985 | - | ||
986 | - // also pick off the port label intersection | ||
987 | - ix = line.intersect(d.target.portEdge[e].offset(xt, yt)); | ||
988 | - pxt = ix.x; | ||
989 | - pyt = ix.y; | ||
990 | - break; | ||
991 | - } | ||
992 | - } | ||
993 | - | ||
994 | - // adjust the endpoints of the link's line to match rectangles | ||
995 | - var sid = safeId(d.id); | ||
996 | - d3.select(this) | ||
997 | - .attr('x1', exs) | ||
998 | - .attr('y1', eys) | ||
999 | - .attr('x2', ext) | ||
1000 | - .attr('y2', eyt); | ||
1001 | - | ||
1002 | - d3.select('#srcPort-' + sid) | ||
1003 | - .attr('x', pxs - portHalfW) | ||
1004 | - .attr('y', pys - portHalfH); | ||
1005 | - | ||
1006 | - d3.select('#tgtPort-' + sid) | ||
1007 | - .attr('x', pxt - portHalfW) | ||
1008 | - .attr('y', pyt - portHalfH); | ||
1009 | - | ||
1010 | - // TODO: fit label rect to size of port number. | ||
1011 | - d3.select('#srcText-' + sid) | ||
1012 | - .attr('x', pxs - 5) | ||
1013 | - .attr('y', pys + 3); | ||
1014 | - | ||
1015 | - d3.select('#tgtText-' + sid) | ||
1016 | - .attr('x', pxt - 5) | ||
1017 | - .attr('y', pyt + 3); | ||
1018 | - | ||
1019 | - }); | ||
1020 | - | ||
1021 | - // position each node by translating the node (group) by x,y | ||
1022 | - network.node | ||
1023 | - .attr('transform', function(d) { | ||
1024 | - return translate(d.x, d.y); | ||
1025 | - }); | ||
1026 | - | ||
1027 | - } | ||
1028 | - | ||
1029 | - // $('#docs-close').on('click', function() { | ||
1030 | - // deselectObject(); | ||
1031 | - // return false; | ||
1032 | - // }); | ||
1033 | - | ||
1034 | - // $(document).on('click', '.select-object', function() { | ||
1035 | - // var obj = graph.data[$(this).data('name')]; | ||
1036 | - // if (obj) { | ||
1037 | - // selectObject(obj); | ||
1038 | - // } | ||
1039 | - // return false; | ||
1040 | - // }); | ||
1041 | - | ||
1042 | - function findNodeFromData(d) { | ||
1043 | - var el = null; | ||
1044 | - network.node.filter('.' + d.class).each(function(n) { | ||
1045 | - if (n.id === d.id) { | ||
1046 | - el = d3.select(this); | ||
1047 | - } | ||
1048 | - }); | ||
1049 | - return el; | ||
1050 | - } | ||
1051 | - | ||
1052 | - function selectObject(obj, el) { | ||
1053 | - var node; | ||
1054 | - if (el) { | ||
1055 | - node = d3.select(el); | ||
1056 | - } else { | ||
1057 | - network.node.each(function(d) { | ||
1058 | - if (d == obj) { | ||
1059 | - node = d3.select(el = this); | ||
1060 | - } | ||
1061 | - }); | ||
1062 | - } | ||
1063 | - if (!node) return; | ||
1064 | - | ||
1065 | - if (node.classed('selected')) { | ||
1066 | - deselectObject(); | ||
1067 | - flyinPane(null); | ||
1068 | - return; | ||
1069 | - } | ||
1070 | - deselectObject(false); | ||
1071 | - | ||
1072 | - selected = { | ||
1073 | - obj : obj, | ||
1074 | - el : el | ||
1075 | - }; | ||
1076 | - | ||
1077 | - node.classed('selected', true); | ||
1078 | - flyinPane(obj); | ||
1079 | - } | ||
1080 | - | ||
1081 | - function deselectObject(doResize) { | ||
1082 | - // Review: logic of 'resize(...)' function. | ||
1083 | - if (doResize || typeof doResize == 'undefined') { | ||
1084 | - resize(false); | ||
1085 | - } | ||
1086 | - | ||
1087 | - // deselect all nodes in the network... | ||
1088 | - network.node.classed('selected', false); | ||
1089 | - selected = {}; | ||
1090 | - flyinPane(null); | ||
1091 | - } | ||
1092 | - | ||
1093 | - function flyinPane(obj) { | ||
1094 | - var pane = d3.select('#flyout'), | ||
1095 | - url; | ||
1096 | - | ||
1097 | - if (obj) { | ||
1098 | - // go get details of the selected object from the server... | ||
1099 | - url = detailJsonUrl(obj.id); | ||
1100 | - d3.json(url, function (err, data) { | ||
1101 | - if (err) { | ||
1102 | - alert('Oops! Error reading JSON...\n\n' + | ||
1103 | - 'URL: ' + url + '\n\n' + | ||
1104 | - 'Error: ' + err.message); | ||
1105 | - return; | ||
1106 | - } | ||
1107 | -// console.log("JSON data... " + url); | ||
1108 | -// console.log(data); | ||
1109 | - | ||
1110 | - displayDetails(data, pane); | ||
1111 | - }); | ||
1112 | - | ||
1113 | - } else { | ||
1114 | - // hide pane | ||
1115 | - pane.transition().duration(750) | ||
1116 | - .style('right', '-320px') | ||
1117 | - .style('opacity', 0.0); | ||
1118 | - } | ||
1119 | - } | ||
1120 | - | ||
1121 | - function displayDetails(data, pane) { | ||
1122 | - $('#flyout').empty(); | ||
1123 | - | ||
1124 | - var title = pane.append("h2"), | ||
1125 | - table = pane.append("table"), | ||
1126 | - tbody = table.append("tbody"); | ||
1127 | - | ||
1128 | - $('<img src="img/' + data.type + '.png">').appendTo(title); | ||
1129 | - $('<span>').attr('class', 'icon').text(data.id).appendTo(title); | ||
1130 | - | ||
1131 | - | ||
1132 | - // TODO: consider using d3 data bind to TR/TD | ||
1133 | - | ||
1134 | - data.propOrder.forEach(function(p) { | ||
1135 | - if (p === '-') { | ||
1136 | - addSep(tbody); | ||
1137 | - } else { | ||
1138 | - addProp(tbody, p, data.props[p]); | ||
1139 | - } | ||
1140 | - }); | ||
1141 | - | ||
1142 | - function addSep(tbody) { | ||
1143 | - var tr = tbody.append('tr'); | ||
1144 | - $('<hr>').appendTo(tr.append('td').attr('colspan', 2)); | ||
1145 | - } | ||
1146 | - | ||
1147 | - function addProp(tbody, label, value) { | ||
1148 | - var tr = tbody.append('tr'); | ||
1149 | - | ||
1150 | - tr.append('td') | ||
1151 | - .attr('class', 'label') | ||
1152 | - .text(label + ' :'); | ||
1153 | - | ||
1154 | - tr.append('td') | ||
1155 | - .attr('class', 'value') | ||
1156 | - .text(value); | ||
1157 | - } | ||
1158 | - | ||
1159 | - // show pane | ||
1160 | - pane.transition().duration(750) | ||
1161 | - .style('right', '20px') | ||
1162 | - .style('opacity', 1.0); | ||
1163 | - } | ||
1164 | - | ||
1165 | - function highlightObject(obj) { | ||
1166 | - if (obj) { | ||
1167 | - if (obj != highlighted) { | ||
1168 | - // TODO set or clear "inactive" class on nodes, based on criteria | ||
1169 | - network.node.classed('inactive', function(d) { | ||
1170 | - // return (obj !== d && | ||
1171 | - // d.relation(obj.id)); | ||
1172 | - return (obj !== d); | ||
1173 | - }); | ||
1174 | - // TODO: same with links | ||
1175 | - network.link.classed('inactive', function(d) { | ||
1176 | - return (obj !== d.source && obj !== d.target); | ||
1177 | - }); | ||
1178 | - } | ||
1179 | - highlighted = obj; | ||
1180 | - } else { | ||
1181 | - if (highlighted) { | ||
1182 | - // clear the inactive flag (no longer suppressed visually) | ||
1183 | - network.node.classed('inactive', false); | ||
1184 | - network.link.classed('inactive', false); | ||
1185 | - } | ||
1186 | - highlighted = null; | ||
1187 | - | ||
1188 | - } | ||
1189 | - } | ||
1190 | - | ||
1191 | - function hoverObject(obj) { | ||
1192 | - if (obj) { | ||
1193 | - hovered = obj; | ||
1194 | - } else { | ||
1195 | - if (hovered) { | ||
1196 | - hovered = null; | ||
1197 | - } | ||
1198 | - } | ||
1199 | - } | ||
1200 | - | ||
1201 | - | ||
1202 | - function resize() { | ||
1203 | - view.height = window.innerHeight - config.mastHeight; | ||
1204 | - view.width = window.innerWidth; | ||
1205 | - $('#view') | ||
1206 | - .css('height', view.height + 'px') | ||
1207 | - .css('width', view.width + 'px'); | ||
1208 | - | ||
1209 | - network.forceWidth = view.width - config.force.marginLR; | ||
1210 | - network.forceHeight = view.height - config.force.marginTB; | ||
1211 | - } | ||
1212 | - | ||
1213 | - // ====================================================================== | ||
1214 | - // register with the UI framework | ||
1215 | - | ||
1216 | - api.addView('network', { | ||
1217 | - load: loadNetworkView | ||
1218 | - }); | ||
1219 | - | ||
1220 | - | ||
1221 | -}(ONOS)); | ||
1222 | - |
web/gui/src/main/webapp/OLD/onos.css
deleted
100644 → 0
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | - | ||
17 | -/* | ||
18 | - ONOS CSS file | ||
19 | - | ||
20 | - @author Simon Hunt | ||
21 | - */ | ||
22 | - | ||
23 | -body, html { | ||
24 | - height: 100%; | ||
25 | -} | ||
26 | - | ||
27 | -/* | ||
28 | - * Classes | ||
29 | - */ | ||
30 | - | ||
31 | -img#logo { | ||
32 | - height: 38px; | ||
33 | - padding-left: 8px; | ||
34 | - padding-right: 8px; | ||
35 | -} | ||
36 | - | ||
37 | -span.title { | ||
38 | - color: #369; | ||
39 | - font-size: 14pt; | ||
40 | - font-style: italic; | ||
41 | - vertical-align: 12px; | ||
42 | -} | ||
43 | - | ||
44 | -span.radio { | ||
45 | - color: darkslateblue; | ||
46 | - font-size: 10pt; | ||
47 | -} | ||
48 | - | ||
49 | -span.right { | ||
50 | - padding-top: 8px; | ||
51 | - padding-right: 16px; | ||
52 | - float: right; | ||
53 | -} | ||
54 | - | ||
55 | -/* | ||
56 | - * Radio Buttons | ||
57 | - */ | ||
58 | - | ||
59 | -span.radio { | ||
60 | - margin: 4px 0; | ||
61 | - border: 1px dotted #222; | ||
62 | - padding: 1px 6px; | ||
63 | - color: #eee; | ||
64 | - cursor: pointer; | ||
65 | -} | ||
66 | - | ||
67 | -span.radio.active { | ||
68 | - background-color: #bbb; | ||
69 | - border: 1px solid #eee; | ||
70 | - padding: 1px 6px; | ||
71 | - color: #666; | ||
72 | - font-weight: bold; | ||
73 | -} | ||
74 | - | ||
75 | -/* | ||
76 | - * === DEBUGGING ====== | ||
77 | - */ | ||
78 | -svg { | ||
79 | - /*border: 1px dashed red;*/ | ||
80 | -} | ||
81 | - | ||
82 | -svg #bg { | ||
83 | - opacity: 0.5; | ||
84 | -} | ||
85 | - | ||
86 | - | ||
87 | -/* | ||
88 | - * Network Graph elements ====================================== | ||
89 | - */ | ||
90 | - | ||
91 | -svg .link { | ||
92 | - fill: none; | ||
93 | - stroke: #666; | ||
94 | - stroke-width: 2.0px; | ||
95 | - opacity: .7; | ||
96 | - | ||
97 | - transition: opacity 250ms; | ||
98 | - -webkit-transition: opacity 250ms; | ||
99 | - -moz-transition: opacity 250ms; | ||
100 | -} | ||
101 | - | ||
102 | -svg .link.host { | ||
103 | - stroke: #666; | ||
104 | - stroke-width: 1px; | ||
105 | -} | ||
106 | - | ||
107 | -svg g.portLayer rect.port { | ||
108 | - fill: #ccc; | ||
109 | -} | ||
110 | - | ||
111 | -svg g.portLayer text { | ||
112 | - font: 8pt sans-serif; | ||
113 | - pointer-events: none; | ||
114 | -} | ||
115 | - | ||
116 | -svg .node.device rect { | ||
117 | - stroke-width: 1.5px; | ||
118 | - | ||
119 | - transition: opacity 250ms; | ||
120 | - -webkit-transition: opacity 250ms; | ||
121 | - -moz-transition: opacity 250ms; | ||
122 | -} | ||
123 | - | ||
124 | -svg .node.device.fixed rect { | ||
125 | - stroke-width: 1.5; | ||
126 | - stroke: #ccc; | ||
127 | -} | ||
128 | - | ||
129 | -svg .node.device.roadm rect { | ||
130 | - fill: #03c; | ||
131 | -} | ||
132 | - | ||
133 | -svg .node.device.switch rect { | ||
134 | - fill: #06f; | ||
135 | -} | ||
136 | - | ||
137 | -svg .node.host circle { | ||
138 | - fill: #c96; | ||
139 | - stroke: #000; | ||
140 | -} | ||
141 | - | ||
142 | -svg .node text { | ||
143 | - fill: white; | ||
144 | - font: 10pt sans-serif; | ||
145 | - pointer-events: none; | ||
146 | -} | ||
147 | - | ||
148 | -/* for debugging */ | ||
149 | -svg .node circle.debug { | ||
150 | - fill: white; | ||
151 | - stroke: red; | ||
152 | -} | ||
153 | -svg .node rect.debug { | ||
154 | - fill: yellow; | ||
155 | - stroke: red; | ||
156 | - opacity: 0.35; | ||
157 | -} | ||
158 | - | ||
159 | - | ||
160 | -svg .node.selected rect, | ||
161 | -svg .node.selected circle { | ||
162 | - filter: url(#blue-glow); | ||
163 | -} | ||
164 | - | ||
165 | -svg .link.inactive, | ||
166 | -svg .port.inactive, | ||
167 | -svg .portText.inactive, | ||
168 | -svg .node.inactive rect, | ||
169 | -svg .node.inactive circle, | ||
170 | -svg .node.inactive text, | ||
171 | -svg .node.inactive image { | ||
172 | - opacity: .1; | ||
173 | -} | ||
174 | - | ||
175 | -svg .node.inactive.selected rect, | ||
176 | -svg .node.inactive.selected text, | ||
177 | -svg .node.inactive.selected image { | ||
178 | - opacity: .6; | ||
179 | -} | ||
180 | - | ||
181 | -/* | ||
182 | - * === currently unused =============================================== | ||
183 | - */ | ||
184 | - | ||
185 | -svg marker#end { | ||
186 | - fill: #666; | ||
187 | - stroke: #666; | ||
188 | - stroke-width: 1.5px; | ||
189 | -} | ||
190 | - | ||
191 | -svg .legend { | ||
192 | - position: fixed; | ||
193 | -} | ||
194 | - | ||
195 | -svg .legend .category rect { | ||
196 | - stroke-width: 1px; | ||
197 | -} | ||
198 | - | ||
199 | -svg .legend .category text { | ||
200 | - fill: #000; | ||
201 | - font: 10px sans-serif; | ||
202 | - pointer-events: none; | ||
203 | -} | ||
204 | - | ||
205 | -/* | ||
206 | - * ============================================================= | ||
207 | - */ | ||
208 | - | ||
209 | -/* | ||
210 | - * Specific structural elements | ||
211 | - */ | ||
212 | - | ||
213 | -/* This is to ensure that the body does not expand to account for the | ||
214 | - flyout details pane, that is positioned "off screen". | ||
215 | - */ | ||
216 | -body { | ||
217 | - overflow: hidden; | ||
218 | -} | ||
219 | - | ||
220 | -#mast { | ||
221 | - height: 36px; | ||
222 | - padding: 4px; | ||
223 | - background-color: #bbb; | ||
224 | - vertical-align: baseline; | ||
225 | - box-shadow: 0px 2px 8px #777; | ||
226 | -} | ||
227 | - | ||
228 | -#frame { | ||
229 | - width: 100%; | ||
230 | - height: 100%; | ||
231 | - background-color: #fff; | ||
232 | -} | ||
233 | - | ||
234 | -#flyout { | ||
235 | - position: absolute; | ||
236 | - z-index: 100; | ||
237 | - display: block; | ||
238 | - top: 10%; | ||
239 | - width: 280px; | ||
240 | - right: -300px; | ||
241 | - opacity: 0; | ||
242 | - background-color: rgba(255,255,255,0.8); | ||
243 | - | ||
244 | - padding: 10px; | ||
245 | - color: black; | ||
246 | - font-size: 10pt; | ||
247 | - box-shadow: 2px 2px 16px #777; | ||
248 | -} | ||
249 | - | ||
250 | -#flyout h2 { | ||
251 | - margin: 8px 4px; | ||
252 | - color: black; | ||
253 | - vertical-align: middle; | ||
254 | -} | ||
255 | - | ||
256 | -#flyout h2 img { | ||
257 | - height: 32px; | ||
258 | - padding-right: 8px; | ||
259 | - vertical-align: middle; | ||
260 | -} | ||
261 | - | ||
262 | -#flyout p, table { | ||
263 | - margin: 4px 4px; | ||
264 | -} | ||
265 | - | ||
266 | -#flyout td.label { | ||
267 | - font-style: italic; | ||
268 | - color: #777; | ||
269 | - padding-right: 12px; | ||
270 | -} | ||
271 | - | ||
272 | -#flyout td.value { | ||
273 | - | ||
274 | -} | ||
275 | - | ||
276 | -#flyout hr { | ||
277 | - height: 1px; | ||
278 | - color: #ccc; | ||
279 | - background-color: #ccc; | ||
280 | - border: 0; | ||
281 | -} | ||
282 | - |
web/gui/src/main/webapp/OLD/onos.js
deleted
100644 → 0
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | - | ||
17 | -/* | ||
18 | - ONOS UI Framework. | ||
19 | - | ||
20 | - @author Simon Hunt | ||
21 | - */ | ||
22 | - | ||
23 | -(function ($) { | ||
24 | - 'use strict'; | ||
25 | - var tsI = new Date().getTime(), // initialize time stamp | ||
26 | - tsB; // build time stamp | ||
27 | - | ||
28 | - // attach our main function to the jQuery object | ||
29 | - $.onos = function (options) { | ||
30 | - // private namespaces | ||
31 | - var publicApi; // public api | ||
32 | - | ||
33 | - // internal state | ||
34 | - var views = {}, | ||
35 | - currentView = null, | ||
36 | - built = false; | ||
37 | - | ||
38 | - // DOM elements etc. | ||
39 | - var $mast; | ||
40 | - | ||
41 | - | ||
42 | - // various functions.................. | ||
43 | - | ||
44 | - // throw an error | ||
45 | - function throwError(msg) { | ||
46 | - // todo: maybe add tracing later | ||
47 | - throw new Error(msg); | ||
48 | - } | ||
49 | - | ||
50 | - // define all the public api functions... | ||
51 | - publicApi = { | ||
52 | - printTime: function () { | ||
53 | - console.log("the time is " + new Date()); | ||
54 | - }, | ||
55 | - | ||
56 | - addView: function (vid, cb) { | ||
57 | - views[vid] = { | ||
58 | - vid: vid, | ||
59 | - cb: cb | ||
60 | - }; | ||
61 | - // TODO: proper registration of views | ||
62 | - // for now, make the one (and only) view current.. | ||
63 | - currentView = views[vid]; | ||
64 | - } | ||
65 | - }; | ||
66 | - | ||
67 | - // function to be called from index.html to build the ONOS UI | ||
68 | - function buildOnosUi() { | ||
69 | - tsB = new Date().getTime(); | ||
70 | - tsI = tsB - tsI; // initialization duration | ||
71 | - | ||
72 | - console.log('ONOS UI initialized in ' + tsI + 'ms'); | ||
73 | - | ||
74 | - if (built) { | ||
75 | - throwError("ONOS UI already built!"); | ||
76 | - } | ||
77 | - built = true; | ||
78 | - | ||
79 | - // TODO: invoke hash navigation | ||
80 | - // --- report build errors --- | ||
81 | - | ||
82 | - // for now, invoke the one and only load function: | ||
83 | - | ||
84 | - currentView.cb.load(); | ||
85 | - } | ||
86 | - | ||
87 | - | ||
88 | - // export the api and build-UI function | ||
89 | - return { | ||
90 | - api: publicApi, | ||
91 | - buildUi: buildOnosUi | ||
92 | - }; | ||
93 | - }; | ||
94 | - | ||
95 | -}(jQuery)); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | -/* | ||
2 | - * Copyright 2014 Open Networking Laboratory | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | - | ||
17 | -/* | ||
18 | - ONOS network topology viewer - PoC version 1.0 | ||
19 | - | ||
20 | - @author Simon Hunt | ||
21 | - */ | ||
22 | - | ||
23 | -(function (onos) { | ||
24 | - 'use strict'; | ||
25 | - | ||
26 | - // configuration data | ||
27 | - var config = { | ||
28 | - useLiveData: true, | ||
29 | - debugOn: false, | ||
30 | - debug: { | ||
31 | - showNodeXY: false, | ||
32 | - showKeyHandler: true | ||
33 | - }, | ||
34 | - options: { | ||
35 | - layering: true, | ||
36 | - collisionPrevention: true, | ||
37 | - loadBackground: true | ||
38 | - }, | ||
39 | - backgroundUrl: 'img/us-map.png', | ||
40 | - data: { | ||
41 | - live: { | ||
42 | - jsonUrl: 'rs/topology/graph', | ||
43 | - detailPrefix: 'rs/topology/graph/', | ||
44 | - detailSuffix: '' | ||
45 | - }, | ||
46 | - fake: { | ||
47 | - jsonUrl: 'json/network2.json', | ||
48 | - detailPrefix: 'json/', | ||
49 | - detailSuffix: '.json' | ||
50 | - } | ||
51 | - }, | ||
52 | - iconUrl: { | ||
53 | - device: 'img/device.png', | ||
54 | - host: 'img/host.png', | ||
55 | - pkt: 'img/pkt.png', | ||
56 | - opt: 'img/opt.png' | ||
57 | - }, | ||
58 | - mastHeight: 36, | ||
59 | - force: { | ||
60 | - note: 'node.class or link.class is used to differentiate', | ||
61 | - linkDistance: { | ||
62 | - infra: 200, | ||
63 | - host: 40 | ||
64 | - }, | ||
65 | - linkStrength: { | ||
66 | - infra: 1.0, | ||
67 | - host: 1.0 | ||
68 | - }, | ||
69 | - charge: { | ||
70 | - device: -800, | ||
71 | - host: -1000 | ||
72 | - }, | ||
73 | - ticksWithoutCollisions: 50, | ||
74 | - marginLR: 20, | ||
75 | - marginTB: 20, | ||
76 | - translate: function() { | ||
77 | - return 'translate(' + | ||
78 | - config.force.marginLR + ',' + | ||
79 | - config.force.marginTB + ')'; | ||
80 | - } | ||
81 | - }, | ||
82 | - labels: { | ||
83 | - imgPad: 16, | ||
84 | - padLR: 8, | ||
85 | - padTB: 6, | ||
86 | - marginLR: 3, | ||
87 | - marginTB: 2, | ||
88 | - port: { | ||
89 | - gap: 3, | ||
90 | - width: 18, | ||
91 | - height: 14 | ||
92 | - } | ||
93 | - }, | ||
94 | - icons: { | ||
95 | - w: 32, | ||
96 | - h: 32, | ||
97 | - xoff: -12, | ||
98 | - yoff: -8 | ||
99 | - }, | ||
100 | - constraints: { | ||
101 | - ypos: { | ||
102 | - host: 0.05, | ||
103 | - switch: 0.3, | ||
104 | - roadm: 0.7 | ||
105 | - } | ||
106 | - }, | ||
107 | - hostLinkWidth: 1.0, | ||
108 | - hostRadius: 7, | ||
109 | - mouseOutTimerDelayMs: 120 | ||
110 | - }; | ||
111 | - | ||
112 | - // state variables | ||
113 | - var netView = {}, | ||
114 | - network = {}, | ||
115 | - selected = {}, | ||
116 | - highlighted = null, | ||
117 | - hovered = null, | ||
118 | - viewMode = 'showAll', | ||
119 | - portLabelsOn = false; | ||
120 | - | ||
121 | - | ||
122 | - function debug(what) { | ||
123 | - return config.debugOn && config.debug[what]; | ||
124 | - } | ||
125 | - | ||
126 | - function urlData() { | ||
127 | - return config.data[config.useLiveData ? 'live' : 'fake']; | ||
128 | - } | ||
129 | - | ||
130 | - function networkJsonUrl() { | ||
131 | - return urlData().jsonUrl; | ||
132 | - } | ||
133 | - | ||
134 | - function safeId(id) { | ||
135 | - return id.replace(/[^a-z0-9]/gi, '_'); | ||
136 | - } | ||
137 | - | ||
138 | - function detailJsonUrl(id) { | ||
139 | - var u = urlData(), | ||
140 | - encId = config.useLiveData ? encodeURIComponent(id) : safeId(id); | ||
141 | - return u.detailPrefix + encId + u.detailSuffix; | ||
142 | - } | ||
143 | - | ||
144 | - | ||
145 | - // load the topology view of the network | ||
146 | - function loadNetworkView() { | ||
147 | - // Hey, here I am, calling something on the ONOS api: | ||
148 | - api.printTime(); | ||
149 | - | ||
150 | - resize(); | ||
151 | - | ||
152 | - // go get our network data from the server... | ||
153 | - var url = networkJsonUrl(); | ||
154 | - d3.json(url , function (err, data) { | ||
155 | - if (err) { | ||
156 | - alert('Oops! Error reading JSON...\n\n' + | ||
157 | - 'URL: ' + url + '\n\n' + | ||
158 | - 'Error: ' + err.message); | ||
159 | - return; | ||
160 | - } | ||
161 | -// console.log("here is the JSON data..."); | ||
162 | -// console.log(data); | ||
163 | - | ||
164 | - network.data = data; | ||
165 | - drawNetwork(); | ||
166 | - }); | ||
167 | - | ||
168 | - // while we wait for the data, set up the handlers... | ||
169 | - setUpClickHandler(); | ||
170 | - setUpRadioButtonHandler(); | ||
171 | - setUpKeyHandler(); | ||
172 | - $(window).on('resize', resize); | ||
173 | - } | ||
174 | - | ||
175 | - function setUpClickHandler() { | ||
176 | - // click handler for "selectable" objects | ||
177 | - $(document).on('click', '.select-object', function () { | ||
178 | - // when any object of class "select-object" is clicked... | ||
179 | - var obj = network.lookup[$(this).data('id')]; | ||
180 | - if (obj) { | ||
181 | - selectObject(obj); | ||
182 | - } | ||
183 | - // stop propagation of event (I think) ... | ||
184 | - return false; | ||
185 | - }); | ||
186 | - } | ||
187 | - | ||
188 | - function setUpRadioButtonHandler() { | ||
189 | - d3.selectAll('#displayModes .radio').on('click', function () { | ||
190 | - var id = d3.select(this).attr('id'); | ||
191 | - if (id !== viewMode) { | ||
192 | - radioButton('displayModes', id); | ||
193 | - viewMode = id; | ||
194 | - doRadioAction(id); | ||
195 | - } | ||
196 | - }); | ||
197 | - } | ||
198 | - | ||
199 | - function doRadioAction(id) { | ||
200 | - showAllLayers(); | ||
201 | - if (id === 'showPkt') { | ||
202 | - showPacketLayer(); | ||
203 | - } else if (id === 'showOpt') { | ||
204 | - showOpticalLayer(); | ||
205 | - } | ||
206 | - } | ||
207 | - | ||
208 | - function showAllLayers() { | ||
209 | - network.node.classed('inactive', false); | ||
210 | - network.link.classed('inactive', false); | ||
211 | - d3.selectAll('svg .port').classed('inactive', false); | ||
212 | - d3.selectAll('svg .portText').classed('inactive', false); | ||
213 | - } | ||
214 | - | ||
215 | - function showPacketLayer() { | ||
216 | - network.node.each(function(d) { | ||
217 | - // deactivate nodes that are not hosts or switches | ||
218 | - if (d.class === 'device' && d.type !== 'switch') { | ||
219 | - d3.select(this).classed('inactive', true); | ||
220 | - } | ||
221 | - }); | ||
222 | - | ||
223 | - network.link.each(function(lnk) { | ||
224 | - // deactivate infrastructure links that have opt's as endpoints | ||
225 | - if (lnk.source.type === 'roadm' || lnk.target.type === 'roadm') { | ||
226 | - d3.select(this).classed('inactive', true); | ||
227 | - } | ||
228 | - }); | ||
229 | - | ||
230 | - // deactivate non-packet ports | ||
231 | - d3.selectAll('svg .optPort').classed('inactive', true) | ||
232 | - } | ||
233 | - | ||
234 | - function showOpticalLayer() { | ||
235 | - network.node.each(function(d) { | ||
236 | - // deactivate nodes that are not optical devices | ||
237 | - if (d.type !== 'roadm') { | ||
238 | - d3.select(this).classed('inactive', true); | ||
239 | - } | ||
240 | - }); | ||
241 | - | ||
242 | - network.link.each(function(lnk) { | ||
243 | - // deactivate infrastructure links that have opt's as endpoints | ||
244 | - if (lnk.source.type !== 'roadm' || lnk.target.type !== 'roadm') { | ||
245 | - d3.select(this).classed('inactive', true); | ||
246 | - } | ||
247 | - }); | ||
248 | - | ||
249 | - // deactivate non-packet ports | ||
250 | - d3.selectAll('svg .pktPort').classed('inactive', true) | ||
251 | - } | ||
252 | - | ||
253 | - function setUpKeyHandler() { | ||
254 | - d3.select('body') | ||
255 | - .on('keydown', function () { | ||
256 | - processKeyEvent(); | ||
257 | - if (debug('showKeyHandler')) { | ||
258 | - network.svg.append('text') | ||
259 | - .attr('x', 5) | ||
260 | - .attr('y', 15) | ||
261 | - .style('font-size', '20pt') | ||
262 | - .text('keyCode: ' + d3.event.keyCode + | ||
263 | - ' applied to : ' + contextLabel()) | ||
264 | - .transition().duration(2000) | ||
265 | - .style('font-size', '2pt') | ||
266 | - .style('fill-opacity', 0.01) | ||
267 | - .remove(); | ||
268 | - } | ||
269 | - }); | ||
270 | - } | ||
271 | - | ||
272 | - function contextLabel() { | ||
273 | - return hovered === null ? "(nothing)" : hovered.id; | ||
274 | - } | ||
275 | - | ||
276 | - function radioButton(group, id) { | ||
277 | - d3.selectAll("#" + group + " .radio").classed("active", false); | ||
278 | - d3.select("#" + group + " #" + id).classed("active", true); | ||
279 | - } | ||
280 | - | ||
281 | - function processKeyEvent() { | ||
282 | - var code = d3.event.keyCode; | ||
283 | - switch (code) { | ||
284 | - case 66: // B | ||
285 | - toggleBackground(); | ||
286 | - break; | ||
287 | - case 71: // G | ||
288 | - cycleLayout(); | ||
289 | - break; | ||
290 | - case 76: // L | ||
291 | - cycleLabels(); | ||
292 | - break; | ||
293 | - case 80: // P | ||
294 | - togglePorts(); | ||
295 | - break; | ||
296 | - case 85: // U | ||
297 | - unpin(); | ||
298 | - break; | ||
299 | - } | ||
300 | - | ||
301 | - } | ||
302 | - | ||
303 | - function toggleBackground() { | ||
304 | - var bg = d3.select('#bg'), | ||
305 | - vis = bg.style('visibility'), | ||
306 | - newvis = (vis === 'hidden') ? 'visible' : 'hidden'; | ||
307 | - bg.style('visibility', newvis); | ||
308 | - } | ||
309 | - | ||
310 | - function cycleLayout() { | ||
311 | - config.options.layering = !config.options.layering; | ||
312 | - network.force.resume(); | ||
313 | - } | ||
314 | - | ||
315 | - function cycleLabels() { | ||
316 | - console.log('Cycle Labels - context = ' + contextLabel()); | ||
317 | - } | ||
318 | - | ||
319 | - function togglePorts() { | ||
320 | - portLabelsOn = !portLabelsOn; | ||
321 | - var portVis = portLabelsOn ? 'visible' : 'hidden'; | ||
322 | - d3.selectAll('.port').style('visibility', portVis); | ||
323 | - d3.selectAll('.portText').style('visibility', portVis); | ||
324 | - } | ||
325 | - | ||
326 | - function unpin() { | ||
327 | - if (hovered) { | ||
328 | - hovered.fixed = false; | ||
329 | - findNodeFromData(hovered).classed('fixed', false); | ||
330 | - network.force.resume(); | ||
331 | - } | ||
332 | - console.log('Unpin - context = ' + contextLabel()); | ||
333 | - } | ||
334 | - | ||
335 | - | ||
336 | - // ======================================================== | ||
337 | - | ||
338 | - function drawNetwork() { | ||
339 | - $('#view').empty(); | ||
340 | - | ||
341 | - prepareNodesAndLinks(); | ||
342 | - createLayout(); | ||
343 | - console.log("\n\nHere is the augmented network object..."); | ||
344 | - console.log(network); | ||
345 | - } | ||
346 | - | ||
347 | - function prepareNodesAndLinks() { | ||
348 | - network.lookup = {}; | ||
349 | - network.nodes = []; | ||
350 | - network.links = []; | ||
351 | - | ||
352 | - var nw = network.forceWidth, | ||
353 | - nh = network.forceHeight; | ||
354 | - | ||
355 | - function yPosConstraintForNode(n) { | ||
356 | - return config.constraints.ypos[n.type || 'host']; | ||
357 | - } | ||
358 | - | ||
359 | - // Note that both 'devices' and 'hosts' get mapped into the nodes array | ||
360 | - | ||
361 | - // first, the devices... | ||
362 | - network.data.devices.forEach(function(n) { | ||
363 | - var ypc = yPosConstraintForNode(n), | ||
364 | - ix = Math.random() * 0.6 * nw + 0.2 * nw, | ||
365 | - iy = ypc * nh, | ||
366 | - node = { | ||
367 | - id: n.id, | ||
368 | - labels: n.labels, | ||
369 | - class: 'device', | ||
370 | - icon: 'device', | ||
371 | - type: n.type, | ||
372 | - x: ix, | ||
373 | - y: iy, | ||
374 | - constraint: { | ||
375 | - weight: 0.7, | ||
376 | - y: iy | ||
377 | - } | ||
378 | - }; | ||
379 | - network.lookup[n.id] = node; | ||
380 | - network.nodes.push(node); | ||
381 | - }); | ||
382 | - | ||
383 | - // then, the hosts... | ||
384 | - network.data.hosts.forEach(function(n) { | ||
385 | - var ypc = yPosConstraintForNode(n), | ||
386 | - ix = Math.random() * 0.6 * nw + 0.2 * nw, | ||
387 | - iy = ypc * nh, | ||
388 | - node = { | ||
389 | - id: n.id, | ||
390 | - labels: n.labels, | ||
391 | - class: 'host', | ||
392 | - icon: 'host', | ||
393 | - type: n.type, | ||
394 | - x: ix, | ||
395 | - y: iy, | ||
396 | - constraint: { | ||
397 | - weight: 0.7, | ||
398 | - y: iy | ||
399 | - } | ||
400 | - }; | ||
401 | - network.lookup[n.id] = node; | ||
402 | - network.nodes.push(node); | ||
403 | - }); | ||
404 | - | ||
405 | - | ||
406 | - // now, process the explicit links... | ||
407 | - network.data.links.forEach(function(lnk) { | ||
408 | - var src = network.lookup[lnk.src], | ||
409 | - dst = network.lookup[lnk.dst], | ||
410 | - id = src.id + "-" + dst.id; | ||
411 | - | ||
412 | - var link = { | ||
413 | - class: 'infra', | ||
414 | - id: id, | ||
415 | - type: lnk.type, | ||
416 | - width: lnk.linkWidth, | ||
417 | - source: src, | ||
418 | - srcPort: lnk.srcPort, | ||
419 | - target: dst, | ||
420 | - tgtPort: lnk.dstPort, | ||
421 | - strength: config.force.linkStrength.infra | ||
422 | - }; | ||
423 | - network.links.push(link); | ||
424 | - }); | ||
425 | - | ||
426 | - // finally, infer host links... | ||
427 | - network.data.hosts.forEach(function(n) { | ||
428 | - var src = network.lookup[n.id], | ||
429 | - dst = network.lookup[n.cp.device], | ||
430 | - id = src.id + "-" + dst.id; | ||
431 | - | ||
432 | - var link = { | ||
433 | - class: 'host', | ||
434 | - id: id, | ||
435 | - type: 'hostLink', | ||
436 | - width: config.hostLinkWidth, | ||
437 | - source: src, | ||
438 | - target: dst, | ||
439 | - strength: config.force.linkStrength.host | ||
440 | - }; | ||
441 | - network.links.push(link); | ||
442 | - }); | ||
443 | - } | ||
444 | - | ||
445 | - function createLayout() { | ||
446 | - | ||
447 | - var cfg = config.force; | ||
448 | - | ||
449 | - network.force = d3.layout.force() | ||
450 | - .size([network.forceWidth, network.forceHeight]) | ||
451 | - .nodes(network.nodes) | ||
452 | - .links(network.links) | ||
453 | - .linkStrength(function(d) { return cfg.linkStrength[d.class]; }) | ||
454 | - .linkDistance(function(d) { return cfg.linkDistance[d.class]; }) | ||
455 | - .charge(function(d) { return cfg.charge[d.class]; }) | ||
456 | - .on('tick', tick); | ||
457 | - | ||
458 | - network.svg = d3.select('#view').append('svg') | ||
459 | - .attr('width', netView.width) | ||
460 | - .attr('height', netView.height) | ||
461 | - .append('g') | ||
462 | - .attr('transform', config.force.translate()); | ||
463 | -// .attr('id', 'zoomable') | ||
464 | -// .call(d3.behavior.zoom().on("zoom", zoomRedraw)); | ||
465 | - | ||
466 | - network.svg.append('svg:image') | ||
467 | - .attr({ | ||
468 | - id: 'bg', | ||
469 | - width: netView.width, | ||
470 | - height: netView.height, | ||
471 | - 'xlink:href': config.backgroundUrl | ||
472 | - }) | ||
473 | - .style('visibility', | ||
474 | - config.options.loadBackground ? 'visible' : 'hidden'); | ||
475 | - | ||
476 | -// function zoomRedraw() { | ||
477 | -// d3.select("#zoomable").attr("transform", | ||
478 | -// "translate(" + d3.event.translate + ")" | ||
479 | -// + " scale(" + d3.event.scale + ")"); | ||
480 | -// } | ||
481 | - | ||
482 | - // TODO: move glow/blur stuff to util script | ||
483 | - var glow = network.svg.append('filter') | ||
484 | - .attr('x', '-50%') | ||
485 | - .attr('y', '-50%') | ||
486 | - .attr('width', '200%') | ||
487 | - .attr('height', '200%') | ||
488 | - .attr('id', 'blue-glow'); | ||
489 | - | ||
490 | - glow.append('feColorMatrix') | ||
491 | - .attr('type', 'matrix') | ||
492 | - .attr('values', '0 0 0 0 0 ' + | ||
493 | - '0 0 0 0 0 ' + | ||
494 | - '0 0 0 0 .7 ' + | ||
495 | - '0 0 0 1 0 '); | ||
496 | - | ||
497 | - glow.append('feGaussianBlur') | ||
498 | - .attr('stdDeviation', 3) | ||
499 | - .attr('result', 'coloredBlur'); | ||
500 | - | ||
501 | - glow.append('feMerge').selectAll('feMergeNode') | ||
502 | - .data(['coloredBlur', 'SourceGraphic']) | ||
503 | - .enter().append('feMergeNode') | ||
504 | - .attr('in', String); | ||
505 | - | ||
506 | - // TODO: legend (and auto adjust on scroll) | ||
507 | -// $('#view').on('scroll', function() { | ||
508 | -// | ||
509 | -// }); | ||
510 | - | ||
511 | - | ||
512 | - // TODO: move drag behavior into separate method. | ||
513 | - // == define node drag behavior... | ||
514 | - network.draggedThreshold = d3.scale.linear() | ||
515 | - .domain([0, 0.1]) | ||
516 | - .range([5, 20]) | ||
517 | - .clamp(true); | ||
518 | - | ||
519 | - function dragged(d) { | ||
520 | - var threshold = network.draggedThreshold(network.force.alpha()), | ||
521 | - dx = d.oldX - d.px, | ||
522 | - dy = d.oldY - d.py; | ||
523 | - if (Math.abs(dx) >= threshold || Math.abs(dy) >= threshold) { | ||
524 | - d.dragged = true; | ||
525 | - } | ||
526 | - return d.dragged; | ||
527 | - } | ||
528 | - | ||
529 | - network.drag = d3.behavior.drag() | ||
530 | - .origin(function(d) { return d; }) | ||
531 | - .on('dragstart', function(d) { | ||
532 | - d.oldX = d.x; | ||
533 | - d.oldY = d.y; | ||
534 | - d.dragged = false; | ||
535 | - d.fixed |= 2; | ||
536 | - }) | ||
537 | - .on('drag', function(d) { | ||
538 | - d.px = d3.event.x; | ||
539 | - d.py = d3.event.y; | ||
540 | - if (dragged(d)) { | ||
541 | - if (!network.force.alpha()) { | ||
542 | - network.force.alpha(.025); | ||
543 | - } | ||
544 | - } | ||
545 | - }) | ||
546 | - .on('dragend', function(d) { | ||
547 | - if (!dragged(d)) { | ||
548 | - selectObject(d, this); | ||
549 | - } | ||
550 | - d.fixed &= ~6; | ||
551 | - | ||
552 | - // once we've finished moving, pin the node in position, | ||
553 | - // if it is a device (not a host) | ||
554 | - if (d.class === 'device') { | ||
555 | - d.fixed = true; | ||
556 | - d3.select(this).classed('fixed', true) | ||
557 | - } | ||
558 | - }); | ||
559 | - | ||
560 | - $('#view').on('click', function(e) { | ||
561 | - if (!$(e.target).closest('.node').length) { | ||
562 | - deselectObject(); | ||
563 | - } | ||
564 | - }); | ||
565 | - | ||
566 | - // ............................................................... | ||
567 | - | ||
568 | - // add links to the display | ||
569 | - network.link = network.svg.append('g').attr('id', 'links') | ||
570 | - .selectAll('.link') | ||
571 | - .data(network.force.links(), function(d) {return d.id}) | ||
572 | - .enter().append('line') | ||
573 | - .attr('class', function(d) {return 'link ' + d.class}); | ||
574 | - | ||
575 | - network.linkSrcPort = network.svg.append('g') | ||
576 | - .attr({ | ||
577 | - id: 'srcPorts', | ||
578 | - class: 'portLayer' | ||
579 | - }); | ||
580 | - network.linkTgtPort = network.svg.append('g') | ||
581 | - .attr({ | ||
582 | - id: 'tgtPorts', | ||
583 | - class: 'portLayer' | ||
584 | - }); | ||
585 | - | ||
586 | - var portVis = portLabelsOn ? 'visible' : 'hidden', | ||
587 | - pw = config.labels.port.width, | ||
588 | - ph = config.labels.port.height; | ||
589 | - | ||
590 | - network.link.filter('.infra').each(function(d) { | ||
591 | - var srcType = d.source.type === 'roadm' ? 'optPort' : 'pktPort', | ||
592 | - tgtType = d.target.type === 'roadm' ? 'optPort' : 'pktPort'; | ||
593 | - | ||
594 | - if (d.source.type) | ||
595 | - | ||
596 | - network.linkSrcPort.append('rect').attr({ | ||
597 | - id: 'srcPort-' + safeId(d.id), | ||
598 | - class: 'port ' + srcType, | ||
599 | - width: pw, | ||
600 | - height: ph, | ||
601 | - rx: 4, | ||
602 | - ry: 4 | ||
603 | - }).style('visibility', portVis); | ||
604 | - | ||
605 | - network.linkTgtPort.append('rect').attr({ | ||
606 | - id: 'tgtPort-' + safeId(d.id), | ||
607 | - class: 'port ' + tgtType, | ||
608 | - width: pw, | ||
609 | - height: ph, | ||
610 | - rx: 4, | ||
611 | - ry: 4 | ||
612 | - }).style('visibility', portVis); | ||
613 | - | ||
614 | - network.linkSrcPort.append('text').attr({ | ||
615 | - id: 'srcText-' + safeId(d.id), | ||
616 | - class: 'portText ' + srcType | ||
617 | - }).text(d.srcPort) | ||
618 | - .style('visibility', portVis); | ||
619 | - | ||
620 | - network.linkTgtPort.append('text').attr({ | ||
621 | - id: 'tgtText-' + safeId(d.id), | ||
622 | - class: 'portText ' + tgtType | ||
623 | - }).text(d.tgtPort) | ||
624 | - .style('visibility', portVis); | ||
625 | - }); | ||
626 | - | ||
627 | - // ............................................................... | ||
628 | - | ||
629 | - // add nodes to the display | ||
630 | - network.node = network.svg.selectAll('.node') | ||
631 | - .data(network.force.nodes(), function(d) {return d.id}) | ||
632 | - .enter().append('g') | ||
633 | - .attr('class', function(d) { | ||
634 | - var cls = 'node ' + d.class; | ||
635 | - if (d.type) { | ||
636 | - cls += ' ' + d.type; | ||
637 | - } | ||
638 | - return cls; | ||
639 | - }) | ||
640 | - .attr('transform', function(d) { | ||
641 | - return translate(d.x, d.y); | ||
642 | - }) | ||
643 | - .call(network.drag) | ||
644 | - .on('mouseover', function(d) { | ||
645 | - // TODO: show tooltip | ||
646 | - if (network.mouseoutTimeout) { | ||
647 | - clearTimeout(network.mouseoutTimeout); | ||
648 | - network.mouseoutTimeout = null; | ||
649 | - } | ||
650 | - hoverObject(d); | ||
651 | - }) | ||
652 | - .on('mouseout', function(d) { | ||
653 | - // TODO: hide tooltip | ||
654 | - if (network.mouseoutTimeout) { | ||
655 | - clearTimeout(network.mouseoutTimeout); | ||
656 | - network.mouseoutTimeout = null; | ||
657 | - } | ||
658 | - network.mouseoutTimeout = setTimeout(function() { | ||
659 | - hoverObject(null); | ||
660 | - }, config.mouseOutTimerDelayMs); | ||
661 | - }); | ||
662 | - | ||
663 | - | ||
664 | - // deal with device nodes first | ||
665 | - network.nodeRect = network.node.filter('.device') | ||
666 | - .append('rect') | ||
667 | - .attr({ | ||
668 | - rx: 5, | ||
669 | - ry: 5, | ||
670 | - width: 100, | ||
671 | - height: 12 | ||
672 | - }); | ||
673 | - // note that width/height are adjusted to fit the label text | ||
674 | - // then padded, and space made for the icon. | ||
675 | - | ||
676 | - network.node.filter('.device').each(function(d) { | ||
677 | - var node = d3.select(this), | ||
678 | - icon = iconUrl(d); | ||
679 | - | ||
680 | - node.append('text') | ||
681 | - // TODO: add label cycle behavior | ||
682 | - .text(d.id) | ||
683 | - .attr('dy', '1.1em'); | ||
684 | - | ||
685 | - if (icon) { | ||
686 | - var cfg = config.icons; | ||
687 | - node.append('svg:image') | ||
688 | - .attr({ | ||
689 | - width: cfg.w, | ||
690 | - height: cfg.h, | ||
691 | - 'xlink:href': icon | ||
692 | - }); | ||
693 | - // note, icon relative positioning (x,y) is done after we have | ||
694 | - // adjusted the bounds of the rectangle... | ||
695 | - } | ||
696 | - | ||
697 | - // debug function to show the modelled x,y coordinates of nodes... | ||
698 | - if (debug('showNodeXY')) { | ||
699 | - node.select('rect').attr('fill-opacity', 0.5); | ||
700 | - node.append('circle') | ||
701 | - .attr({ | ||
702 | - class: 'debug', | ||
703 | - cx: 0, | ||
704 | - cy: 0, | ||
705 | - r: '3px' | ||
706 | - }); | ||
707 | - } | ||
708 | - }); | ||
709 | - | ||
710 | - // now process host nodes | ||
711 | - network.nodeCircle = network.node.filter('.host') | ||
712 | - .append('circle') | ||
713 | - .attr({ | ||
714 | - r: config.hostRadius | ||
715 | - }); | ||
716 | - | ||
717 | - network.node.filter('.host').each(function(d) { | ||
718 | - var node = d3.select(this), | ||
719 | - icon = iconUrl(d); | ||
720 | - | ||
721 | - // debug function to show the modelled x,y coordinates of nodes... | ||
722 | - if (debug('showNodeXY')) { | ||
723 | - node.select('circle').attr('fill-opacity', 0.5); | ||
724 | - node.append('circle') | ||
725 | - .attr({ | ||
726 | - class: 'debug', | ||
727 | - cx: 0, | ||
728 | - cy: 0, | ||
729 | - r: '3px' | ||
730 | - }); | ||
731 | - } | ||
732 | - }); | ||
733 | - | ||
734 | - // this function is scheduled to happen soon after the given thread ends | ||
735 | - setTimeout(function() { | ||
736 | - var lab = config.labels, | ||
737 | - portGap = lab.port.gap, | ||
738 | - midW = portGap + lab.port.width/ 2, | ||
739 | - midH = portGap + lab.port.height / 2; | ||
740 | - | ||
741 | - // post process the device nodes, to pad their size to fit the | ||
742 | - // label text and attach the icon to the right location. | ||
743 | - network.node.filter('.device').each(function(d) { | ||
744 | - // for every node, recompute size, padding, etc. so text fits | ||
745 | - var node = d3.select(this), | ||
746 | - text = node.select('text'), | ||
747 | - box = adjustRectToFitText(node); | ||
748 | - | ||
749 | - // now make the computed adjustment | ||
750 | - node.select('rect') | ||
751 | - .attr(box); | ||
752 | - | ||
753 | - node.select('image') | ||
754 | - .attr('x', box.x + config.icons.xoff) | ||
755 | - .attr('y', box.y + config.icons.yoff); | ||
756 | - | ||
757 | - var bounds = boundsFromBox(box), | ||
758 | - portBounds = { | ||
759 | - x1: bounds.x1 - midW, | ||
760 | - x2: bounds.x2 + midW, | ||
761 | - y1: bounds.y1 - midH, | ||
762 | - y2: bounds.y2 + midH | ||
763 | - }; | ||
764 | - | ||
765 | - // todo: clean up extent and edge work.. | ||
766 | - d.extent = { | ||
767 | - left: bounds.x1 - lab.marginLR, | ||
768 | - right: bounds.x2 + lab.marginLR, | ||
769 | - top: bounds.y1 - lab.marginTB, | ||
770 | - bottom: bounds.y2 + lab.marginTB | ||
771 | - }; | ||
772 | - | ||
773 | - d.edge = { | ||
774 | - left : new geo.LineSegment(bounds.x1, bounds.y1, bounds.x1, bounds.y2), | ||
775 | - right : new geo.LineSegment(bounds.x2, bounds.y1, bounds.x2, bounds.y2), | ||
776 | - top : new geo.LineSegment(bounds.x1, bounds.y1, bounds.x2, bounds.y1), | ||
777 | - bottom : new geo.LineSegment(bounds.x1, bounds.y2, bounds.x2, bounds.y2) | ||
778 | - }; | ||
779 | - | ||
780 | - d.portEdge = { | ||
781 | - left : new geo.LineSegment( | ||
782 | - portBounds.x1, portBounds.y1, portBounds.x1, portBounds.y2 | ||
783 | - ), | ||
784 | - right : new geo.LineSegment( | ||
785 | - portBounds.x2, portBounds.y1, portBounds.x2, portBounds.y2 | ||
786 | - ), | ||
787 | - top : new geo.LineSegment( | ||
788 | - portBounds.x1, portBounds.y1, portBounds.x2, portBounds.y1 | ||
789 | - ), | ||
790 | - bottom : new geo.LineSegment( | ||
791 | - portBounds.x1, portBounds.y2, portBounds.x2, portBounds.y2 | ||
792 | - ) | ||
793 | - }; | ||
794 | - | ||
795 | - }); | ||
796 | - | ||
797 | - network.numTicks = 0; | ||
798 | - network.preventCollisions = false; | ||
799 | - network.force.start(); | ||
800 | - for (var i = 0; i < config.force.ticksWithoutCollisions; i++) { | ||
801 | - network.force.tick(); | ||
802 | - } | ||
803 | - network.preventCollisions = true; | ||
804 | - $('#view').css('visibility', 'visible'); | ||
805 | - }); | ||
806 | - | ||
807 | - | ||
808 | - // returns the newly computed bounding box of the rectangle | ||
809 | - function adjustRectToFitText(n) { | ||
810 | - var text = n.select('text'), | ||
811 | - box = text.node().getBBox(), | ||
812 | - lab = config.labels; | ||
813 | - | ||
814 | - // not sure why n.data() returns an array of 1 element... | ||
815 | - var data = n.data()[0]; | ||
816 | - | ||
817 | - text.attr('text-anchor', 'middle') | ||
818 | - .attr('y', '-0.8em') | ||
819 | - .attr('x', lab.imgPad/2) | ||
820 | - ; | ||
821 | - | ||
822 | - // translate the bbox so that it is centered on [x,y] | ||
823 | - box.x = -box.width / 2; | ||
824 | - box.y = -box.height / 2; | ||
825 | - | ||
826 | - // add padding | ||
827 | - box.x -= (lab.padLR + lab.imgPad/2); | ||
828 | - box.width += lab.padLR * 2 + lab.imgPad; | ||
829 | - box.y -= lab.padTB; | ||
830 | - box.height += lab.padTB * 2; | ||
831 | - | ||
832 | - return box; | ||
833 | - } | ||
834 | - | ||
835 | - function boundsFromBox(box) { | ||
836 | - return { | ||
837 | - x1: box.x, | ||
838 | - y1: box.y, | ||
839 | - x2: box.x + box.width, | ||
840 | - y2: box.y + box.height | ||
841 | - }; | ||
842 | - } | ||
843 | - | ||
844 | - } | ||
845 | - | ||
846 | - function iconUrl(d) { | ||
847 | - return 'img/' + d.type + '.png'; | ||
848 | -// return config.iconUrl[d.icon]; | ||
849 | - } | ||
850 | - | ||
851 | - function translate(x, y) { | ||
852 | - return 'translate(' + x + ',' + y + ')'; | ||
853 | - } | ||
854 | - | ||
855 | - // prevents collisions amongst device nodes | ||
856 | - function preventCollisions() { | ||
857 | - var quadtree = d3.geom.quadtree(network.nodes), | ||
858 | - hrad = config.hostRadius; | ||
859 | - | ||
860 | - network.nodes.forEach(function(n) { | ||
861 | - var nx1, nx2, ny1, ny2; | ||
862 | - | ||
863 | - if (n.class === 'device') { | ||
864 | - nx1 = n.x + n.extent.left; | ||
865 | - nx2 = n.x + n.extent.right; | ||
866 | - ny1 = n.y + n.extent.top; | ||
867 | - ny2 = n.y + n.extent.bottom; | ||
868 | - | ||
869 | - } else { | ||
870 | - nx1 = n.x - hrad; | ||
871 | - nx2 = n.x + hrad; | ||
872 | - ny1 = n.y - hrad; | ||
873 | - ny2 = n.y + hrad; | ||
874 | - } | ||
875 | - | ||
876 | - quadtree.visit(function(quad, x1, y1, x2, y2) { | ||
877 | - if (quad.point && quad.point !== n) { | ||
878 | - // check if the rectangles/circles intersect | ||
879 | - var p = quad.point, | ||
880 | - px1, px2, py1, py2, ix; | ||
881 | - | ||
882 | - if (p.class === 'device') { | ||
883 | - px1 = p.x + p.extent.left; | ||
884 | - px2 = p.x + p.extent.right; | ||
885 | - py1 = p.y + p.extent.top; | ||
886 | - py2 = p.y + p.extent.bottom; | ||
887 | - | ||
888 | - } else { | ||
889 | - px1 = p.x - hrad; | ||
890 | - px2 = p.x + hrad; | ||
891 | - py1 = p.y - hrad; | ||
892 | - py2 = p.y + hrad; | ||
893 | - } | ||
894 | - | ||
895 | - ix = (px1 <= nx2 && nx1 <= px2 && py1 <= ny2 && ny1 <= py2); | ||
896 | - | ||
897 | - if (ix) { | ||
898 | - var xa1 = nx2 - px1, // shift n left , p right | ||
899 | - xa2 = px2 - nx1, // shift n right, p left | ||
900 | - ya1 = ny2 - py1, // shift n up , p down | ||
901 | - ya2 = py2 - ny1, // shift n down , p up | ||
902 | - adj = Math.min(xa1, xa2, ya1, ya2); | ||
903 | - | ||
904 | - if (adj == xa1) { | ||
905 | - n.x -= adj / 2; | ||
906 | - p.x += adj / 2; | ||
907 | - } else if (adj == xa2) { | ||
908 | - n.x += adj / 2; | ||
909 | - p.x -= adj / 2; | ||
910 | - } else if (adj == ya1) { | ||
911 | - n.y -= adj / 2; | ||
912 | - p.y += adj / 2; | ||
913 | - } else if (adj == ya2) { | ||
914 | - n.y += adj / 2; | ||
915 | - p.y -= adj / 2; | ||
916 | - } | ||
917 | - } | ||
918 | - return ix; | ||
919 | - } | ||
920 | - }); | ||
921 | - | ||
922 | - }); | ||
923 | - } | ||
924 | - | ||
925 | - function tick(e) { | ||
926 | - network.numTicks++; | ||
927 | - | ||
928 | - if (config.options.layering) { | ||
929 | - // adjust the y-coord of each node, based on y-pos constraints | ||
930 | - network.nodes.forEach(function (n) { | ||
931 | - var z = e.alpha * n.constraint.weight; | ||
932 | - if (!isNaN(n.constraint.y)) { | ||
933 | - n.y = (n.constraint.y * z + n.y * (1 - z)); | ||
934 | - } | ||
935 | - }); | ||
936 | - } | ||
937 | - | ||
938 | - if (config.options.collisionPrevention && network.preventCollisions) { | ||
939 | - preventCollisions(); | ||
940 | - } | ||
941 | - | ||
942 | - var portHalfW = config.labels.port.width / 2, | ||
943 | - portHalfH = config.labels.port.height / 2; | ||
944 | - | ||
945 | - // clip visualization of links at bounds of nodes... | ||
946 | - network.link.each(function(d) { | ||
947 | - var xs = d.source.x, | ||
948 | - ys = d.source.y, | ||
949 | - xt = d.target.x, | ||
950 | - yt = d.target.y, | ||
951 | - line = new geo.LineSegment(xs, ys, xt, yt), | ||
952 | - e, ix, | ||
953 | - exs, eys, ext, eyt, | ||
954 | - pxs, pys, pxt, pyt; | ||
955 | - | ||
956 | - if (d.class === 'host') { | ||
957 | - // no adjustment for source end of link, since hosts are dots | ||
958 | - exs = xs; | ||
959 | - eys = ys; | ||
960 | - | ||
961 | - } else { | ||
962 | - for (e in d.source.edge) { | ||
963 | - ix = line.intersect(d.source.edge[e].offset(xs, ys)); | ||
964 | - if (ix.in1 && ix.in2) { | ||
965 | - exs = ix.x; | ||
966 | - eys = ix.y; | ||
967 | - | ||
968 | - // also pick off the port label intersection | ||
969 | - ix = line.intersect(d.source.portEdge[e].offset(xs, ys)); | ||
970 | - pxs = ix.x; | ||
971 | - pys = ix.y; | ||
972 | - break; | ||
973 | - } | ||
974 | - } | ||
975 | - } | ||
976 | - | ||
977 | - for (e in d.target.edge) { | ||
978 | - ix = line.intersect(d.target.edge[e].offset(xt, yt)); | ||
979 | - if (ix.in1 && ix.in2) { | ||
980 | - ext = ix.x; | ||
981 | - eyt = ix.y; | ||
982 | - | ||
983 | - // also pick off the port label intersection | ||
984 | - ix = line.intersect(d.target.portEdge[e].offset(xt, yt)); | ||
985 | - pxt = ix.x; | ||
986 | - pyt = ix.y; | ||
987 | - break; | ||
988 | - } | ||
989 | - } | ||
990 | - | ||
991 | - // adjust the endpoints of the link's line to match rectangles | ||
992 | - var sid = safeId(d.id); | ||
993 | - d3.select(this) | ||
994 | - .attr('x1', exs) | ||
995 | - .attr('y1', eys) | ||
996 | - .attr('x2', ext) | ||
997 | - .attr('y2', eyt); | ||
998 | - | ||
999 | - d3.select('#srcPort-' + sid) | ||
1000 | - .attr('x', pxs - portHalfW) | ||
1001 | - .attr('y', pys - portHalfH); | ||
1002 | - | ||
1003 | - d3.select('#tgtPort-' + sid) | ||
1004 | - .attr('x', pxt - portHalfW) | ||
1005 | - .attr('y', pyt - portHalfH); | ||
1006 | - | ||
1007 | - // TODO: fit label rect to size of port number. | ||
1008 | - d3.select('#srcText-' + sid) | ||
1009 | - .attr('x', pxs - 5) | ||
1010 | - .attr('y', pys + 3); | ||
1011 | - | ||
1012 | - d3.select('#tgtText-' + sid) | ||
1013 | - .attr('x', pxt - 5) | ||
1014 | - .attr('y', pyt + 3); | ||
1015 | - | ||
1016 | - }); | ||
1017 | - | ||
1018 | - // position each node by translating the node (group) by x,y | ||
1019 | - network.node | ||
1020 | - .attr('transform', function(d) { | ||
1021 | - return translate(d.x, d.y); | ||
1022 | - }); | ||
1023 | - | ||
1024 | - } | ||
1025 | - | ||
1026 | - // $('#docs-close').on('click', function() { | ||
1027 | - // deselectObject(); | ||
1028 | - // return false; | ||
1029 | - // }); | ||
1030 | - | ||
1031 | - // $(document).on('click', '.select-object', function() { | ||
1032 | - // var obj = graph.data[$(this).data('name')]; | ||
1033 | - // if (obj) { | ||
1034 | - // selectObject(obj); | ||
1035 | - // } | ||
1036 | - // return false; | ||
1037 | - // }); | ||
1038 | - | ||
1039 | - function findNodeFromData(d) { | ||
1040 | - var el = null; | ||
1041 | - network.node.filter('.' + d.class).each(function(n) { | ||
1042 | - if (n.id === d.id) { | ||
1043 | - el = d3.select(this); | ||
1044 | - } | ||
1045 | - }); | ||
1046 | - return el; | ||
1047 | - } | ||
1048 | - | ||
1049 | - function selectObject(obj, el) { | ||
1050 | - var node; | ||
1051 | - if (el) { | ||
1052 | - node = d3.select(el); | ||
1053 | - } else { | ||
1054 | - network.node.each(function(d) { | ||
1055 | - if (d == obj) { | ||
1056 | - node = d3.select(el = this); | ||
1057 | - } | ||
1058 | - }); | ||
1059 | - } | ||
1060 | - if (!node) return; | ||
1061 | - | ||
1062 | - if (node.classed('selected')) { | ||
1063 | - deselectObject(); | ||
1064 | - flyinPane(null); | ||
1065 | - return; | ||
1066 | - } | ||
1067 | - deselectObject(false); | ||
1068 | - | ||
1069 | - selected = { | ||
1070 | - obj : obj, | ||
1071 | - el : el | ||
1072 | - }; | ||
1073 | - | ||
1074 | - node.classed('selected', true); | ||
1075 | - flyinPane(obj); | ||
1076 | - } | ||
1077 | - | ||
1078 | - function deselectObject(doResize) { | ||
1079 | - // Review: logic of 'resize(...)' function. | ||
1080 | - if (doResize || typeof doResize == 'undefined') { | ||
1081 | - resize(false); | ||
1082 | - } | ||
1083 | - | ||
1084 | - // deselect all nodes in the network... | ||
1085 | - network.node.classed('selected', false); | ||
1086 | - selected = {}; | ||
1087 | - flyinPane(null); | ||
1088 | - } | ||
1089 | - | ||
1090 | - function flyinPane(obj) { | ||
1091 | - var pane = d3.select('#flyout'), | ||
1092 | - url; | ||
1093 | - | ||
1094 | - if (obj) { | ||
1095 | - // go get details of the selected object from the server... | ||
1096 | - url = detailJsonUrl(obj.id); | ||
1097 | - d3.json(url, function (err, data) { | ||
1098 | - if (err) { | ||
1099 | - alert('Oops! Error reading JSON...\n\n' + | ||
1100 | - 'URL: ' + url + '\n\n' + | ||
1101 | - 'Error: ' + err.message); | ||
1102 | - return; | ||
1103 | - } | ||
1104 | -// console.log("JSON data... " + url); | ||
1105 | -// console.log(data); | ||
1106 | - | ||
1107 | - displayDetails(data, pane); | ||
1108 | - }); | ||
1109 | - | ||
1110 | - } else { | ||
1111 | - // hide pane | ||
1112 | - pane.transition().duration(750) | ||
1113 | - .style('right', '-320px') | ||
1114 | - .style('opacity', 0.0); | ||
1115 | - } | ||
1116 | - } | ||
1117 | - | ||
1118 | - function displayDetails(data, pane) { | ||
1119 | - $('#flyout').empty(); | ||
1120 | - | ||
1121 | - var title = pane.append("h2"), | ||
1122 | - table = pane.append("table"), | ||
1123 | - tbody = table.append("tbody"); | ||
1124 | - | ||
1125 | - $('<img src="img/' + data.type + '.png">').appendTo(title); | ||
1126 | - $('<span>').attr('class', 'icon').text(data.id).appendTo(title); | ||
1127 | - | ||
1128 | - | ||
1129 | - // TODO: consider using d3 data bind to TR/TD | ||
1130 | - | ||
1131 | - data.propOrder.forEach(function(p) { | ||
1132 | - if (p === '-') { | ||
1133 | - addSep(tbody); | ||
1134 | - } else { | ||
1135 | - addProp(tbody, p, data.props[p]); | ||
1136 | - } | ||
1137 | - }); | ||
1138 | - | ||
1139 | - function addSep(tbody) { | ||
1140 | - var tr = tbody.append('tr'); | ||
1141 | - $('<hr>').appendTo(tr.append('td').attr('colspan', 2)); | ||
1142 | - } | ||
1143 | - | ||
1144 | - function addProp(tbody, label, value) { | ||
1145 | - var tr = tbody.append('tr'); | ||
1146 | - | ||
1147 | - tr.append('td') | ||
1148 | - .attr('class', 'label') | ||
1149 | - .text(label + ' :'); | ||
1150 | - | ||
1151 | - tr.append('td') | ||
1152 | - .attr('class', 'value') | ||
1153 | - .text(value); | ||
1154 | - } | ||
1155 | - | ||
1156 | - // show pane | ||
1157 | - pane.transition().duration(750) | ||
1158 | - .style('right', '20px') | ||
1159 | - .style('opacity', 1.0); | ||
1160 | - } | ||
1161 | - | ||
1162 | - function highlightObject(obj) { | ||
1163 | - if (obj) { | ||
1164 | - if (obj != highlighted) { | ||
1165 | - // TODO set or clear "inactive" class on nodes, based on criteria | ||
1166 | - network.node.classed('inactive', function(d) { | ||
1167 | - // return (obj !== d && | ||
1168 | - // d.relation(obj.id)); | ||
1169 | - return (obj !== d); | ||
1170 | - }); | ||
1171 | - // TODO: same with links | ||
1172 | - network.link.classed('inactive', function(d) { | ||
1173 | - return (obj !== d.source && obj !== d.target); | ||
1174 | - }); | ||
1175 | - } | ||
1176 | - highlighted = obj; | ||
1177 | - } else { | ||
1178 | - if (highlighted) { | ||
1179 | - // clear the inactive flag (no longer suppressed visually) | ||
1180 | - network.node.classed('inactive', false); | ||
1181 | - network.link.classed('inactive', false); | ||
1182 | - } | ||
1183 | - highlighted = null; | ||
1184 | - | ||
1185 | - } | ||
1186 | - } | ||
1187 | - | ||
1188 | - function hoverObject(obj) { | ||
1189 | - if (obj) { | ||
1190 | - hovered = obj; | ||
1191 | - } else { | ||
1192 | - if (hovered) { | ||
1193 | - hovered = null; | ||
1194 | - } | ||
1195 | - } | ||
1196 | - } | ||
1197 | - | ||
1198 | - | ||
1199 | - function resize() { | ||
1200 | - netView.height = window.innerHeight - config.mastHeight; | ||
1201 | - netView.width = window.innerWidth; | ||
1202 | - $('#view') | ||
1203 | - .css('height', netView.height + 'px') | ||
1204 | - .css('width', netView.width + 'px'); | ||
1205 | - | ||
1206 | - network.forceWidth = netView.width - config.force.marginLR; | ||
1207 | - network.forceHeight = netView.height - config.force.marginTB; | ||
1208 | - } | ||
1209 | - | ||
1210 | - // ====================================================================== | ||
1211 | - // register with the UI framework | ||
1212 | - | ||
1213 | - onos.ui.addView('topo', { | ||
1214 | - load: loadNetworkView | ||
1215 | - }); | ||
1216 | - | ||
1217 | - | ||
1218 | -}(ONOS)); | ||
1219 | - |
9.27 KB
9.83 KB
1.48 KB
2.07 KB
8.83 KB
9.27 KB
28.5 KB
899 Bytes
800 Bytes
665 Bytes
991 Bytes
1.14 KB
848 Bytes
-
Please register or login to post a comment