本文来自网易云社区html
做者:田亚楠git
对应原文:Inheritancegithub
咱们能够继承已有的「显示对象」,建立新的自定义类。实现方法有不少种,下面介绍其中之一。数据库
举例:实现一个继承于 Container 类的自定义类 Button:canvas
共分 4 步:segmentfault
自定义构造器ide
继承父类,得到父类的功能函数
重写已有方法,扩展自身方法工具
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 是不一样的。上面代码的逻辑是:
首先经过 extend,赋予 Button 全部 Container 的方法(只是放在调用链 Button.prototype 上);
再经过 promote,将调用链上的方法 提高(promote) 到 Button 对象上,并修改了方法名,防止命名冲突,便于记忆。
对应原文:HITTEST
显示对象拥有函数 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 坐标系的坐标。
从 DEMO2 能够看出 globalToLocal 方法会将目标对象的父元素的「图形变换」的因素都考虑在内。 若是有多级元素嵌套,咱们仍可使用该方法将 global 坐标转换为内层子元素的 local 坐标。
除了检测指针相对于图形的位置,咱们还能够检测一个显示对象相对于另外一个显示对象的位置。
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 次/秒。 设置的值越高,相应速度越快,但相应的须要更多的计算量。
这样作的好处是使 检查的频率 与 设置的帧率 解耦。
有几点须要注意:
没有 mouseup 和 pressdown 事件。能够把 mousedown、pressmove、pressup 分红一组。
pressup 与 click 事件的区别是,click 事件在同一点按下与抬起时触发,而 pressup 会在任意一处拿起时都会触发。
on 方法能够用来替代 addEventListener,而且 on 方法还额外提供了一些参数:
circle.on(type, listener, scope, once, data, useCapture);
监听事件的回调函数 listener 的参数是一个 EaselJS 定义的 MouseEvent 对象,它包含一些有用的属性:
type:事件类型('mousedown'、'pressmove'、'pressup' 等)
target:触发事件的显示对象
nativeEvent:基于的原生事件对象
stageX、stageY:触发事件的点在 global 坐标系的坐标
还有一些不经常使用的属性,可参考 API
参考:DEMO
经过上面的 DEMO,当多个事件同时触发时(更换绑定顺序结果不变):
先触发 click 再触发 pressup
先 rollover 再 mouseover
先 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 事件为例):
target:触发事件的节点中最内层的节点。好比点击有多个节点重合(父节点子节点都有),那么最内层的子节点就是 target。
currentTarget:事件流转到的当前节点。
createjs 中的对象/容器处理事件也通过 3 个一样的阶段:
捕获阶段:
首先触发 stage 的捕获事件(stage 上绑定的 useCapture == true 的事件),而后依次触发 target 的最外层祖先容器到最内层父容器的捕获事件
目标阶段:
target 对象触发自身的事件(包括全部捕获事件和冒泡事件)
冒泡阶段:
与捕获阶段相反,依次触发 target 的最内层父容器到最外层祖先容器,直到 stage 对象的冒泡事件(useCapture == false 默认值)
这个 DEMO 中全部容器与显示对象都注册了 click 事件(包括 useCapture 值为 true 和 false 两种), 其中 button 对象是一个 Container 容器对象,它包含两个显示对象:background、label。你能够经过点击「红色背景」和「白色文字」来分别查看对应「事件阶段」结果。
另外还有两个属性用来控制捕获&冒泡:
mouseChildren 可用来将一个显示对象集合做为一个事件总体,如上面的 DEMO 中,设置 button.mouseChildren = false; 那么 button 这个容器 所包含的全部子显示对象的事件将不会触发,整个 button 集合将做为总体对事件进行相应。
mouseEnabled 顾名思义,能够用来禁止一个对象的全部事件。须要注意的是,若是 button 这个集合设置了 button.mouseEnabled = false; 那么它的全部子显示对象的事件将都不会再被触发了。
前文介绍了鼠标交互的各类事件,但能够被触发事件的只有显示对象的「可见 且 不透明 」的像素点。 在上面事件阶段的 DEMO 中,能够发现 label (按钮的文字)上注册的事件想要被触发, 必须精确的点击到「文字的线条」上。
createjs 提供了 hitArea 。你能够设置另外一个对象 objB 做为显示对象 objA 的 hitArea,当点击到 objB 时就至关于点击到了 objA。 这个 objB 不须要添加到显示对象列表,也不须要可见,但它会在交互事件的触发中替代 objA。
注意:hitTest 命中检测并不适用于 hitArea,命中检测仍是针对显示对象的「可见且不透明」的像素点(否则命中检测的逻辑就显得混乱了)。 hitArea 只针对交互事件的触发。若是真的有这种需求,能够很是简单的本身实现。
参考:DEMO
上面的 demo 中,container 对象为全部蓝色的圆形的总体,它的 hitArea 是红色的圆形, 当指针 mouseover 红色的圆形时,container 的 mouseover 事件会被触发。
在 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
Container.getObjectUnderPoint(x, y, mode) ,参考 API doc
Container.getObjectsUnderPoint(x, y[, mode = 0]) ,参考 API doc
DisplayObject.hitTest(x, y),本文前面的「命中测试」部分介绍过
...请阅读 API doc
相关阅读: canvas 动画库 CreateJs 之 EaselJS(上篇)
网易云免费体验馆,0成本体验20+款云产品!
更多网易研发、产品、运营经验分享请访问网易云社区。
相关文章:
【推荐】 Andorid自定义attr的各类坑
【推荐】 快速登陆机器&数据库
【推荐】 教你如何选择BI数据可视化工具