基于 HTML5 的 3D 网络拓扑树呈现

在HT for
Web中2D和3D应用都帮忙树状布局数据的彰显,表现效果区别,2D上的树状构造在表现层级关系明显,可是只要数据量大的话,看起来就没那么直观,找到钦点的节点比较不方便,而3D上的树状架构在显示上合营HT
for
Web的弹力结构组件会显得比较直观,一眼望去能够把方方面面树状布局数据看个大意,但是在弹力构造的功效下,其档期的顺序构造看得就不是那么清楚了。所以当时布局清晰的3D树的须要就来了,那么这几个3D树具体长成啥样呢,大家来三只亲眼看见下~

安详严整火速支付基于 HTML5 网络拓扑图应用,html5拓扑图

前日起来大家就从最底蕴深入剖析怎么样营造 HTML5 Canvas 拓扑图应用,HT
内部封装了二个拓扑图形组件 ht.graph.GraphView(以下简单的称呼 GraphView)是 HT
框架中 2D 成效最丰盛的机件,其有关类库都在 ht.graph 包下。GraphView
拥有宗旨图形的表现和编排作用,拓扑节点连线及机关布局功用,电力和邮电通讯等行业预订义对象,具备动漫渲染等特效,因而其应用面很广阔,可视作监督世界的绘图工具和人机分界面,可作为普通的图形化编辑工具,可扩充成职业流和组织图等集团应用。轻巧说来正是:拓扑图是泛化的传教,邮电通讯网管的互联网拓扑图、电力的电网拓扑图、工业调节的监察和控制图、专门的职业流程图、思维脑图等等,轻易说正是节点连线构成的那些都是这里指的拓扑图。

用 HT
开垦二个网络拓扑图是非常轻便的一件事,只供给短短几行代码就能够做到二个大致的服务器与顾客端的拓扑图:

奥门新浦京官方网站 1

以那件事例十三分根基,大概做到了服务器与顾客端在拓扑上的享有作用。话相当少说,猜猜看那几个例子蕴涵HTML 标签的富有片段共计花了稍微行代码?减去空行也就 50
行,作者还做了重重样式部分的宏图,终究给大家看的事例无法太丑嘛~

世家能够在 tuputu_jb51.rar 自行下载代码,注意因为有 json
文件,会存在图片跨域难点,必要用 Firefox 只怕地面服务器跑起来。

笔者们在最先阶就印证一下,HT 是基于 HTML5
标准的公司应用图形分界面一条龙施工方案, 其包括通用组件、拓扑组件和 3D
渲染引擎等丰富的图形分界面开辟类库,顾客只要求引进 ht.js
就可以,何况跟其他别样东西完全不冲突,因为 HT 只是声称了多个全局变量
ht,如此而已。

接下去拆解解析代码部分,首先,搭建拓扑图场景:

dm = new ht.DataModel();//数据容器
gv = new ht.graph.GraphView(dm);//拓扑组件 参数为dm 绑定的数据模型
gv.addToDOM();//将拓扑图添加进body体中

