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 @@ ...@@ -20,8 +20,12 @@
20 (function () { 20 (function () {
21 'use strict'; 21 'use strict';
22 22
23 + // injected services
23 var $log; 24 var $log;
24 25
26 + // configuration
27 + var mastHeight = 36;
28 +
25 angular.module('onosMast', ['onosNav']) 29 angular.module('onosMast', ['onosNav'])
26 .controller('MastCtrl', ['$log', 'NavService', function (_$log_, ns) { 30 .controller('MastCtrl', ['$log', 'NavService', function (_$log_, ns) {
27 var self = this; 31 var self = this;
...@@ -37,6 +41,13 @@ ...@@ -37,6 +41,13 @@
37 }; 41 };
38 42
39 $log.log('MastCtrl has been created'); 43 $log.log('MastCtrl has been created');
44 + }])
45 +
46 + // also define a service to allow lookup of mast height.
47 + .factory('MastService', [function () {
48 + return {
49 + mastHeight: function () { return mastHeight; }
50 + }
40 }]); 51 }]);
41 52
42 }()); 53 }());
......
...@@ -34,9 +34,99 @@ ...@@ -34,9 +34,99 @@
34 $log = _$log_; 34 $log = _$log_;
35 fs = _fs_; 35 fs = _fs_;
36 36
37 - function createDragBehavior() { 37 + function createDragBehavior(force, selectCb, atDragEnd,
38 - $log.warn('SvgUtilService: createDragBehavior -- To Be Implemented'); 38 + dragEnabled, clickEnabled) {
39 - } 39 + var draggedThreshold = d3.scale.linear()
40 + .domain([0, 0.1])
41 + .range([5, 20])
42 + .clamp(true),
43 + drag,
44 + fSel = fs.isF(selectCb),
45 + fEnd = fs.isF(atDragEnd),
46 + fDEn = fs.isF(dragEnabled),
47 + fCEn = fs.isF(clickEnabled),
48 + bad = [];
49 +
50 + function naf(what) {
51 + return 'SvgUtilService: createDragBehavior(): ' + what +
52 + ' is not a function';
53 + }
54 +
55 + if (!fSel) {
56 + bad.push(naf('selectCb'));
57 + }
58 + if (!fEnd) {
59 + bad.push(naf('atDragEnd'));
60 + }
61 + if (!fDEn) {
62 + bad.push(naf('dragEnabled'));
63 + }
64 + if (!fCEn) {
65 + bad.push(naf('clickEnabled'));
66 + }
67 +
68 + if (bad.length) {
69 + $log.error(bad.join('\n'));
70 + return null;
71 + }
72 +
73 +
74 + function dragged(d) {
75 + var threshold = draggedThreshold(force.alpha()),
76 + dx = d.oldX - d.px,
77 + dy = d.oldY - d.py;
78 + if (Math.abs(dx) >= threshold || Math.abs(dy) >= threshold) {
79 + d.dragged = true;
80 + }
81 + return d.dragged;
82 + }
83 +
84 + drag = d3.behavior.drag()
85 + .origin(function(d) { return d; })
86 + .on('dragstart', function(d) {
87 + if (clickEnabled() || dragEnabled()) {
88 + d3.event.sourceEvent.stopPropagation();
89 +
90 + d.oldX = d.x;
91 + d.oldY = d.y;
92 + d.dragged = false;
93 + d.fixed |= 2;
94 + d.dragStarted = true;
95 + }
96 + })
97 + .on('drag', function(d) {
98 + if (dragEnabled()) {
99 + d.px = d3.event.x;
100 + d.py = d3.event.y;
101 + if (dragged(d)) {
102 + if (!force.alpha()) {
103 + force.alpha(.025);
104 + }
105 + }
106 + }
107 + })
108 + .on('dragend', function(d) {
109 + if (d.dragStarted) {
110 + d.dragStarted = false;
111 + if (!dragged(d)) {
112 + // consider this the same as a 'click'
113 + // (selection of a node)
114 + if (clickEnabled()) {
115 + selectCb(d, this);
116 + // TODO: set 'this' context instead of param
117 + }
118 + }
119 + d.fixed &= ~6;
120 +
121 + // hook at the end of a drag gesture
122 + if (dragEnabled()) {
123 + atDragEnd(d, this);
124 + // TODO: set 'this' context instead of param
125 + }
126 + }
127 + });
128 +
129 + return drag; }
40 130
41 function loadGlow() { 131 function loadGlow() {
42 $log.warn('SvgUtilService: loadGlow -- To Be Implemented'); 132 $log.warn('SvgUtilService: loadGlow -- To Be Implemented');
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
20 (function () { 20 (function () {
21 'use strict'; 21 'use strict';
22 22
23 + var $window;
24 +
23 function isF(f) { 25 function isF(f) {
24 return typeof f === 'function' ? f : null; 26 return typeof f === 'function' ? f : null;
25 } 27 }
...@@ -58,15 +60,29 @@ ...@@ -58,15 +60,29 @@
58 return true; 60 return true;
59 } 61 }
60 62
63 + // Returns width and height of window inner dimensions.
64 + // offH, offW : offset width/height are subtracted, if present
65 + function windowSize(offH, offW) {
66 + var oh = offH || 0,
67 + ow = offW || 0;
68 + return {
69 + height: $window.innerHeight - oh,
70 + width: $window.innerWidth - ow
71 + };
72 + }
73 +
61 angular.module('onosUtil') 74 angular.module('onosUtil')
62 - .factory('FnService', [function () { 75 + .factory('FnService', ['$window', function (_$window_) {
76 + $window = _$window_;
77 +
63 return { 78 return {
64 isF: isF, 79 isF: isF,
65 isA: isA, 80 isA: isA,
66 isS: isS, 81 isS: isS,
67 isO: isO, 82 isO: isO,
68 contains: contains, 83 contains: contains,
69 - areFunctions: areFunctions 84 + areFunctions: areFunctions,
85 + windowSize: windowSize
70 }; 86 };
71 }]); 87 }]);
72 88
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
28 ]; 28 ];
29 29
30 // references to injected services etc. 30 // references to injected services etc.
31 - var $log, ks, zs, gs, ms, ps, tes, tfs; 31 + var $log, fs, ks, zs, gs, ms, ps, tes, tfs;
32 32
33 // DOM elements 33 // DOM elements
34 var ovtopo, svg, defs, zoomLayer, mapG, forceG; 34 var ovtopo, svg, defs, zoomLayer, mapG, forceG;
...@@ -102,7 +102,8 @@ ...@@ -102,7 +102,8 @@
102 102
103 // callback invoked when the SVG view has been resized.. 103 // callback invoked when the SVG view has been resized..
104 function svgResized(w, h) { 104 function svgResized(w, h) {
105 - // not used now, but may be required later... 105 + $log.debug('TopoView just resized... ' + w + 'x' + h);
106 + tfs.resize(w, h);
106 } 107 }
107 108
108 // --- Background Map ------------------------------------------------ 109 // --- Background Map ------------------------------------------------
...@@ -133,7 +134,7 @@ ...@@ -133,7 +134,7 @@
133 134
134 function setUpForce() { 135 function setUpForce() {
135 forceG = zoomLayer.append('g').attr('id', 'topo-force'); 136 forceG = zoomLayer.append('g').attr('id', 'topo-force');
136 - tfs.initForce(forceG); 137 + tfs.initForce(forceG, svg.attr('width'), svg.attr('height'));
137 } 138 }
138 139
139 140
...@@ -143,13 +144,15 @@ ...@@ -143,13 +144,15 @@
143 144
144 .controller('OvTopoCtrl', [ 145 .controller('OvTopoCtrl', [
145 '$scope', '$log', '$location', '$timeout', 146 '$scope', '$log', '$location', '$timeout',
147 + 'FnService', 'MastService',
146 'KeyService', 'ZoomService', 'GlyphService', 'MapService', 148 'KeyService', 'ZoomService', 'GlyphService', 'MapService',
147 'PanelService', 'TopoEventService', 'TopoForceService', 149 'PanelService', 'TopoEventService', 'TopoForceService',
148 150
149 - function ($scope, _$log_, $loc, $timeout, 151 + function ($scope, _$log_, $loc, $timeout, _fs_, mast,
150 _ks_, _zs_, _gs_, _ms_, _ps_, _tes_, _tfs_) { 152 _ks_, _zs_, _gs_, _ms_, _ps_, _tes_, _tfs_) {
151 var self = this; 153 var self = this;
152 $log = _$log_; 154 $log = _$log_;
155 + fs = _fs_;
153 ks = _ks_; 156 ks = _ks_;
154 zs = _zs_; 157 zs = _zs_;
155 gs = _gs_; 158 gs = _gs_;
...@@ -159,7 +162,7 @@ ...@@ -159,7 +162,7 @@
159 tfs = _tfs_; 162 tfs = _tfs_;
160 163
161 self.notifyResize = function () { 164 self.notifyResize = function () {
162 - svgResized(svg.style('width'), svg.style('height')); 165 + svgResized(svg.attr('width'), svg.attr('height'));
163 }; 166 };
164 167
165 // Cleanup on destroyed scope.. 168 // Cleanup on destroyed scope..
...@@ -172,6 +175,8 @@ ...@@ -172,6 +175,8 @@
172 // svg layer and initialization of components 175 // svg layer and initialization of components
173 ovtopo = d3.select('#ov-topo'); 176 ovtopo = d3.select('#ov-topo');
174 svg = ovtopo.select('svg'); 177 svg = ovtopo.select('svg');
178 + // set the svg size to match that of the window, less the masthead
179 + svg.attr(fs.windowSize(mast.mastHeight()));
175 180
176 // bind to topo event dispatcher.. 181 // bind to topo event dispatcher..
177 evDispatcher = tes.bindDispatcher('TODO: topo-DOM-elements-here'); 182 evDispatcher = tes.bindDispatcher('TODO: topo-DOM-elements-here');
......
...@@ -96,8 +96,9 @@ ...@@ -96,8 +96,9 @@
96 // forceG is the SVG group to display the force layout in 96 // forceG is the SVG group to display the force layout in
97 // w, h are the initial dimensions of the SVG 97 // w, h are the initial dimensions of the SVG
98 // opts are, well, optional :) 98 // opts are, well, optional :)
99 - function initForce (forceG, w, h, opts) { 99 + function initForce(forceG, w, h, opts) {
100 - // TODO: create the force layout and initialize 100 + $log.debug('initForce().. WxH = ' + w + 'x' + h);
101 +
101 settings = angular.extend({}, defaultSettings, opts); 102 settings = angular.extend({}, defaultSettings, opts);
102 103
103 linkG = forceG.append('g').attr('id', 'topo-links'); 104 linkG = forceG.append('g').attr('id', 'topo-links');
...@@ -109,7 +110,7 @@ ...@@ -109,7 +110,7 @@
109 node = nodeG.selectAll('.node'); 110 node = nodeG.selectAll('.node');
110 111
111 force = d3.layout.force() 112 force = d3.layout.force()
112 - .size(w, h) 113 + .size([w, h])
113 .nodes(network.nodes) 114 .nodes(network.nodes)
114 .links(network.links) 115 .links(network.links)
115 .gravity(settings.gravity) 116 .gravity(settings.gravity)
...@@ -124,8 +125,9 @@ ...@@ -124,8 +125,9 @@
124 } 125 }
125 126
126 function resize(w, h) { 127 function resize(w, h) {
127 - force.size(w, h); 128 + force.size([w, h]);
128 // Review -- do we need to nudge the layout ? 129 // Review -- do we need to nudge the layout ?
130 +
129 } 131 }
130 132
131 return { 133 return {
......
...@@ -21,15 +21,20 @@ describe('Controller: MastCtrl', function () { ...@@ -21,15 +21,20 @@ describe('Controller: MastCtrl', function () {
21 // instantiate the masthead module 21 // instantiate the masthead module
22 beforeEach(module('onosMast')); 22 beforeEach(module('onosMast'));
23 23
24 - var $log, ctrl; 24 + var $log, ctrl, ms;
25 25
26 // we need an instance of the controller 26 // we need an instance of the controller
27 - beforeEach(inject(function(_$log_, $controller) { 27 + beforeEach(inject(function(_$log_, $controller, MastService) {
28 $log = _$log_; 28 $log = _$log_;
29 ctrl = $controller('MastCtrl'); 29 ctrl = $controller('MastCtrl');
30 + ms = MastService;
30 })); 31 }));
31 32
32 it('should start with no radio buttons', function () { 33 it('should start with no radio buttons', function () {
33 expect(ctrl.radio).toBeNull(); 34 expect(ctrl.radio).toBeNull();
34 }); 35 });
36 +
37 + it('should declare height to be 36', function () {
38 + expect(ms.mastHeight()).toBe(36);
39 + })
35 }); 40 });
......
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
18 ONOS GUI -- Util -- General Purpose Functions - Unit Tests 18 ONOS GUI -- Util -- General Purpose Functions - Unit Tests
19 */ 19 */
20 describe('factory: fw/util/fn.js', function() { 20 describe('factory: fw/util/fn.js', function() {
21 - var fs, 21 + var $window,
22 + fs,
22 someFunction = function () {}, 23 someFunction = function () {},
23 someArray = [1, 2, 3], 24 someArray = [1, 2, 3],
24 someObject = { foo: 'bar'}, 25 someObject = { foo: 'bar'},
...@@ -29,8 +30,12 @@ describe('factory: fw/util/fn.js', function() { ...@@ -29,8 +30,12 @@ describe('factory: fw/util/fn.js', function() {
29 30
30 beforeEach(module('onosUtil')); 31 beforeEach(module('onosUtil'));
31 32
32 - beforeEach(inject(function (FnService) { 33 + beforeEach(inject(function (_$window_, FnService) {
34 + $window = _$window_;
33 fs = FnService; 35 fs = FnService;
36 +
37 + $window.innerWidth = 400;
38 + $window.innerHeight = 200;
34 })); 39 }));
35 40
36 41
...@@ -186,4 +191,28 @@ describe('factory: fw/util/fn.js', function() { ...@@ -186,4 +191,28 @@ describe('factory: fw/util/fn.js', function() {
186 }); 191 });
187 192
188 193
194 + // === Tests for windowSize()
195 + it('windowSize(): noargs', function () {
196 + var dim = fs.windowSize();
197 + expect(dim.width).toEqual(400);
198 + expect(dim.height).toEqual(200);
199 + });
200 +
201 + it('windowSize(): adjust height', function () {
202 + var dim = fs.windowSize(50);
203 + expect(dim.width).toEqual(400);
204 + expect(dim.height).toEqual(150);
205 + });
206 +
207 + it('windowSize(): adjust width', function () {
208 + var dim = fs.windowSize(0, 50);
209 + expect(dim.width).toEqual(350);
210 + expect(dim.height).toEqual(200);
211 + });
212 +
213 + it('windowSize(): adjust width and height', function () {
214 + var dim = fs.windowSize(101, 201);
215 + expect(dim.width).toEqual(199);
216 + expect(dim.height).toEqual(99);
217 + });
189 }); 218 });
......
...@@ -34,7 +34,7 @@ describe('factory: view/topo/topoForce.js', function() { ...@@ -34,7 +34,7 @@ describe('factory: view/topo/topoForce.js', function() {
34 34
35 it('should define api functions', function () { 35 it('should define api functions', function () {
36 expect(fs.areFunctions(tfs, [ 36 expect(fs.areFunctions(tfs, [
37 - 'initForce' 37 + 'initForce', 'resize'
38 ])).toBeTruthy(); 38 ])).toBeTruthy();
39 }); 39 });
40 40
......