日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

canvas 判断哪个元素被点击_监听 Canvas 内部元素点击事件的三种方法

發布時間:2024/7/5 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 canvas 判断哪个元素被点击_监听 Canvas 内部元素点击事件的三种方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

canvas內部元素不能像DOM元素一樣方便的添加交互事件監聽,因為canvas內不存在“元素”這個概念,他們僅僅是canvas繪制出來的圖形。這對于交互開發來說是一個必經障礙,想要監聽圖形的點擊事件思路很簡單,只要監聽canvas元素本身的點擊事件,再判斷點擊坐標位于哪一個圖形內部,就變相實現了圖形點擊事件。本文將介紹三種方法,判斷坐標點是否位于某個canvas圖形內部。

約定

本文介紹的三種方法適用于識別canvas內形狀不規則而且位置無規律的圖形點擊事件,對于形狀規則或者位置有規律的場景,肯定有更簡便的實現,這里不做討論。

像素法

像素檢測法的思路是,將canvas中的多個圖形(如果有多個的話)分別離屏繪制,并用getImageData()方法分別獲取到像素數據保存起來。當canvas元素監聽到點擊事件時,通過點擊坐標可以直接推算出點擊發生在canvas上的第幾個像素,然后遍歷前面保存的圖形數據,看看這個像素的alpha值是不是0,如果是0說明落點不在當前圖形內,否則就說明點到了這個圖形。

根據點擊坐標得到所點擊的像素序號的方法:

像素序號 = (縱坐標-1) * canvas寬度 + 橫坐標

比如在寬度為 5 的畫布上點擊坐標(3,3),根據上述公式得到像素序號是(3-1) * 5 + 3 = 18,如圖所示:

因為canvas導出的圖形數據是將每個像素以rgba的順序存成4個數字組成的數組,所以想訪問指定像素的alpha值,只要讀取這個數組的第pIndex * 4 + 3個值就可以了,如果這個值不為0,說明該像素可見,也就是點擊到了該圖形。

這個方法是我認為思路最直接、結果最準確、而且對圖形形狀沒有任何要求的方法,但這個方法有一個致命的局限,當圖形需要在畫布上移動時,要頻繁的創建數據緩存才能保證檢測結果準確,受到畫布尺寸和圖形數量的影響,getImageData()方法的性能會成為嚴重的瓶頸。所以如果canvas圖形是靜態的,這個方法非常適合,否則就不適合用這個方法了。

角度法

角度判斷法的原理很容易理解,如果一個點在多邊形內部,則該點與多邊形所有頂點兩兩構成的夾角,相加應該剛好等于360°。

計算過程可以轉變為以下三個步驟:

已知多邊形頂點和已知坐標,將坐標與頂點兩兩組合成三點隊列

已知三點求夾角,可以使用余玄定理

判斷夾角之和是否360°

每一步都很簡單,實現如下:

//計算兩點距離

const getDistence = function (p1, p2) {

return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y))

};

//角度法判斷點在多邊形內部

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

}

這個方法有一個局限性,就是圖形必須是凸多邊形。如果不是凸多邊形需要先切割成凸多邊形再計算,這就比較復雜了。

類似的思路還有面積法,如果一個點在多邊形內部,那么該點與多邊形所有頂點兩兩構成的三角形,面積相加應該等于多邊形的面積,首先計算多邊形的面積就很麻煩,所以這種方法可以直接pass掉。

射線法

射線法是一個我講不清道理但非常好用的方法,只要判斷點與多邊形一側的交點個數為奇數,則點在多邊形內部。需要注意的是,只要數任何一側的焦點個數就可以,比如左側。這個方法不限制多邊形的類型,凸多邊形、凹多邊形甚至環形都可以。

實現起來也非常簡單:

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]

};

}

//判斷左側相交

let sortByY = [B.y, C.y].sort((a,b) => a-b)

if (sortByY[0] < A.y && sortByY[1] > A.y){

if(B.x

leftSide++

}

}

}

return leftSide % 2 === 1

}

射線法有一種特殊情況,當點在多變形的一條邊上時需要特殊處理。但在工程中我認為也可以不處理,因為如果用戶剛好點在圖形的邊界上,那么程序認為他沒有點到也講的過去。

總結

以上三種方法都可以實現canvas中不規則圖形的點擊檢測。其中,像素法的優勢在于不挑形狀,而且在靜態場景中有一定的性能優勢;角度法應該說只有理論價值,實用性不佳;工程中最實用的當屬射線法,局限性小,實現簡單,多數時候只需要知道射線法就可以了。

總結

以上是生活随笔為你收集整理的canvas 判断哪个元素被点击_监听 Canvas 内部元素点击事件的三种方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。