HT 的具备组件的根部都以一个 div,通过 getView(卡塔尔 方法获得,大家在
addToDOM 方法中就用到了那个艺术:

addToDOM = function(){   
    var self = this,
        view = self.getView(),  //获取组件底层 div
        style = view.style; 
    document.body.appendChild(view);//将底层 div 添加进 body 体中           
    style.left = '0';//HT 一般将组件都设置为 absolute 的绝对定位
    style.right = '0';
    style.top = '0';
    style.bottom = '0';      
    window.addEventListener('resize', function () { self.iv(); }, false); //事件监听窗口大小变化,iv 为延时刷新组件         
}

然后向拓扑场景中增多“服务器”以致“客商端”节点:

var server = new ht.Node();
server.setName('server');//设置节点名称,显示在节点下方
server.setImage('serverImage');//设置节点图片
server.setSize(20, 60);//设置节点大小
dm.add(server);//将节点添加进数据容器dm中
server.setPosition(100, 100);//设置节点坐标(x, y)

var group = new ht.Group();//组,组中可以有多个节点
group.setImage('groupImage');//设置图片
dm.add(group);
var client = new ht.Node();//这个节点是添加进组中的
client.setName('client');
client.setImage('clientImage');
dm.add(client);
group.addChild(client);//组添加孩子
group.setExpanded(true);//设置组为展开模式
client.setPosition(200, 100);//设置节点位置 如果组中只有一个节点,那么这个节点的位置可以为组的位置

服务端与顾客端的连线?2 行代码消除!其实 HT
中加多节点的点子特简单,常常就 2
行代码能截至:先申明实例变量,然后将以此实例变量增添进数据容器中。

var edge = new ht.Edge(server, client);
dm.add(edge);

我们很好奇虚线是如何做出来的?虚线的演进是搭建在连线之上的,步骤有 3
个:

  1. 引入 ht-dashflow.js 文件 ;
  2. 将连线的样式属性 edge.dash.flow 设置为 true;
  3. 在情景组件中开采虚线流动的开关,这里正是 gv.enableDashFlow(trueState of Qatar;

是否极度轻巧!接下去我们看看怎么设置:

edge.s({//节点设置样式属性
    'edge.dash': true,//显示虚线
    'edge.dash.flow': true,//开启虚线流动
    'edge.dash.color': 'yellow',//虚线颜色
    'edge.dash.pattern': [8, 8],//虚线样式
    'label': 'flow',//节点注释
    'label.background': 'pink',//节点注释背景颜色        
});

如此有着的显示部分就介绍完成啦~等等,好像还少点什么?对了,笔者忘了介绍 HT
中的 ht.Group
类了,顾名思义,正是“组”的意味,组中能够满含众多节点,双击可兆示或隐瞒组内的具备节点,上面代码有写到,但是自身还做了一点手脚,就是组右上角的展现部分,其实就是贰个标明,用来唤起表达的:

group.s({
    'group.background': 'rgba(255, 255, 0, 0.1)',//设置组的背景颜色
    'note': "Double click me!",//标注 显示的内容
    'note.position': 13,//标注位置
    'note.offset.y': 10,//标注位置y轴偏移
});

咱们能够透过 note.position 来改换标记的任务(具体地点消息请参照他事他说加以考察HT for
Web 地点手册 ),也得以使用 note.offset.x 和 note.offset.y
来改动标明之处。

全部代码拆解深入分析达成!作者会尽快更新,要是我们感到进度慢的话,能够和谐去咱们官方网址(
HT for Web
)上学习,希望大家能有越多的得到,学习是协和的事情,快动手实行将那片小说的内容产生你和谐的知识吧!
上述正是本文的全体内容,希望对大家的学习抱有助于,也冀望我们多多点拨帮客之家。

HTML5
互连网拓扑图应用,html5拓扑图 明日起头咱们就从最底子拆解分析怎样塑造 HTML5
Canvas 拓扑图应用,HT 内部封装了一个拓扑…

几近来,3D
模型已经用于各个分裂的世界。在医治行当利用它们制作器官的高精度模型;电影行当将它们用于活动的人物、物体以及现实电影;录像游戏行当将它们当做Computer与录制游戏中的财富;在正确领域将它们作为化合物的标准模型;建筑业将它们用来突显建议的构筑物恐怕风景表现;工程界将它们用于设计新设备、交通工具、结构以致此外应用领域;在前段时间数十年,地学领域起初营造空间维度地质模型,何况3D
模型经常做成动漫,比如,在故事片电影以致计算机与摄像游戏中山大学量地应用三个维度模型。它们能够在三个维度建立模型工具中利用或然独立行使。为了便于产生动画,平日在模型中参预一些特别的多寡,比方,一些生人还是动物的三维模型中有全体的骨骼系统,那样活动时看起来会愈发真实,并且能够通过难题与骨骼调节移动。

奥门新浦京官方网站 2

这一个各样都让大家前端开垦者认为假如大家能够不要学习 unity3d
大概其余娱乐开辟工具就能够促成 3D
效果,并且可以精准的靠代码来决定移动照旧趋向就好了。。。于是自个儿动用 HT
For
Web 中的 3D组件 来达成了一个小例子,用了 HT 中 3D组件奥门新浦京官方网站 , 的大部意义,做那么些例子正是想把 3D
组件十全十美的通晓,尽量放进贰个例子中,届时候外人有亟待就足以参照了。

要落到实处如此的意义,该从何入手呢?接下去我们就将那些标题拆解成几何个小意思来消除。

先来探视全体完毕的效率图:

1. 创造二个树状布局

有精通过HT for
Web的意中人,对树状布局数据的创设应该都不生分,在那地小编就不做深切的究查了。树状构造数据的创设相当轻巧,在这里处为了让代码更简短,作者封装了三个办法来创设树状构造数据,具体代码如下:

/**
 * 创建连线
 * @param {ht.DataModel} dataModel - 数据容器
 * @param {ht.Node} source - 起点
 * @param {ht.Node} target - 终点
 */
function createEdge(dataModel, source, target) {
    // 创建连线,链接父亲节点及孩子节点
    var edge = new ht.Edge();
    edge.setSource(source);
    edge.setTarget(target);
    dataModel.add(edge);
}

/**
 * 创建节点对象
 * @param {ht.DataModel} dataModel - 数据容器
 * @param {ht.Node} [parent] - 父亲节点
 * @returns {ht.Node} 节点对象
 */
function createNode(dataModel, parent) {
    var node = new ht.Node();
    if (parent) {
        // 设置父亲节点
        node.setParent(parent);

        createEdge(dataModel, parent, node);
    }
    // 添加到数据容器中
    dataModel.add(node);
    return node;
}

/**
 * 创建结构树
 * @param {ht.DataModel} dataModel - 数据容器
 * @param {ht.Node} parent - 父亲节点
 * @param {Number} level - 深度
 * @param {Array} count - 每层节点个数
 * @param {function(ht.Node, Number, Number)} callback - 回调函数(节点对象,节点对应的层级,节点在层级中的编号)
 */
function createTreeNodes(dataModel, parent, level, count, callback) {
    level--;
    var num = (typeof count === 'number' ? count : count[level]);

    while (num--) {
        var node = createNode(dataModel, parent);
        // 调用回调函数,用户可以在回调里面设置节点相关属性
        callback(node, level, num);
        if (level === 0) continue;
        // 递归调用创建孩子节点
        createTreeNodes(dataModel, node, level, count, callback);
    }
}

嘿嘿,代码写得大概有些复杂了,轻易的做法正是嵌套多少个for循环来创设树状构造数据,在此处作者就相当少说了,接下去我们来探求第4个难题。

奥门新浦京官方网站 3

2. 在2D拓扑下模拟3D树状构造每层的半径总结

在3D下的树状结构体最大的难点就在于,每一种节点的等级次序及每层节点围绕其老爹节点的半径总结。现在树状构造数据现本来就有了,那么接下去就该起来忖度半径了,大家从两层树状结构最早推算:

奥门新浦京官方网站 4

本身今后先创立了两层的树状构造,全数的子节点是一字排开,并未环绕其阿爹节点,那么大家该怎样去明确这一个孩子节点的岗位吗?

率先我们得精晓,每一个末端节点都有一圈归于自个儿的园地,不然节点与节点之间将会设有重叠的景观,所以在这里地,大家假诺末端节点的小圈子半径为25,那么五个相邻节点之间的最短间隔将是两倍的节点领域半径,也即是50,而那几个末端节点将均匀地围绕在其阿爹节点四周,那么相邻四个节点的张角就能够断定出来,有了张角,有了两点间的相距,那么节点绕其老爹节点的最短半径也就可以计算出来了,假若张角为a,两点间最小间隔为b,那么最小半径r的总结公式为:

r = b / 2 / sin(a / 2);

那正是说接下去小编么就来构造下那么些树,代码是这么写的:

/**
 * 布局树
 * @param {ht.Node} root - 根节点
 * @param {Number} [minR] - 末端节点的最小半径
 */
function layout(root, minR) {
    // 设置默认半径
    minR = (minR == null ? 25 : minR);
    // 获取到所有的孩子节点对象数组
    var children = root.getChildren().toArray();
    // 获取孩子节点个数
    var len = children.length;
    // 计算张角
    var degree = Math.PI * 2 / len;
    // 根据三角函数计算绕父亲节点的半径
    var sin = Math.sin(degree / 2),
        r = minR / sin;
    // 获取父亲节点的位置坐标
    var rootPosition = root.p();

    children.forEach(function(child, index) {
        // 根据三角函数计算每个节点相对于父亲节点的偏移量
        var s = Math.sin(degree * index),
            c = Math.cos(degree * index),
            x = s * r,
            y = c * r;

        // 设置孩子节点的位置坐标
        child.p(x + rootPosition.x, y + rootPosition.y);
    });
}

在代码中,你会开掘自家将末端半径暗中认可设置为25了,如此,我们透过调用layout(卡塔尔方法就足以对组织树举行架构了,其构造功效如下:

奥门新浦京官方网站 5

从功能图能够看得出,末端节点的私下认可半径而不是很特出,构造出来的功力连线都快看不到了,因而大家得以增加末端节点的暗许半径来解决结构太密的标题,如将暗中同意半径设置成40的功用图如下:

奥门新浦京官方网站 6

今昔两层的树状遍布解决了,那么我们来看看三层的树状分布该怎么管理。

将第二层和第三层用作一个总体,那么实际上三层的树状构造跟两层是一样的,分化的是在管理第二层节点时,应该将其当作一个两层的树状布局来管理,那么像这种规律的拍卖用递归最佳可是了,由此大家将代码稍稍该着下,在探问效果怎么样:

奥门新浦京官方网站 7

不行,节点都重叠在联合签字了,看来轻松的递归是可怜的,那么具体的难点出在哪儿啊?

周到剖判了下,开采老爹节点的园地半径是由其子女节点的圈子半径决定的,由此在构造时供给掌握自家节点的小圈子半径,何况节点的职分决议于老爹节点的领域半径及岗位音讯,那样一来就无法边总括半径边构造节点地方了。

那么以往只好将半径的预计和布局分开来,做两步操作了,大家先来解析下节点半径的乘除:

率先必要精通最要紧的标准,阿爹节点的半径决意于其孩子节点的半径,这么些规范告诉我们,只可以从下往上总括节点半径,因此大家规划的递归函数必须是先递归后计算,废话相当少说,大家来看下具体的代码达成:

/**
 * 就按节点领域半径
 * @param {ht.Node} root - 根节点对象
 * @param {Number} minR - 最小半径
 */
function countRadius(root, minR) {
    minR = (minR == null ? 25 : minR);

    // 若果是末端节点,则设置其半径为最小半径
    if (!root.hasChildren()) {
        root.a('radius', minR);
        return;
    }

    // 遍历孩子节点递归计算半径
    var children = root.getChildren();
    children.each(function(child) {
        countRadius(child, minR);
    });

    var child0 = root.getChildAt(0);
    // 获取孩子节点半径
    var radius = child0.a('radius');

    // 计算子节点的1/2张角
    var degree = Math.PI / children.size();
    // 计算父亲节点的半径
    var pRadius = radius / Math.sin(degree);

    // 设置父亲节点的半径及其孩子节点的布局张角
    root.a('radius', pRadius);
    root.a('degree', degree * 2);
}

OK,半径的测算扫除了,那么接下去就该消除布局难题了,结构树状布局数据须要显明:孩子节点的坐标地点决计于其阿爹节点的坐标地方,由此布局的递归形式和计量半径的递归情势各异,大家供给先布局阿爹节点再递归纳构孩子节点,具体看看代码吧:

/**
 * 布局树
 * @param {ht.Node} root - 根节点
 */
function layout(root) {
    // 获取到所有的孩子节点对象数组
    var children = root.getChildren().toArray();
    // 获取孩子节点个数
    var len = children.length;
    // 计算张角
    var degree = root.a('degree');
    // 根据三角函数计算绕父亲节点的半径
    var r = root.a('radius');
    // 获取父亲节点的位置坐标
    var rootPosition = root.p();

    children.forEach(function(child, index) {
        // 根据三角函数计算每个节点相对于父亲节点的偏移量
        var s = Math.sin(degree * index),
            c = Math.cos(degree * index),
            x = s * r,
            y = c * r;

        // 设置孩子节点的位置坐标
        child.p(x + rootPosition.x, y + rootPosition.y);

        // 递归调用布局孩子节点
        layout(child);
    });
}

代码写完了,接下去正是亲眼看见神蹟的每天了,大家来寻访效果图吧:

奥门新浦京官方网站 8

不对啊,代码应该是没难题的哟,为何来得出来的成效照旧会重叠呢?可是精心察看大家得以窥见比较上个版本的布局会好广大,最少这一次只是前面节点重叠了,那么难点出在哪儿吧?

不精晓大家有未有开采,消除节点自己的尺寸,尾数第二层节点与节点之间的天地是相切的,那么也便是说节点的半径不止和其孩子节点的半径有关,还与其孙子节点的半径有关,那我们把总计节点半径的章程退换下,将外孙子节点的半径也构思进来再看看效果怎么着,改换后的代码如下:

/**
 * 就按节点领域半径
 * @param {ht.Node} root - 根节点对象
 * @param {Number} minR - 最小半径
 */
function countRadius(root, minR) {
   ……

    var child0 = root.getChildAt(0);
    // 获取孩子节点半径
    var radius = child0.a('radius');

    var child00 = child0.getChildAt(0);
    // 半径加上孙子节点半径,避免节点重叠
    if (child00) radius += child00.a('radius');

   ……
}

上面就来探问效果啊~

奥门新浦京官方网站 9

哈哈哈,看来大家深入分析对了,果然就不再重叠了,那大家来探视再多一层节点会是怎么的壮观场景吧?

奥门新浦京官方网站 10

哦,NO!这不是本人想见见的功力,又重叠了,好讨厌。

绝不焦急,大家再来细心解析分析下,在头里,大家提到过叁个名词——领域半径,什么是世界半径呢?超轻松,便是足以宽容下自家及其全体子女节点的小小半径,那么难点就来了,末端节点的领域半径为我们钦命的微小半径,那么尾数第二层的天地半径是有一点点吗?实际不是我们眼下总计出来的半径,而应该加上末端节点本人的世界半径,因为它们中间存在着包括关系,子节点的小圈子必需含有于其阿爹节点的领域中,那大家在探问上海体育场地,是还是不是感到末端节点的园地被侵吞了。那么大家前边总括出来的半径代表着怎么样啊?前边总括出来的半径其实代表着子女节点的构造半径,在结构的时候是经过该半径来布局的。

OK,那大家来总计下,节点的天地半径是其下每层节点的构造半径之和,而构造半径要求依据其子女节点个数及其领域半径合作决定。

好了,大家昨天知晓难点的所在了,那么大家的代码该怎样去完成吗?接着往下看:

/**
 * 就按节点领域半径及布局半径
 * @param {ht.Node} root - 根节点对象
 * @param {Number} minR - 最小半径
 */
function countRadius(root, minR) {
    minR = (minR == null ? 25 : minR);

    // 若果是末端节点,则设置其布局半径及领域半径为最小半径
    if (!root.hasChildren()) {
        root.a('radius', minR);
        root.a('totalRadius', minR);
        return;
    }

    // 遍历孩子节点递归计算半径
    var children = root.getChildren();
    children.each(function(child) {
        countRadius(child, minR);
    });

    var child0 = root.getChildAt(0);
    // 获取孩子节点半径
    var radius = child0.a('radius'),
        totalRadius = child0.a('totalRadius');

    // 计算子节点的1/2张角
    var degree = Math.PI / children.size();
    // 计算父亲节点的布局半径
    var pRadius = totalRadius / Math.sin(degree);

    // 缓存父亲节点的布局半径
    root.a('radius', pRadius);
    // 缓存父亲节点的领域半径
    root.a('totalRadius', pRadius + totalRadius);
    // 缓存其孩子节点的布局张角
    root.a('degree', degree * 2);
}

在代码中我们将节点的天地半径缓存起来,从下往上一层一层地叠合上去。接下来大家一块验证其科学:

奥门新浦京官方网站 11

消除,正是那样子了,2D拓扑上面的布局消除了,那么接下去该出动3D拓扑啦~

用 HT for Web,现成的 3d
模板成立三层底板不是主题素材,问题是要如何将图中首先层的“Computer”和“机柜组件”放上去?笔者是在网络down 下来的 obj
格式的文书,然后我动用 HT 中的
ht.Default.loadObj(objUrl, mtlUrl, params卡塔尔 函数将模型加载进去,其中的
params
部分能够参谋 ,代码如下:

3. 踏向z轴坐标,呈现3D下的树状构造

3D拓扑上边布局无非就是多加了一个坐标系,而且以此坐标系只是调节节点的可观而已,并不会影响到节点之间的交汇,所以接下去我们来改变下大家的次序,让其能够在3D上健康构造。

也不必要太大的改换,大家只须要改革下布局器况且将2D拓扑组件改成3D拓扑组件就足以了。

/**
 * 布局树
 * @param {ht.Node} root - 根节点
 */
function layout(root) {
    // 获取到所有的孩子节点对象数组
    var children = root.getChildren().toArray();
    // 获取孩子节点个数
    var len = children.length;
    // 计算张角
    var degree = root.a('degree');
    // 根据三角函数计算绕父亲节点的半径
    var r = root.a('radius');
    // 获取父亲节点的位置坐标
    var rootPosition = root.p3();

    children.forEach(function(child, index) {
        // 根据三角函数计算每个节点相对于父亲节点的偏移量
        var s = Math.sin(degree * index),
            c = Math.cos(degree * index),
            x = s * r,
            z = c * r;

        // 设置孩子节点的位置坐标
        child.p3(x + rootPosition[0], rootPosition[1] - 100, z + rootPosition[2]);

        // 递归调用布局孩子节点
        layout(child);
    });
}

地点是改动成3D搭架子后的布局器代码,你会意识和2D的结构器代码就差二个坐标系的的测算,其余的都同一,看下在3D上布局的坚决守护:

奥门新浦京官方网站 12

恩,三衅三浴的了,在篇章的启幕,大家得以见见每一层的节点都有两样的水彩及大小,那么些都以比较轻便,在那处自身就不做深切的讲课,具体的代码完结如下:

var level = 4,
    size = (level + 1) * 20;

var root = createNode(dataModel);
root.setName('root');
root.p(100, 100);

root.s('shape3d', 'sphere');
root.s('shape3d.color', randomColor());
root.s3(size, size, size);

var colors = {},
    sizes = {};
createTreeNodes(dataModel, root, level - 1, 5, function(data, level, num) {
    if (!colors[level]) {
        colors[level] = randomColor();
        sizes[level] = (level + 1) * 20;
    }

    size = sizes[level];

    data.setName('item-' + level + '-' + num);
    // 设置节点形状为球形
    data.s('shape3d', 'sphere');
    data.s('shape3d.color', colors[level]);
    data.s3(size, size, size);
});

在此引进了一个任性生成颜色值的办法,对每一层随机生成一种颜色,并将节点的形态改成了球形,让页面看起来雅观些(其实非常不好看)。

奥门新浦京官方网站 13

提个外话,节点上能够贴上海体育场地片,还足以设置文字的向阳,能够借助客商的见识动态调节岗位,等等一层层的开展,那些大家都能够去尝试,相信都能够做出多少个极好看的3D树出来。

到此,整个德姆o的炮制就得了了,前几日的字数某个长,感激我们的恒心阅读,在计划上或则是抒发上有何建议或意见应接咱们提出,点击这里能够访问HT
for Web官英特网的手册。

ht.Default.loadObj('obj/机柜组件1.obj', 'obj/机柜组件1.mtl', {  //加载 obj 文件
    cube: true,  //是否将模型缩放到单位1的尺寸范围内,默认为false
    center: true,  //模型是否居中,默认为false,设置为true则会移动模型位置使其内容居中
    shape3d: 'box',  //如果指定了shape3d名称,则HT将自动将加载解析后的所有材质模型构建成数组的方式,以该名称进行注册
    finishFunc: function(modelMap, array, rawS3){  //用于加载后的回调处理 
      if(modelMap){  
        device2 = createNode('box', floor1);  //创建一个节点,在第一层“地板”上
    device2.p3([x1-120, y1+13, z1+60]);  //设置这个节点坐标
    device2.s3(rawS3);  //设置这个节点大小
    createEdge(device1, device2);  //创建连线
    device3 = createNode('box', floor1);  
    device3.s3(rawS3);  
    device3.p3([x1+120, y1+13, z1+60]);  
    createEdge(device1, device3);  
      }  
    }  
}); 

此中 finishiFunc 函数中的七个参数定义如下:

  • modelMap:调用 ht.Default.parseObj
    拆解深入分析后的重临值,若加载或解析战败则再次来到值为空
  • array:全数材料模型组成的数组
  • rawS3:满含全部模型的原始尺寸

诚如在事实上行使中大家都会将图元的分寸设置为模型的原始尺寸。

“计算机”上方有个革命的立体能旋转的“警报”,是依赖ht.Default.setShape3dModel 函数(HT for Web
建立模型手册 State of Qatar注册的一个3d 模型,在 ht
中,封装好的建立模型函数有成都百货上千,相比较功底的就是球体,圆柱,立方体等等,那边作者用的是布局环形的艺术
createRingModel 来变化“警示”最外面的环,惊讶号的上有些正是用的
createSmoothSphereModel 布局的球体,惊讶号的下局地便是用
createSmoothCylinderModel 来结构的圆柱。作者一起先从来使用了 3d
模型中封装好的函数,引致新兴根本不清楚函数中应用的参数是做哪些用的,何况也不知情
3d 模型是怎么构成的,然后本身又再度看了前方的“模型基本功”,才了然原本 3d
模型采取的多个面,最幼功的是三角面,之后复杂的面也是由多个三角面来形成的,然后绕着一根特定的轴旋转之后变成的,当然,这几个轴是你来决定的,区别的轴能够生成不一致的形状,对于颜色等风格方面包车型地铁安装能够参照 HT
for Web
风格手册(卡塔尔。至于哪些让这个3d 模型旋转起来,ht 中封装了 addScheduleTask(Task卡塔尔 方法,笔者在第三层 Task
中调用了 ht 封装的一个转悠函数 setRotation
来安装旋转的顺序和方向,并且钦定了旋转的对象。以下是自定义“警示”的 3d
模型的不二等秘书技(注意:因为本例的模子是自定义组合的,借使要安装完整模型的颜色要用
“all.blend” style 属性):

function createAlarm(device, formPane) {
    var ringModel = ht.Default.createRingModel([ 8, 1, 10, 1, 10, -1, 8, -1, 8, 1 ], null, null, false, false, 100);//根据xy平面的曲线,环绕一周形成3D模型。
    var sphereModel = ht.Default.createSmoothSphereModel(8, 8, 0, Math.PI*2, 0, Math.PI, 2);//构建光滑球体模型 
    var cylinderModel = ht.Default.createSmoothCylinderModel(8, true, true, 1, 2, 0, Math.PI*2, 8);//构建光滑圆柱体模型

    var alarmArr = [//组合模型 由三个模型ringModel、sphereModel、cylinderModel组合而成
        {
          shape3d: ringModel,//定义模型类型
          r3: [Math.PI/2, 0, 0],//设置旋转角度
          color: {//设置模型颜色
            func: 'style@all.blend',//数据绑定style样式中的all.blend属性,可通过data.s()获取和设置这个属性
          }
        },{
          shape3d: sphereModel,
          t3: [0, 4, 0],
          color: {
            func: 'style@all.blend',
          }
        },{
          shape3d: cylinderModel,
          t3: [0, -3, 0],
          color: {
            func: 'style@all.blend',
          }
        }
    ];
    ht.Default.setShape3dModel('alarm', {//注册自定义3D模型
      shape3d: alarmArr
    });

    var alarmTip = createNode('alarm', device);//创建shape3d为alarm的节点
    alarmTip.s3([2, 2, 2]);//设置节点大小
    alarmTip.p3(device.p3()[0], device.p3()[1]+60, device.p3()[2]);
    alarmTip.s('all.blend', 'red');//改变此属性可改变模型的颜色,因为模型创建的时候已经数据绑定了

    return alarmTip;
}

接下去看看怎么让这几个“告急”节点“闪烁”,笔者是直接将以此动漫跟节点绑定,那样能够间接通过节点来决定动漫。所以在地点大家创建alarm 的模子时就能够直接将动漫片绑在节点上:

if(formPane){
    alarmNode.scaleFunc = function() {//设置大小变化动画
        var size = alarmNode.s3();//获取节点的大小
        if (size[0] === 2 && size[1] === 2 && size[2] === 2) alarmNode.s3([1, 1, 1]);
        else alarmNode.s3([2, 2, 2]);
        alarmNode.scaleTimer = setTimeout(alarmNode.scaleFunc, formPane.v('scaleInterval'));//设置动画
    }
    alarmNode.blinkFunc = function(){//设置闪烁的动画
        var color = alarmNode.s('all.blend');//获取节点的style样式
        if (color === 'red') alarmNode.s({'all.blend': 'yellow'});//如果节点颜色为红色,那么设置为黄色
        else alarmNode.s({'all.blend': 'red'});
        alarmNode.blinkTimer = setTimeout(alarmNode.blinkFunc, formPane.v('blinkInterval'));
    }
    alarmNode.rotateFunc = function() {//设置旋转动画
        alarmNode.setRotation(alarmNode.getRotation() + Math.PI/20);//获取节点当前的旋转角度,在这个旋转角度之上添加 Math.PI/20 个角度
        alarmNode.rotateTimer = setTimeout(alarmNode.rotateFunc, formPane.v('rotInterval'));
    }
}

上边的卡通片自己设置了足以由此 form
表单面板上的性质来支配节点闪烁的速度,以致闪烁节点的卡通等等,主要说一下这么些效果在
form 表单上的得以达成:

formPane.addRow([//向form表单面板上添加一行元素
    {
        checkBox: {//复选框
            label: 'Enable Blink',//复选框对应的文本内容
            selected: true,//设置选中复选框
            onValueChanged: function(){//复选框值变化时回调的函数
                var data = dataModel.getDataByTag('colorAlarm');//通过tag标签获取节点
                if (this.getValue()) {//获取复选框当前值true/false
                    data.blinkTimer = setTimeout(data.blinkFunc, formPane.v('blinkInterval'));//直接通过设置节点的blinkTimer来设置动画
                }
                else {
                    clearTimeout(data.blinkTimer);//清除动画
                }
            }
        }
    },
    {
        id: 'blinkInterval',//form可以通过getValue(简写为v)来获取这个item的值
        slider: {//设置了该属性后HT将根据属性值自动构建ht.widget.Slider对象,并保存在element属性上
            min: 0,//滑动条最小值
            max: 1000,//滑动条最大值
            step: 50,//滑动条步进
            value: 500,//当前滑动条的值
        }
    }
], [0.1, 0.1]);//设置这行的两个item元素的宽度小于1的值为比例

最终来讲说 3D
管线上的小球流动的一些,这些职能确实充裕实用,何况做出来的功效也真正不错,跟大家分享~

第一,成立一条连线连接初步节点和完工节点并设置那些连线的样式,用 ht.Edge
能够将连线吸附在开局节点和得了节点上,那样活动那七个节点中的自便二个节点连线都会随着节点移动的任务变动,非常常有益:

var polyline = new ht.Edge(source, target);//创建连线
dataModel.add(polyline);//将连线添加进数据容器中
polyline.s({
    'edge.width': 5,//连线宽度
    'edge.type': 'points',//连线类型 为points时连线走向将由edge.points属性决定,用于绘制折线
    'edge.points': [//可设置类型为ht.List的{x:100, y:100}格式的点对象数组,当edge.type为points时起作用
        {x: source.getPosition3d()[0]+200, y: source.getPosition3d()[2], e: source.getPosition3d()[1]},
        {x: target.getPosition3d()[0]+400, y: target.getPosition3d()[2], e: target.getPosition3d()[1]}
    ],
    'edge.segments': [1, 4],//用于描述点连接样式,数组元素为整型值
    'shape3d': 'cylinder',//圆柱
    'shape3d.color': 'rgba(242, 200, 40, 0.4)',
    'shape3d.resolution': 30,//微分段数,可以决定曲线的平滑度
    'edge.source.t3': [20, 0, 0],//连线source端偏移,[tx, ty, tz]格式,默认为空
    'edge.target.t3': [20, 0, 0]//连线target端偏移,[tx, ty, tz]格式,默认为空
});

因为我们在成立连线的时候设置的 points
仅为曲线上的五个点,所以只要要博取曲线近来产生的点,是缺乏 source 和
target
多少个点的,我们重置一个数组,将那五个点增多进去,后边获取曲线上全部一些时会用上:

var list = new ht.List();
list.push({x: source.getPosition3d()[0], y: source.getPosition3d()[2], e: source.getPosition3d()[1]});//向数组中添加source点
polyline.s('edge.points').each(function(item){//添加style属性中已设置的两个点
    list.push(item);
});
list.push({x: target.getPosition3d()[0], y: target.getPosition3d()[2], e: target.getPosition3d()[1]});//添加target点

下一场创立八个在管线上海滑稽剧团动的小球节点,那是仅是设置节点,真正加多进数据容器
dataModel
中需求安装完全小学球的坐标时再增多,若无给节点设置岗位就将节点增多进数据容器中,节点的开第三地方正是3D 场景的中心心 [0, 0, 0] 之处。小球滑动的动漫代码如下:

var ball = new ht.Node();//创建小球节点
ball.s({//设置小球节点的样式
    'shape3d': 'sphere',//设置小球的3d模型为球形
    'shape3d.color': 'rgba(40, 90, 240, 0.4)'//设置3d模型的颜色
});

var delta = 10, flag = 0;
setInterval(function(){
    flag++;
    var length = (polyline.a('total') || 0) % polyline.a('length') + delta;//小球当前走过的曲线长度
    var cache = ht.Default.getLineCacheInfo(list, polyline.s('edge.segments'));//获取曲线上的点的信息
    var lineLength = ht.Default.getLineLength(cache);//获取曲线的总长度
    polyline.a('length', lineLength - 50);//因为我设置了edge的t3(相当于2d中的offset),所以线段长度实际没有那么长
    var offset = ht.Default.getLineOffset(cache, length);//曲线根据曲线上点的信息的偏移量
    ball.setPosition3d(offset.point.x + 10, offset.point.y, offset.point.z);//设置节点的坐标
    polyline.a('total', length);
    if(flag === 1) dataModel.add(ball);//这时候节点已经有了坐标了,可以添加进数据容器中了
}, 10);

咱俩还足以看看第二层上有五个优秀的绝超越八分之四形“平行四边形”和“梯形”,平行四边形是靠
createParallelogramModel
模型函数,这么些函数比较简单,createExtrusionModel(array, segments, top,
bottom, resolution, repeatUVLength, tall, elevationState of Qatar,array
是你要产生的图样的坐标点,那边只是本着于 xz 轴上画的平面图形,segments
指的是怎么连接那多少个坐标点,可参照他事他说加以调查 HT for Web
形状手册(),top
和 bottom 正是令你接收是还是不是有最上部只怕尾部,resolution
微分段数,大家刻画一段曲线的时候大概只要确认几个分级的点然后在每八个点时期的连线上把它分成四个段,那样那条线段就能够变得平平整整,ht
为了客商能够轻易操作这个线条,就封装了那多少个参数,repeatUVLength
默认为空,设置值后顶上部分和底部的贴图将基于制订长度值进行重复,tall
模型的中度,默以为 5,elevation 模型宗旨的 y 轴地方,暗中认可值为
0,设置那么些值能够使 xz 上的平面绕着 y 轴旋转。

底层的一个环形的机能是由此五个算法来贯彻的,环形得认可那些环形上有多少个元素,然后算每三个里面包车型大巴角度,在通过
sin、cos 来计量每一个要素的职分,得出了如下代码:

names = ['设备2', '设备3', '设备4', '设备5', '设备6', '设备7', '设备8', '设备9'];  
names.forEach(function(name, index) {  
    x = 400, y = 200, angle = 45, r = 120;  
    x = x3 + Math.sin((2 * Math.PI / 360) * angle * index) * r;  
    y = z3 + Math.cos((2 * Math.PI / 360) * angle * index) * r;  
    device = createRect([x, y3 + 15, y], [w * 0.1, 15, h * 0.1], '', '', floor3);  
    createEdge(device5, device);  
}); 

别的如若还应该有不懂的一些能够去官方网址(卡塔尔国查六柱预测应的手册,大概留言私信都能够。

沾满本文例子:

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注