如何在html5中監(jiān)聽canvas內(nèi)部元素點擊事件?相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
創(chuàng)新互聯(lián)為企業(yè)提供:品牌網(wǎng)站制作、網(wǎng)絡(luò)營銷策劃、小程序開發(fā)、營銷型網(wǎng)站建設(shè)和網(wǎng)站運營托管,一站式網(wǎng)絡(luò)營銷整體服務(wù)。實現(xiàn)不斷獲取潛在客戶之核心目標(biāo),建立了企業(yè)專屬的“全網(wǎng)整合營銷推廣”,就用不著再為了獲取潛在客戶而苦惱,相反,客戶會主動找您,生意就找上門來了!
像素法
像素檢測法的思路是,將canvas中的多個圖形(如果有多個的話)分別離屏繪制,并用 getImageData() 方法分別獲取到像素數(shù)據(jù)保存起來。當(dāng)canvas元素監(jiān)聽到點擊事件時,通過點擊坐標(biāo)可以直接推算出點擊發(fā)生在canvas上的第幾個像素,然后遍歷前面保存的圖形數(shù)據(jù),看看這個像素的alpha值是不是0,如果是0說明落點不在當(dāng)前圖形內(nèi),否則就說明點到了這個圖形。
根據(jù)點擊坐標(biāo)得到所點擊的像素序號的方法:
像素序號 = (縱坐標(biāo)-1) * canvas寬度 + 橫坐標(biāo)
比如在寬度為 5 的畫布上點擊坐標(biāo) (3,3) ,根據(jù)上述公式得到像素序號是 (3-1) * 5 + 3 = 18 ,如圖所示:
因為canvas導(dǎo)出的圖形數(shù)據(jù)是將每個像素以 rgba 的順序存成4個數(shù)字組成的數(shù)組,所以想訪問指定像素的alpha值,只要讀取這個數(shù)組的第 pIndex * 4 + 3 個值就可以了,如果這個值不為0,說明該像素可見,也就是點擊到了該圖形。
這個方法是我認(rèn)為思路最直接、結(jié)果最準(zhǔn)確、而且對圖形形狀沒有任何要求的方法,但這個方法有一個致命的局限,當(dāng)圖形需要在畫布上移動時,要頻繁的創(chuàng)建數(shù)據(jù)緩存才能保證檢測結(jié)果準(zhǔn)確,受到畫布尺寸和圖形數(shù)量的影響, getImageData() 方法的性能會成為嚴(yán)重的瓶頸。所以如果canvas圖形是靜態(tài)的,這個方法非常適合,否則就不適合用這個方法了。
角度法
角度判斷法的原理很容易理解,如果一個點在多邊形內(nèi)部,則該點與多邊形所有頂點兩兩構(gòu)成的夾角,相加應(yīng)該剛好等于360°。
計算過程可以轉(zhuǎn)變?yōu)橐韵氯齻€步驟:
1.已知多邊形頂點和已知坐標(biāo),將坐標(biāo)與頂點兩兩組合成三點隊列
2. 已知三點求夾角,可以使用 余玄定理
3.判斷夾角之和是否360°
每一步都很簡單,實現(xiàn)如下:
//計算兩點距離 const getDistence = function (p1, p2) { return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)) }; //角度法判斷點在多邊形內(nèi)部 const checkPointInPolyline = (point, polylinePoints) => { let totalA = 0; const A = point; for (let i = 0; i < polylinePoints.length; i++) { let B, C; if (i === polylinePoints.length - 1) { B = { x: polylinePoints[i][0], y: polylinePoints[i][1] }; C = { x: polylinePoints[0][0], y: polylinePoints[0][1] }; } else { B = { x: polylinePoints[i][0], y: polylinePoints[i][1] }; C = { x: polylinePoints[i + 1][0], y: polylinePoints[i + 1][1] }; } //計算角度 const angleA = Math.acos((Math.pow(getDistence(A, C), 2) + Math.pow(getDistence(A, B), 2) - Math.pow(getDistence(B, C), 2)) / (2 * getDistence(A, C) * getDistence(A, B))) totalA += angleA } //判斷角度之和 return totalA === 2 * Math.PI }
這個方法有一個局限性,就是圖形必須是 凸多邊形 。如果不是凸多邊形需要先切割成凸多邊形再計算,這就比較復(fù)雜了。
類似的思路還有面積法,如果一個點在多邊形內(nèi)部,那么該點與多邊形所有頂點兩兩構(gòu)成的三角形,面積相加應(yīng)該等于多邊形的面積,首先計算多邊形的面積就很麻煩,所以這種方法可以直接pass掉。
射線法
射線法是一個我講不清道理但非常好用的方法,只要判斷點與多邊形一側(cè)的交點個數(shù)為奇數(shù),則點在多邊形內(nèi)部。需要注意的是,只要數(shù)任何一側(cè)的焦點個數(shù)就可以,比如左側(cè)。這個方法不限制多邊形的類型,凸多邊形、凹多邊形甚至環(huán)形都可以。
實現(xiàn)起來也非常簡單:
const checkPointInPolyline = (point, polylinePoints) => { //射線法 let leftSide = 0; const A = point; for (let i = 0; i < polylinePoints.length; i++) { let B, C; if (i === polylinePoints.length - 1) { B = { x: polylinePoints[i][0], y: polylinePoints[i][1] }; C = { x: polylinePoints[0][0], y: polylinePoints[0][1] }; } else { B = { x: polylinePoints[i][0], y: polylinePoints[i][1] }; C = { x: polylinePoints[i + 1][0], y: polylinePoints[i + 1][1] }; } //判斷左側(cè)相交 let sortByY = [B.y, C.y].sort((a,b) => a-b) if (sortByY[0] < A.y && sortByY[1] > A.y){ if(B.x看完上述內(nèi)容,你們掌握如何在html5中監(jiān)聽canvas內(nèi)部元素點擊事件的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
網(wǎng)站名稱:如何在html5中監(jiān)聽canvas內(nèi)部元素點擊事件
網(wǎng)頁路徑:http://weahome.cn/article/psoies.html