基於Jtopo的網路拓撲編輯器初探

来源:http://www.cnblogs.com/gongxufan/archive/2017/11/03/7779578.html
-Advertisement-
Play Games

為了方便演示,我已經把一個靜態DEMO部署到github,傳送門 關於項目訪問,因為讀取遠程json數據,直接用瀏覽器打開有安全限制.請將項目放到tomcat啟動訪問或者直接用idea/webstorm打開項目直接右鍵打開,如下圖所示: 完整代碼單獨放到了github:https://github. ...


為了方便演示,我已經把一個靜態DEMO部署到github,傳送門

關於項目訪問,因為讀取遠程json數據,直接用瀏覽器打開有安全限制.請將項目放到tomcat啟動訪問或者直接用idea/webstorm打開項目直接右鍵打開,如下圖所示:


完整代碼單獨放到了github:https://github.com/gongxufan/web-topology

基本的操作可以看下麵的GIF圖,節點從左邊圖標欄拖拽至編輯區,通過單擊節點圖標,然後鬆開滑鼠按鍵則可拖動一條連線。在目標節點單擊,怎完成一次連線操作。左欄可以選擇多種連線方式。



這個拓撲編輯器UI是easyUI做的佈局,節點的編輯和連線則是基於jTopo二次開發的。jTopo提供了Stage、Scene、Node、Container以及對動畫的支持,API使用相對簡單易用。缺點是文檔缺乏,但是我們可以通過作者提供的DEMO進行熟悉。一旦熟悉其源碼,則十分便於二次開發。用來實現一些動畫也是輕而易舉的。由於是基於canvas的繪畫,所以每次更改和操作其實都會重繪整個畫布。當中還是有不少可以優化的地方。其實想D3.js也可以走到這樣的效果,只是近期工作都在後端就沒去探究了。

由於只是摘取個人開發項目的前端部分,由於公司許可原因只能開發這一部分了,有興趣的可以去我的github上clone下來參考。核心部分代碼都在editor.js,提供了節點拖拽、節點連線、佈局等方法支持。這個是一個初始版本。代碼粗糙,僅供參考。

下麵摘取幾個重要的地方稍微講解:

1、編輯器初始化代碼

 //創建JTOP舞臺屏幕對象
    var canvas = document.getElementById('drawCanvas');
    canvas.width = $("#contextBody").width();
    canvas.height = $("#contextBody").height();
    //載入空白的編輯器
    if(stageJson == "-1"){
        this.stage = new JTopo.Stage(canvas);
        this.stage.topoLevel = 1;
        this.stage.parentLevel = 0;
        this.modeIdIndex = 1;
        this.scene=  new JTopo.Scene(this.stage);
        this.scene.totalLevel = 1;
    }else{
        this.stage = JTopo.createStageFromJson(stageJson, canvas);
        this.scene = this.stage.childs[0];
    }

 

我們可以調用JTopo.Stage(canvas)來初始化一個畫圖區域,接下來就可以使用API進行節點和動畫的操作了。整個畫圖對象的JSON層次結構如下所示:

{
  "version": "0.4.8",
  "deviceNum": "19",
  "wheelZoom": 0.95,
  "width": 864,
  "height": 569,
  "id": "ST172.19.105.52015100809430700001",
  "topoLevel": "1",
  "parentLevel": "0",
  "nextLevel": "0",
  "childs": [
    {
      "elementType": "scene",
      "id": "S172.19.105.52015100809430700002",
      "topoLevel": "1",
      "parentLevel": "0",
      "nextLevel": "0",
      "translateX": 106.5,
      "translateY": 20,
      "scaleX": 1,
      "scaleY": 1,
      "totalLevel": "1",
      "childs": [
        {
          "elementType": "node",
          "id": "",
          "topoLevel": 1,
          "parentLevel": "0",
          "nextLevel": "0",
          "x": 211.5,
          "y": 135,
          "width": 32,
          "height": 32,
          "visible": true,
          "rotate": 0,
          "scaleX": 1,
          "scaleY": 1,
          "zIndex": 3,
          "deviceId": "1404683827351.4666",
          "dataType": "VR",
          "nodeImage": "tpIcon_9.png",
          "text": "CS路由器",
          "textPosition": "Bottom_Center",
          "templateId": undefined
        }
      ]
    }
  ]
}

其結構為:

 


通常我們只需要一個 Scene對象即可管理所有的對象,當然如果要實現更複雜的分組對象管理則可以創建多個Scene對象進行單獨管理。同時我們可以調用JTopo.createStageFromJson(stageJson, canvas)方法來講一個保存好的拓撲結構重新渲染。

2、節點的拖拽

節點的拖拽使用的原生H5的drag&drop來實現

