1. 程式人生 > >為canvas繪製的多個圖形設定點選事件

為canvas繪製的多個圖形設定點選事件

一、給Canvas元素繫結事件基礎知識

由於事件只能達到Canvas元素這一層,所以,如果想進一步深入,識別點擊發生在Canvas內部的哪一個圖形上,就需要增加程式碼來進行處理。

基本思路是:給Canvas元素繫結事件,當事件發生時,檢查事件物件的位置,然後檢查哪些圖形覆蓋了該位置。只要滑鼠點選在這個範圍裡,就可以視為點選了該矩形,也就可以手動觸發矩形需要處理的點選事件。

第一步:封裝一個獲取事件物件位置的函式getEventPosition()

function getEventPosition(ev){
  var x, y;
  if (ev.layerX || ev.layerX == 0) {
    x = ev.layerX;
    y = ev.layerY;
  } else if (ev.offsetX || ev.offsetX == 0) { // Opera
    x = ev.offsetX;
    y = ev.offsetY;
  }
  return {x: x, y: y};
}
//注:使用上面這個函式,需要給Canvas元素的position設為absolute。

第二步:給canvas新增點選事件

cvs = document.getElementById('mycanvas');
cvs.addEventListener('click', function(e){
  //...
}, false);

第三步:判斷事件物件的座標是否在圖形內:

cvs = document.getElementById('mycanvas');
ctx = canvas.getContext('2d');
ctx.rect(10, 10, 100, 100);
ctx.stroke();
ctx.isPointInPath(50, 50);     //true
ctx.isPointInPath(5, 5);     //false

注意:canvas中繪製多個圖形時,isPointInPath()只能判斷事件物件的位置是否在最後一個繪製的圖形上,而之前繪製的圖形已經無法判斷

cvs = document.getElementById('mycanvas');
ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.rect(10, 10, 100, 100);
ctx.stroke();
ctx.isPointInPath(20, 20);     //true
ctx.beginPath();
ctx.rect(110, 110, 100, 100);
ctx.stroke();
ctx.isPointInPath(150, 150);     //true
ctx.isPointInPath(20, 20);     //false

二.當canvas繪製多個圖形時的點選事件

具體思路:當點選事件發生時,重繪所有圖形,每繪製一個就使用isPointInPath方法,判斷事件座標是否在該圖形覆蓋範圍內。

第一步:為了實現重繪,需要將圖形的引數儲存下來

arr = [
  {x:10, y:10, width:100, height:100},
  {x:110, y:110, width:100, height:100}
];
 
cvs = document.getElementById('mycanvas');
ctx = canvas.getContext('2d');
 

第二步:新增點選事件

cvs.addEventListener('click', function(e){
  p = getEventPosition(e);
  draw(p);
}, false);

第三步:每次點選時重繪圖形

//圖形繪製
function draw(p){
  var who = [];//儲存點選事件包含圖形的index值
  ctx.clearRect(0, 0, cvs.width, cvs.height);
  arr.forEach(function(v, i){
    ctx.beginPath();
    ctx.rect(v.x, v.y, v.width, v.height);
    ctx.stroke();
    if(p && ctx.isPointInPath(p.x, p.y)){
      //如果傳入了事件座標,就用isPointInPath判斷一下
      //如果當前環境覆蓋了該座標,就將圖形的index放到數組裡
      who.push(i);
    }
  });
  //根據陣列中的index值,可以到arr陣列中找到相應的元素。
  return who;
}

在上面程式碼中,點選事件發生時draw方法會執行一次重繪,並在重繪過程中檢查每一個圖形是否覆蓋了事件座標,如果判斷為真,則視為點選了該圖形,並將該圖形的index值放入陣列,最後將陣列作為draw方法的返回值。在這種處理機制下,如果Canvas裡有N個圖形,它們有一部分是重疊的,而點選事件恰巧發生在這個重疊區域上,那麼draw方法的返回數組裡會有N個成員。這時就有點類似事件冒泡的情況,陣列的最後一個成員處於Canvas最上層,而第一個成員則在最下層,我們可以視為最上層的成員是e.target,而其他成員則是冒泡過程中傳遞到的節點。當然這只是最簡單的一種處理方法,如果真要模擬DOM處理,還要給圖形設定父子級關係。

相關推薦

canvas繪製圖形設定事件

一、給Canvas元素繫結事件基礎知識 由於事件只能達到Canvas元素這一層,所以,如果想進一步深入,識別點擊發生在Canvas內部的哪一個圖形上,就需要增加程式碼來進行處理。 基本思路是:給Canvas元素繫結事件,當事件發生時,檢查事件物件的位置,然後檢查哪些圖形覆

jquery實現根據不同class按鈕新增事件

一、實現功能 在專案中需要新增幾個button來實現點選不同的button就可以設定字母的顏色。但是button上面不能有文字。所以不能根據$('button').html()獲取button的文字來

