Simon Hunt

GUI -- Completed Show Summary panel.

- added GlyphService.addGlyph().
- added SvgUtilService.translate().

Change-Id: I0bbc51a8f1d9c24b8b4f1377236570070da6f160
/*
* Copyright 2014,2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Glyph Service -- CSS file
*/
svg .glyph {
stroke: none;
fill-rule: evenodd;
}
.light svg .glyph,
.dark svg .glyph.overlay {
fill: black;
}
.dark svg .glyph,
.light svg .glyph.overlay {
fill: white;
}
......@@ -20,9 +20,11 @@
(function () {
'use strict';
var $log,
fs,
glyphs = d3.map(),
// injected references
var $log, fs, sus;
// internal state
var glyphs = d3.map(),
msgGS = 'GlyphService.';
// ----------------------------------------------------------------------
......@@ -133,78 +135,102 @@
// ----------------------------------------------------------------------
angular.module('onosSvg')
.factory('GlyphService', ['$log', 'FnService', function (_$log_, _fs_) {
$log = _$log_;
fs = _fs_;
function clear() {
// start with a fresh map
glyphs = d3.map();
function clear() {
// start with a fresh map
glyphs = d3.map();
}
function init() {
clear();
register(birdViewBox, birdData);
register(glyphViewBox, glyphData);
register(badgeViewBox, badgeData);
}
function register(viewBox, data, overwrite) {
var dmap = d3.map(data),
dups = [],
ok;
dmap.forEach(function (key, value) {
if (!overwrite && glyphs.get(key)) {
dups.push(key);
} else {
glyphs.set(key, {id: key, vb: viewBox, d: value});
}
function init() {
clear();
register(birdViewBox, birdData);
register(glyphViewBox, glyphData);
register(badgeViewBox, badgeData);
}
function register(viewBox, data, overwrite) {
var dmap = d3.map(data),
dups = [],
ok;
dmap.forEach(function (key, value) {
if (!overwrite && glyphs.get(key)) {
dups.push(key);
} else {
glyphs.set(key, {id: key, vb: viewBox, d: value});
});
ok = (dups.length == 0);
if (!ok) {
dups.forEach(function (id) {
$log.warn(msgGS + 'register(): ID collision: "'+id+'"');
});
}
return ok;
}
function ids() {
return glyphs.keys();
}
function glyph(id) {
return glyphs.get(id);
}
// Note: defs should be a D3 selection of a single <defs> element
function loadDefs(defs, glyphIds, noClear) {
var list = fs.isA(glyphIds) || ids(),
clearCache = !noClear;
if (clearCache) {
// remove all existing content
defs.html(null);
}
// load up the requested glyphs
list.forEach(function (id) {
var g = glyph(id);
if (g) {
if (noClear) {
// quick exit if symbol is already present
if (defs.select('symbol#' + g.id).size() > 0) {
return;
}
});
ok = (dups.length == 0);
if (!ok) {
dups.forEach(function (id) {
$log.warn(msgGS + 'register(): ID collision: "'+id+'"');
});
}
return ok;
defs.append('symbol')
.attr({ id: g.id, viewBox: g.vb })
.append('path').attr('d', g.d);
}
});
}
function addGlyph(elem, glyphId, size, overlay, trans) {
var sz = size || 40,
ovr = !!overlay,
xns = fs.isA(trans),
atr = {
width: sz,
height: sz,
'class': 'glyph',
'xlink:href': '#' + glyphId
};
function ids() {
return glyphs.keys();
}
if (xns) {
atr.transform = sus.translate(trans);
}
elem.append('use').attr(atr).classed('overlay', ovr);
function glyph(id) {
return glyphs.get(id);
}
}
// Note: defs should be a D3 selection of a single <defs> element
function loadDefs(defs, glyphIds, noClear) {
var list = fs.isA(glyphIds) || ids(),
clearCache = !noClear;
// ----------------------------------------------------------------------
if (clearCache) {
// remove all existing content
defs.html(null);
}
angular.module('onosSvg')
.factory('GlyphService',
['$log', 'FnService', 'SvgUtilService',
// load up the requested glyphs
list.forEach(function (id) {
var g = glyph(id);
if (g) {
if (noClear) {
// quick exit if symbol is already present
if (defs.select('symbol#' + g.id).size() > 0) {
return;
}
}
defs.append('symbol')
.attr({ id: g.id, viewBox: g.vb })
.append('path').attr('d', g.d);
}
});
}
function (_$log_, _fs_, _sus_) {
$log = _$log_;
fs = _fs_;
sus = _sus_;
return {
clear: clear,
......@@ -212,8 +238,10 @@
register: register,
ids: ids,
glyph: glyph,
loadDefs: loadDefs
loadDefs: loadDefs,
addGlyph: addGlyph
};
}]);
}]
);
}());
......
......@@ -136,10 +136,18 @@
$log.warn('SvgUtilService: cat7 -- To Be Implemented');
}
function translate(x, y) {
if (fs.isA(x) && x.length === 2 && !y) {
return 'translate(' + x[0] + ',' + x[1] + ')';
}
return 'translate(' + x + ',' + y + ')';
}
return {
createDragBehavior: createDragBehavior,
loadGlow: loadGlow,
cat7: cat7
cat7: cat7,
translate: translate
};
}]);
}());
......
......@@ -66,6 +66,7 @@
<link rel="stylesheet" href="onos.css">
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="fw/mast/mast.css">
<link rel="stylesheet" href="fw/svg/glyph.css">
<link rel="stylesheet" href="fw/svg/icon.css">
<link rel="stylesheet" href="fw/layer/panel.css">
<link rel="stylesheet" href="fw/nav/nav.css">
......
......@@ -56,17 +56,6 @@
height: 42px;
}
#topo-p-summary svg .glyphIcon {
stroke: none;
fill-rule: evenodd;
}
.light #topo-p-summary svg .glyphIcon {
fill: black;
}
.dark #topo-p-summary svg .glyphIcon {
fill: #ddd;
}
#topo-p-summary h2 {
position: absolute;
margin: 0 4px;
......
......@@ -23,7 +23,7 @@
'use strict';
// injected refs
var $log, ps;
var $log, ps, gs;
// constants
var idSum = 'topo-p-summary',
......@@ -70,18 +70,15 @@
function populateSummary(data) {
summaryPanel.empty();
var svg = summaryPanel.append('svg').attr({
width: 40,
height: 40
}).style('background-color', 'goldenrod'),
iid = '#' + (data.type || 'unknown');
var svg = summaryPanel.append('svg'); //.style('background-color', 'goldenrod'),
//iid = '#' + (data.type || 'unknown');
var title = summaryPanel.append('h2'),
table = summaryPanel.append('table'),
tbody = table.append('tbody');
// append glyph iid to SVG // black fill
// append glyph bird to SVG // white fill
gs.addGlyph(svg, 'node', 40);
gs.addGlyph(svg, 'bird', 24, true, [8,12]);
title.text(data.id);
......@@ -103,11 +100,12 @@
angular.module('ovTopo')
.factory('TopoPanelService',
['$log', 'PanelService',
['$log', 'PanelService', 'GlyphService',
function (_$log_, _ps_) {
function (_$log_, _ps_, _gs_) {
$log = _$log_;
ps = _ps_;
gs = _gs_;
function initPanels() {
summaryPanel = ps.createPanel(idSum, panelOpts);
......
......@@ -18,7 +18,7 @@
ONOS GUI -- SVG -- Glyph Service - Unit Tests
*/
describe('factory: fw/svg/glyph.js', function() {
var $log, fs, gs, d3Elem;
var $log, fs, gs, d3Elem, svg;
var numBaseGlyphs = 13,
vbBird = '352 224 113 112',
......@@ -47,13 +47,16 @@ describe('factory: fw/svg/glyph.js', function() {
beforeEach(module('onosUtil', 'onosSvg'));
beforeEach(inject(function (_$log_, FnService, GlyphService) {
var body = d3.select('body');
$log = _$log_;
fs = FnService;
gs = GlyphService;
d3Elem = d3.select('body').append('defs').attr('id', 'myDefs');
d3Elem = body.append('defs').attr('id', 'myDefs');
svg = body.append('svg').attr('id', 'mySvg');
}));
afterEach(function () {
d3.select('#mySvg').remove();
d3.select('#myDefs').remove();
gs.clear();
});
......@@ -64,7 +67,7 @@ describe('factory: fw/svg/glyph.js', function() {
it('should define api functions', function () {
expect(fs.areFunctions(gs, [
'clear', 'init', 'register', 'ids', 'glyph', 'loadDefs'
'clear', 'init', 'register', 'ids', 'glyph', 'loadDefs', 'addGlyph'
])).toBeTruthy();
});
......@@ -246,4 +249,40 @@ describe('factory: fw/svg/glyph.js', function() {
verifyLoadedInDom('chain', vbGlyph);
verifyLoadedInDom('node', vbGlyph);
});
it('should add a glyph with default size', function () {
gs.init();
gs.addGlyph(svg, 'crown');
var what = svg.selectAll('use');
expect(what.size()).toEqual(1);
expect(what.attr('width')).toEqual('40');
expect(what.attr('height')).toEqual('40');
expect(what.attr('xlink:href')).toEqual('#crown');
expect(what.classed('glyph')).toBeTruthy();
expect(what.classed('overlay')).toBeFalsy();
});
it('should add a glyph with given size', function () {
gs.init();
gs.addGlyph(svg, 'crown', 37);
var what = svg.selectAll('use');
expect(what.size()).toEqual(1);
expect(what.attr('width')).toEqual('37');
expect(what.attr('height')).toEqual('37');
expect(what.attr('xlink:href')).toEqual('#crown');
expect(what.classed('glyph')).toBeTruthy();
expect(what.classed('overlay')).toBeFalsy();
});
it('should add a glyph marked as overlay', function () {
gs.init();
gs.addGlyph(svg, 'crown', 20, true);
var what = svg.selectAll('use');
expect(what.size()).toEqual(1);
expect(what.attr('width')).toEqual('20');
expect(what.attr('height')).toEqual('20');
expect(what.attr('xlink:href')).toEqual('#crown');
expect(what.classed('glyph')).toBeTruthy();
expect(what.classed('overlay')).toBeTruthy();
});
});
......
......@@ -39,8 +39,18 @@ describe('factory: fw/svg/svgUtil.js', function() {
it('should define api functions', function () {
expect(fs.areFunctions(sus, [
'createDragBehavior', 'loadGlow', 'cat7'
'createDragBehavior', 'loadGlow', 'cat7', 'translate'
])).toBeTruthy();
});
// TODO: add unit tests for drag behavior etc.
it('should translate from two args', function () {
expect(sus.translate(1,2)).toEqual('translate(1,2)');
});
it('should translate from an array', function () {
expect(sus.translate([3,4])).toEqual('translate(3,4)');
});
});
......