canvas 动画库 CreateJs 之 EaselJS(下篇)

摘要:
circle.hitTest;上面的写法检测指针当前的位置是否在circle圆形中,但存在一个问题。无论createjs.Stage类,还是createjs.Shape类,都继承于createjs.Container类。因此我们需要通过circle.globalToLocal,来将global坐标系的坐标转换为circle坐标系的坐标。「显示对象」通过使用addEventListener即可监听事件。比如click事件:circle.addEventListener;可以监听的事件有:click,dblclick,mousedown,pressmove,pressup,mouseover/mouseout,androllover/rollout.其中最后4个是有一定关联的,它们默认不启用,使用的时候需要:stage.enableMouseOver;其中frequency是指在一秒内检查(计算)多少次事件是否触发。有几点需要注意:没有mouseup和pressdown事件。可以把mousedown、pressmove、pressup分成一组。

本文来自网易云社区

作者:田亚楠


继承

对应原文:Inheritance

我们可以继承已有的「显示对象」,创建新的自定义类。实现方法有很多种,下面介绍其中之一。

举例:实现一个继承于 Container 类的自定义类 Button:

共分 4 步:

  1. 自定义构造器

  2. 继承父类,获得父类的功能

  3. 重写已有方法,扩展自身方法

  4. promote 继承来的方法,返回自定义类

(function(){//自定义构造器
//-调用继承的父类构造器()
//-label为自定义入参
varButton=function(label){this.Container_constructor();this.label=label;
};//继承Container类
//-将Container添加到Button的调用链上,赋予Button所有Container的方法
//-返回值为Button.prototype
varp=createjs.extend(Button,createjs.Container);//重写draw方法
//-首先调用父类的draw方法
p.draw=function(){this.Container_draw();//添加自定义逻辑
};//将父类Container的所有方法(包括constructor)都重写添加到Button
//-例如上文用到的:Container_constructor、Container_draw
//-新方法命名规则:prefix_methodName,prefix为参数"Container"
window.Button=createjs.promote(Button,"Container");
})();

createjs.promote 跟 createjs.extend 是不同的。上面代码的逻辑是:

  1. 首先通过 extend,赋予 Button 所有 Container 的方法(只是放在调用链 Button.prototype 上);

  2. 再通过 promote,将调用链上的方法 提升(promote) 到 Button 对象上,并修改了方法名,防止命名冲突,便于记忆。

原文中的 DEMO源码


命中测试

对应原文:HITTEST


hitTest & globalToLocal

显示对象拥有函数 hitTest ,用来检测一个点是否在该显示对象中间。我们可以通过它来检测指针(鼠标/手指点按)是否在一个图形中。

circle.hitTest(stage.mouseX,stage.mouseY);

上面的写法检测指针当前的位置(stage.mouseX, stage.mouseY)是否在 circle 圆形中,但存在一个问题。

无论 createjs.Stage 类,还是 createjs.Shape 类,都继承于 createjs.Container 类。 他们都是一个容器,都拥有 addChild 方法,因此可以互相嵌套。并且他们都位于「各自的坐标系」中。 其中 stage 的坐标系我们可以称为 global(世界坐标系),而其他的容器对象如 cirlce 的坐标系我们称为 local。

circle.hitTest 的参数当然需要基于 circle 的坐标系,而 stage.mouseX 获得的点的坐标系是基于 global 的。

因此我们需要通过 circle.globalToLocal(stage.mouseX, stage.mouseY)(返回值为:{x, y} 对象), 来将 global 坐标系的坐标转换为 circle 坐标系的坐标。

参考:DEMODEMO2

从 DEMO2 可以看出 globalToLocal 方法会将目标对象的父元素的「图形变换」的因素都考虑在内。 如果有多级元素嵌套,我们仍可以使用该方法将 global 坐标转换为内层子元素的 local 坐标。

localToLocal

