GUI -- Continued porting topology behavior over to the new codebase. WIP.
- added FnService.windowSize() function.
- added MastService and mastHeight() function.
- implemented SvgUtilService.createDragBehavior().
Change-Id: I5dae35244ab8220e1b95ddfd55b180e6adcb7a00
diff --git a/web/gui/src/main/webapp/app/fw/mast/mast.js b/web/gui/src/main/webapp/app/fw/mast/mast.js
index 6b08b1c..bdb3e67 100644
--- a/web/gui/src/main/webapp/app/fw/mast/mast.js
+++ b/web/gui/src/main/webapp/app/fw/mast/mast.js
@@ -20,8 +20,12 @@
(function () {
'use strict';
+ // injected services
var $log;
+ // configuration
+ var mastHeight = 36;
+
angular.module('onosMast', ['onosNav'])
.controller('MastCtrl', ['$log', 'NavService', function (_$log_, ns) {
var self = this;
@@ -37,6 +41,13 @@
};
$log.log('MastCtrl has been created');
+ }])
+
+ // also define a service to allow lookup of mast height.
+ .factory('MastService', [function () {
+ return {
+ mastHeight: function () { return mastHeight; }
+ }
}]);
}());
diff --git a/web/gui/src/main/webapp/app/fw/svg/svgUtil.js b/web/gui/src/main/webapp/app/fw/svg/svgUtil.js
index ef6049c..a0e0fff 100644
--- a/web/gui/src/main/webapp/app/fw/svg/svgUtil.js
+++ b/web/gui/src/main/webapp/app/fw/svg/svgUtil.js
@@ -34,9 +34,99 @@
$log = _$log_;
fs = _fs_;
- function createDragBehavior() {
- $log.warn('SvgUtilService: createDragBehavior -- To Be Implemented');
- }
+ function createDragBehavior(force, selectCb, atDragEnd,
+ dragEnabled, clickEnabled) {
+ var draggedThreshold = d3.scale.linear()
+ .domain([0, 0.1])
+ .range([5, 20])
+ .clamp(true),
+ drag,
+ fSel = fs.isF(selectCb),
+ fEnd = fs.isF(atDragEnd),
+ fDEn = fs.isF(dragEnabled),
+ fCEn = fs.isF(clickEnabled),
+ bad = [];
+
+ function naf(what) {
+ return 'SvgUtilService: createDragBehavior(): ' + what +
+ ' is not a function';
+ }
+
+ if (!fSel) {
+ bad.push(naf('selectCb'));
+ }
+ if (!fEnd) {
+ bad.push(naf('atDragEnd'));
+ }
+ if (!fDEn) {
+ bad.push(naf('dragEnabled'));
+ }
+ if (!fCEn) {
+ bad.push(naf('clickEnabled'));
+ }
+
+ if (bad.length) {
+ $log.error(bad.join('\n'));
+ return null;
+ }
+
+
+ function dragged(d) {
+ var threshold = draggedThreshold(force.alpha()),
+ dx = d.oldX - d.px,
+ dy = d.oldY - d.py;
+ if (Math.abs(dx) >= threshold || Math.abs(dy) >= threshold) {
+ d.dragged = true;
+ }
+ return d.dragged;
+ }
+
+ drag = d3.behavior.drag()
+ .origin(function(d) { return d; })
+ .on('dragstart', function(d) {
+ if (clickEnabled() || dragEnabled()) {
+ d3.event.sourceEvent.stopPropagation();
+
+ d.oldX = d.x;
+ d.oldY = d.y;
+ d.dragged = false;
+ d.fixed |= 2;
+ d.dragStarted = true;
+ }
+ })
+ .on('drag', function(d) {
+ if (dragEnabled()) {
+ d.px = d3.event.x;
+ d.py = d3.event.y;
+ if (dragged(d)) {
+ if (!force.alpha()) {
+ force.alpha(.025);
+ }
+ }
+ }
+ })
+ .on('dragend', function(d) {
+ if (d.dragStarted) {
+ d.dragStarted = false;
+ if (!dragged(d)) {
+ // consider this the same as a 'click'
+ // (selection of a node)
+ if (clickEnabled()) {
+ selectCb(d, this);
+ // TODO: set 'this' context instead of param
+ }
+ }
+ d.fixed &= ~6;
+
+ // hook at the end of a drag gesture
+ if (dragEnabled()) {
+ atDragEnd(d, this);
+ // TODO: set 'this' context instead of param
+ }
+ }
+ });
+
+ return drag; }
function loadGlow() {
$log.warn('SvgUtilService: loadGlow -- To Be Implemented');
diff --git a/web/gui/src/main/webapp/app/fw/util/fn.js b/web/gui/src/main/webapp/app/fw/util/fn.js
index 10cb6ff..932a7c6 100644
--- a/web/gui/src/main/webapp/app/fw/util/fn.js
+++ b/web/gui/src/main/webapp/app/fw/util/fn.js
@@ -20,6 +20,8 @@
(function () {
'use strict';
+ var $window;
+
function isF(f) {
return typeof f === 'function' ? f : null;
}
@@ -58,15 +60,29 @@
return true;
}
+ // Returns width and height of window inner dimensions.
+ // offH, offW : offset width/height are subtracted, if present
+ function windowSize(offH, offW) {
+ var oh = offH || 0,
+ ow = offW || 0;
+ return {
+ height: $window.innerHeight - oh,
+ width: $window.innerWidth - ow
+ };
+ }
+
angular.module('onosUtil')
- .factory('FnService', [function () {
+ .factory('FnService', ['$window', function (_$window_) {
+ $window = _$window_;
+
return {
isF: isF,
isA: isA,
isS: isS,
isO: isO,
contains: contains,
- areFunctions: areFunctions
+ areFunctions: areFunctions,
+ windowSize: windowSize
};
}]);
diff --git a/web/gui/src/main/webapp/app/view/topo/topo.js b/web/gui/src/main/webapp/app/view/topo/topo.js
index 8bff419..a22e7ba 100644
--- a/web/gui/src/main/webapp/app/view/topo/topo.js
+++ b/web/gui/src/main/webapp/app/view/topo/topo.js
@@ -28,7 +28,7 @@
];
// references to injected services etc.
- var $log, ks, zs, gs, ms, ps, tes, tfs;
+ var $log, fs, ks, zs, gs, ms, ps, tes, tfs;
// DOM elements
var ovtopo, svg, defs, zoomLayer, mapG, forceG;
@@ -102,7 +102,8 @@
// callback invoked when the SVG view has been resized..
function svgResized(w, h) {
- // not used now, but may be required later...
+ $log.debug('TopoView just resized... ' + w + 'x' + h);
+ tfs.resize(w, h);
}
// --- Background Map ------------------------------------------------
@@ -133,7 +134,7 @@
function setUpForce() {
forceG = zoomLayer.append('g').attr('id', 'topo-force');
- tfs.initForce(forceG);
+ tfs.initForce(forceG, svg.attr('width'), svg.attr('height'));
}
@@ -143,13 +144,15 @@
.controller('OvTopoCtrl', [
'$scope', '$log', '$location', '$timeout',
+ 'FnService', 'MastService',
'KeyService', 'ZoomService', 'GlyphService', 'MapService',
'PanelService', 'TopoEventService', 'TopoForceService',
- function ($scope, _$log_, $loc, $timeout,
+ function ($scope, _$log_, $loc, $timeout, _fs_, mast,
_ks_, _zs_, _gs_, _ms_, _ps_, _tes_, _tfs_) {
var self = this;
$log = _$log_;
+ fs = _fs_;
ks = _ks_;
zs = _zs_;
gs = _gs_;
@@ -159,7 +162,7 @@
tfs = _tfs_;
self.notifyResize = function () {
- svgResized(svg.style('width'), svg.style('height'));
+ svgResized(svg.attr('width'), svg.attr('height'));
};
// Cleanup on destroyed scope..
@@ -172,6 +175,8 @@
// svg layer and initialization of components
ovtopo = d3.select('#ov-topo');
svg = ovtopo.select('svg');
+ // set the svg size to match that of the window, less the masthead
+ svg.attr(fs.windowSize(mast.mastHeight()));
// bind to topo event dispatcher..
evDispatcher = tes.bindDispatcher('TODO: topo-DOM-elements-here');
diff --git a/web/gui/src/main/webapp/app/view/topo/topoForce.js b/web/gui/src/main/webapp/app/view/topo/topoForce.js
index 6c3d501..196188c 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoForce.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoForce.js
@@ -96,8 +96,9 @@
// forceG is the SVG group to display the force layout in
// w, h are the initial dimensions of the SVG
// opts are, well, optional :)
- function initForce (forceG, w, h, opts) {
- // TODO: create the force layout and initialize
+ function initForce(forceG, w, h, opts) {
+ $log.debug('initForce().. WxH = ' + w + 'x' + h);
+
settings = angular.extend({}, defaultSettings, opts);
linkG = forceG.append('g').attr('id', 'topo-links');
@@ -109,7 +110,7 @@
node = nodeG.selectAll('.node');
force = d3.layout.force()
- .size(w, h)
+ .size([w, h])
.nodes(network.nodes)
.links(network.links)
.gravity(settings.gravity)
@@ -124,8 +125,9 @@
}
function resize(w, h) {
- force.size(w, h);
+ force.size([w, h]);
// Review -- do we need to nudge the layout ?
+
}
return {
diff --git a/web/gui/src/main/webapp/tests/app/fw/mast/mast-spec.js b/web/gui/src/main/webapp/tests/app/fw/mast/mast-spec.js
index 131be1f..67fbfbb 100644
--- a/web/gui/src/main/webapp/tests/app/fw/mast/mast-spec.js
+++ b/web/gui/src/main/webapp/tests/app/fw/mast/mast-spec.js
@@ -21,15 +21,20 @@
// instantiate the masthead module
beforeEach(module('onosMast'));
- var $log, ctrl;
+ var $log, ctrl, ms;
// we need an instance of the controller
- beforeEach(inject(function(_$log_, $controller) {
+ beforeEach(inject(function(_$log_, $controller, MastService) {
$log = _$log_;
ctrl = $controller('MastCtrl');
+ ms = MastService;
}));
it('should start with no radio buttons', function () {
expect(ctrl.radio).toBeNull();
});
+
+ it('should declare height to be 36', function () {
+ expect(ms.mastHeight()).toBe(36);
+ })
});
diff --git a/web/gui/src/main/webapp/tests/app/fw/util/fn-spec.js b/web/gui/src/main/webapp/tests/app/fw/util/fn-spec.js
index 56819ae..e5b7223 100644
--- a/web/gui/src/main/webapp/tests/app/fw/util/fn-spec.js
+++ b/web/gui/src/main/webapp/tests/app/fw/util/fn-spec.js
@@ -18,7 +18,8 @@
ONOS GUI -- Util -- General Purpose Functions - Unit Tests
*/
describe('factory: fw/util/fn.js', function() {
- var fs,
+ var $window,
+ fs,
someFunction = function () {},
someArray = [1, 2, 3],
someObject = { foo: 'bar'},
@@ -29,8 +30,12 @@
beforeEach(module('onosUtil'));
- beforeEach(inject(function (FnService) {
+ beforeEach(inject(function (_$window_, FnService) {
+ $window = _$window_;
fs = FnService;
+
+ $window.innerWidth = 400;
+ $window.innerHeight = 200;
}));
@@ -186,4 +191,28 @@
});
+ // === Tests for windowSize()
+ it('windowSize(): noargs', function () {
+ var dim = fs.windowSize();
+ expect(dim.width).toEqual(400);
+ expect(dim.height).toEqual(200);
+ });
+
+ it('windowSize(): adjust height', function () {
+ var dim = fs.windowSize(50);
+ expect(dim.width).toEqual(400);
+ expect(dim.height).toEqual(150);
+ });
+
+ it('windowSize(): adjust width', function () {
+ var dim = fs.windowSize(0, 50);
+ expect(dim.width).toEqual(350);
+ expect(dim.height).toEqual(200);
+ });
+
+ it('windowSize(): adjust width and height', function () {
+ var dim = fs.windowSize(101, 201);
+ expect(dim.width).toEqual(199);
+ expect(dim.height).toEqual(99);
+ });
});
diff --git a/web/gui/src/main/webapp/tests/app/view/topo/topoForce-spec.js b/web/gui/src/main/webapp/tests/app/view/topo/topoForce-spec.js
index e5f0073..f8b4e66 100644
--- a/web/gui/src/main/webapp/tests/app/view/topo/topoForce-spec.js
+++ b/web/gui/src/main/webapp/tests/app/view/topo/topoForce-spec.js
@@ -34,7 +34,7 @@
it('should define api functions', function () {
expect(fs.areFunctions(tfs, [
- 'initForce'
+ 'initForce', 'resize'
])).toBeTruthy();
});