很多人都有这样的疑问,基于HTML5 Canvas实现的元素怎么和用户进行交互?在这里我们用到HT for Webhttp://www.hightopo.com/guide/guide/core/beginners/ht-beginners-guide.html)写了个Demo进行示例。

  场景如下所示,在该场景中双击温度和湿度下的Node,会生成输入框供用户填写内容,这之后,用户按下“Enter”键可以将输入内容传到Node中,同时删除输入框,地址::http://www.hightopo.com/demo/GraphInput/display.html

接下来我们探讨一下具体实现:

准备工作如下:

<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 入门手册http://www.hightopo.com/guide/guide/core/beginners/ht-beginners-guide.html#ref_graphviewinteraction),在这里,我们用内置的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的朋友,也望大家不吝赐教。

基于HTML5 Canvas实现用户交互的更多相关文章

  1. 基于 HTML5 Canvas 的可交互旋钮组件

    前言 此次的 Demo 效果如下: Demo 链接:https://hightopo.com/demo/comp-knob/ 整体思路 组件参数 绘制旋钮 绘制刻度 绘制指针 绘制标尺 绘制文本 1. ...

  2. 基于html5 Canvas图表库 : ECharts

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

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

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

  4. 基于HTML5 Canvas实现的图片马赛克模糊特效

    效果请点击下面网址: http://hovertree.com/texiao/html5/1.htm 一.开门见山受美国肖像画家Chuck Close的启发,此脚本通过使用HTML5 canvas元素 ...

  5. 基于html5 canvas和js实现的水果忍者网页版

    今天爱编程小编给大家分享一款基于html5 canvas和js实现的水果忍者网页版. <水果忍者>是一款非常受喜欢的手机游戏,刚看到新闻说<水果忍者>四周年新版要上线了.网页版 ...

  6. 基于HTML5 Canvas的线性区域图表教程

    之前我们看到过很多用jQuery实现的网页图表,有些还是比较实用的.今天我们来介绍一款基于HTML5 Canvas的线性区域图表应用,这个图表应用允许你使用多组数据来同时展示,并且将数据结果以线性图的 ...

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

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

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

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

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

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

随机推荐

  1. 性能调优案例分享:jvm crash的原因 1

    性能调优案例分享:jvm crash的原因   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq: ...

  2. 测试开发Python培训:自动发布新浪微博-技术篇

    测试开发Python培训:自动发布新浪微博-技术篇   在前面我们教大家如何登陆,大家需要先看自动登陆新浪微博(http://www.cnblogs.com/laoli0201/articles/48 ...

  3. ElasticSearch查询 第五篇:布尔查询

    布尔查询是最常用的组合查询,不仅将多个查询条件组合在一起,并且将查询的结果和结果的评分组合在一起.当查询条件是多个表达式的组合时,布尔查询非常有用,实际上,布尔查询把多个子查询组合(combine)成 ...

  4. 什么是javascript的回调函数?

    回调函数(callback) 基本上每本书里都会提一提实际上我们几乎每天都在用回调函数,那么如果问你到底什么是回调函数呢? 1. 回调函数是作为参数传递给另一个函数 2. 函数运行到某种程度时,执行回 ...

  5. linux常用20命令 --转载

    玩过Linux的人都会知道,Linux中的命令的确是非常多,但是玩过Linux的人也从来不会因为Linux的命令如此之多而烦恼,因为我们只需要掌握我们最常用的命令就可以了.当然你也可以在使用时去找一下 ...

  6. 前馈神经网络-反向传播(Back Propagation)公式推导走读

        构造:输入神经元个数等于输入向量维度,输出神经元个数等于输出向量维度.(x1=(1,2,3),则需要三个输入神经元)   一 前向后传播   隐层:

  7. lca最近公共祖先(模板)

    洛谷上的lca模板题--传送门 学了求lca的tarjan算法(离线),在洛谷上做模板题,结果后三个点超时. 又把询问改成链式前向星,才ok. 这个博客,tarjan分析的很详细. 附代码-- #in ...

  8. superslide2插件

    地址:http://www.superslide2.com/ 做自适应要注意该宽度和高度 等比缩放

  9. lua 数据类型

    lua 数据类型 8 种数据类型 类型 说明 nil 空类型 boolean 布尔类型 number 数值型, 浮点型 string 字符串 function 函数 userdata 用户自定义结构 ...

  10. NuGet 自定义配置

    默认配置: 默认配置文件的路径%APPDATA%\NuGet\NuGet.Config (DOS) 或 $ENV:APPDATA\NuGet\NuGet.Config (PowerShell),(例如 ...