GUI -- Completed Show Summary panel.
- added GlyphService.addGlyph(). - added SvgUtilService.translate(). Change-Id: I0bbc51a8f1d9c24b8b4f1377236570070da6f160
Showing
8 changed files
with
201 additions
and
94 deletions
web/gui/src/main/webapp/app/fw/svg/glyph.css
0 → 100644
1 | +/* | ||
2 | + * Copyright 2014,2015 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 GUI -- Glyph Service -- CSS file | ||
19 | + */ | ||
20 | + | ||
21 | +svg .glyph { | ||
22 | + stroke: none; | ||
23 | + fill-rule: evenodd; | ||
24 | +} | ||
25 | + | ||
26 | +.light svg .glyph, | ||
27 | +.dark svg .glyph.overlay { | ||
28 | + fill: black; | ||
29 | +} | ||
30 | + | ||
31 | +.dark svg .glyph, | ||
32 | +.light svg .glyph.overlay { | ||
33 | + fill: white; | ||
34 | +} |
... | @@ -20,9 +20,11 @@ | ... | @@ -20,9 +20,11 @@ |
20 | (function () { | 20 | (function () { |
21 | 'use strict'; | 21 | 'use strict'; |
22 | 22 | ||
23 | - var $log, | 23 | + // injected references |
24 | - fs, | 24 | + var $log, fs, sus; |
25 | - glyphs = d3.map(), | 25 | + |
26 | + // internal state | ||
27 | + var glyphs = d3.map(), | ||
26 | msgGS = 'GlyphService.'; | 28 | msgGS = 'GlyphService.'; |
27 | 29 | ||
28 | // ---------------------------------------------------------------------- | 30 | // ---------------------------------------------------------------------- |
... | @@ -133,78 +135,102 @@ | ... | @@ -133,78 +135,102 @@ |
133 | 135 | ||
134 | // ---------------------------------------------------------------------- | 136 | // ---------------------------------------------------------------------- |
135 | 137 | ||
136 | - angular.module('onosSvg') | 138 | + function clear() { |
137 | - .factory('GlyphService', ['$log', 'FnService', function (_$log_, _fs_) { | 139 | + // start with a fresh map |
138 | - $log = _$log_; | 140 | + glyphs = d3.map(); |
139 | - fs = _fs_; | 141 | + } |
140 | - | 142 | + |
141 | - function clear() { | 143 | + function init() { |
142 | - // start with a fresh map | 144 | + clear(); |
143 | - glyphs = d3.map(); | 145 | + register(birdViewBox, birdData); |
146 | + register(glyphViewBox, glyphData); | ||
147 | + register(badgeViewBox, badgeData); | ||
148 | + } | ||
149 | + | ||
150 | + function register(viewBox, data, overwrite) { | ||
151 | + var dmap = d3.map(data), | ||
152 | + dups = [], | ||
153 | + ok; | ||
154 | + | ||
155 | + dmap.forEach(function (key, value) { | ||
156 | + if (!overwrite && glyphs.get(key)) { | ||
157 | + dups.push(key); | ||
158 | + } else { | ||
159 | + glyphs.set(key, {id: key, vb: viewBox, d: value}); | ||
144 | } | 160 | } |
145 | - | 161 | + }); |
146 | - function init() { | 162 | + ok = (dups.length == 0); |
147 | - clear(); | 163 | + if (!ok) { |
148 | - register(birdViewBox, birdData); | 164 | + dups.forEach(function (id) { |
149 | - register(glyphViewBox, glyphData); | 165 | + $log.warn(msgGS + 'register(): ID collision: "'+id+'"'); |
150 | - register(badgeViewBox, badgeData); | 166 | + }); |
151 | - } | 167 | + } |
152 | - | 168 | + return ok; |
153 | - function register(viewBox, data, overwrite) { | 169 | + } |
154 | - var dmap = d3.map(data), | 170 | + |
155 | - dups = [], | 171 | + function ids() { |
156 | - ok; | 172 | + return glyphs.keys(); |
157 | - | 173 | + } |
158 | - dmap.forEach(function (key, value) { | 174 | + |
159 | - if (!overwrite && glyphs.get(key)) { | 175 | + function glyph(id) { |
160 | - dups.push(key); | 176 | + return glyphs.get(id); |
161 | - } else { | 177 | + } |
162 | - glyphs.set(key, {id: key, vb: viewBox, d: value}); | 178 | + |
179 | + // Note: defs should be a D3 selection of a single <defs> element | ||
180 | + function loadDefs(defs, glyphIds, noClear) { | ||
181 | + var list = fs.isA(glyphIds) || ids(), | ||
182 | + clearCache = !noClear; | ||
183 | + | ||
184 | + if (clearCache) { | ||
185 | + // remove all existing content | ||
186 | + defs.html(null); | ||
187 | + } | ||
188 | + | ||
189 | + // load up the requested glyphs | ||
190 | + list.forEach(function (id) { | ||
191 | + var g = glyph(id); | ||
192 | + if (g) { | ||
193 | + if (noClear) { | ||
194 | + // quick exit if symbol is already present | ||
195 | + if (defs.select('symbol#' + g.id).size() > 0) { | ||
196 | + return; | ||
163 | } | 197 | } |
164 | - }); | ||
165 | - ok = (dups.length == 0); | ||
166 | - if (!ok) { | ||
167 | - dups.forEach(function (id) { | ||
168 | - $log.warn(msgGS + 'register(): ID collision: "'+id+'"'); | ||
169 | - }); | ||
170 | } | 198 | } |
171 | - return ok; | 199 | + defs.append('symbol') |
200 | + .attr({ id: g.id, viewBox: g.vb }) | ||
201 | + .append('path').attr('d', g.d); | ||
172 | } | 202 | } |
203 | + }); | ||
204 | + } | ||
205 | + | ||
206 | + function addGlyph(elem, glyphId, size, overlay, trans) { | ||
207 | + var sz = size || 40, | ||
208 | + ovr = !!overlay, | ||
209 | + xns = fs.isA(trans), | ||
210 | + atr = { | ||
211 | + width: sz, | ||
212 | + height: sz, | ||
213 | + 'class': 'glyph', | ||
214 | + 'xlink:href': '#' + glyphId | ||
215 | + }; | ||
173 | 216 | ||
174 | - function ids() { | 217 | + if (xns) { |
175 | - return glyphs.keys(); | 218 | + atr.transform = sus.translate(trans); |
176 | - } | 219 | + } |
220 | + elem.append('use').attr(atr).classed('overlay', ovr); | ||
177 | 221 | ||
178 | - function glyph(id) { | 222 | + } |
179 | - return glyphs.get(id); | ||
180 | - } | ||
181 | 223 | ||
182 | - // Note: defs should be a D3 selection of a single <defs> element | 224 | + // ---------------------------------------------------------------------- |
183 | - function loadDefs(defs, glyphIds, noClear) { | ||
184 | - var list = fs.isA(glyphIds) || ids(), | ||
185 | - clearCache = !noClear; | ||
186 | 225 | ||
187 | - if (clearCache) { | 226 | + angular.module('onosSvg') |
188 | - // remove all existing content | 227 | + .factory('GlyphService', |
189 | - defs.html(null); | 228 | + ['$log', 'FnService', 'SvgUtilService', |
190 | - } | ||
191 | 229 | ||
192 | - // load up the requested glyphs | 230 | + function (_$log_, _fs_, _sus_) { |
193 | - list.forEach(function (id) { | 231 | + $log = _$log_; |
194 | - var g = glyph(id); | 232 | + fs = _fs_; |
195 | - if (g) { | 233 | + sus = _sus_; |
196 | - if (noClear) { | ||
197 | - // quick exit if symbol is already present | ||
198 | - if (defs.select('symbol#' + g.id).size() > 0) { | ||
199 | - return; | ||
200 | - } | ||
201 | - } | ||
202 | - defs.append('symbol') | ||
203 | - .attr({ id: g.id, viewBox: g.vb }) | ||
204 | - .append('path').attr('d', g.d); | ||
205 | - } | ||
206 | - }); | ||
207 | - } | ||
208 | 234 | ||
209 | return { | 235 | return { |
210 | clear: clear, | 236 | clear: clear, |
... | @@ -212,8 +238,10 @@ | ... | @@ -212,8 +238,10 @@ |
212 | register: register, | 238 | register: register, |
213 | ids: ids, | 239 | ids: ids, |
214 | glyph: glyph, | 240 | glyph: glyph, |
215 | - loadDefs: loadDefs | 241 | + loadDefs: loadDefs, |
242 | + addGlyph: addGlyph | ||
216 | }; | 243 | }; |
217 | - }]); | 244 | + }] |
245 | + ); | ||
218 | 246 | ||
219 | }()); | 247 | }()); | ... | ... |
... | @@ -136,10 +136,18 @@ | ... | @@ -136,10 +136,18 @@ |
136 | $log.warn('SvgUtilService: cat7 -- To Be Implemented'); | 136 | $log.warn('SvgUtilService: cat7 -- To Be Implemented'); |
137 | } | 137 | } |
138 | 138 | ||
139 | + function translate(x, y) { | ||
140 | + if (fs.isA(x) && x.length === 2 && !y) { | ||
141 | + return 'translate(' + x[0] + ',' + x[1] + ')'; | ||
142 | + } | ||
143 | + return 'translate(' + x + ',' + y + ')'; | ||
144 | + } | ||
145 | + | ||
139 | return { | 146 | return { |
140 | createDragBehavior: createDragBehavior, | 147 | createDragBehavior: createDragBehavior, |
141 | loadGlow: loadGlow, | 148 | loadGlow: loadGlow, |
142 | - cat7: cat7 | 149 | + cat7: cat7, |
150 | + translate: translate | ||
143 | }; | 151 | }; |
144 | }]); | 152 | }]); |
145 | }()); | 153 | }()); | ... | ... |
... | @@ -66,6 +66,7 @@ | ... | @@ -66,6 +66,7 @@ |
66 | <link rel="stylesheet" href="onos.css"> | 66 | <link rel="stylesheet" href="onos.css"> |
67 | <link rel="stylesheet" href="common.css"> | 67 | <link rel="stylesheet" href="common.css"> |
68 | <link rel="stylesheet" href="fw/mast/mast.css"> | 68 | <link rel="stylesheet" href="fw/mast/mast.css"> |
69 | + <link rel="stylesheet" href="fw/svg/glyph.css"> | ||
69 | <link rel="stylesheet" href="fw/svg/icon.css"> | 70 | <link rel="stylesheet" href="fw/svg/icon.css"> |
70 | <link rel="stylesheet" href="fw/layer/panel.css"> | 71 | <link rel="stylesheet" href="fw/layer/panel.css"> |
71 | <link rel="stylesheet" href="fw/nav/nav.css"> | 72 | <link rel="stylesheet" href="fw/nav/nav.css"> | ... | ... |
... | @@ -56,17 +56,6 @@ | ... | @@ -56,17 +56,6 @@ |
56 | height: 42px; | 56 | height: 42px; |
57 | } | 57 | } |
58 | 58 | ||
59 | -#topo-p-summary svg .glyphIcon { | ||
60 | - stroke: none; | ||
61 | - fill-rule: evenodd; | ||
62 | -} | ||
63 | -.light #topo-p-summary svg .glyphIcon { | ||
64 | - fill: black; | ||
65 | -} | ||
66 | -.dark #topo-p-summary svg .glyphIcon { | ||
67 | - fill: #ddd; | ||
68 | -} | ||
69 | - | ||
70 | #topo-p-summary h2 { | 59 | #topo-p-summary h2 { |
71 | position: absolute; | 60 | position: absolute; |
72 | margin: 0 4px; | 61 | margin: 0 4px; | ... | ... |
... | @@ -23,7 +23,7 @@ | ... | @@ -23,7 +23,7 @@ |
23 | 'use strict'; | 23 | 'use strict'; |
24 | 24 | ||
25 | // injected refs | 25 | // injected refs |
26 | - var $log, ps; | 26 | + var $log, ps, gs; |
27 | 27 | ||
28 | // constants | 28 | // constants |
29 | var idSum = 'topo-p-summary', | 29 | var idSum = 'topo-p-summary', |
... | @@ -70,18 +70,15 @@ | ... | @@ -70,18 +70,15 @@ |
70 | function populateSummary(data) { | 70 | function populateSummary(data) { |
71 | summaryPanel.empty(); | 71 | summaryPanel.empty(); |
72 | 72 | ||
73 | - var svg = summaryPanel.append('svg').attr({ | 73 | + var svg = summaryPanel.append('svg'); //.style('background-color', 'goldenrod'), |
74 | - width: 40, | 74 | + //iid = '#' + (data.type || 'unknown'); |
75 | - height: 40 | ||
76 | - }).style('background-color', 'goldenrod'), | ||
77 | - iid = '#' + (data.type || 'unknown'); | ||
78 | 75 | ||
79 | var title = summaryPanel.append('h2'), | 76 | var title = summaryPanel.append('h2'), |
80 | table = summaryPanel.append('table'), | 77 | table = summaryPanel.append('table'), |
81 | tbody = table.append('tbody'); | 78 | tbody = table.append('tbody'); |
82 | 79 | ||
83 | - // append glyph iid to SVG // black fill | 80 | + gs.addGlyph(svg, 'node', 40); |
84 | - // append glyph bird to SVG // white fill | 81 | + gs.addGlyph(svg, 'bird', 24, true, [8,12]); |
85 | 82 | ||
86 | title.text(data.id); | 83 | title.text(data.id); |
87 | 84 | ||
... | @@ -103,11 +100,12 @@ | ... | @@ -103,11 +100,12 @@ |
103 | 100 | ||
104 | angular.module('ovTopo') | 101 | angular.module('ovTopo') |
105 | .factory('TopoPanelService', | 102 | .factory('TopoPanelService', |
106 | - ['$log', 'PanelService', | 103 | + ['$log', 'PanelService', 'GlyphService', |
107 | 104 | ||
108 | - function (_$log_, _ps_) { | 105 | + function (_$log_, _ps_, _gs_) { |
109 | $log = _$log_; | 106 | $log = _$log_; |
110 | ps = _ps_; | 107 | ps = _ps_; |
108 | + gs = _gs_; | ||
111 | 109 | ||
112 | function initPanels() { | 110 | function initPanels() { |
113 | summaryPanel = ps.createPanel(idSum, panelOpts); | 111 | summaryPanel = ps.createPanel(idSum, panelOpts); | ... | ... |
... | @@ -18,7 +18,7 @@ | ... | @@ -18,7 +18,7 @@ |
18 | ONOS GUI -- SVG -- Glyph Service - Unit Tests | 18 | ONOS GUI -- SVG -- Glyph Service - Unit Tests |
19 | */ | 19 | */ |
20 | describe('factory: fw/svg/glyph.js', function() { | 20 | describe('factory: fw/svg/glyph.js', function() { |
21 | - var $log, fs, gs, d3Elem; | 21 | + var $log, fs, gs, d3Elem, svg; |
22 | 22 | ||
23 | var numBaseGlyphs = 13, | 23 | var numBaseGlyphs = 13, |
24 | vbBird = '352 224 113 112', | 24 | vbBird = '352 224 113 112', |
... | @@ -47,13 +47,16 @@ describe('factory: fw/svg/glyph.js', function() { | ... | @@ -47,13 +47,16 @@ describe('factory: fw/svg/glyph.js', function() { |
47 | beforeEach(module('onosUtil', 'onosSvg')); | 47 | beforeEach(module('onosUtil', 'onosSvg')); |
48 | 48 | ||
49 | beforeEach(inject(function (_$log_, FnService, GlyphService) { | 49 | beforeEach(inject(function (_$log_, FnService, GlyphService) { |
50 | + var body = d3.select('body'); | ||
50 | $log = _$log_; | 51 | $log = _$log_; |
51 | fs = FnService; | 52 | fs = FnService; |
52 | gs = GlyphService; | 53 | gs = GlyphService; |
53 | - d3Elem = d3.select('body').append('defs').attr('id', 'myDefs'); | 54 | + d3Elem = body.append('defs').attr('id', 'myDefs'); |
55 | + svg = body.append('svg').attr('id', 'mySvg'); | ||
54 | })); | 56 | })); |
55 | 57 | ||
56 | afterEach(function () { | 58 | afterEach(function () { |
59 | + d3.select('#mySvg').remove(); | ||
57 | d3.select('#myDefs').remove(); | 60 | d3.select('#myDefs').remove(); |
58 | gs.clear(); | 61 | gs.clear(); |
59 | }); | 62 | }); |
... | @@ -64,7 +67,7 @@ describe('factory: fw/svg/glyph.js', function() { | ... | @@ -64,7 +67,7 @@ describe('factory: fw/svg/glyph.js', function() { |
64 | 67 | ||
65 | it('should define api functions', function () { | 68 | it('should define api functions', function () { |
66 | expect(fs.areFunctions(gs, [ | 69 | expect(fs.areFunctions(gs, [ |
67 | - 'clear', 'init', 'register', 'ids', 'glyph', 'loadDefs' | 70 | + 'clear', 'init', 'register', 'ids', 'glyph', 'loadDefs', 'addGlyph' |
68 | ])).toBeTruthy(); | 71 | ])).toBeTruthy(); |
69 | }); | 72 | }); |
70 | 73 | ||
... | @@ -246,4 +249,40 @@ describe('factory: fw/svg/glyph.js', function() { | ... | @@ -246,4 +249,40 @@ describe('factory: fw/svg/glyph.js', function() { |
246 | verifyLoadedInDom('chain', vbGlyph); | 249 | verifyLoadedInDom('chain', vbGlyph); |
247 | verifyLoadedInDom('node', vbGlyph); | 250 | verifyLoadedInDom('node', vbGlyph); |
248 | }); | 251 | }); |
252 | + | ||
253 | + it('should add a glyph with default size', function () { | ||
254 | + gs.init(); | ||
255 | + gs.addGlyph(svg, 'crown'); | ||
256 | + var what = svg.selectAll('use'); | ||
257 | + expect(what.size()).toEqual(1); | ||
258 | + expect(what.attr('width')).toEqual('40'); | ||
259 | + expect(what.attr('height')).toEqual('40'); | ||
260 | + expect(what.attr('xlink:href')).toEqual('#crown'); | ||
261 | + expect(what.classed('glyph')).toBeTruthy(); | ||
262 | + expect(what.classed('overlay')).toBeFalsy(); | ||
263 | + }); | ||
264 | + | ||
265 | + it('should add a glyph with given size', function () { | ||
266 | + gs.init(); | ||
267 | + gs.addGlyph(svg, 'crown', 37); | ||
268 | + var what = svg.selectAll('use'); | ||
269 | + expect(what.size()).toEqual(1); | ||
270 | + expect(what.attr('width')).toEqual('37'); | ||
271 | + expect(what.attr('height')).toEqual('37'); | ||
272 | + expect(what.attr('xlink:href')).toEqual('#crown'); | ||
273 | + expect(what.classed('glyph')).toBeTruthy(); | ||
274 | + expect(what.classed('overlay')).toBeFalsy(); | ||
275 | + }); | ||
276 | + | ||
277 | + it('should add a glyph marked as overlay', function () { | ||
278 | + gs.init(); | ||
279 | + gs.addGlyph(svg, 'crown', 20, true); | ||
280 | + var what = svg.selectAll('use'); | ||
281 | + expect(what.size()).toEqual(1); | ||
282 | + expect(what.attr('width')).toEqual('20'); | ||
283 | + expect(what.attr('height')).toEqual('20'); | ||
284 | + expect(what.attr('xlink:href')).toEqual('#crown'); | ||
285 | + expect(what.classed('glyph')).toBeTruthy(); | ||
286 | + expect(what.classed('overlay')).toBeTruthy(); | ||
287 | + }); | ||
249 | }); | 288 | }); | ... | ... |
... | @@ -39,8 +39,18 @@ describe('factory: fw/svg/svgUtil.js', function() { | ... | @@ -39,8 +39,18 @@ describe('factory: fw/svg/svgUtil.js', function() { |
39 | 39 | ||
40 | it('should define api functions', function () { | 40 | it('should define api functions', function () { |
41 | expect(fs.areFunctions(sus, [ | 41 | expect(fs.areFunctions(sus, [ |
42 | - 'createDragBehavior', 'loadGlow', 'cat7' | 42 | + 'createDragBehavior', 'loadGlow', 'cat7', 'translate' |
43 | ])).toBeTruthy(); | 43 | ])).toBeTruthy(); |
44 | }); | 44 | }); |
45 | 45 | ||
46 | + // TODO: add unit tests for drag behavior etc. | ||
47 | + | ||
48 | + it('should translate from two args', function () { | ||
49 | + expect(sus.translate(1,2)).toEqual('translate(1,2)'); | ||
50 | + }); | ||
51 | + | ||
52 | + it('should translate from an array', function () { | ||
53 | + expect(sus.translate([3,4])).toEqual('translate(3,4)'); | ||
54 | + }); | ||
55 | + | ||
46 | }); | 56 | }); | ... | ... |
-
Please register or login to post a comment