用户鼠标移入时,有弹出框出现,这样的需求很常见。这在处理HTML元素实现时简单,但是如果是对 HTML5 Canvas 构成的图形进行处理,这种方法不再适用,因为 Canvas 使用的是另外一套机制,无论在 Canvas 上绘制多少图形,Canvas 都是一个整体。而图形本身实际都是 Canvas 的一部分,不可单独获取,所以也就无法直接给某个图形增加 JavaScript 事件。然而,在 HT for Web 中,这种需求很容易实现,先附上Demohttp://www.hightopo.com/demo/blog_meadow_20170605/index.html

  这个场景图是基于 HT for Web 的 JSON 文件,可能大家对怎么生成这样的 JSON 文件有疑惑,其实这里是基于这个麻雀虽小五脏俱全的“HTML5拓扑图编辑器http://www.hightopo.com/demo/2deditor_20151010/HT-2D-Editor.html)进行了扩展,很容易就自定义出满足我需求拓扑编辑器。不仅如此,在这个 Demo 中,定义的三种类型弹框的矢量图 ‘tips1.json’、‘tips2.json’、‘tips3.json’ 是通过这个矢量编辑器http://www.hightopo.com/demo/vector-editor/index.html)简单绘制了下,也还蛮好用。在上述场景中,用户将鼠标移入到草地等对象时,会有弹出框显示它的详细信息。

具体实现如下:

准备工作

  引入我们的 HThttp://www.hightopo.com/):

<script src='ht.js'></script>

  

dataModel = new ht.DataModel();
graphView = new ht.graph.GraphView(dataModel);
graphView.addToDOM();

 

   HT提供了自定义的 JSON 格式的矢量描述形式,以 HT 标准定义的 JSON 矢量格式,也可以作为图片进行注册和使用, HT 的矢量方式比传统格式更节省空间,缩放不失真,戳 HT for Web 了解详细信息。这里,将三种形状的 JSON 弹出框注册成图片以便后续调用:

ht.Default.setImage('tips1', 'symbols/tips1.json');
ht.Default.setImage('tips2', 'symbols/tips2.json');
ht.Default.setImage('tips3', 'symbols/tips3.json');

 然后获取有交互效果的对象,其中各个对象中的属性名是给各个图元设置好的标签名: 

 

//树
var tree = {
'tree1' : true,
'tree2' : true,
'tree3' : true
}; //草地
var grass = {
'grass1' : true,
'grass2' : true,
'grass3' : true
}; //山
var mountain = {
'mountain': true
};

 

弹出框

其实弹出框的本质是一个 Node,当用户鼠标移入移出时,

1、控制 Node 的隐藏和显示可以达到弹框的效果;

2、鼠标位置的改变伴随着 Node 位置的改变;

3、鼠标移入到不同的对象上时, Node 上的贴图也跟着发生变化;

4、Node 中的属性值也随着鼠标位置发生变化。

所以,要实现弹框,首先应新建 Node,并将其的层级设置为‘higher’,在这之前还需要将场景图的 JSON 文件反序列化,并且给反序列化后的图元均设置为层级‘lower’,防止被已有的图元挡住:

ht.Default.xhrLoad('meadow.json', function(text) {
const json = ht.Default.parse(text);
if(json.title) document.title = json.title;
dataModel.deserialize(json); //设置层级
dataModel.each(function(data){
data.setLayer('lower');
}); //新建node
var node = new ht.Node();
node.s('2d.visible',false);
node.setLayer('higher');
dataModel.add(node); })

然后,对底层的 DIV 监听 mousemove 事件,判断鼠标的位置是否在上述三个对象之上,根据对象类型,调用 layout() 函数对 Node 重新布局:

 

graphView.getView().addEventListener('mousemove', function(e) {
node.s('2d.visible',false);
var hoverData = graphView.getDataAt(e);
pos = graphView.getLogicalPoint(e);
if(!hoverData) return;
if(tree[hoverData.getTag()]){
layout(node, pos, 'tips1');
} else if (grass[hoverData.getTag()]) {
layout(node, pos, 'tips2');
} else if (mountain[hoverData.getTag()]) {
layout(node, pos, 'tips3');
}
});

  layout()函数所做的事情,已经在前面详细的阐述,其中,弹框中属性值的更新是将 JSON 文件的的 text 属性进行数据绑定,绑定的格式很简单,只需将以前的参数值用一个带 func 属性的对象替换即可,func 的内容有一下几种类型:

