前端开发框架总结之利用Jtopo实现网络拓扑功能(一)

                      前端开发框架总结之利用Jtopo实现网络拓扑功能(一)

前言:

    前段时间由于项目需要实现一个网络设备拓扑管理的功能,经过一番比较,最终选择了利用JTopo插件来实现相关功能。首先JTopo是免费的,其次官网上的一些拓扑示例还算比较全面,能覆盖大部分拓扑场景,再次个人认为JTopo从功能定位和API设计及实现来讲还是很清晰且简洁的,比较容易理解和上手使用。基于这三点原因加入了JTopo的二次开发大军。

在Jtopo的二次开发过程中,有一些使用的心得再次分享出来,供大家参考。


  • 拓扑工具栏

为了实现一个易用的拓扑管理功能,工具栏是必不可少的。在官网的示例中,使用了一个Toolbar的插件,查看其实现无非是简单布局+JTopo基础api的调用,只是样式实在太丑。因此在实际项目中,如果你想实现一个漂亮的风格一致的拓扑工具栏,那还是完全自己实现把。

  • 拓扑结点的生成

使用js创建一个拓扑结点这个官方demo中已经很详细了,我们使用API可以设置结点的background、size、text、image、location、以及字体样式等基本属性,另外还可以给结点自定义属性。

但是在实际的使用场景中,初始是没有拓扑结点的,我们需要通过一定的用户交互操作来生成所需要的拓扑结点。这里交互方式有很多种,比如直接拖拽页面元素到画布以生成相应结点,再比如可以拓扑用户填写结点信息后直接生成拓扑结点等等。在我的项目中为了兼容各种初始场景和操作方便,采用了通用组件库拖拽和树型结构的设备树拖拽以生成拓扑结点的方式。

组件库的拖拽功能主要的使用的技术要点包括HTML5的draggables属性及其相应事件监听和JTopo结点相关API。这其中主要有drop、dragover、dragstart事件的监听。另外此功能的实现有几个细节:

1、可以利用div的"data-*"自定义属性来标识被拖拽的元素的特殊属性。

2、可以利用event.dataTransfer.setData('text',e.target.dataset.type)方法给拖拽事件附件一些想要传递的数据,以此我们可以根据这些值决定最终生成的拓扑的image、text等属性。注:此处的key值需要用text,否则IE会有兼容性bug。

3、必须要监听dragover属性。且使用preventDefault方法组织浏览器默认行为,否则无法监听到drop事件。

4、拓扑元素的生成,需要注意新生成的元素的location的设置。我们可以使用drop事件的event的一些属性,结合scene的translate、scale等值来计算出想要的位置。这里要注意画布缩放的场景可以会带来的位置不准确。每个人的页面布局方式不同可以计算方式也不一样,但是使用的属性和计算逻辑是大差不差的。

组件库布局代码片段:

{{x.name}}

js代码片段:

    function onShortcurDrag(e) {
        e.dataTransfer.setData("text",e.target.dataset.type);
    }

    function onShortcutDrop(event) {
        event.preventDefault();
        var type = event.dataTransfer.getData('text');

        if(type){

            var shortcut;
            $scope.shortcuts.forEach(function (item) {
                if(item.type == type){
                    shortcut = item;
                }
            });

            if(shortcut){

                //var node = new JTopo.Node(shortcut.name);
                var node = new JTopo.Node('点击右键关联设备');

                console.log("event,X:" + event.x + ",y:" + event.y);
                console.log("event,tX:" + event.tx + ",ty:" + event.ty);
                console.log("event,pageX:" + event.pageX + ",pageY:" + event.pageY);
                console.log("event,offsetX:" + event.offsetX + ",offsetY:" + event.offsetY);
                console.log("event,clientX:" + event.clientX + ",clientY:" + event.clientY);
                console.log("event,screenX:" + event.screenX + ",screenY:" + event.screenX);
                console.log("stage.scaleX:" + stage.scaleX);

                var coordinate =  calcLocation(event.offsetX - 25 - scene.translateX, event.offsetY - 25 - scene.translateY);
                node.setLocation(coordinate.x, coordinate.y);
                node.setImage(shortcut.topo);
                node.setSize(50,50);
                node.fontColor = '100,105,116';
                node.type = shortcut.type;
                node.virtualId = new Date().getTime();

                node.addEventListener('mousedrag',nodeMouseDrag);
                node.addEventListener('mouseup',nodeMouseUp);
                node.addEventListener('dbclick',nodeDbClick);
                node.addEventListener('click',nodeClick);

                scene.add(node);
                currentDragNode = node;
            }
        }

    }

    function onShortcutDragOver(e) {
        //此处不可少,否则会监听不到drop事件。
        e.preventDefault();
    }

    $scope.onShortcutLoaded = function () {

        //绑定dragstart事件。
        $scope.shortcuts.forEach(function (shortcut) {
            var elem = document.getElementById(shortcut.id);
            elem.addEventListener('dragstart',onShortcurDrag);
        });

        //绑定drop事件。
        var elem = document.getElementById("canvas");
        elem.addEventListener('drop',onShortcutDrop);
        elem.addEventListener('dragover',onShortcutDragOver);

    }

另一种是利用设备树的拖拽直接生成拓扑结点。设备树的实现使用了zTree插件。这种方式跟组件库的思路相似只不过是利用的ztree的一些时间监听而已。

js代码片段

    function dropTree2Dom(event, treeId, treeNodes, targetNode, moveType) {

        if(event.target && event.target.id == 'canvas'){

            console.log("dropTree2Dom:" + treeNodes);

            var node = new JTopo.Node(treeNodes[0].name);

            console.log("event,X:" + event.x + ",y:" + event.y);
            console.log("event,tX:" + event.tx + ",ty:" + event.ty);
            console.log("event,pageX:" + event.pageX + ",pageY:" + event.pageY);
            console.log("event,offsetX:" + event.offsetX + ",offsetY:" + event.offsetY);
            console.log("event,clientX:" + event.clientX + ",clientY:" + event.clientY);
            console.log("event,screenX:" + event.screenX + ",screenY:" + event.screenX);

            console.log("stage.scaleX:" + stage.scaleX);

            //node.setLocation(event.offsetX - 25 - scene.translateX, event.offsetY - 25 - scene.translateY);
            var coordinate =  calcLocation(event.offsetX - 25 - scene.translateX, event.offsetY - 25 - scene.translateY);
            node.setLocation(coordinate.x, coordinate.y);

            node.setImage(getImageByType(treeNodes[0].type));

            node.setSize(50,50);

            node.fontColor = '100,105,116';

            node.addEventListener('mousedrag',nodeMouseDrag);
            node.addEventListener('mouseup',nodeMouseUp);
            node.addEventListener('dbclick',nodeDbClick);
            node.addEventListener('click',nodeClick);

            node.deviceId = treeNodes[0].deviceId;
            node.type = treeNodes[0].type;
            node.virtualId = new Date().getTime();

            scene.add(node);

            currentDragNode = node;
        }

    }

我们新生成的拓扑结点增加了两个自定义的属性deviceId、virtualId,分别用来标识结点关联的真实设备id和结点自身的唯一标识。这些自定义属性的使用可以帮助我们更好的实现一些真实的拓扑场景。

你可能感兴趣的:(前端技术)