除了检测指针相对于图形的位置,我们还可以检测一个显示对象相对于另一个显示对象的位置。

objA.localToLocal(posX, posY, objB) 方法,可以将 objA 对象的 local 坐标系中的点(posX, posY), 映射到 objB 对象的 local 坐标系中。返回值仍然为 {x:, y:}。

注意:(posX, posY)坐标是从 objA 映射到 objB,source.localToLocal(x, y, target)

参考:DEMO

鼠标交互

对应原文:Mouse Interaction

基础

鼠标交互,就是监听鼠标/手指等的交互事件。「显示对象」通过使用 addEventListener 即可监听事件。比如 click 事件:

circle.addEventListener('click',function(){alert('circleclicked')});

可以监听的事件有:
click, dblclick,
mousedown, pressmove, pressup,
mouseover / mouseout, and rollover / rollout.

其中最后 4 个(mouseover / mouseout, rollover / rollout)是有一定关联的,它们默认不启用,使用的时候需要:

stage.enableMouseOver(frequency);

其中 frequency 是指在一秒内检查(计算)多少次事件是否触发。默认值为 20 次/秒。 设置的值越高,相应速度越快,但相应的需要更多的计算量。

这样做的好处是使 检查的频率 与 设置的帧率 解耦。

有几点需要注意:

  1. 没有 mouseup 和 pressdown 事件。可以把 mousedown、pressmove、pressup 分成一组。

  2. pressup 与 click 事件的区别是,click 事件在同一点按下与抬起时触发,而 pressup 会在任意一处拿起时都会触发。

  3. on 方法可以用来替代 addEventListener,并且 on 方法还额外提供了一些参数:

circle.on(type,listener,scope,once,data,useCapture);

监听事件的回调函数 listener 的参数是一个 EaselJS 定义的 MouseEvent 对象,它包含一些有用的属性:

  1. type:事件类型('mousedown'、'pressmove'、'pressup' 等)

  2. target:触发事件的显示对象

  3. nativeEvent:基于的原生事件对象

  4. stageX、stageY:触发事件的点在 global 坐标系的坐标

  5. 还有一些不常用的属性,可参考 API

参考:DEMO

通过上面的 DEMO,当多个事件同时触发时(更换绑定顺序结果不变):

  1. 先触发 click 再触发 pressup

  2. 先 rollover 再 mouseover

  3. 先 mouseout 再 rollout

对性能的好处

事件 mouseover / mouseout, rollover / rollout 也可以通过对检查频率的设置,来优化性能。 要知道小于 100ms 的响应时间用户是几乎不会感知到的,而它只需要 10fps,相对于 60fps 的动画来说性能提升了 6 倍。

而其他的事件 click, dblclick, mousedown, pressmove, pressup, 我们可以通过监听原生事件,在「对应的原生事件」触发的时候才调用回调,而不是放到 tick 循环中,因此可以提升性能。

事件冒泡

对于 DOM 节点来说,当一个事件被触发之后,会经过 3 个阶段:捕获阶段、目标阶段、冒泡阶段

canvas 动画库 CreateJs 之 EaselJS(下篇)第1张

参考文章:事件阶段MDN 文章中有一个很直观的demo

补充:当事件进行到目标阶段时,目标阶段上注册的捕获事件和冒泡事件的触发顺序是由注册顺序决定的(addEventListener 代码的执行顺序)

注册捕获事件需要使用 addEventListener(type, listener, useCapture) 的第三个参数 useCapture 设置为 true,

跟在 DOM 上绑定事件一样,createjs 也对事件的触发有着相似的处理方法。

由于是对虚拟的 js 对象(而非 DOM 结构)进行事件的绑定,因此它内部的处理方式是 createjs 仿照 DOM 的机制实现的一套逻辑。 跟 DOM 事件没有必然联系。其本质上都是 canvas 元素触发了事件之后,再由 createjs 进行处理。

