topo2NodeModel.js 3.95 KB
/*
 * 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 Layout Module.
 Module that contains the d3.force.layout logic
 */

(function () {
    'use strict';

    var randomService;
    var fn;

    //internal state;
    var defaultLinkType = 'direct',
        nearDist = 15;

    function positionNode(node, forUpdate) {

        var meta = node.metaUi,
            x = meta && meta.x,
            y = meta && meta.y,
            dim = [800, 600],
            xy;

        // if the device contains explicit LONG/LAT data, use that to position
        if (setLongLat(node)) {
            //indicate we want to update cached meta data...
            return true;
        }

        // else if we have [x,y] cached in meta data, use that...
        if (x !== undefined && y !== undefined) {
            node.fixed = true;
            node.px = node.x = x;
            node.py = node.y = y;
            return;
        }

        // if this is a node update (not a node add).. skip randomizer
        if (forUpdate) {
            return;
        }

        // Note: Placing incoming unpinned nodes at exactly the same point
        //        (center of the view) causes them to explode outwards when
        //        the force layout kicks in. So, we spread them out a bit
        //        initially, to provide a more serene layout convergence.
        //       Additionally, if the node is a host, we place it near
        //        the device it is connected to.

        function rand() {
            return {
                x: randomService.randDim(dim[0]),
                y: randomService.randDim(dim[1])
            };
        }

        function near(node) {
            return {
                x: node.x + nearDist + randomService.spread(nearDist),
                y: node.y + nearDist + randomService.spread(nearDist)
            };
        }

        function getDevice(cp) {
            // console.log(cp);
            // var d = lu[cp.device];
            // return d || rand();
            return rand();
        }

        xy = (node.class === 'host') ? near(getDevice(node.cp)) : rand();
        angular.extend(node, xy);
    }

    function setLongLat(node) {
        var loc = node.location,
            coord;

        if (loc && loc.type === 'lnglat') {
            coord = [0, 0];
            node.fixed = true;
            node.px = node.x = coord[0];
            node.py = node.y = coord[1];
            return true;
        }
    }

    angular.module('ovTopo2')
    .factory('Topo2NodeModel',
        ['Topo2Model', 'FnService',  'RandomService',
        function (Model, _fn_, _RandomService_) {

            randomService = _RandomService_;
            fn = _fn_;

            return Model.extend({
                initialize: function () {
                    this.node = this.createNode();
                },
                svgClassName: function () {
                    return fn.classNames('node', this.nodeType, this.get('type'), {
                        online: this.get('online')
                    });
                },
                createNode: function () {

                    var node = angular.extend({}, this.attributes);

                    // Augment as needed...
                    node.class = this.nodeType;
                    node.svgClass = this.svgClassName();
                    positionNode(node);
                    return node;
                }
            });
        }]
    );
})();