学习 HT for Web 中的交互事件
Posted 图扑软件
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习 HT for Web 中的交互事件相关的知识,希望对你有一定的参考价值。
交互事件增强了用户体验,使得我们的作品更加生动。今天,使用 HT for Web 写了个典型的 Demo 来了解 HT 中的交互事件。
场景如下所示,在该场景中双击温度和湿度下的 Node,会生成输入框供用户填写内容,这之后,用户按下 “Enter” 键可以将输入内容传到 Node 中,同时删除输入框,地址:http://www.hightopo.com/demo/GraphInput/display.html
接下来我们探讨一下具体实现:
准备工作如下:先引入我们的 ht.js
<script src='ht.js'></script>
新建一张拓扑图纸,并将其加入页面。
dataModel = new ht.DataModel();
graphView = new ht.graph.GraphView(dataModel);
graphView.addToDOM();
1、 利用系统中定义好的矢量资源进行反序列化来实现场景图:
ht.Default.xhrLoad('TemperatureIndex.json', function(text)
var json = ht.Default.parse(text);
if(json.title) document.title = json.title;
dataModel.deserialize(json);
2、 双击事件
本例双击会产生输入框,在我们的 HT 中,GraphView 默认内置了一些交互器,以实现基本的选择、单双击、缩放、平移和编辑等交互的功能,内置的交互器有:
内置的 Interactor 在交互过程中会派发事件,可通过 GraphView#addInteractorListener 进行监听,简写为mi(详情可看 HT for Web 入门手册),在这里,我们用内置的 graphView.addInteractorListener 监听双击事件:
graphView.addInteractorListener(function(e)
if (e.kind !== 'doubleClickData') return;
if (currentInput) removeInput();
var data = e.data;
if (clickableTags[data.getTag()])
setTimeout(function()
createInput('input', data);
, 0);
);
3、 创建输入框
在双击事件发生时,首先需要判断发生双击事件的元素是不是场景中定义的标签名为 ‘temperature’ 和 ‘humidity’ 的 node 图元,我们用 clickableTags 对象来保存两个 node:
var clickableTags =
'temperature': true,
'humidity': true
在双击的图元是 ‘temperature’ 或者 ‘humidity’ 时,调用 createInput() 函数生成输入框, createInput() 代码如下:
function createInput(tagName,node)
if (currentInput)
removeInput(graphView, currentInput);
return;
else
var element = document.createElement(tagName);
graphView.getView().appendChild(element);
element.bindingNode = node;
ht.Default.setFocus(element);
currentInput = element;
layout(currentInput); // 布局
return currentInput;
在 createInput() 函数中,用全局变量 currentInput 保存着当前生成的输入框元素,为保证再次生成输入框时,调用 removeInput() 清除上次生成的输入框元素,从而不影响性能。
4、 布局
生成的输入框应该放在哪儿?这就是 layout() 函数中所做的事情。layout() 函数修改生成的输入框的位置信息,让其在 GraphView 拓扑图组件上的位置刚好与 node 图元的位置相同。
function layout(element)
var rect = element.bindingNode.getRect();
var x = rect.x;
var y = rect.y;
element.style.position = 'absolute';
element.style.width = rect.width + 'px';
element.style.height = rect.height + 'px';
element.style.top = y + 'px';
element.style.left = x + 'px';
element.style.background = '#fff';
element.style.color = '#000';
element.style.textAlign = 'center';
以 ‘temperature’ 为例,在点击标签名为 ‘temperature’ 的 node 图元时,会在其上生成一个输入框,获取该 node 图元的宽、高、位置信息,并分别赋值给绝对定位后输入框的宽、高、位置,这样即可让输入框刚好覆盖住 node 图元。
5、 平移和缩放
做到这里,可能细心思考的朋友会发现,在对整个场景图进行平移和缩放时,按照上诉布局方式,输入框的位置和大小却没有跟随着 node 图元的位置进行改变,所以我们在布局时还需要思考到平移、缩放事件。
首先,layout 函数的内容中,元素的宽、高、位置信息必须加入平移和缩放产生的结果,所以,最终 layout 代码如下:
function layout(element)
var rect = element.bindingNode.getRect();
var zoom = graphView.getZoom();
var tx = graphView.tx();
var ty = graphView.ty();
rect.x *= zoom;
rect.y *= zoom;
rect.width *= zoom;
rect.height *= zoom;
var x = tx + rect.x;
var y = ty + rect.y;
element.style.position = 'absolute';
element.style.width = rect.width + 'px';
element.style.height = rect.height + 'px';
element.style.top = y + 'px';
element.style.left = x + 'px';
element.style.background = '#fff';
element.style.color = '#000';
element.style.textAlign = 'center';
其次,我们需要对平移和缩放事件添加监听,以便能在该事件发生时,再次调用 layout() 函数将输入框的位置进行同步,在这里,我们用内置的交互器 addPropertyChangeListener(简写为mp),监听 zoom、translateX、translateY 属性的变化:
var changeProperties =
'zoom': true,
'translateX': true,
'translateY':true
graphView.mp(function(e)
if (changeProperties[e.property])
var elements = document.getElementsByTagName('input');
for (var i = 0; i < elements.length; i++)
layout(elements[i]);
);
6、 更新 node
大家在 Demo 中可以发现,我们按下 Enter 键时,输入的文字会同步到 node 中,其实这里做了两件事: 给 node 设值后删除输入框。
a、给 node 设值,是用一个名为 setText() 的函数来实现的,实现代码如下:
function setText(tagName)
var element = document.getElementsByTagName(tagName);
if(!element) return;
for (var i = 0; i < element.length; i++)
var value = (element[i].value) ? element[i].value : 32 ;
element[i].bindingNode.s('text', value);
在检测输入框中有值时,给 node 图元赋值用到我们 HT 的 setStyle(简写为s)方法。
b、删除输入框
function removeInput()
if(!currentInput) return;
graphView.getView().removeChild(currentInput);
currentInput = null;
c、添加 Enter 的事件监听器
因为没有监听键盘的内置交互器,所以我们通过 graphView.getView().addEventListener 直接对底层的 div 添加监听。
graphView.getView().addEventListener('keydown', function(event)
if(ht.Default.isEnter(event))
setText('input');
removeInput();
else if(ht.Default.isEsc(event))
removeInput();
, false);
最后,再贴上 Demo 地址(http://www.hightopo.com/demo/GraphInput/display.html ),希望能够帮助那些需要在拓扑图中加入原生 html 的朋友,也望大家不吝赐教。
以上是关于学习 HT for Web 中的交互事件的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript 中的事件流和事件处理程序(读书笔记思维导图)