1、function类型,直接调用该函数,并传入相关 Data 和 view 对象,由函数返回值决定参数值,即 func(data, view);调用。

2、string类型:

style@***开头,则返回 data.getStyle(***)值,其中***代表 style 的属性名。

attr@***开头,则返回 data.getAttr(***)值,其中***代表 attr 的属性名。

field@***开头,则返回 data.***值,其中***代表 attr 的属性名。

如果不匹配以上几种情况,则直接将 string 类型作为 data 对象的函数名调用 data***(view),返回值作为参数值。

除了 func 属性外,还可以设置 value 属性作为默认值,如果对应的 func 取得的值为 undefined 或者 null 时,则会采用 value 属性定义的默认值,详情可见 HT for Web数据绑定手册http://www.hightopo.com/guide/guide/core/datamodel/ht-datamodel-guide.html)。例如,在这里,'tips1.json'文件中对阳光值进行数据绑定的结果如下:

 

"text": {
"func": "attr@sunshine",
"value": "阳光值"
},

 下面贴上 layout() 函数的源代码:

function layout(node, pos, type){
node.s('2d.visible',true);
node.setImage(type);
if(type == 'tips1'){
node.setPosition(pos.x + node.getWidth()/2, pos.y - node.getHeight()/2);
node.a({
'sunshine' : '阳光值 : '+ (pos.x/1000).toFixed(2),
'rain' : '雨露值 : '+ (pos.y/1000).toFixed(2),
'love' : '爱心值 : ***'
});
} else if(type == 'tips2'){
node.setPosition(pos.x , pos.y - node.getHeight()/2);
node.a({
'temp' : '温度 : 30',
'humidity' : '湿度 : '+Math.round(pos.x/100)+'%'
});
} else if(type == 'tips3'){
node.setPosition(pos.x - node.getWidth()/2, pos.y - node.getHeight()/2);
node.a({
'hight' : '海拔 : ' + Math.round(pos.y)+'米',
'landscapes' : '地貌 : 喀斯特'
});
}
}

 

云移动

最后,我们的 Demo 还有个云移动的动画效果,在 HT 的数据模型驱动的图形组件的设计架构下,动画可理解为将某些属性由起始值逐渐变为目标值的过程, HT 提供了ht.Default.startAnim的动画函数,ht.Default.startAnim 支持 Frame-Based 和 Time-Based 两种方式的动画:

Frame-Based 方式用户通过指定 frames 动画帧数,以及 interval 动画帧间隔参数控制动画效果;

Time-Based 方式用户只需要指定 duration 的动画周期的毫秒数即可,HT 将在指定的时间周期内完成动画。

详情见 HT for Web。

在这里我们用的是 Time-Based 方式,源码如下:

