亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

html5中監(jiān)聽canvas內部元素點擊事件的三種方法

  發(fā)布時間:2019-04-28 14:19:00   作者:佚名   我要評論
這篇文章主要介紹了html5中監(jiān)聽canvas內部元素點擊事件的三種方法

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

約定

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

像素法

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

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

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

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

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

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

角度法

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

計算過程可以轉變?yōu)橐韵氯齻€步驟:

1.已知多邊形頂點和已知坐標,將坐標與頂點兩兩組合成三點隊列
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))
};
//角度法判斷點在多邊形內部
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掉。

射線法

射線法是一個我講不清道理但非常好用的方法,只要判斷點與多邊形一側的交點個數(shù)為奇數(shù),則點在多邊形內部。需要注意的是,只要數(shù)任何一側的焦點個數(shù)就可以,比如左側。這個方法不限制多邊形的類型,凸多邊形、凹多邊形甚至環(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]
      };
    }
    //判斷左側相交
    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
}

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

總結

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

相關文章

  • 如何在Canvas上的圖形/圖像綁定事件監(jiān)聽的實現(xiàn)

    這篇文章主要介紹了如何在Canvas上的圖形/圖像綁定事件監(jiān)聽的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著
    2020-09-16
  • 如何在Canvas中添加事件的方法示例

    這篇文章主要介紹了如何在Canvas中添加事件的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學
    2019-05-21
  • 詳解Canvas事件綁定

    這篇文章主要介紹了詳解Canvas事件綁定的相關資料,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-27
  • HTML5 Canvas的事件處理介紹

    這篇文章主要介紹了HTML5 Canvas的事件處理介紹,本文講解了Canvas的限制、給Canvas元素綁定事件、isPointInPath方法、循環(huán)重繪和事件冒泡等內容,需要的朋友可以參考下
    2015-04-24
  • 一個不錯的HTML5 Canvas多層點擊事件監(jiān)聽實例

    寫到一個多層點擊事件的監(jiān)聽。覺得還是挺好玩的。于是把它從模塊中抽化出來了,喜歡的朋友可以參考下
    2014-04-29
  • HTML5 Canvas鼠標與鍵盤事件demo示例

    本文的主要母的是演示HTML5 Canvas鼠標事件,獲取Canvas對象上的鼠標坐標,演示鍵盤事件通過鍵盤控制Canvas上對象移動,感興趣的朋友可以參考下哈,希望對大家有所幫助
    2013-07-04
  • 詳解如何在Canvas中添加事件的方法

    這篇文章主要介紹了詳解如何在Canvas中添加事件的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學
    2021-04-16

最新評論