3D拓撲自動布局之Web Workers篇


2D拓撲的應用在電信網管和電力SCADA領域早已習以為常了,隨着OpenGL特別是WebGL技術的普及,3D方式的數據可視化也慢慢從佛殿神堂步入了尋常百姓家,似乎和最近高檔會所被整改為普通茶館是一樣的節奏。

3D呈現固然比2D方式更直觀,但如果擺放圖元布局卻比2D麻煩,畢竟增加了一個維度,手工布局不如以前2D手工操作方便,因此3D的自動布局功能比2D凸顯其重要性。最近玩了玩HT的彈力自動布局插件挺有意思,特別在平板上Touch方式拖拽三維空間圖元節點時,對我這種控制欲較強者很有滿足感。


 

彈力布局也不是啥新鮮玩意兒了,傳統彈力布局算法都是采用通過CPU迭代運算的方式,對於海量數據特別是在純客戶端運算的方式肯定是不可行的,因此這些年也有很多采用GPU的方式進行並行計算的方式可極大提高性能,等OpenCL更成熟HT for Web提供了WebCL的解決方案我再來張開這個話題。今天的話題采用的還是CPU,只不過我把自動布局的算法拉到了Web Worker來運算,純屬為了好玩實際意義不大,畢竟Worker運算結果還得不斷序列化給GUI頁面層,不斷來回數據傳輸也挺耗性能,當然如果你讓Worker運行一段時間,只把最終結果push回Web層進行呈現還是有點實際意義的,畢竟不用Worker時js單線程運行,對這種計算密集型的算法只會卡死界面無法進行其他業務操作。


 

以下是頁面部分的代碼,通過new Worker('workderjs')構建Worker后台運行對象,通過worker.addEventListener('message', ..)監聽后台自動布局后派發的圖元位置信息進行更新,通過worker.postMessage(info)發送界面拖拽圖元位置變化信息。

       function reload() {                    
            var info = {
                A: parseInt($("A").value), 
                B: parseInt($("B").value)
            };
            reloadModel(dataModel, info);
            worker.postMessage(info);
        }

        function init() {        
            dataModel = new ht.DataModel();                   
            g3d = new ht.graph3d.Graph3dView(dataModel); 
            toolbar = new ht.widget.Toolbar(items);
            borderPane = new ht.widget.BorderPane();
            borderPane.setTopView(toolbar);
            borderPane.setCenterView(g3d);       

            g3d.mi(function(evt){
                if(evt.kind === 'betweenMove'){                
                    moveMap = {};
                    g3d.sm().each(function(data){
                        if(data instanceof ht.Node){
                            moveMap[data._id] = data.p3();
                        }
                    });
                    worker.postMessage({moveMap: moveMap});                
                }
            }); 

            worker = new Worker("worker.js");    
            worker.addEventListener('message', function(e) {
                var info = e.data;
                for(var id in info.result){
                    var data = dataModel.getDataById([id]);
                    if(data && !g3d.isSelected(data)){
                        data.p3(info.result[id]);
                    }                
                }  
            }); 

            reload();
        }

以下是后台Work.js的代碼,通過importScripts("ht.js")引入HT核心包,通過importScripts("ht-forcelayout.js")引入HT的彈力布局插件,通過importScripts("util.js")引入和頁面代碼共享的一些通用函數,通過self.postMessage({result: result})發送自動布局運算結果推送到頁面,通過
self.addEventListener('message', ...)監聽頁面發過來的位置變化信息,從而實現了前后台的互通。

importScripts("ht.js");
importScripts("ht-forcelayout.js");
importScripts("util.js");

ht = self.ht;
dataModel = new ht.DataModel();
forceLayout = new ht.layout.Force3dLayout(dataModel);

forceLayout.onRelaxed = function(){    
    var result = {};
    dataModel.each(function(data){
       if(data instanceof ht.Node){
           result[data._id] = data.p3();
       } 
    });
    self.postMessage({result: result});
};
forceLayout.start();    

self.addEventListener('message', function(e) {
    var info = e.data;
    if(info.moveMap){
        dataModel.sm().cs();
        for(var id in info.moveMap){
            var data = dataModel.getDataById(id);
            if(data){
                data.p3(info.moveMap[id]);
                dataModel.sm().as(data);
            }
        }
    }
    else{
        reloadModel(dataModel, info);                 
    }        
}, false);

以下視頻為在Android平板上跑3D拓撲自動布局的效果,這個例子純粹為了玩玩Web Workers,這樣折騰性能並不會提高,甚至因為來回序列化更費性能,Web Worker可以使用的場景並不太多,比較適合純數學運算的業務邏輯,同時還需要注意跑在Worker的代碼是不能操作任何界面對象,例如window和document之類的對象。

下篇《3D拓撲自動布局之Node.js篇》我們再將算法移到Node.js端玩

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM