基于HTML5 Canvas 实现弹出框

  用户鼠标移入时,有弹出框出现,这样的需求很常见。这在处理HTML元素实现时简单,但是如果是对 HTML5 Canvas 构成的图形进行处理,这种方法不再适用,因为 Canvas 使用的是另外一套机制,无论在 Canvas 上绘制多少图形,Canvas 都是一个整体。而图形本身实际都是 Canvas 的一部分,不可单独获取,所以也就无法直接给某个图形增加 JavaScript 事件。然而,在 HT for Web 中,这种需求很容易实现,先附上Demo:http://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)简单绘制了下,也还蛮好用。在上述场景中,用户将鼠标移入到草地等对象时,会有弹出框显示它的详细信息。

具体实现如下:

准备工作

   引入我们的 HT(http://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');});//新建nodevar 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),供大家参考。

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/541278.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

半素数c语言,非常简单的c题目 不懂 紧急求助

1 半素数素数是指大于1且只有1和他本身两个因子的正整数&#xff0c;例如2、3、5、89都是素数&#xff0c;2、4、10都不是素数。在这里我给半素数下一个定义&#xff1a;一个大于1的正整数能分解为两个素数的乘积&#xff0c;那么这个正整数就是半素数&#xff0c;比如62*3&am…

JavaScript | 嵌套if的示例

Example: 例&#xff1a; In this example, we are reading salary of an employee and finding the discount and net pay based on given salary and discount rate. 在此示例中&#xff0c;我们正在读取员工的薪水&#xff0c;并根据给定的薪水和折扣率找到折扣和净工资。 …

POJ 1014 Dividing 背包

二进制优化&#xff0c;事实上是物体的分解问题。 就是比方一个物体有数量限制&#xff0c;比方是13&#xff0c;那么就须要把这个物体分解为1。 2&#xff0c; 4&#xff0c; 6 假设这个物体有数量为25&#xff0c;那么就分解为1&#xff0c; 2&#xff0c; 4。 8。 10 看出规…

node.js 中间件_Node.js中的Passport中间件(模块)

node.js 中间件Hi! Welcome to Node.js Authentication Series, where well study and program the passport module or middleware. 嗨&#xff01; 欢迎使用Node.js身份验证系列 &#xff0c;我们将在其中研究和编程通行证模块或中间件 。 Nowadays, an important tool in m…

android开发自动提示框,Android 多种简单的弹出框样式设置代码

简介这是一个基于AlertDialog和Dialog这两个类封装的多种弹出框样式&#xff0c;其中提供各种简单样式的弹出框使用说明。同时也可自定义弹出框。项目地址&#xff1a;http://www.easck.com/jjdxmashl/jjdxm_dialogui特性1.使用链式开发代码简洁明了2.所有的弹出框样式都在Dial…

小程序中利用Moment.js格式时间

2019独角兽企业重金招聘Python工程师标准>>> LeanCloud给的日期是ISO格式&#xff0c;比如2017-06-05T14:08:20.589Z&#xff0c;直接显示在页面上体验不好。 凡是有关日期的&#xff0c;格式化、计算&#xff0c;用moment就够了。 1.下载 http://momentjs.com/ 选m…

php 检查数组为空_检查数组是否为空在PHP中

php 检查数组为空Given an array and we have to check if array is an empty or not using PHP. 给定一个数组&#xff0c;我们必须检查数组是否为空或不使用PHP。 To check whether an array is empty or not, we can use a built-in function empty(), in other cases wher…

JEESZ分布式架构3--CentOs下安装MySQL(环境准备)

声明&#xff1a;因为运行环境是基于Linux系统的&#xff0c;在做此框架之前需要做一些前期的环境准备工作CentOs下安装MySQL网上很多实例&#xff0c;因为博客后期作为框架的原生教程&#xff0c;故这边做详细的安装记录&#xff0c;我这边已经下载好了MySQL&#xff0c;通过s…

一个函数里两个setjmp_C语言中setjmp.h的longjmp()函数

一个函数里两个setjmpWe can call this function as an advance version of goto statement but with more dynamic range. The longjump() function allows us to pass parameters to know that the control has been jumped or not. 我们可以将此函数称为goto语句的高级版本&…

linux sublime nodejs,Ubuntu环境下sublime3 nodejs安装与插件配置

1.sudo add-apt-repository ppa:webupd8team/sublime-text-3回车&#xff0c;出现很多信息。但是我们看看图片最后字知道&#xff0c;这地方在等待我们确认是否添加这个仓库&#xff0c;按enter键继续&#xff0c;按crtlc取消。此时&#xff0c;按ENTER继续&#xff0c;建立信任…

李洪强iOS开发之FMDB线程安全的用法

// // ViewController.m // 04 - FMDB线程安全的用法 // // Created by 李洪强 on 2017/6/6. // Copyright © 2017年 李洪强. All rights reserved. // #import "ViewController.h" //导入头文件 #import "FMDB.h" interface ViewController () p…

SCHAR_MIN常数,C ++中的示例

C SCHAR_MIN宏常量 (C SCHAR_MIN macro constant) SCHAR_MIN constant is a macro constant which is defied in climits header, it is used to get the minimum value of a signed char object, it returns the minimum value that a signed char object can store, which i…

android分开两个线程做事,android开发教程之handle实现多线程和异步处理

这次浅谈一下Handler,为什么会出现Handler这个功能特性呢&#xff1f;首先&#xff0c;在之前的基本控件&#xff0c;基本都是在Activity的onCreate(Bundle savedInstanceState)方法中调用和处理的&#xff0c;但是&#xff0c;在有些情况&#xff0c;比如在网络上下载软件等一…

夏夜

儿时的夏夜毕竟是最有夏夜的味道。屋堂的煤油灯啪嗒的跳动&#xff0c;忽明忽暗&#xff0c;真怕它脆弱的明亮突然变黑暗。屋外弯月星稀&#xff0c;月光优雅的撒在平静的湖面上&#xff0c;清纯而又温和。水鸟在湖岸边慵懒的伸了伸脖子。正享受着夏夜的宁静和清凉。调皮的小孩…

Python operator.lt()函数与示例

operator.lt()函数 (operator.lt() Function) operator.lt() function is a library function of operator module, it is used to perform "less than operation" on two values and returns True if the first value is less than the second value, False, otherw…

android实现滑动切换图,Android:使用ViewPager实现左右滑动切换图片加点点

图片发自简书App1、引入android-support-v4.jar包&#xff0c;在主布局里加入< ?xml version"1.0" encoding"utf-8"?>< RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.…

div的替代品

人们在标签使用中最常见到的错误之一就是随意将HTML5的<section>等价于<div>——具体地说&#xff0c;就是直接用作替代品(用于样式)。在XHTML或者HTML4中&#xff0c;我们常看到这样的代码&#xff1a; <!-- HTML 4-style code --> <div id"wrapper…

threadgroup_Java ThreadGroup list()方法与示例

threadgroupThreadGroup类的list()方法 (ThreadGroup Class list() method) list() method is available in java.lang package. list()方法在java.lang包中可用。 list() method is used to list or display information (like name, priority, thread group, etc.) to the st…

html的柱状图去除右边纵坐标,excel如何把次坐标轴逆序

excel2010设置水平坐标轴逆序类型,但垂直坐标轴刻设置水平坐标轴逆序且垂直坐标轴轴仍位于图表左侧的步骤是&#xff1a;打开带有图表的Excel工作表&#xff1b;在图表区域的水平轴标签位置双击鼠标左键&#xff0c;打开“设置坐标轴格式”&#xff1b;勾寻逆序类别”&#xff…

jhipster项目迁移websocket

2019独角兽企业重金招聘Python工程师标准>>> 1、 在项目目录下命令行安装 两个组件 bower install sockjs-client bower install stomp-websocket 2、在index.html 中加入组件js的引用 <script src"bower_components/sockjs-client/dist/sockjs.js">…