Simon Hunt
Committed by Gerrit Code Review

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
......@@ -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; }
}
}]);
}());
......
......@@ -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');
......
......@@ -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
};
}]);
......
......@@ -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');
......
......@@ -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 {
......
......@@ -21,15 +21,20 @@ describe('Controller: MastCtrl', function () {
// 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);
})
});
......
......@@ -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 @@ describe('factory: fw/util/fn.js', function() {
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 @@ describe('factory: fw/util/fn.js', function() {
});
// === 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);
});
});
......
......@@ -34,7 +34,7 @@ describe('factory: view/topo/topoForce.js', function() {
it('should define api functions', function () {
expect(fs.areFunctions(tfs, [
'initForce'
'initForce', 'resize'
])).toBeTruthy();
});
......