技術(shù)具有"繼承性务傲、延展性"
修正為:
技術(shù)具有"延續(xù)性狈癞,延展性"
本篇目的:
- 為什么不能使用DOM內(nèi)置的事件分發(fā)系統(tǒng)
- 暫時(shí)先選擇鼠標(biāo)事件
- 實(shí)現(xiàn)一個(gè)簡單的鼠標(biāo)事件分發(fā)和處理框架
- demo演示與驗(yàn)證
由于動(dòng)畫履羞,數(shù)學(xué)峦萎,碰撞等demo演示,需要進(jìn)行事件交互忆首。
目前還沒有事件分發(fā)系統(tǒng)骨杂,因此今天我們來實(shí)現(xiàn)一個(gè)簡單的事件分發(fā)系統(tǒng)以及事件處理的流程
為什么不能使用DOM內(nèi)置的冒泡事件系統(tǒng)
很簡單,因?yàn)镈OM事件系統(tǒng)僅能分發(fā)到canvas元素雄卷。
而我們的2D精靈系統(tǒng)是直接通過canvas2D繪制出來的搓蚪,并沒有并入到DOM文檔樹中,因此DOM 事件分發(fā)到canvas后丁鹉,就結(jié)束了妒潭。
所以我們要在事件分發(fā)到canvas后,繼續(xù)進(jìn)行分發(fā)給每個(gè)精靈揣钦,讓他們有機(jī)會(huì)接受到事件并進(jìn)行處理雳灾。這就是今天的任務(wù)!冯凹!
暫時(shí)先選擇鼠標(biāo)事件
原因:
在手機(jī)端谎亩,豎屏顯示范圍太小了,查了一些資料宇姚,發(fā)現(xiàn)h5目前沒有一個(gè)通用的進(jìn)入頁面直接橫屏的功能匈庭,需要研究一下變通的實(shí)現(xiàn)方式。
如果一旦實(shí)現(xiàn)手機(jī)端自動(dòng)橫屏效果浑劳,我會(huì)將mouse事件更改為touch事件阱持,也就是幾句代碼的事情
touch/mouse事件最大區(qū)別是move事件。只要鼠標(biāo)移動(dòng)就會(huì)產(chǎn)生mousemove事件魔熏。而touchmove事件必須按下移動(dòng)才產(chǎn)生衷咽。后面我一些例子,建立在mousemove基礎(chǔ)上
關(guān)鍵原因就是我現(xiàn)在還沒實(shí)現(xiàn)h5頁面自動(dòng)橫屏效果蒜绽。導(dǎo)致手機(jī)演示不是很爽镶骗。
實(shí)現(xiàn)一個(gè)簡單的鼠標(biāo)事件分發(fā)和處理系統(tǒng)
- 需要一個(gè)函數(shù),將窗口客戶區(qū)坐標(biāo)轉(zhuǎn)換到canvas2D坐標(biāo)表示,該函數(shù)就加在BLFRender2D中去吧:
ToCanvasCoord(x, y) {
var bbox = this.context.canvas.getBoundingClientRect();
return {
x: x - bbox.left * (this.context.canvas.width / bbox.width),
y: y - bbox.top * (this.context.canvas.height / bbox.height)
};
}
原因和如何使用躲雅,等會(huì)demo會(huì)演示和解釋
- BLFSprite基類中增加鼠標(biāo)事件處理方法:
onMouseDown(x, y) {
console.log("deal mouseDown event");
return false;
}
onMouseUp(x, y) {
console.log("deal mouseUp event");
return false;
}
onMouseMove(x, y) {
console.log("deal mouseMove event");
return false;
}
關(guān)于返回值true/false鼎姊,請(qǐng)看下面的代碼注釋
- BLFSpriteManager中增加事件分發(fā)函數(shù):
dispatchMouseDownEvent(x, y) {
//超級(jí)簡單,用于演示用的事件分發(fā)體系
//事件分發(fā)是核心之一
//目前比較流行的有:dom3 level3事件系統(tǒng)
// ios responder 職責(zé)鏈?zhǔn)录到y(tǒng)
// android中那個(gè)復(fù)雜無比,效率底下的事件分發(fā)系統(tǒng)(會(huì)被罵嗎?哈哈)
for (let i = this.sprites.length - 1; i >= 0; i--) {
//如果i指向的精靈事件處理完成(true)此蜈,就中斷事件分發(fā)
if (this.sprites[i].onMouseDown(x, y))
return;
}
}
dispatchMouseUpEvent(x, y) {
for (let i = this.sprites.length - 1; i >= 0; i--) {
//如果i指向的精靈事件處理完成(true)即横,就中斷事件分發(fā)
if (this.sprites[i].onMouseUp(x, y))
return;
}
}
dispatchMouseMoveEvent(x, y) {
for (let i = this.sprites.length - 1; i >= 0; i--) {
//如果i指向的精靈事件處理完成(true)噪生,就中斷事件分發(fā)
if (this.sprites[i].onMouseMove(x, y))
return;
}
}
- 如果循環(huán)中當(dāng)前i指向的精靈事件處理完成(true)裆赵,就中斷事件分發(fā),退出函數(shù)
- 事件分發(fā)循環(huán)是從后到前方式(let i = this.sprites.length - 1; i >= 0; i--),這是因?yàn)楫?dāng)兩個(gè)精靈重疊時(shí),肯定是上面的精靈進(jìn)行事件處理跺嗽,而不是被遮擋住的精靈(先前景战授,后背景)
- 而繪制時(shí),肯定是先背景桨嫁,后前景(昨天孩子寫生油畫植兰,老師講解也強(qiáng)調(diào)如此,經(jīng)典的畫家算法)
- 最后璃吧,在BLFEngine2D的構(gòu)造函數(shù)中將DOM 事件轉(zhuǎn)發(fā)到各個(gè)精靈上:
canvas.addEventListener("mousedown", (e) => {
//先將客戶區(qū)的點(diǎn)轉(zhuǎn)換為相對(duì)canvas坐標(biāo)系的點(diǎn)表示
let pt = this.render.ToCanvasCoord(e.clientX, e.clientY);
console.log("e.clientX = " + e.clientX + " e.clientY = " + e.clientY);
console.log("canvasX = " + pt.x + " canvasY = " + pt.y);
this.sprMgr.dispatchMouseDownEvent(pt.x, pt.y);
}, false);
canvas.addEventListener("mouseup", (e) => {
//先將客戶區(qū)的點(diǎn)轉(zhuǎn)換為相對(duì)canvas坐標(biāo)系的點(diǎn)表示
let pt = this.render.ToCanvasCoord(e.clientX, e.clientY);
this.sprMgr.dispatchMouseUpEvent(pt.x, pt.y);
}, false);
canvas.addEventListener("mousemove", (e) => {
//先將客戶區(qū)的點(diǎn)轉(zhuǎn)換為相對(duì)canvas坐標(biāo)系的點(diǎn)表示
let pt = this.render.ToCanvasCoord(e.clientX, e.clientY);
this.sprMgr.dispatchMouseMoveEvent(pt.x, pt.y);
}, false);
關(guān)鍵的一步是將客戶區(qū)的點(diǎn)轉(zhuǎn)換為相對(duì)canvas坐標(biāo)系的點(diǎn)表示楣导。可能的情況是你的canvs畫布的原點(diǎn)和客戶區(qū)的原點(diǎn)沒有重合時(shí)畜挨,如果不進(jìn)行坐標(biāo)變換筒繁,會(huì)出現(xiàn)非常大的問題
關(guān)于DOM3 level3 冒泡事件,我個(gè)人是非常喜歡的一種事件分發(fā)體系巴元。其實(shí)使用中有很多訣竅毡咏。本系列中,我會(huì)專門抽一章來聊一聊冒泡事件逮刨。實(shí)際上呕缭,我從webkit中抽取了很多超級(jí)有用的代碼,包括冒泡事件系統(tǒng)(webkit我個(gè)人感覺應(yīng)該是超過100萬行代碼的龐大c++程序)
demo演示與驗(yàn)證:
以前我們的demo都是canvs畫布與客戶區(qū)原點(diǎn)對(duì)齊的
現(xiàn)在我們改變一下:將canvas右移100個(gè)像素
<style>
.canvas {
position: absolute;
left: 100px;
}
</style>
- 使用絕對(duì)定位修己,left設(shè)置為100px,css一定要用單位哦
添加畫布恢总,使用canvas樣式:
<canvas id="myCanvas" class="canvas" width="800" height="600" style="border: 1px solid black">你的瀏覽器還不支持哦</canvas>
客戶區(qū): 649 392
canvas: 549 384
紅色框部分左右差100 px
藍(lán)色框部分上下差8 px
問題: 為什么客戶區(qū)和canvas上下差8px?(有興趣可以留言回答)
本篇結(jié)束,下一篇我們進(jìn)入鼠標(biāo)hitTest方面的內(nèi)容
附:
昨天晚上聽了一堂視聽課睬愤,關(guān)于mysql MyISAM/InnoDB 索引底層實(shí)現(xiàn)(B+樹)离熏。收獲是巨大的。只有了解了原理戴涝,才能有效的使用滋戳!。
其實(shí)我個(gè)人一直很努力的學(xué)習(xí)各種樹結(jié)構(gòu)啥刻,它太重要了<檠臁!
quake3中實(shí)現(xiàn)的自適應(yīng)哈夫曼樹(用于網(wǎng)絡(luò)傳輸數(shù)據(jù)最小化)
quake3 BSP樹(整個(gè)quake引擎之所以如此高效可帽,就是因?yàn)槭褂昧薭inary space partitioning tree,空間二叉分割樹)
分割空間娄涩,加快渲染,與碰撞檢測(cè)的quadtree(二維分割,四叉樹蓄拣,廣泛用于地形渲染和碰撞檢測(cè))扬虚,octree(三維分割,八叉樹)
kd樹(四叉/八叉都是kd的特殊形式)
用于ui/2d/3d中組成場(chǎng)景用的通用樹結(jié)構(gòu)
用于加快室內(nèi)場(chǎng)景管理球恤,動(dòng)態(tài)光影計(jì)算的portal樹
各種加快碰撞檢測(cè)的包圍體層次樹
還有就是數(shù)據(jù)結(jié)構(gòu)中各種經(jīng)典的樹結(jié)構(gòu):二叉樹辜昵,紅黑樹,還有昨天的b樹/b+樹......
樹是非常非常非常重要的數(shù)據(jù)結(jié)構(gòu)咽斧,如果想深入了解圖形堪置,數(shù)據(jù)庫,游戲引擎等,那么各種樹的數(shù)據(jù)結(jié)構(gòu)一定要了解,并且知道用在哪些方面
設(shè)計(jì)模式在UI系統(tǒng)開發(fā)中的應(yīng)用(導(dǎo)讀)這篇文章中幽崩,提供了一個(gè)通用樹結(jié)構(gòu)相關(guān)圖,很值得研究
在閑聊c++系列中坎匿,我的文章以基礎(chǔ)知識(shí)為主。別看現(xiàn)在外面的新技術(shù)層出不窮雷激,但本質(zhì)都是很基礎(chǔ)的知識(shí)替蔬。
一個(gè)新技術(shù)不可能是憑空出來的,技術(shù)都是具有:
繼承性 : 從上到下
延展性 : 從左到右
突然發(fā)現(xiàn)侥锦,好有哲理哦=浴!恭垦!
修正為:
一個(gè)新技術(shù)不可能是憑空出來的快毛,技術(shù)都是具有:
延續(xù)性 : 從上到下
延展性 : 從左到右
這樣比較押韻!番挺!