亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > HTML > 正文

html5中監聽canvas內部元素點擊事件的三種方法

2024-08-26 00:21:25
字體:
來源:轉載
供稿:網友

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

約定

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

像素法

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

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

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

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

html5,監聽,canvas,內部元素,點擊事件

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

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

角度法

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

html5,監聽,canvas,內部元素,點擊事件

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

1.已知多邊形頂點和已知坐標,將坐標與頂點兩兩組合成三點隊列
2. 已知三點求夾角,可以使用 余玄定理 
3.判斷夾角之和是否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掉。

射線法

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

html5,監聽,canvas,內部元素,點擊事件

實現起來也非常簡單:


 

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<A.x || C.x < A.x){        leftSide++      }    }  }  return leftSide % 2 === 1}

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

總結

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


注:相關教程知識閱讀請移步到HTML教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩在线视频免费观看| 一个人看的www欧美| 国产精品一区二区三区成人| 国产精品一区二区三| 日韩电视剧在线观看免费网站| 国产精品草莓在线免费观看| 在线观看久久久久久| 8090成年在线看片午夜| 在线电影欧美日韩一区二区私密| 色老头一区二区三区| 午夜剧场成人观在线视频免费观看| 国产精品狼人色视频一区| 岛国av一区二区在线在线观看| 在线看欧美日韩| 亚洲人午夜精品免费| 国产在线高清精品| 国产精品久久综合av爱欲tv| 高清欧美性猛交| 国产在线播放91| 国产精品久久久久久久久久久新郎| 国产在线精品自拍| 亚洲深夜福利网站| 国产日产欧美a一级在线| 国产精品一区二区电影| 日韩有码在线电影| 欧美日韩亚洲系列| 欧美最猛性xxxxx免费| 亚洲xxxxx电影| 精品成人乱色一区二区| 中日韩美女免费视频网站在线观看| 亚洲在线一区二区| 韩日精品中文字幕| 性欧美xxxx| 亚洲影视九九影院在线观看| 91在线观看免费| 国产视频一区在线| 亚洲精品99久久久久中文字幕| 亚洲欧洲偷拍精品| 亚洲色在线视频| 91中文精品字幕在线视频| 久久好看免费视频| 国产一区二区在线免费视频| 国产精品久久久久久久久久小说| 欧美成年人视频| 欧美国产日韩一区二区在线观看| 日韩免费视频在线观看| 亚洲黄色www网站| 国产精品亚洲片夜色在线| 久久伊人精品天天| 久久久亚洲国产| 国产精品国产亚洲伊人久久| 黑人巨大精品欧美一区二区免费| 亚洲欧洲av一区二区| 亚洲久久久久久久久久| 欧美另类第一页| 欧美成人亚洲成人日韩成人| 欧美性生活大片免费观看网址| 久久久久久中文| 国产精品专区第二| 日本aⅴ大伊香蕉精品视频| 国产免费亚洲高清| 成人激情电影一区二区| 69av在线播放| 亚洲视频在线免费观看| 欧美日韩精品国产| 国产成人精品最新| 国产免费成人av| 欧美大片大片在线播放| 久久久精品影院| 亚洲免费高清视频| 精品国内亚洲在观看18黄| 亚洲天天在线日亚洲洲精| www.日韩欧美| 国产美女高潮久久白浆| 色妞久久福利网| 欧美激情伊人电影| 亚洲午夜av久久乱码| 91久久久久久久久久| 91精品国产自产在线观看永久| 亚洲free性xxxx护士hd| 操人视频在线观看欧美| 欧美另类极品videosbestfree| 永久免费看mv网站入口亚洲| 日本欧美精品在线| 亚洲第一级黄色片| 色综合亚洲精品激情狠狠| 亚洲国产精品成人精品| 欧美激情视频给我| 日韩欧美一区二区三区久久| 亚洲成av人影院在线观看| 亚洲黄色av女优在线观看| 国产精品久久久久久久av电影| 国产小视频91| 中文字幕亚洲一区在线观看| 欧美噜噜久久久xxx| 日韩美女av在线免费观看| 国产日韩欧美在线播放| 亚洲一区二区久久久| 亚洲欧美日韩天堂一区二区| 日韩电影视频免费| 亚洲成人黄色在线观看| 中文字幕在线成人| 亚洲欧美日韩精品久久奇米色影视| 欧美福利视频在线观看| 亚洲欧美激情一区| 亚洲精品成人久久| 欧美专区福利在线| 97久久精品国产| 欧美精品一二区| 91精品视频在线免费观看| 国产精品免费在线免费| 国产99久久精品一区二区 夜夜躁日日躁| 国产精品视频地址| 欧美精品免费播放| 亚洲伊人久久大香线蕉av| 亚洲欧美变态国产另类| 97超级碰碰碰| 美女性感视频久久久| 清纯唯美亚洲综合| 欧美日韩亚洲精品一区二区三区| 成人av.网址在线网站| 国产精品在线看| 日韩美女av在线免费观看| 日韩av影院在线观看| 黄色成人在线免费| 日韩av片电影专区| 亚洲精品www| 91综合免费在线| 亚洲欧美色图片| 亚洲欧洲偷拍精品| 91精品国产91久久久久久不卡| 国产精品老牛影院在线观看| 日韩精品极品在线观看播放免费视频| 欧美天天综合色影久久精品| 欧美日韩国产va另类| 国产一区二区视频在线观看| 亚洲色图国产精品| 成人欧美在线观看| 国产日本欧美视频| 国产精品91久久久久久| 一本一本久久a久久精品综合小说| 国产大片精品免费永久看nba| 亚洲自拍高清视频网站| 久久久久久久久久久网站| 色999日韩欧美国产| 久久男人的天堂| 亚洲第一级黄色片| 日韩精品视频中文在线观看| 亚洲无亚洲人成网站77777| 欧美在线视频免费播放| 国产日韩欧美电影在线观看| 日韩精品一区二区视频| 成人h片在线播放免费网站| 懂色aⅴ精品一区二区三区蜜月| www.99久久热国产日韩欧美.com| 久久久久久久久久婷婷| 欧美在线观看日本一区| 在线观看国产精品日韩av| 欧美高清视频在线播放| 精品国产一区二区三区久久| 色yeye香蕉凹凸一区二区av| 国产精品扒开腿做爽爽爽的视频| 日韩精品视频在线观看网址| 久久亚洲综合国产精品99麻豆精品福利|