很多人都有这样的疑问,基于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. 让TextView里面的文字逐个显示的动画效果实现(1)

    最近使用TextView时想要实现里面的文字逐个显示的动画效果,就如同打字一样. 主要实现思想:新建一个TextView的派生类,先将要逐个显示的字符串保存变量 mOriginalStr 中,然后启动 ...

  2. HTML基础学习(二)—CSS

    一.CSS概述     CSS(Cascading Stytle Sheets)层叠样式表,用来定义网页的显示效果.可以解决HTNL代码对样式定义的重复,提高了后期样式代码的可维护性,并增强了网页的显 ...

  3. 用C#写经理评分系统

    先写需求: 01.显示员工信息      02.实现项目经理给员工评分的功能 第一步:      建立两个类,员工类和项目经理类      定义属性和方法     员工类:工号.年龄.姓名.人气值.项 ...

  4. ArrayList,LinkedList的对比

    ArrayList,LinkedList都是Collection接口的通用实现方式,两者采用了不用的存储策略,用来适应不同场合的需要. 实现方式 ArrayList的内部采用集合的方式存储数据 唯一需 ...

  5. Java线程池(ThreadPool)详解

    线程五个状态(生命周期): 线程运行时间 假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间.    如果:T1 + T3 远大于 T2,则可以 ...

  6. Virtualbox 复制 CentOS 虚拟机无法联网

    Centos刚装好后无法联网 复制虚拟机后,出现 No such device eth0 我们要处理的三个问题: 在Virtualbox上安装好Centos后如何联网 如何在Virtualbox上复制 ...

  7. VS2003"无法启动调试 没有正确安装调试器"的解决方法

    在用VS2003做项目的时候,经常调试程序,但是有时候回出现如下问题“无法启动调试,没有正确安装调试器,请运行安装程序或修复调试器”.第一次碰到还以为是运气不好,就重新用vs2003安装程序重新修复了 ...

  8. LED操作

    灯上拉 GPIO_InitTypeDef GPIO_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); GPIO_InitS ...

  9. 查询sql server进程死锁方案

    SELECT a.spid , a.blocked , lastwaittype = RTRIM( a.lastwaittype ), waitresource = RTRIM( a.waitreso ...

  10. Patterns for application development with ASP.NET Core

    此文章翻译自 NDC { London } 16-20 January 2017 上, Damian Edwards和David Fowler的演讲,如果翻译不周,请大家指出错误. Logging 生 ...