今天又返回好好地消化了一下我们的数据容器 DataModel,这里给新手做一个典型的数据模型事件处理的例子作为参考。这个例子看起来很简单,实际上结合了数据模型中非常重要的三个事件处理的部分:属性变化事件监听、选中变化事件监听以及数据模型变化事件监听。

为了让这个例子具现化,我将这个简单的例子做了一点改动,下面我会一一解释。

例子地址:http://hightopo.com/guide/guide/core/datamodel/examples/example_datamodel.html

这是我改造之后的模样,将 dataModel 数据容器共享,通过对数据容器的增删事件的监听得到的现在的结果,并且在显示上做了一点“手脚”。下面我们从头解析这例子,你们会知道为什么我特地将这个简单的例子提出来。

首先,我们得创建场景将作为基础,整个场景我算是分为三个部分,顶部工具栏,2D 部分以及 3D 部分。顶部工具栏部分使用的纯 HTML 写的:

<button οnclick="addData()">Add</button>
<button οnclick="removeData()">Remove</button>
<button οnclick="clearDataModel()">Clear</button>
<span id="property" class="output"></span>
<span id="model" class="output"></span>
<span id="selection" class="output"></span>

因为有点击事件,所以我们直接在 button 按钮上进行,后面的 span 标签显示纯文本内容。

我们知道,HT 的所有组件都是基于一个根部 div 的,要将这个 div 部署到 html 页面上很简单,但是 HT 内部对这个 div 设置了绝对定位,所以我们在添加这个 div 进 HTML 页面中时,也要设置绝对定位中的位置,我在页面中添加了一个 div,将 HT 的部分都添加进这个 div 中:

<div id="myDiv" style="border: 1px solid red; width: 800px; height: 600px;position: absolute; "></div>

dataModel = new ht.DataModel();
g3d = new ht.graph3d.Graph3dView(dataModel);
g3d.setGridVisible(true);//设置网格可见
g3d.setEye(185, 50, 470);//设置3d的眼睛位置
g3d.setCenter(200, 47, 10);//设置3d的中心位置, 这两个属性都是为了让用户看3d上的场景更舒服,更直接
g2d = new ht.graph.GraphView(dataModel);
g2d.setEditable(true);//设置2d图元可编辑
g2d.fitContent(true);//将所有的图元显示到页面上
splitView = new ht.widget.SplitView(g2d, g3d, 'v', 0.3);//分割组件,装了2d和3d两个场景
splitView.addToDOM();//将分割组件添加进body中,并设置绝对定位的位置
myDiv = document.getElementById('myDiv');
myDiv.appendChild(splitView.getView());//将分割组件添加进myDiv中

接着添加节点进入 dataModel 数据模型之中,我们这里做的是机房的机柜,本来想做的是服务器,手头上暂时只有这个资源,也不赖。我封装了一个增加函数,一个删除函数,还有一个清楚函数,分别对应的是工具栏上的“Add”、“Remove”以及“Clear”三个功能:

function addData() {var data = new ht.Node();data.setPosition(index*60, 50);data.setName('node'+index);data.setSize(40, 40);data.setImage('cabinet');data.s({'image.stretch': 'centerUniform','shape3d': 'cabinet'});index++;dataModel.add(data);return data;
}
function removeData() {if(!dataModel.sm().ld()) return;dataModel.remove(dataModel.sm().ld());
}
function clearDataModel(){dataModel.clear();index = 0;
}

其中,代码中出现的“data.setImage('cabinet')”,是我通过 ht.Default.setImage('cabinet', 'imageURL') 方式定义的,调用的时候直接 data.setImage('imageName') 即可,具体参考 HT for Web 入门手册 image 章节。

2D 的图片显示肯定和 3D 的模型显示是不一样的,2D 中我们直接用贴图就能解决,而 HT 3D 中支持 obj 格式的模型显示,就是这个部分:

HT 封装了解析 obj 格式的函数 ht.Default.loadObj 函数用来导入模型,该函数有三个参数,第一第二分别为 obj 文件的路径和 mtl 文件的路径,第三个参数为 json 格式控制参数,具体参数请参考 HT for Web OBJ 手册 loadObj 函数章节(ps:用 obj 模型会导致跨域问题,要放到服务器上运行):

ht.Default.loadObj('obj/机柜组件1.obj', 'obj/机柜组件1.mtl', {cube: true,//是否将模型缩放到单位1的尺寸范围内,默认为falsecenter: true,//模型是否居中prefix: 'obj/',//路径前缀,如果前面参数写了路径前缀,这个不写也可以shape3d: 'cabinet',//指定 shape3d 名称finishFunc: function(modelMap, array, rawS3){//调用ht.Default.parseObj解析后的返回值,若加载或解析失败则返回值为空window.rawS3 = rawS3;//让当前模型的尺寸为原始尺寸if(modelMap){cabinet1 = addData();//添加两个节点到 dataModel 中cabinet2 = addData();}}
});