Matlab一個視窗中繪製圖形

subplot指令 將影象視窗分成若干個區域,在每個區域內分別繪圖. handle = subplot(m, n, p); 上述指令將影象劃分為 m*n 個子區域, p用於指向子區域. 順序為 1 2 3 … n n+1 n+2 n+3 2n ……………………………………..

使用matplotlib在同一個視窗繪製圖形

程式碼如下: import numpy as np import matplotlib.pyplot as plt #建立自變數陣列 x= np.linspace(0,2*np.pi,500) #建立函式值陣列 y1 = np.sin(x) y2 = np.cos(x) y3 = np

使用matplotlib繪製圖形單獨顯示

一 程式碼 import numpy as np import matplotlib.pyplot as plt #建立自變數陣列 x= np.linspace(0,2*np.pi,500) #建立

涉及Fragment,其中一個fragment中的“登入”按鈕,跳轉到“登入”介面時,出現程式閃退現象

問題說明:我想實現從當前fragment_me中點選一下登入按鈕,跳轉到登入介面,所以我在MeFragment.java裡的onCreate()方法中為TextView控制元件新增監聽事件。但在實際執行中,我點選“Me”之後,會出現閃退現象。 錯誤:空指標異常 出現閃

swiper 導航有,被的項居中顯示。

<div class="swiper-container"> <div class="swiper-wrapper"> <div class="swiper-slide">slider1</div> <div

高德地圖 infoWindow 預設關閉資訊窗體 彈出

地圖載入完成不想把info窗體顯示,所以找了很多都沒有。最後測試之後這樣改: 官網API的程式碼如下: 結果如下: 預設不開啟,把  marker.emit('click', {target: marker});刪掉就行。

動態新增未知View,並動態設定事件

先看看效果 有時候,你不知道需求裡面有幾個View,要根據後臺傳的個數來動態新增 擼程式碼 因為是可以橫向滑動的,所有我用一個HorizontalScrollView包裹一個LinearLayout,在LinearLayout裡面動態add需要的Vie

Button設定事件的四種方式

Button的點選事件可以有好多種你知道麼? 第一種(匿名內部類): private Button btn1; @Override protected void onCreate(Bundle savedInstanceState) { supe

MPAndroidChart之RadarChart新增lable新增事件

關於RadarChart 先貼上MPAndroidChart 的GitHub上地址:https://github.com/PhilJay/MPAndroidChart  RadarChart的使用這裡不做介紹,如有需要請自行查閱! 直奔主題,檢視RadarChart的監聽方法,

EditText監聽輸入完成和設定事件時與父控制元件的衝突問題

最近在做專案時,發現一個問題,最後找到了解決辦法,特在此記錄一下,便於以後自己回憶以及和大家分享 問題描述:我在專案的頁面B放了一個線性佈局,裡面有EditText,本意是從A頁面跳轉到B頁面時,可能會先做別的操作,在修改EditText裡面的內容(闡述一下:

EditText 設定事件

有些時候搜尋一些商品 為了美觀會跳轉到另一個頁面進行搜尋 所以需要支援edittext的點選事件,但是前提要讓edittext失去焦點要不然會彈出軟鍵盤 EditText seachEditText

RecyclerView 條目載入 和事件

compile 'com.android.support:recyclerview-v7:25.1.0' //////////////////////////////////////////////////////////////如果巢狀 ScrollowView 需要加上

RecyclerView的基本使用(優化圖片載入、設定條目間距、設定Adapter、設定事件等)

首先需要v7包 如果顯示的是圖片,可以用下面這個AutoLoadRecyclerView,他可以在快速滑動時停止載入,避免OOM和記憶體資源浪費 public class AutoLoadRecyclerView extends RecyclerView { p

Echarts設定事件

通常在使用Echarts畫圖之後會碰到一個需求,通過點選生成後圖形具體某一項來傳遞相應的引數然後進行一個頁面的跳轉,當我遇到這個需求第一就想到了用on繫結點選事件的方法,然後就在程式碼上進行嘗試,果然可以實現這個功能,我在這塊展示的是一個柱狀圖,通過點選事件輸出

Android程式:GridView的應用(仿桌面圖示排列並設定事件

實現效果: MainActivity : public class MainActivity extends Activity implements OnItemClickListener { private GridView gridVi

【Android】自定義Dialog如何設定事件

我一直用findViewById,結果檢視log,總是提示我沒有獲取到控制元件,讓我疑惑了幾天,上網查了下。dialog.getWindow().findViewById(R.id.cancel_tv)

React Native ListView的Item設定事件時null is not an object

先貼下程式碼: <ListView contentContainerStyle = {styles.list}

js 實現間隔相同時間自動觸發兩按鈕的事件,兩按鈕觸發事件時間間隔一樣,然後迴圈

問題: function clickTuo() { $("#ffimg1").trigger("click"); }; function clickTuo2() {