createjs 中的 on 方法也有 useCapture 参数用来注册捕获事件:circle.on(type, listener, scope, once, data, useCapture)

我们先明确一下名词的定义(以 click 事件为例):

  1. target:触发事件的节点中最内层的节点。比如点击有多个节点重合(父节点子节点都有),那么最内层的子节点就是 target。

  2. currentTarget:事件流转到的当前节点。

createjs 中的对象/容器处理事件也经过 3 个同样的阶段:

  1. 捕获阶段:
    首先触发 stage 的捕获事件(stage 上绑定的 useCapture == true 的事件),然后依次触发 target 的最外层祖先容器到最内层父容器的捕获事件

  2. 目标阶段:
    target 对象触发自身的事件(包括所有捕获事件和冒泡事件)

  3. 冒泡阶段:
    与捕获阶段相反,依次触发 target 的最内层父容器到最外层祖先容器,直到 stage 对象的冒泡事件(useCapture == false 默认值)

这个 DEMO 中所有容器与显示对象都注册了 click 事件(包括 useCapture 值为 true 和 false 两种), 其中 button 对象是一个 Container 容器对象,它包含两个显示对象:background、label。你可以通过点击「红色背景」和「白色文字」来分别查看对应「事件阶段」结果。

另外还有两个属性用来控制捕获&冒泡:

  1. mouseChildren 可用来将一个显示对象集合作为一个事件整体,如上面的 DEMO 中,设置 button.mouseChildren = false; 那么 button 这个容器 所包含的所有子显示对象的事件将不会触发,整个 button 集合将作为整体对事件进行相应。

  2. mouseEnabled 顾名思义,可以用来禁止一个对象的所有事件。需要注意的是,如果 button 这个集合设置了 button.mouseEnabled = false; 那么它的所有子显示对象的事件将都不会再被触发了。

HITAREA

前文介绍了鼠标交互的各种事件,但可以被触发事件的只有显示对象的「可见 且 不透明 」的像素点。 在上面事件阶段的 DEMO 中,可以发现 label (按钮的文字)上注册的事件想要被触发, 必须精确的点击到「文字的线条」上。

createjs 提供了 hitArea 。你可以设置另一个对象 objB 作为显示对象 objA 的 hitArea,当点击到 objB 时就相当于点击到了 objA。 这个 objB 不需要添加到显示对象列表,也不需要可见,但它会在交互事件的触发中替代 objA。

注意:hitTest 命中检测并不适用于 hitArea,命中检测还是针对显示对象的「可见且不透明」的像素点(不然命中检测的逻辑就显得混乱了)。 hitArea 只针对交互事件的触发。如果真的有这种需求,可以非常简单的自己实现。

参考:DEMO

上面的 demo 中,container 对象为所有蓝色的圆形的整体,它的 hitArea 是红色的圆形, 当指针 mouseover 红色的圆形时,container 的 mouseover 事件会被触发。

stage 对象的交互事件

在 EaselJS 0.5 版本之前,stage 对象是无法绑定交互事件的,后来有人提了 ISSUES,在之后的版本中解决掉了这个问题。

一般的显示对象监听事件触发的范围为「可见且不透明」的像素点,而 stage 对象显然不同。

stage 对象有它特殊的交互事件:stagemousedown, stagemouseup, stagemousemove,整个 canvas 都对它们生效。

注:stage 对象还可以监听 click、mouseleave、mouseenter,后两者可以监听指针进入/离开 canvas。

当指针离开 canvas 范围之后 stagemousemove 事件就不会触发了,如果希望在画布之外继续触发事件,需要设置: stage.mouseMoveOutside = true; 。 之后当离开画布范围后,stage 的 3 个特殊事件都会继续被监听。

evt.stageX, evt.stageY 不会超出画布的边界范围(大于 0 小于 width/height),如果希望获取到外界的坐标,可以使用 evt.rawX, evt.rawY。