现在,节点和模型都已经导入到场景中了,终于来到了我们今天的重点,事件交互部分。ht.DataModel 数据容器管理着 Data 数据的增删以及变化事件的派发,这里我们就这两种事件进行对 Data 数据的管理。

1. addDataModelChangeListener(function(e) {}, scope) 增加数据模型增删变化事件监听器,可用简写 mm(func, scope), func 为监听器函数,scope 为监听器函数域(可选),在监听器函数中的 event 有两个属性: kind 和 data,其中 kind 为事件的类型:

  • e.kind === 'add'代表添加Data对象,e.data为被添加的对象
  • e.kind === 'remove'代表删除Data对象,e.data为被删除的对象
  • e.kind === 'clear'代表容器被清除

这里我们将对模型的增删事件的监听结果传给 HTML 中的 id 为 model 的 span 作为内容:

var model = document.getElementById('model');
dataModel.addDataModelChangeListener(function(e) {if(e.kind === 'add')//如果事件类型为 add 增加节点model.innerHTML = e.data + ' added';//就将model 的内容替换为 添加的节点 addedif(e.kind === 'remove')model.innerHTML = e.data + ' removed';if(e.kind === 'clear')model.innerHTML = 'dataModel cleared'
});

2. addDataPropertyChangeListener(function(e) {}, scope) 增加模型中 Data 数据属性变化事件监听器,可用简写 md(func, scope),其中 event 事件有四种属性:

  • e.data代表属性变化的对象
  • e.property代表变化属性的名字
  • e.newValue代表属性的新值
  • e.oldValue代表属性的老值
  • Data对象在设置属性值函数内调用firePropertyChange(property, oldValue, newValue)触发属性变化事件:
    • get/set类型属性,如setAge(98)触发事件的e.propertyage
    • style类型属性名前加s:前缀以区分,如setStyle('age', 98)触发事件的e.propertys:age
    • attr类型属性名前加a:前缀以区分,如setAttr('age', 98)触发事件的e.propertya:age

这里我们将对模型中 Data 的属性变化事件的监听结果传给 HTML 中的 id 为 property 的 span 作为内容:

var model = document.getElementById('model');
dataModel.addDataPropertyChangeListener(function(e) {property.innerHTML = e.data + '\'s ' + e.property + ' has changed, the old value is ' + e.oldValue + ' and the new value is ' + e.newValue;
});

3. 最后,我们对选中的节点进行增加监听器,监听选中变化事件。ht.SelectionModel管理 DataModel 模型中 Data 对象的选择状态, 每个 DataModel 对象都内置一个 SelectionModel 选择模型,控制这个 SelectionModel 即可控制所有绑定该 DataModel 的组件的对象选择状态, 这意味着共享同一 DataModel 的组件默认就具有选中联动功能。

如果希望某些组件不与其他组件选中联动,可通过调用 view.setSelectionModelShared(false), 这样该 view 将创建一个专属的 SelectionModel 实例。

综上所述有两种途径可得到 SelectionModel:

  • dataModel.getSelectionModel()获取数据容器中组件共享的选中模型。
  • view.getSelectionModel()获取当前组件使用的选中模型,selectionModelSharedfalse时,返回view专用的选择模型。

addSelectionChangeListener(function(e) {}, scope)增加监听器,监听选中变化事件,简写为 ms(func, scope):

  • e.datas包含所有选中状态变化的对象,之前选中现在取消选中,或之前没选中现在被选中的对象
  • e.kind === 'set'代表此事件由setSelection(datas)引发
  • e.kind === 'remove'代表此事件由removeSelection(datas)引发
  • e.kind === 'append'代表此事件由appendSelection(datas)引发
  • e.kind === 'clear'代表此事件由clearSelection(datas)引发

这里我们将对模型中 Data 的选中变化事件的监听结果传给 HTML 中的 id 为 selection 的 span 作为内容:

var selection = document.getElementById('selection');
dataModel.sm().addSelectionChangeListener(function(e){if(dataModel.sm().size() === 0) selection.innerHTML = 'Nothing selected';//如果选中模型的“长度”为0,即没有选中内容else if(dataModel.sm().size() === 1) selection.innerHTML = e.datas + ' selected';else selection.innerHTML = dataModel.sm().size() + ' datas selected';
});

以上,所有的代码全部分析完毕!大家可以天马行空,创建出属于你自己的3维模型!