/**
 * 圖元拖放功能實現
 * @param modeDiv
 * @param drawArea
 */
networkTopologyEditor.prototype.drag = function (modeDiv, drawArea, text) {
    if (!text) text = "";
    var self = this;
    //拖拽開始,攜帶必要的參數
    modeDiv.ondragstart = function (e) {
        e = e || window.event;
        var dragSrc = this;
        var backImg = $(dragSrc).find("img").eq(0).attr("src");
        backImg = backImg.substring(backImg.lastIndexOf('/') + 1);
        var datatype = $(this).attr("datatype");
        try {
            //IE只允許KEY為text和URL
            e.dataTransfer.setData('text', backImg + ";" + text + ";" + datatype);
        } catch (ex) {
            console.log(ex);
        }
    };
    //阻止預設事件
    drawArea.ondragover = function (e) {
        e.preventDefault();
        return false;
    };
    //創建節點
    drawArea.ondrop = function (e) {
        e = e || window.event;
        var data = e.dataTransfer.getData("text");
        var img, text,datatype;
        if (data) {
            var datas = data.split(";");
            if (datas && datas.length == 3) {
                img = datas[0];
                text = datas[1];
                datatype = datas[2];
                var node = new JTopo.Node();
                node.fontColor = self.config.nodeFontColor;
                node.setBound((e.layerX ? e.layerX : e.offsetX) - self.scene.translateX - self.config.defaultWidth / 2, (e.layerY ? e.layerY : e.offsetY) - self.scene.translateY - self.config.defaultHeight / 2,self.config.defaultWidth,self.config.defaultHeight);
                //設備圖片
                node.setImage(context + 'post/web-topology/icon/' + img);
                //var cuurId = "device" + (++self.modeIdIndex);
                var cuurId = "" + new Date().getTime() * Math.random();
                node.deviceId = cuurId;
                node.dataType = datatype;
                node.nodeImage = img;
                ++self.modeIdIndex;
                node.text = text;
                node.layout = self.layout;
                //節點所屬層次
                node.topoLevel = parseInt($("#selectLevel").find("option:selected").val());
                //節點所屬父層次
                node.parentLevel = $("#parentLevel").val();
                //子網連接點的下一個層,預設為0
                node.nextLevel = "0";
                self.scene.add(node);

                //載入屬性面板
                /* if(self.currDataType)
                 self.clearOldPanels(self.currDataType)
                 self.currDeviceId = cuurId;
                 self.createNewPanels(datatype,self.templateId,self.currentModeId);*/
                //self.currDataType = datatype;
                self.currentNode = node;
            }
        }
        if (e.preventDefault()) {
            e.preventDefault();
        }
        if (e.stopPropagation()) {
            e.stopPropagation();
        }
    }
}

在ondragstart回調方法中傳遞底圖以及必要參數,然後在ondrop進行節點的創建

 

新建節點使用JTopo.Node()構造,設置好相關屬性然後通過scene.add(node)加入到Stage。為何執行add操作在界面上就可以看到新的節點了呢?原因是Stage有一個frames屬性,它定義了畫布重繪頻率1000/frames。

frames [屬性]

設置當前舞臺播放的幀數/秒

預設為:24

frames可以為0,表示:不自動繪製,由用戶手工調用Stage對象的paint()方法來觸發。

如果小於0意味著:只有鍵盤、滑鼠有動作時才會重繪,例如:stage.frames = -24。

 

預設畫面幀數為24幀,也就是每1000/24ms就會重繪屏幕。後臺刷新的代碼如下:

 

function() {
                    0 == stage.frames ? setTimeout(arguments.callee, 100) : stage.frames < 0 ? (stage.repaint(),
                        setTimeout(arguments.callee, 1e3 / -stage.frames)) : (stage.repaint(),
                        setTimeout(arguments.callee, 1e3 / stage.frames))
                }
                ()
setTimeout會調用下麵的重繪函數,

 

              this.paint = function() {
                    null  != this.canvas && (this.graphics.save(),
                        this.graphics.clearRect(0, 0, this.width, this.height),
                        this.childs.forEach(function(a) {
                                1 == a.visible && a.repaint(stage.graphics)
                            }
                        ),
                    1 == this.eagleEye.visible && this.eagleEye.paint(this),
                        this.graphics.restore())
                }
                ,
                this.repaint = function() {
                    0 != this.frames && (this.frames < 0 && 0 == this.needRepaint || (this.paint(),
                    this.frames < 0 && (this.needRepaint = !1)))
                }
paint對遍歷所有可見對象 ,依次調用repaint方法。

3、節點連線

