很多人都有这样的疑问,基于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. Struts2基础学习(二)—Action

    一.ActionSupport      为了让用户开发的Action类更加规范,Struts2提供了一个Action接口,这个接口定义了Struts2的Action处理类应该实现的规范.下面是标准A ...

  2. ls命令的20个实用范例

    contents ls -l -h -lhS -l --block-size=M -a -d */ -g -G -n --color=never -i -p -r -R -t ls ~ ls --ve ...

  3. 爬楼梯问题-斐波那契序列的应用.md

    N 阶楼梯,一次可以爬1.2.3...n步,求爬楼梯的种类数 /** * 斐波那契序列 */ public class ClimbingStairs { // Sol 1: 递归 // 递归 公式:F ...

  4. JS window对象的top、parent、opener含义介绍 以及防止网页被嵌入框架的代码

    1.top该变更永远指分割窗口最高层次的浏览器窗口.如果计划从分割窗口的最高层次开始执行命令,就可以用top变量. 2.openeropener用于在window.open的页面引用执行该window ...

  5. 第九章 Criteria查询及注解

    第九章   Criteria查询及注解9.1 使用Criteria查询数据    9.1.1 条件查询        Criteria查询步骤:            1)使用session接口的cr ...

  6. 测试页面,页面里边一次加载50张不同的图片,每张5M以上,查看浏览器的内存使用情况

    测试页面 1.需要你写个测试页面,页面里边一次加载50张不同的图片,每张5M,查看浏览器的内存使用情况 2.可以10张 递增的方式测试 3.图片需要缩放,比如所有图片缩放成600*800的比例 目的 ...

  7. sptt规范介绍

    相关资源 如何开发sptt工程的原子操作 移动端测试方案--sptt sptt规范 一个标准的sptt工程的目录如下: [sptt-project] | -- [ios] | | -- [atoms] ...

  8. const常量类型

    1.定义:const常量类型表示一个”常值变量“,其值是不能被修改的变量.即一旦变量被声明为const类型,编译器将禁止任何试图修改该变量的操作. 2.声明:const <声明数据类型> ...

  9. require.js+bootstrap实现简单的页面登录和页面跳转

    小颖的这个demo其实很简单的,大家一起来先来看看页面效果图:          目录: 代码: inde.html <!DOCTYPE html> <html> <he ...

  10. sass入门学习篇(二)

    从语法开始但是语法也不是一两句的事情,首先看基本的导入,使用 一,sass有两种后缀名文件:一种后缀名为sass,不使用大括号和分号:另一种就是我们这里使用的scss文件,建议scss. 二,导入 使 ...