Topo2: Implement Link Labels
JIRA Tasks; ONOS-6263

Change-Id: If0304d90e1f5d5b3aff0332271c8e9a1b3b30b38
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Badge.js b/web/gui/src/main/webapp/app/view/topo2/topo2Badge.js
new file mode 100644
index 0000000..429627e
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Badge.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017-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 -- Topo2Badge
+ A badge positioned at the top-left corner of a node
+ usage: new NodeBadge({text, icon}, DOM Element, Node);
+ */
+
+// TODO: Create a badge class
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Label.js b/web/gui/src/main/webapp/app/view/topo2/topo2Label.js
new file mode 100644
index 0000000..8a47424
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Label.js
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2017-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 -- Topo2Label
+ The base class for creating a label
+ */
+
+(function () {
+
+    // TODO: THEME
+    var defaultStyles = {
+        label: {
+            text: {
+                fill: '#000000'
+            },
+            rect: {
+                fill: '#ffffff'
+            }
+        },
+        icon: {
+            glyph: {
+                fill: '#000000'
+            },
+            rect: {
+                fill: '#ffffff'
+            }
+        }
+    };
+
+    angular.module('ovTopo2')
+        .factory('Topo2Label', [
+            'Topo2Model', 'SvgUtilService', 'IconService', 'Topo2ZoomService',
+            function (Model, sus, is, t2zs) {
+                return Model.extend({
+                    className: 'topo2-label',
+                    _iconG: {},
+                    _labelG: {},
+
+                    initialize: function (data, node, options) {
+                        this.parent = node;
+                        this.options = options || {};
+
+                        t2zs.addZoomEventListener(this.setScale.bind(this));
+                        this.render();
+                    },
+                    onChange: function (property, value, options) {
+                        if (property === 'x' || property === 'y') {
+                            this._position();
+                        }
+                    },
+
+                    setPosition: function () {},
+                    setScale: function () {},
+
+                    applyStyles: function () {
+                        var styles = _.extend({}, defaultStyles, this.get('styles'));
+
+                        if (this.get('text')) {
+                            this._labelG.text.style(styles.label.text);
+                            this._labelG.rect.style(styles.label.rect);
+                        }
+
+                        if (this.get('icon')) {
+                            this._iconG.glyph.style(styles.icon.glyph);
+                            this._iconG.rect.style(styles.icon.rect);
+                        }
+                    },
+
+                    _position: function () {
+                        this.el.style('transform', sus.translate(this.get('x') + 'px',
+                            this.get('y') + 'px'));
+                    },
+                    labelDimensions: function () {
+                        return this.content.node().getBBox();
+                    },
+                    renderText: function () {
+                        this._labelG.el = this.content.append('g')
+                            .attr('class', 'label-group');
+
+                        this._labelG.rect = this._labelG.el.append('rect');
+                        this._labelG.text = this._labelG.el.append('text')
+                            .text(this.get('text'))
+                            .attr('y', '0.4em')
+                            .style('text-anchor', 'middle');
+
+                        this._labelG.rect.attr({
+                            width: this._labelG.text.node().getBBox().width + 20,
+                            height: this._labelG.text.node().getBBox().height + 10
+                        }).style({
+                            transform: sus.translate('-50%', '-50%')
+                        });
+                    },
+                    renderIcon: function () {
+                        var bbox = this._labelG.el.node().getBBox();
+                        this.iconSize = bbox.height;
+
+                        this._iconG.el = this.content.append('g')
+                            .attr('class', 'icon-group');
+
+                        this._iconG.rect = this._iconG.el.append('rect')
+                            .attr({
+                                width: this.iconSize,
+                                height: this.iconSize
+                            });
+
+                        this._iconG.glyph = is.addDeviceIcon(this._iconG.el,
+                            this.get('icon'), this.iconSize);
+
+
+                        var iconX = (-bbox.width / 2) - this.iconSize + 'px',
+                            iconY = -this.iconSize /2  + 'px';
+                        this._iconG.el.style({
+                            transform: sus.translate(iconX, iconY)
+                        });
+                    },
+                    render: function () {
+                        this.el = this.parent.append('g')
+                            .attr('class', 'topo2-label')
+                            .style({
+                                transform: 'translate(300px, 300px)'
+                            });
+
+                        this.content = this.el.append('g')
+                            .attr('class', 'topo2-label__content');
+
+                        this.renderText();
+
+                        if (this.get('icon')) {
+                            this.renderIcon();
+                        }
+
+                        this.applyStyles();
+                        this.setPosition();
+                        this.setScale();
+                    }
+                });
+            }
+        ]);
+})();
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2LabelCollection.js b/web/gui/src/main/webapp/app/view/topo2/topo2LabelCollection.js
new file mode 100644
index 0000000..895f491
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2LabelCollection.js
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017-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 -- Topo2LabelCollection
+ A collection of any type of label (Topo2Label, Topo2Badge, Topo2LinkLabel)
+ */
+
+
+(function () {
+
+    var instance;
+
+    angular.module('ovTopo2')
+        .factory('Topo2LabelCollection', [
+            'Topo2Collection',
+            function (Collection) {
+
+                var LabelCollection = Collection.extend({
+                    initialize: function () {
+                        instance = this;
+                    }
+                });
+
+                return instance || new LabelCollection();
+            }
+        ]);
+
+
+})();
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2LinkLabel.js b/web/gui/src/main/webapp/app/view/topo2/topo2LinkLabel.js
new file mode 100644
index 0000000..6e6d7fa
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2LinkLabel.js
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017-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 -- Topo2LinkLabel
+ A label positioned at the center point of a link
+ usage: new LinkLabel({text, icon}, DOM Element, Link);
+ */
+
+(function () {
+
+    angular.module('ovTopo2')
+        .factory('Topo2LinkLabel', [
+            'Topo2Label', 'Topo2ZoomService',
+            function (Label, t2zs) {
+                return Label.extend({
+                    className: 'topo2-linklabel',
+                    maxHeight: 30,
+                    minHeight: 20,
+                    setPosition: function () {
+                        var link = this.options.link;
+                        this.set({
+                            x: (link.source.x + link.target.x) / 2,
+                            y: (link.source.y + link.target.y) / 2
+                        });
+                    },
+                    setScale: function () {
+                        this.content.style('transform',
+                            'scale(' + t2zs.adjustmentScale(20, 30) + ')');
+                    }
+                });
+            }
+        ]);
+})();
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Zoom.js b/web/gui/src/main/webapp/app/view/topo2/topo2Zoom.js
index c37c92b..3e6f12a 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Zoom.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Zoom.js
@@ -68,6 +68,19 @@
         }
     }
 
