用户鼠标移入时,有弹出框出现,这样的需求很常见。这在处理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. 基于51单片机IIC通信的PCF8591学习笔记

    引言 PCF8591 是单电源,低功耗8 位CMOS 数据采集器件,具有4 个模拟输入.一个输出和一个串行I2C 总线接口.3 个地址引脚A0.A1 和A2 用于编程硬件地址,允许将最多8 个器件连接 ...

  2. tolua#代码简要分析

    简介 tolua#是Unity静态绑定lua的一个解决方案,它通过C#提供的反射信息分析代码并生成包装的类.它是一个用来简化在C#中集成lua的插件,可以自动生成用于在lua中访问Unity的绑定代码 ...

  3. Android Weekly Notes Issue #253

    Android Weekly Issue #253 April 16th, 2017 Android Weely Issue #253. 本期内容包括: Android O新推出的自定义字体支持; 用 ...

  4. 从网络通信角度谈web性能优化

    衡量一个网站的性能有多个指标,DNS解析时间,TCP链接时间,HTTP重定向时间,等待服务器响应时间等等,从用户角度来看,就可以归结为该网站访问速度的快慢.也就是说性能等于网站的访问速度. 早些年Am ...

  5. 带你玩转 jQuery

    一.简介 定义 jQuery创始人是美国John Resig,是优秀的Javascript框架: jQuery是一个轻量级.快速简洁的javaScript库.源码戳这 jQuery对象 jQuery产 ...

  6. SQL Server中关于基数估计如何计算预估行数的一些探讨

    关于SQL Server 2014中的基数估计,官方文档Optimizing Your Query Plans with the SQL Server 2014 Cardinality Estimat ...

  7. 蓝桥杯-兰顿蚂蚁-java

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

  8. 十分钟彻底理解javascript 的 this指向,不懂请砸店

    函数的this指向谁,和函数在哪里被定义的,函数在哪里被执行的没有半毛钱关系,只遵守下面的规律: 在非严格模式中: 1.自执行函数里面,this永远指向window; <script> v ...

  9. iOS刨根问底-深入理解RunLoop

    开源的RunloopRef 通常所说的RunLoop指的是NSRunloop或者CFRunloopRef,CFRunloopRef是纯C的函数,而NSRunloop仅仅是CFRunloopRef的OC ...

  10. 2016年BAT公司常见的Web前端面试题整理

    1.JavaScript是一门什么样的语言,它有哪些特点? 没有标准答案. 2.JavaScript的数据类型都有什么? 基本数据类型:String,boolean,Number,Undefined ...