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

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

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

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

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

<button onclick="addData()">Add</button>
<button onclick="removeData()">Remove</button>
<button onclick="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的尺寸范围内,默认为false
center: 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 的内容替换为 添加的节点 added
if(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 Canvas实现工控2D叶轮旋转

    之前在拓扑上的应用都是些静态的图元,今天我们将在拓扑上设计一个会动的图元——叶轮旋转. http://www.hightopo.com/guide/guide/core/serialization/e ...

  2. 基于HTML5 Canvas实现用户交互

    很多人都有这样的疑问,基于HTML5 Canvas实现的元素怎么和用户进行交互?在这里我们用到HT for Web(http://www.hightopo.com/guide/guide/core/b ...

  3. 基于 HTML5 Canvas 的智能安防 SCADA 巡逻模块

    基于 HTML5 Canvas 的智能安防 SCADA 巡逻模块 前言 最近学习了 HT for Web flow 插件,除了正常的 flow 效果,其中还有两个十分好用的两个接口 getPercen ...

  4. 一款基于HTML5 Canvas的画板涂鸦动画

    今天给各网友分享一款基于HTML5 Canvas的画板涂鸦动画.记得之前我们分享过一款HTML5 Canvas画板工具,可以切换不同的笔刷,功能十分强大.本文今天要再来分享一款基于HTML5 Canv ...

  5. 基于HTML5 Canvas和jQuery 的绘图工具的实现

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

  6. 基于HTML5 Canvas的网页画板实现教程

    HTML5的功能非常强大,尤其是Canvas的应用更加广泛,Canvas画布上面不仅可以绘制任意的图形,而且可以实现多种多样的动画,甚至是一些交互式的应用,比如网页网版.这次我们要来看的就是一款基于H ...

  7. 基于html5 Canvas图表库 : ECharts

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

  8. 基于html5 canvas 的客户端异步上传图片的插件,支持客户端压缩图片尺寸

    /** * Created by xx on 15-05-28. * 基于html5 canvas 的客户端异步上传画片的插件 * 在实际应用中,常常要用于上传图片的功能.在现在越来越多的手机weba ...

  9. JavaScript 基于HTML5 canvas 获取文本占用的像素宽度

    基于HTML5 canvas 获取文本占用的像素宽度   by:授客 QQ:1033553122 直接上代码   // 获取单行文本的像素宽度 getTextPixelWith(text, fontS ...

随机推荐

  1. 一款低延迟的分布式数据库同步系统--databus

    每次看到马路对面摩托罗拉的大牌子,都想起谷歌125亿美元收购摩托罗拉移动,后来又以29亿美元卖给联想的事情.谷歌所做的决策都比较考虑长远利益,在这串交易中,谷歌获得了摩托罗拉最有价值的几千项专利,稳健 ...

  2. 【转载】使用CSS将图片转换成黑白(灰色、置灰)

    文章转载自 张鑫旭-鑫空间-鑫生活 http://www.zhangxinxu.com/ 原文链接:http://www.zhangxinxu.com/wordpress/?p=2547原文摘要: . ...

  3. 前端笔记----jquery入门知识点总结

    一.jquery的加载方法 $(document).ready(function(){js代码}); $(function(){js代码});(一般使用这个); 注意点1:使用jquery必须先导入函 ...

  4. Android基础知识03—Activity的基本用法

    ------Activity 活动------ 活动 Activity 是一种包含用户界面的组件,即一个界面就是一个活动 创建活动的过程: >> 创建一个类,继承自Activity类,并且 ...

  5. LeetCode 665. Non-decreasing Array (不递减数组)

    Given an array with n integers, your task is to check if it could become non-decreasing by modifying ...

  6. LeetCode 339. Nested List Weight Sum (嵌套列表重和)$

    Given a nested list of integers, return the sum of all integers in the list weighted by their depth. ...

  7. Linux_服务器_01_查看公网IP

    在linux终端提示符下,输入以下命令: 精选: curl icanhazip.com/curl ifconfig.mecurl ipecho.net/plain 可以看到下图已经查询到公网IP地址了 ...

  8. C语言程序内存布局

    C语言程序内存布局 如有转载,请注明出处:http://blog.csdn.net/embedded_sky/article/details/44457453 作者:super_bert@csdn 一 ...

  9. dfs序和欧拉序

    生命不息,学习不止,昨天学了两个算法,总结一下,然而只是略懂,请路过的大佬多多谅解.   一.dfs序 1.什么是dfs序? 其实完全可以从字面意义上理解,dfs序就是指一棵树被dfs时所经过的节点的 ...

  10. Python中编码问题:u'\xe6\x97\xa0\xe5\x90\x8d' 类型的转为utf-8的解决办法

    相信小伙伴们遇到过类似这样的问题,python2中各种头疼的转码,类似u'\xe6\x97\xa0\xe5\x90\x8d' 的编码,直接s.decode()是无法解决编码问题.尝试了无数办法,都无法 ...