+    function adjustmentScale(min, max) {
+        var _scale = 1,
+            size = (min + max) / 2;
+
+        if (size * scale() < max) {
+            _scale = min / (size * scale());
+        } else if (size * scale() > max) {
+            _scale = min / (size * scale());
+        }
+
+        return _scale;
+    }
+
     function scale() {
         return zoomer.scale();
     }
@@ -92,6 +105,7 @@
                 removeZoomEventListener: removeZoomEventListener,
 
                 scale: scale,
+                adjustmentScale: adjustmentScale,
                 panAndZoom: panAndZoom
             };
         }]);
diff --git a/web/gui/src/main/webapp/index.html b/web/gui/src/main/webapp/index.html
index 5f3e9ff..061cd7b 100644
--- a/web/gui/src/main/webapp/index.html
+++ b/web/gui/src/main/webapp/index.html
@@ -134,6 +134,7 @@
     <script src="app/view/topo2/topo2.js"></script>
     <script src="app/view/topo2/topo2Breadcrumb.js"></script>
     <script src="app/view/topo2/topo2Background.js"></script>
+    <script src="app/view/topo2/topo2Badge.js"></script>
     <script src="app/view/topo2/topo2Collection.js"></script>
     <script src="app/view/topo2/topo2DetailsPanel.js"></script>
     <script src="app/view/topo2/topo2Device.js"></script>
@@ -144,8 +145,11 @@
     <script src="app/view/topo2/topo2HostsPanel.js"></script>
     <script src="app/view/topo2/topo2Instance.js"></script>
     <script src="app/view/topo2/topo2KeyCommands.js"></script>
+    <script src="app/view/topo2/topo2Label.js"></script>
+    <script src="app/view/topo2/topo2LabelCollection.js"></script>
     <script src="app/view/topo2/topo2Layout.js"></script>
     <script src="app/view/topo2/topo2Link.js"></script>
+    <script src="app/view/topo2/topo2LinkLabel.js"></script>
     <script src="app/view/topo2/topo2LinkPanel.js"></script>
     <script src="app/view/topo2/topo2Map.js"></script>
     <script src="app/view/topo2/topo2MapConfig.js"></script>