本文來自網易雲社區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數據可視化工具