//超出画布之后仍允许监听stage的各种事件stage.mouseMoveOutside=true;
stage.on("stagemousemove",function(evt){//永远在边界以内
console.log("stageX/Y:"+evt.stageX+","+evt.stageY);//可以超出边界,小于0或大于canvas的宽高(CW/CH)
console.log("rawX/Y:"+evt.rawX+","+evt.rawY);
});

我们可以通过 stage.mouseInBounds (参考之前 hitTest 的这个 DEMO 有用到)来判断指针是否离开 canvas 范围。 或者监听 stage 的事件:mouseleave, mouseenter 来判断。

参考:DEMO

拖拽

通过对前面介绍过的一些事件的监听,我们可以非常方便的实现拖拽效果。主要是使用 mousedown, pressmove, pressup 这一组事件。

直接看 DEMO

其它常用 API

  1. Container.getObjectUnderPoint(x, y, mode) ,参考 API doc

  2. Container.getObjectsUnderPoint(x, y[, mode = 0]) ,参考 API doc

  3. DisplayObject.hitTest(x, y),本文前面的「命中测试」部分介绍过

  4. ...请阅读 API doc

相关阅读: canvas 动画库 CreateJs 之 EaselJS(上篇)

网易云免费体验馆,0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区


相关文章:
【推荐】Kubernetes在网易云中的落地优化实践

免责声明:文章转载自《canvas 动画库 CreateJs 之 EaselJS(下篇)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇android 电容屏(一):电容屏基本原理篇MapGuide应用开发系列(11)创建自己的第一个MapGuide应用程序下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ANDROID L——Material Design综合应用(Demo)

转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! Material Design: Material Design是Google推出的一个全新的设计语言,它的特点就是拟物扁平化。 我将Material Design分为例如以下四部分: 主题和布局——ANDROID L——Material...

从点击Button到弹出一个MessageBox, 背后发生了什么

思考一个最简单的程序行为:我们的Dialog上有一个Button, 当用户用鼠标点击这个Button时, 我们弹出一个MessageBox。 这个看似简单的行为, 谁能说清楚它是如何运行起来的,背后究竟发生了什么?  下面是我个人尝试的解答: (1)我们的鼠标点击事件到达设备的驱动程序, 驱动程序把消息放入系统硬件输入队列SHIQ(system ha...

canvas和svg

canvas 画布   位图   1.   不要在style中给canvas设置宽高  会有位移差   2. 给c设置一个绘图环境 得到的是一个对象     var c=document.getElementById("c1")     var can=c.getContentext("2d");   3. fillRect()   绘制一个填充的方块 默...

html5 canvas 实现简单的画图

今天早上看了一下 canvas 前端画图,数据可视化, 百度的 echart.js , d3等 js 库都已经提供了强大的绘制各种图形的 API。 下面记录一下 有关canvas 绘图的基本知识: <html> <head > <script src ='http://t.zoukankan.com/aop.js'...

第八部分 验证码的识别(极验验证码)

前言:验证码是众多网站采取的反爬措施。验证码的花样也很多,主要有下面这几种类验证码:图形验证码:数字、英文字母、混淆曲线组合成的验证码。行为验证码:识别文字,点击与文字相符的图片验证码。交互式验证码:极难滑动验证码,滑动拼合滑块方可完成验证。点触验证码:点击正确结果才可完成验证。还有滑动宫格验证码、计算题验证码等。下面涉及到的验证码有普通图形验证码、极验滑...

[HTML5]WAI-ARIA介绍

认识ARIA 目前互联网应用日益增强,其中大部分是通过混合技术(AJAX、DHTML、JavaScript 和 SVG)创建或自定义一些模拟桌面GUI程序的的 Web widget 小组件来增强 Web 应用程序的交互,但部分类似Dialog 的对话框、弹出层,模拟select 的下拉菜单等小组件并没能提供所需的语义作支持,残障人士有可能无法读懂当前信息。...