基于HTML5 Canvas 点击添加 2D 3D 机柜模型相关推荐

  1. 用html5制作机柜,基于HTML5 Canvas 点击添加 2D 3D 机柜模型

    今天又返回好好地消化了一下我们的数据容器 DataModel,这里给新手做一个典型的数据模型事件处理的例子作为参考.这个例子看起来很简单,实际上结合了数据模型中非常重要的三个事件处理的部分:属性变化事 ...

  2. 基于HTML5 Canvas实现工控2D叶轮旋转

    之前在拓扑上的应用都是些静态的图元,今天我们将在拓扑上设计一个会动的图元--叶轮旋转. 我们先来看下这个叶轮模型长什么样 从模型上看,这个叶轮模型有三个叶片,每一个叶片都是不规则图形,显然无法用上我们 ...

  3. background 旋转_基于HTML5 Canvas实现工控2D叶轮旋转

    之前在拓扑上的应用都是些静态的图元,今天我们将在拓扑上设计一个会动的图元--叶轮旋转. 我们先来看下这个叶轮模型长什么样 从模型上看,这个叶轮模型有三个叶片,每一个叶片都是不规则图形,显然无法用上我们 ...

  4. 基于HTML5 Canvas和jQuery 的画图工具的实现

    简介 HTML5 提供了强大的Canvas元素,使用Canvas并结合Javascript 可以实现一些非常强大的功能.本文就介绍一下基于HTML5 Canvas 的画图工具的实现.废话少说,先看成品 ...

  5. HTML绘制交互图,基于 HTML5 Canvas 的交互式地铁线路图

    原标题:基于 HTML5 Canvas 的交互式地铁线路图 作者:xhload3d my.oschina.net/xhload3d/blog/1629064 摘要:感觉目前地铁上的地铁线路图也不是很人 ...

  6. html5 can,基于html5 can-vas实现漫天飞雪效果实例

    本文实例讲述了基于html5 canvas实现漫天飞雪效果的方法,运行该实例可以看到很棒的下雪效果.如下图所示: 主要代码如下:代码如下:ttp://www.w3.org/TR/xhtml1/DTD/ ...

  7. 基于html5 Canvas图表库 : ECharts

    基于html5 Canvas图表库 : ECharts 分类 编程技术 ECharts开源来自百度商业前端数据可视化团队,基于html5 Canvas,是一个纯Javascript图表库,提供直观,生 ...

  8. echart图片库_基于html5 Canvas图表库 : ECharts

    ECharts开源来自百度商业前端数据可视化团队,基于html5 Canvas,是一个纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表.创新的拖拽重计算.数据视图.值 ...

  9. php项目网页音乐播放器插件,基于HTML5 canvas和Web Audio的音频播放器插件

    wavesurfer.js是一款基于HTML5 canvas和Web Audio的音频播放器插件.通过wavesurfer.js你可以使用它来制作各种HTML5音频播放器,它可以在各种支持 Web A ...

最新文章

  1. 简述神经网络的训练过程?
  2. 闲诗一首:《扬州即行》
  3. CSS 7:网页布局(传统布局,flex布局,布局套路)
  4. HDU 4614 Vases and Flowers 【线段树】+【二分】
  5. Windows 公共控件库研究
  6. 汇编语言运算符优先级
  7. VTK:可视化之RandomProbe
  8. Educational Codeforces Round 81 (Rated for Div. 2) E. Permutation Separation 线段树 + dp
  9. 利用tensorflow构建AlexNet模型,实现小数量级的猫狗分类(只有train)
  10. windows 下安装Python
  11. javascript(定时函数)
  12. 树莓派raspberry pi 4 SSH默认密码无法登录解决办法
  13. 动态生成icon图标
  14. 基于Python+ResNet实现的不良图片识别模型
  15. 计算机网络课程论文:《浅谈交换机、路由器》
  16. mac上彻底删除 搜狗输入法 鼠须管输入法
  17. 编写仿supersu的权限管理工具(aosp11 root、实现aosp系统内置wifi、root管理apk)
  18. 【学习记录】阿里天池SQL练习题1-python与SQL方式比较
  19. notepad++格式化xml文件
  20. odoo----权限机制

热门文章

  1. 字符串和字符的概念与区别
  2. C#调用sap接口获取数据到DataTable
  3. 毕业生求职前必看的十部电影
  4. 2021年前端最优秀的开发工具
  5. 学习英语01——听力——剑雅12 T8S2
  6. 图像处理之滤波器介绍
  7. shell,给你一个目录,里面有很多文件,把他们改成 1.txt 2.txt 3.txt ....以此类推、盗墓者是个丑奴儿
  8. 一个不错的 png压缩工具 pngquant 使用介绍 批量压缩png
  9. 【转】宇宙的基本法则
  10. cf-723C Polycarp at the Radio