這裡採用的連線方法是在節點按下滑鼠左鍵,然後鬆開滑鼠則創建一個連線,起點是被點擊的節點,終點則隨滑鼠移動而動態更新。因此單機一個節點鬆開滑鼠則可以看到隨滑鼠移動的一條連線。然後在某個節點點擊左鍵鬆開怎完成了兩個節點的連線。效果如下:
部分代碼實現如下:

jTopo支持支線、折線、曲線等的常見,但是折線的拐角處長度現在只能在創建的時候指定。如需動態的秒點創建需要二次開發。代碼如下:
                  
if(self.lineType == "line"){
                        self.link = new JTopo.Link(self.tempNodeA, self.tempNodeZ);
                        self.link.lineType = "line";
                    }else if(self.lineType == "foldLine"){
                        self.link = new JTopo.FoldLink(self.tempNodeA, self.tempNodeZ);
                        self.link.lineType = "foldLine";
                        self.link.direction =  self.config.direction;
                    }else if(self.lineType == "flexLine"){
                        self.link = new JTopo.FlexionalLink(self.tempNodeA, self.tempNodeZ);
                        self.link.direction =  self.config.direction;
                        self.link.lineType = "flexLine";
                    }else if(self.lineType == "curveLine"){
                        self.link = new JTopo.CurveLink(self.tempNodeA, self.tempNodeZ);
                        self.link.lineType = "curveLine";
                    }
其餘細節在此不做贅述,這個項目需要讀者具備:H5、easyUI、jTopo、canvas、JSON等基本知識。至於jTopo只需看看其作者提供的DEMO和很少的API就可以很快上手。最好的學習方法是打斷點不同的調試跟蹤,查看整個工作機制。這裡演示的拓撲編輯也是一個很簡單不完整的例子,其實還是有很多可以定製化的東西,比如連線以及連線方式都可以進一步定製。 參考資料: http://www.jtopo.com/
http://www.jeasyui.com/documentation/
http://www.w3school.com.cn/html5/


 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 全局安裝webpack cnpm install --save-dev webpack 2. 初始化 cnpm init cnpm install --save-dev webpack 創建項目目錄( dist為生成目錄 ) 3. 配置文件 webpack.config.js 創建main.j ...
  • 今天在使用滑鼠事件時,用錯了mouseout,於是做個測試總結。 結論: mouseenter:當滑鼠移入某元素時觸發。 mouseleave:當滑鼠移出某元素時觸發。 mouseover:當滑鼠移入某元素時觸發,移入和移出其子元素時也會觸發。 mouseout:當滑鼠移出某元素時觸發,移入和移出其 ...
  • 面試中經常考到面向對象的一些知識,在這記錄一下,如有不對歡迎指正,願在前端的道路上共勉! 一、原型 1.什麼是原型: 簡單說就像css的class一樣,是公用的,給DOM元素加個class名就可以公用樣式,那麼原型就相當於css裡面的class,都可以用。 在構造函數創建出來的時候,系統會預設的幫構 ...
  • (web前端學習交流群:328058344 禁止閑聊,非喜勿進!) 顏色 桃紅~紛紅 顏色 紫 顏色 褐~橘~米白 顏色 金~黃 顏色 ~黃 綠 顏色 藍 顏色 黑~灰~白 顏色 ...
  • 轉自st.gg 為什麼用 $scope.user = $scope.master; $scope.master 會跟著 $scope.user 改變?angular.copy 和 = 號賦值有什麼區別呢?新手還沒有搞懂,請教各位了。 你可以這麼來理解: 記憶體里有一段地址儲存了 { firstName ...
  • 前段時間不是很忙,剛好公司需要開發一個微信小程式,於是我就入坑了(此坑還是有點深滴,請備好乾糧)。 我是一名iOS開發工程師,個人覺得入門開發小程式的話,需要基本的web前端知識,比如說:代碼的書寫格式,規範,標簽以及樣式的使用等,但作為一門如此新的開發語言,它也有自己的獨特之處,就像我們的swif ...
  • 轉自CSDN: 工作有問題上CSDN上轉轉. $apply()和$digest()在AngularJS中是兩個核心概念,但是有時候它們又讓人困惑。而為了瞭解AngularJS的工作方式,首先需要瞭解$apply()和$digest()是如何工作的。這篇文章旨在解釋$apply()和$digest() ...
  • Vue 2.5 發佈了:15篇前端熱文回看 2017-11-02 前端大全 (點擊上方公眾號,可快速關註) 本文精選了「前端大全」2017 年 10 月的 15 篇熱門文章。其中有職場分享、技術分享和技術資源。 註:以下文章,點擊標題即可閱讀 《Vue 2.5 發佈了》 我們很高興宣佈 Vue 2. ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...