| /* |
| * Copyright 2016-present 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 -- Topology Force Module. |
| Visualization of the topology in an SVG layer, using a D3 Force Layout. |
| */ |
| |
| (function () { |
| 'use strict'; |
| |
| // injected refs |
| var $log, |
| wss; |
| |
| var t2is, t2rs, t2ls, t2vs, t2bcs, t2ss; |
| var svg, forceG, uplink, dim, opts, zoomer; |
| |
| // D3 Selections |
| var node; |
| |
| // ========================== Helper Functions |
| |
| function init(_svg_, _forceG_, _uplink_, _dim_, zoomer, _opts_) { |
| svg = _svg_; |
| forceG = _forceG_; |
| uplink = _uplink_; |
| dim = _dim_; |
| opts = _opts_; |
| |
| t2ls = t2ls(svg, forceG, uplink, dim, zoomer, opts); |
| t2bcs.addLayout(t2ls); |
| t2rs.layout = t2ls; |
| t2ss.init(svg, zoomer); |
| } |
| |
| function destroy() { |
| $log.debug('Destroy topo force layout'); |
| } |
| |
| // ========================== Temporary Code (to be deleted later) |
| |
| function request(dir, rid) { |
| wss.sendEvent('topo2navRegion', { |
| dir: dir, |
| rid: rid |
| }); |
| } |
| |
| function doTmpCurrentLayout(data) { |
| var topdiv = d3.select('#topo2tmp'); |
| var parentRegion = data.parent; |
| var span = topdiv.select('.parentRegion').select('span'); |
| span.text(parentRegion || '[no parent]'); |
| span.classed('nav-me', Boolean(parentRegion)); |
| } |
| |
| function doTmpCurrentRegion(data) { |
| var topdiv = d3.select('#topo2tmp'); |
| var span = topdiv.select('.thisRegion').select('span'); |
| var div; |
| |
| span.text(data.id); |
| |
| div = topdiv.select('.subRegions').select('div'); |
| data.subregions.forEach(function (r) { |
| |
| function nav() { |
| request('down', r.id); |
| } |
| |
| div.append('p') |
| .classed('nav-me', true) |
| .text(r.id) |
| .on('click', nav); |
| }); |
| |
| div = topdiv.select('.devices').select('div'); |
| data.layerOrder.forEach(function (tag, idx) { |
| var devs = data.devices[idx]; |
| devs.forEach(function (d) { |
| div.append('p') |
| .text('[' + tag + '] ' + d.id); |
| }); |
| |
| }); |
| |
| div = topdiv.select('.hosts').select('div'); |
| data.layerOrder.forEach(function (tag, idx) { |
| var hosts = data.hosts[idx]; |
| hosts.forEach(function (h) { |
| div.append('p') |
| .text('[' + tag + '] ' + h.id); |
| }); |
| }); |
| |
| div = topdiv.select('.links').select('div'); |
| var links = data.links; |
| links.forEach(function (lnk) { |
| div.append('p') |
| .text(lnk.id); |
| }); |
| } |
| |
| function doTmpPeerRegions(data) { |
| |
| } |
| |
| // ========================== Event Handlers |
| |
| function allInstances(data) { |
| $log.debug('>> topo2AllInstances event:', data); |
| doTmpCurrentLayout(data); |
| t2is.allInstances(data); |
| } |
| |
| function currentLayout(data) { |
| $log.debug('>> topo2CurrentLayout event:', data); |
| t2bcs.addBreadcrumb(data.crumbs); |
| t2rs.addLayout(data); |
| } |
| |
| function currentRegion(data) { |
| $log.debug('>> topo2CurrentRegion event:', data); |
| doTmpCurrentRegion(data); |
| t2rs.addRegion(data); |
| t2ls.createForceLayout(); |
| } |
| |
| function topo2PeerRegions(data) { |
| $log.debug('>> topo2PeerRegions event:', data); |
| doTmpPeerRegions(data); |
| } |
| |
| function modelEvent(data) { |
| $log.debug('>> topo2UiModelEvent event:', data); |
| |
| // TODO: Interpret the event and update our topo model state (if needed) |
| // To Decide: Can we assume that the server will only send events |
| // related to objects that we are currently showing? |
| // (e.g. filtered by subregion contents?) |
| t2rs.update(data); |
| } |
| |
| function showMastership(masterId) { |
| if (masterId) { |
| showMastershipFor(masterId); |
| } else { |
| restoreLayerState(); |
| } |
| } |
| |
| function restoreLayerState() { |
| // NOTE: this level of indirection required, for when we have |
| // the layer filter functionality re-implemented |
| suppressLayers(false); |
| } |
| |
| // ========================== Main Service Definition |
| |
| function showMastershipFor(id) { |
| suppressLayers(true); |
| node.each(function (n) { |
| if (n.master === id) { |
| n.el.classed('suppressedmax', false); |
| } |
| }); |
| } |
| |
| function supAmt(less) { |
| return less ? 'suppressed' : 'suppressedmax'; |
| } |
| |
| function suppressLayers(b, less) { |
| var cls = supAmt(less); |
| node.classed(cls, b); |
| // link.classed(cls, b); |
| } |
| |
| function newDim(_dim_) { |
| dim = _dim_; |
| t2vs.newDim(dim); |
| } |
| |
| // ========================== Main Service Definition |
| |
| function update(elements) { |
| angular.forEach(elements, function (el) { |
| el.update(); |
| }); |
| } |
| |
| function updateNodes() { |
| update(t2rs.regionNodes()); |
| } |
| |
| function updateLinks() { |
| update(t2rs.regionLinks()); |
| } |
| |
| function resetAllLocations() { |
| var nodes = t2rs.regionNodes(); |
| |
| angular.forEach(nodes, function (node) { |
| node.resetPosition(); |
| }); |
| |
| t2ls.update(); |
| t2ls.tick(); |
| } |
| |
| function unpin() { |
| var hovered = t2rs.filterRegionNodes(function (model) { |
| return model.get('hovered'); |
| }); |
| |
| angular.forEach(hovered, function (model) { |
| model.fixed = false; |
| model.el.classed('fixed', false); |
| }); |
| } |
| |
| angular.module('ovTopo2') |
| .factory('Topo2ForceService', [ |
| '$log', 'WebSocketService', 'Topo2InstanceService', |
| 'Topo2RegionService', 'Topo2LayoutService', 'Topo2ViewService', |
| 'Topo2BreadcrumbService', 'Topo2ZoomService', 'Topo2SelectService', |
| function (_$log_, _wss_, _t2is_, _t2rs_, _t2ls_, |
| _t2vs_, _t2bcs_, zoomService, _t2ss_) { |
| |
| $log = _$log_; |
| wss = _wss_; |
| t2is = _t2is_; |
| t2rs = _t2rs_; |
| t2ls = _t2ls_; |
| t2vs = _t2vs_; |
| t2bcs = _t2bcs_; |
| t2ss = _t2ss_; |
| |
| var onZoom = function () { |
| var nodes = [].concat( |
| t2rs.regionNodes(), |
| t2rs.regionLinks() |
| ); |
| |
| angular.forEach(nodes, function (node) { |
| node.setScale(); |
| }); |
| }; |
| |
| zoomService.addZoomEventListener(onZoom); |
| |
| return { |
| |
| init: init, |
| newDim: newDim, |
| |
| destroy: destroy, |
| topo2AllInstances: allInstances, |
| topo2CurrentLayout: currentLayout, |
| topo2CurrentRegion: currentRegion, |
| |
| topo2UiModelEvent: modelEvent, |
| |
| showMastership: showMastership, |
| topo2PeerRegions: topo2PeerRegions, |
| |
| updateNodes: updateNodes, |
| updateLinks: updateLinks, |
| resetAllLocations: resetAllLocations, |
| unpin: unpin |
| }; |
| }]); |
| })(); |