canvas 动画库 CreateJs 之 EaselJS(下篇)

本文来自网易云社区

作者:田亚楠

继承

对应原文:Inheritance

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

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

共分 4 步:

  1. 自定义构造器
  2. 继承父类,获得父类的功能
  3. 重写已有方法,扩展自身方法
  4. promote 继承来的方法,返回自定义类
(function () {    // 自定义构造器
    //  - 调用继承的父类构造器()
    //  - label 为自定义入参
    var Button = function (label) {      this.Container_constructor();      this.label = label;
    };    // 继承 Container 类
    //  - 将 Container 添加到 Button 的调用链上,赋予 Button 所有 Container 的方法
    //  - 返回值为 Button.prototype
    var p = 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(‘circle clicked‘) });

可以监听的事件有:
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 个阶段:捕获阶段、目标阶段、冒泡阶段

参考文章:事件阶段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在网易云中的落地优化实践

原文地址:https://www.cnblogs.com/163yun/p/9717325.html

时间: 2024-08-08 20:59:41

canvas 动画库 CreateJs 之 EaselJS(下篇)的相关文章

canvas 动画库 CreateJs 之 EaselJS(上篇)

本文来自网易云社区 作者:田亚楠 须知 本文主要是根据 createjs 中的 EaselJS 在 github 上的 tutorials 目录下的文章整理而来 (原文链接),同时也包含了很多本人的理解,如过有叙述不当的地方,请联系我 :-D 本文对原文中的一些知识点的解释进行了删减,对另外一些进行了扩展,同时对文中的 demo 进行了改写,如果感到阅读困难的话请参考原文(本文中有对应的原文链接) 如果文中提供的 demo 无法打开,可以参考原文中的 demo. 从一个简单例子开始 对应原文:G

[转] iOS 动画库 Pop 和 Canvas 各自的优势和劣势是什么?

iOS 动画库 Pop 和 Canvas 各自的优势和劣势是什么? http://www.zhihu.com/question/23654895/answer/25541037 拿 Canvas 来和 Pop 比其实不大合适,虽然两者都自称「动画库」,但是「库」这个词的含义有所区别.本质上 Canvas 是一个「动画合集」而 Pop 是一个「动画引擎」. 先说 Canvas.Canvas 的目的是「Animate in Xcode Without Code」.开发者可以通过在 Storyboar

Html5添加轻量级炫酷js粒子动画库插件教程

一.使用方法 该粒子动画库插件使用方法非常简单,首先要在页面中引入particles.js文件. <script src="js/particles.js"></script> 在页面中使用一个div来作为放置粒子的容器. <div id="particles-js"></div> 然后可以按下面的方法调用该粒子插件: particlesJS('particles-js', { particles: { color:

Html5游戏框架createJs组件--EaselJS(二)绘图类graphics

有端友问我是否有文档,有确实有,但没有中文的,只有英文的,先提供浏览地址供大家参考学习createJs英文文档.                        EaselJS其实主要就是createJs组件中控制canvas绘图的,那么就会涉及密切相关的绘图操作,绘图操作利用Graphics类实现,我们来仔细的研究研究Graphics类. 先回顾一下EaselJS(一里面的那个圆形绘图): <!DOCTYPE HTML> <html lang="en-US">

前端能力模型-动画类型及动画库的介绍

一.背景: 合适的动画不仅更能吸引人们的眼球,也能让你的应用体验更为流畅,而将动画的效果做到极致,才能让用户感到使用你的应用是一种享受,而不是觉得生硬和枯燥. 二.动画技术分类: 按技术类型来进行分类,分为三类:JS动画,CSS3动画,html5动画,接下来分别对三类动画进行讲解. 1)JS动画 通过一个定时器setInterval间隔来改变元素样式,动画结束时clearInterval即可.(早期类库:jquery.prototype.mootools) 优缺点: 优点:可控性很强,兼容性较好

html5轻量级炫酷js粒子动画库插件

这是一款基于html5 canvas的轻量级炫酷js粒子动画库插件.该粒子动画库js插件可以设置粒子的形状.旋转.分布.颜色等属性,还可以动态添加粒子,效果非常酷. 同样的例子效果还有:HTML5 Canvas彩色的光粒子模拟粒子运动动画效果. 在线演示:http://www.htmleaf.com/Demo/201501301300.html 下载地址:http://www.htmleaf.com/html5/html5-canvas/201501301299.html

1、CreateJS介绍-EaselJS

需要在html5文件中引入的CreateJS库文件是easeljs-0.7.1.min.js HTML5文件如下: 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>1.CreateJS介绍-EaselJS</title> 6 <script src="easeljs-0

聊聊JS动画库:Velocity.js

前言 又到了炎热的7月,很久没有更新技术文章了,原因是上月月底实习结束,从公司离职.然后最近在弄自己的项目和考驾照,为了下次公司的应聘做准备,送别了女朋友到外地,哩哩啦啦半个月把一切事情都办妥后,还是静下心来学习新技术和写一写技术文章,希望能继续坚持下去吧. JS动画 随着互联网越来越丰富多样,网页端的美化和新技术层出不穷,作为一个网站的浏览者,更多吸引他们的除了保证网站的流畅之外还有各种炫酷的交互动效. 网页的交互动效大概分为 css动画,js动画 . JS动画的优点 既然我们大概了解了这两类

JS动画之缓动函数分析及动画库

上一篇讲了JS动画定时器相关知识,这一篇介绍下缓动函数及流行的动画库. 熟悉的图 实际使用 jquery animate()+jquery.easing插件的使用: $(selector).animate(styles,speed,easing,callback) 原生js使用:张鑫旭同学的文章 缓动函数知识 什么是缓动函数?我的理解是动画参数与数学公式结合的函数. 各流行库缓动函数对比,以easeInQuad为例,如图: Tween.js jQuery.easing GSAP CreateJS