GUI -- Implemented Instance Panel.
- handling addInstance event.
Change-Id: Ic98a3291bd37ecf1155dbe1696167d0635a31972
diff --git a/web/gui/src/main/webapp/app/view/topo/topoInst.js b/web/gui/src/main/webapp/app/view/topo/topoInst.js
new file mode 100644
index 0000000..0d3a2ac
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo/topoInst.js
@@ -0,0 +1,304 @@
+/*
+ * Copyright 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 -- Topology Instances Module.
+ Defines modeling of ONOS instances.
+ */
+
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, ps, sus, gs;
+
+ // configuration
+ var instCfg = {
+ rectPad: 8,
+ nodeOx: 9,
+ nodeOy: 9,
+ nodeDim: 40,
+ birdOx: 19,
+ birdOy: 21,
+ birdDim: 21,
+ uiDy: 45,
+ titleDy: 30,
+ textYOff: 20,
+ textYSpc: 15
+ },
+ showLogicErrors = true,
+ idIns = 'topo-p-instance',
+ instOpts = {
+ edge: 'left',
+ width: 20
+ };
+
+ // internal state
+ var onosInstances,
+ onosOrder,
+ oiShowMaster,
+ oiBox;
+
+
+ // ==========================
+ // *** ADD INSTANCE ***
+
+ function addInstance(data) {
+ var id = data.id;
+
+ if (onosInstances[id]) {
+ updateInstance(data);
+ return;
+ }
+ onosInstances[id] = data;
+ onosOrder.push(data);
+ updateInstances();
+ }
+
+ function updateInstance(data) {
+ var id = data.id,
+ d = onosInstances[id];
+ if (d) {
+ angular.extend(d, data);
+ updateInstances();
+ } else {
+ logicError('updateInstance: lookup fail: ID = "' + id + '"');
+ }
+ }
+
+ function computeDim(self) {
+ var css = window.getComputedStyle(self);
+ return {
+ w: sus.stripPx(css.width),
+ h: sus.stripPx(css.height)
+ };
+ }
+
+ function clickInst(d) {
+ var el = d3.select(this),
+ aff = el.classed('affinity');
+ if (!aff) {
+ setAffinity(el, d);
+ } else {
+ cancelAffinity();
+ }
+ }
+
+ function setAffinity(el, d) {
+ d3.selectAll('.onosInst')
+ .classed('mastership', true)
+ .classed('affinity', false);
+ el.classed('affinity', true);
+
+ // TODO: suppress the layers and highlight only specific nodes...
+ //suppressLayers(true);
+ //node.each(function (n) {
+ // if (n.master === d.id) {
+ // n.el.classed('suppressed', false);
+ // }
+ //});
+ oiShowMaster = true;
+ }
+
+ function cancelAffinity() {
+ d3.selectAll('.onosInst')
+ .classed('mastership affinity', false);
+
+ // TODO: restore layer state
+ //restoreLayerState();
+ oiShowMaster = false;
+ }
+
+ function instRectAttr(dim) {
+ var pad = instCfg.rectPad;
+ return {
+ x: pad,
+ y: pad,
+ width: dim.w - pad*2,
+ height: dim.h - pad*2,
+ rx: 6
+ };
+ }
+
+ function viewBox(dim) {
+ return '0 0 ' + dim.w + ' ' + dim.h;
+ }
+
+ function attachUiBadge(svg) {
+ gs.addGlyph(svg, 'uiAttached', 30, true, [12, instCfg.uiDy])
+ .classed('badgeIcon uiBadge', true);
+ }
+
+ function instColor(id, online) {
+ // TODO: fix this..
+ //return cat7.get(id, !online, network.view.getTheme());
+ return 'blue';
+ }
+
+ // ==============================
+
+ function updateInstances() {
+ var onoses = oiBox.el().selectAll('.onosInst')
+ .data(onosOrder, function (d) { return d.id; }),
+ instDim = {w:0,h:0},
+ c = instCfg;
+
+ function nSw(n) {
+ return '# Switches: ' + n;
+ }
+
+ // operate on existing onos instances if necessary
+ onoses.each(function (d) {
+ var el = d3.select(this),
+ svg = el.select('svg');
+ instDim = computeDim(this);
+
+ // update online state
+ el.classed('online', d.online);
+
+ // update ui-attached state
+ svg.select('use.uiBadge').remove();
+ if (d.uiAttached) {
+ attachUiBadge(svg);
+ }
+
+ function updAttr(id, value) {
+ svg.select('text.instLabel.'+id).text(value);
+ }
+
+ updAttr('ip', d.ip);
+ updAttr('ns', nSw(d.switches));
+ });
+
+
+ // operate on new onos instances
+ var entering = onoses.enter()
+ .append('div')
+ .attr('class', 'onosInst')
+ .classed('online', function (d) { return d.online; })
+ .on('click', clickInst);
+
+ entering.each(function (d) {
+ var el = d3.select(this),
+ rectAttr,
+ svg;
+ instDim = computeDim(this);
+ rectAttr = instRectAttr(instDim);
+
+ svg = el.append('svg').attr({
+ width: instDim.w,
+ height: instDim.h,
+ viewBox: viewBox(instDim)
+ });
+
+ svg.append('rect').attr(rectAttr);
+
+ gs.addGlyph(svg, 'bird', 28, true, [14, 14])
+ .classed('badgeIcon', true);
+
+ if (d.uiAttached) {
+ attachUiBadge(svg);
+ }
+
+ var left = c.nodeOx + c.nodeDim,
+ len = rectAttr.width - left,
+ hlen = len / 2,
+ midline = hlen + left;
+
+ // title
+ svg.append('text')
+ .attr({
+ class: 'instTitle',
+ x: midline,
+ y: c.titleDy
+ })
+ .text(d.id);
+
+ // a couple of attributes
+ var ty = c.titleDy + c.textYOff;
+
+ function addAttr(id, label) {
+ svg.append('text').attr({
+ class: 'instLabel ' + id,
+ x: midline,
+ y: ty
+ }).text(label);
+ ty += c.textYSpc;
+ }
+
+ addAttr('ip', d.ip);
+ addAttr('ns', nSw(d.switches));
+ });
+
+ // operate on existing + new onoses here
+ // set the affinity colors...
+ onoses.each(function (d) {
+ var el = d3.select(this),
+ rect = el.select('svg').select('rect'),
+ col = instColor(d.id, d.online);
+ rect.style('fill', col);
+ });
+
+ // adjust the panel size appropriately...
+ oiBox.width(instDim.w * onosOrder.length);
+ oiBox.height(instDim.h);
+
+ // remove any outgoing instances
+ onoses.exit().remove();
+ }
+
+
+ // ==========================
+
+ function logicError(msg) {
+ if (showLogicErrors) {
+ $log.warn('TopoInstService: ' + msg);
+ }
+ }
+
+ function initInst() {
+ oiBox = ps.createPanel(idIns, instOpts);
+ oiBox.show();
+
+ onosInstances = {};
+ onosOrder = [];
+ oiShowMaster = false;
+ }
+
+ function destroyInst() {
+ ps.destroyPanel(idIns);
+ oiBox = null;
+ }
+
+ // ==========================
+
+ angular.module('ovTopo')
+ .factory('TopoInstService',
+ ['$log', 'PanelService', 'SvgUtilService', 'GlyphService',
+
+ function (_$log_, _ps_, _sus_, _gs_) {
+ $log = _$log_;
+ ps = _ps_;
+ sus = _sus_;
+ gs = _gs_;
+
+ return {
+ initInst: initInst,
+ destroyInst: destroyInst,
+ addInstance: addInstance
+ };
+ }]);
+}());