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端玩

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏前端知识分享

第54天:原生js实现轮播图效果

一系列的大小相等的图片平铺,利用CSS布局只显示一张图片,其余隐藏。通过计算偏移量利用定时器实现自动播放,或通过手动点击事件切换图片。

631
来自专栏HTML5学堂

HTML5视音频-解决全屏下出现的控制栏

HTML5学堂:HTML5视音频-解决全屏下的控制栏。HTML5可以简简单单的实现视频、音频的播放功能,功能虽好用,但是它的默认样式有点淡淡的忧伤,问题虽存在,...

2726
来自专栏贾鹏辉的技术专栏@CrazyCodeBoy

React Native年度报告(2017-2018)

概述 在过去的一年中React Native经历了从v0.40到v0.52的十几次的版本迭代,我们看到在这十几次的版本迭代中React Native的组件库在不...

2816
来自专栏一“技”之长

AppleWatch开发入门二——界面布局 原

        在iphone开发中,最基本的布局方式是通过frame,将控件的位置和大小固定在屏幕上,后来,由于手机屏幕的尺寸有了略微变化,有了autores...

762
来自专栏互联网杂技

移动前端开发之viewport的深入理解

在移动设备上进行网页的重构或开发,首先得搞明白的就是移动设备上的viewport了,只有明白了viewport的概念以及弄清楚了跟viewport有关的meta...

3595
来自专栏偏前端工程师的驿站

当css属性width设为100%时

  平常在写页面html代码时,经常会使用到width:100%来使控件宽度为父控件的内容宽度。但如果父控件为body,而且没有明确设置body的宽度,那么就会...

1825
来自专栏前端人人

React技巧1(状态组件与无状态组件的使用)

本教程总共5篇,每日更新一篇,请关注我们!你可以进入历史消息查看以往文章,也敬请期待我们的新文章! 1.React 技巧1(状态组件与无状态组件的使用) --...

3066
来自专栏无原型不设计

Mockplus:如何调整图标的大小和方向?

使用属性面板上的大小设置,可以很方便地调节图标大小。 ? 调整方向还是通过属性面板来完成: ? 另外:有些图标调整了大小之后可以用做特别的用途哟,比如 S...

1923
来自专栏糊一笑

深入常用CSS声明(一) —— Background

一直对一些自己常用的css声明掌握得不是很全,只知道常用的一些属性和值,但是对于其他的用法确实一知半解,这篇文章旨在扫盲,先不说有多深的理解,至少做到能够看到这...

2805
来自专栏斜述视角

0基础学习网页制作-Html

文章来自:4月14日早,在贵州大学北校区10栋715寝室,对物理学院同学培训的内容。

512

扫码关注云+社区