var cloud = dataModel.getDataByTag('cloud');
parent = dataModel.getDataByTag('mountain');
round1 = parent.getPosition().x - parent.getWidth()/2 + cloud.getWidth()/2;
round2 = parent.getPosition().x + parent.getWidth()/2 - cloud.getWidth()/2;
end = round1; //云运动动画
var animParam = {
duration: 10000,
finishFunc: function() {
end = (end == round1) ? round2 : round1;
ht.Default.startAnim(animParam);
},
action: function(v, t) {
var p = cloud.getPosition();
cloud.setPosition(p.x + (end - p.x) * v , p.y);
}
};
ht.Default.startAnim(animParam);

  最后,再次放上我们的 Demo (http://www.hightopo.com/demo/blog_meadow_20170605/index.html),供大家参考。

 

 

 

基于HTML5 Canvas 实现弹出框的更多相关文章

  1. .NET MVC 学习笔记(四)— 基于Bootstarp自定义弹出框

    .NET MVC 学习笔记(四)—— 基于Bootstarp自定义弹出框 转载自:https://www.cnblogs.com/nele/p/5327380.html (function ($) { ...

  2. 基于js alert confirm样式弹出框

    基于js alert confirm样式弹出框.这是一款根据alert confirm优化样式的确认对话框代码. 在线预览   源码下载 实现的代码. html代码: <div id=" ...

  3. 基于Vue.js PC桌面端弹出框组件|vue自定义弹层组件|vue模态框

    vue.js构建的轻量级PC网页端交互式弹层组件VLayer. 前段时间有分享过一个vue移动端弹窗组件,今天给大家分享一个最近开发的vue pc端弹出层组件. VLayer 一款集Alert.Dia ...

  4. 自定义弹出框基于zepto 记得引入zepto

    html <!DOCTYPE html> <html> <meta charset="utf-8"> <title></tit ...

  5. 基于Selenium2+Java的UI自动化(6)-操作Alert、confirm、prompt弹出框

    alert.confirm.prompt这样的js对话框在selenium1 时代处理起来比价麻烦,常常要用autoit来帮助处理.而现在webdriver对这些弹出框做了专门的处理,使用seleni ...

  6. javascript基于对象的弹出框封装

    先睹为快,移动端:戳这里,打开页面后点击投票查看效果.PC端测试直接切换body的overflow属性:hidden和auto一样可以,比下面相对简化,又有人说这样偶尔不行..如果你知道优缺点欢迎给出 ...

  7. 依赖弹出框lhdaiglog的基于WebUploader批量上传图片

    初始上传界面 //链接添加弹窗 html代码段↓ var msgcontent = ""; msgcontent += '<ul class="linkAddBox ...

  8. 基于 HTML5 Canvas 的拓扑组件 ToolTip 应用

    前言 ToolTip 效果是网页制作中常见的使用特效.当用户将鼠标悬浮在某个控件上时,ToolTip 显示并向用户展示相应的提示信息:当鼠标离开时,ToolTip 隐藏.一般情况下,我们使用 Tool ...

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

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

随机推荐

  1. AspNetPager 分页的详细用法(ASP.NET)

    1.[添加AspNetPager.dll文件] 2.[使用方法] public static DataTable GetRecord(SystemModel.Pager mt, ref int Tot ...

  2. java复习(6)---异常处理

    JAVA异常处理知识点及可运行实例 接着复习java知识点,异常处理是工程中非常重要的. 1.处理异常语句: try{ .... }catch(Exception e){ ..... } finall ...

  3. 运行第一个Docker容器

    1. Docker介绍 Docker由dotCloud公司发起的一个内部项目,后来Docker火了,dotCloud公司改名为Docker了: Docker使用了Go语言开发,基于 Linux 内核的 ...

  4. Google Firebase Unity接入的坑

    就说跑demo碰到的坑吧 https://firebase.google.com/docs/unity/setup 这是Firebase Unity的setup指南 大概写写步骤: 1. Fireba ...

  5. 防止微信浏览器video标签全屏的问题

    在微信浏览器里面使用video标签,会自动变成全屏,改成下面就好了,起码可以在video标签之上加入其他元素. <video id="videoID" webkit-play ...

  6. hdu5145 NPY and girls

    人生中第一道莫队,本来以为是一道水题的.. 首先这题只有区间查询,没有修改操作,使用莫队比较明显,但统计答案有点麻烦.. 根据题意,在n个人里选m个不相同种类的人,设第i种人数量为ai,总方案为c(n ...

  7. linux性能之iostat

    在使用linux系统的过程中,总是可能需要当前io性能的状态信息是怎么样?这里就就是一下iostat,可以通过iostat来初步查看io的状态信息. 1.常用方式 iostat -xdk 1 10 或 ...

  8. 蓝桥杯-组素数-java

    /* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...

  9. 【源码学习】之requirejs

    对于现在的前端生态来说,requirejs是有点过时了,webpack帮我们包干了一切.但是对于学习源码这件事情来说,永远是不过时的! 最近稍微闲下来了一点,就着以前做过的项目,我也来看看requir ...

  10. Oracle数据库悲观锁与乐观锁详解

    数据的锁定分为两种方法,第一种叫做悲观锁,第二种叫做乐观锁.什么叫悲观锁呢,悲观锁顾名思义,就是对数据的冲突采取一种悲观的态度,也就是说假设数据肯定会冲突,所以在数据开始读取的时候就把数据锁定住.而乐 ...