如何在Canvas中新增事件?

2022-07-11 03:33:10 字數 4792 閱讀 5582

作為乙個前端,給元素新增事件是一件司空見慣的事情。可是在canvas中,其所畫的任何東西都是無法獲取的,更別說新增事件,那麼我們對其就束手無策了嗎?當然不是的!我們在平時專案中肯定都用過許多canvas的框架,我們發現事件在這些框架中已經使用的十分成熟了,而且並沒有出現特別嚴重的問題。那麼我們可以肯定的是,事件在canvas中並不是乙個無法觸及的事情。  

我們都知道乙個元素在觸發乙個事件時,其滑鼠的位置基本處於該元素之上,那麼我們就自然而然的想到通過當前滑鼠的位置以及物體所佔據的位置進行比對,從而我們就能得出該物體是否應觸發事件。這種方式比較簡單,我就不用**演示了,不過既然我叫它傻瓜式的方式,很明顯它不是乙個有效的解決方式。因為物體所佔據的位置並不一定是十分容易獲取,如果是矩形、圓形等我們還能通過一些簡單的公式獲取其佔據的位置,可是在複雜點的多邊形,甚至是多邊形的某些邊是弧線的,顯而易見,我們這時候再獲取其所佔據的位置時是一件極其複雜且難度極大的事情,所以這種方式只適合自己在做一些demo中使用,並不適用於大多數的情況。

既然上面這種方式碰壁了,那麼我們只能另闢蹊徑。在翻閱canvasapi的時候,找到了乙個方法ispointinpath,貌似正是我們苦苦尋找的良藥。

介紹ispointinpath

ispointinpath的作用:顧名思義,我們很直觀的可以知道該方法用以判斷點是否處於路徑當中。

ispointinpath的入參出參:ctx.ispointinpath([path, ]x, y [, fillrule]),該方法的引數有4個,其中path和fillrule為選填,x和y為必填。我們依次介紹4個引數。

path:看到這個引數,我開始以為是beginpath或者closepath的返回值,很可惜的是這兩個方法並沒有返回值,在查閱了資料後,發現是path2d建構函式new的物件。path2d建構函式具體用法。不過可惜的是該方法可能由於相容性的問題,目前看了一些開源框架都還未使用。

x,y:這兩個引數很好理解,就是x軸和y軸的距離,需要注意的是,其相對位置是canvas的左上角。

fillrule:nonzero(預設),evenodd。非零環繞規則和奇偶規則是圖形學中判斷乙個點是否處於多邊形內的規則,其中非零環繞規則是canvas的預設規則。想具體了解這兩種規則的,可以自己去查閱資料,這裡就不增加篇幅介紹了。

上面介紹完了入參,那麼ispointinpath方法的出參想必大家都可以猜到了,就是true和false。

使用ispointinpath

上一節介紹完ispointinpath方法後,我們現在就來使用它吧。

先來乙個簡單的demo:

const canvas = document.getelementbyid('canvas')

const ctx = canvas.getcontext('2d')

ctx.beginpath()

ctx.moveto(10, 10)

ctx.lineto(10, 50)

ctx.lineto(50, 50)

ctx.lineto(50, 10)

ctx.fillstyle= 'black'

ctx.fill()

ctx.closepath()

canvas.addeventlistener('click', function (e) )

如圖所示,灰色部分為canvas所佔據的區域,黑色為我們實際新增事件的區域,在我們點選黑色區域後,實際也的確如我們所願,列印出來的值為true。貌似canvas的事件監聽就這麼簡單的解決了,不過事情真有這麼簡單嗎。顯然是不可能的!我們再來舉個例子,這時候有兩個區域,並且我們需要分別給其繫結不同的事件:

const canvas = document.getelementbyid('canvas')

const ctx = canvas.getcontext('2d')

ctx.beginpath()

ctx.moveto(10, 10)

ctx.lineto(10, 50)

ctx.lineto(50, 50)

ctx.lineto(50, 10)

ctx.fillstyle= 'black'

ctx.fill()

ctx.closepath()

ctx.beginpath()

ctx.moveto(100, 100)

ctx.lineto(100, 150)

ctx.lineto(150, 150)

ctx.lineto(150, 100)

ctx.fillstyle= 'red'

ctx.fill()

ctx.closepath()

canvas.addeventlistener('click', function (e) )

這個時候,結果就不再如同我們所預計的一樣,當點選其中黑色區域時,列印的值為false,點選紅色區域時,列印的值為true。

其實原因很簡單,因為上述**,我們實際建立了兩個path,而ispointinpath方法實際只檢測當前點是否處於最後乙個path當中,而例子中紅色區域為最後乙個path,所以只有點選紅色區域時,ispointinpath方法才能判斷為true。現在我們改造一下**:

const canvas = document.getelementbyid('canvas')

const ctx = canvas.getcontext('2d')

let drawarray =

function draw1 ()

function draw2 ()

drawarray.push(draw1, draw2)

drawarray.foreach(it => )

canvas.addeventlistener('click', function (e) )

})

上面的**我們進行了乙個很大的改造,我們將每個path放入到乙個單獨的函式當中,並將它們push到乙個陣列當中。當觸發點選事件時,我們清空canvas,並遍歷陣列重新繪製,每當繪製乙個path進行一次判斷,從而在呼叫ispointinpath方法時,我們能實時的獲取當前的最後乙個path,進而判斷出當前點所處的path當中。

現在我們已經間接的實現了對每個path的單獨事件監聽,可是其實現的方式需要一次又一次的重繪,那麼有辦法不需要重繪就能監聽事件嗎?

首先我們需要知道一次又一次重繪的原因是因為ispointinpath方法是監聽的最後乙個path,不過我們在介紹這個方法的時候,說過其第乙個引數是乙個path物件,當我們傳遞了這個引數後,path就不再去取最後乙個path而是使用我們傳遞進去的這個path,現在我們來個demo來驗證其可行性:

const canvas = document.getelementbyid('canvas')

const ctx = canvas.getcontext('2d')

const path1 = new path2d();

path1.rect(10, 10, 100,100);

ctx.fill(path1)

const path2 = new path2d();

path2.moveto(220, 60);

path2.arc(170, 60, 50, 0, 2 * math.pi);

ctx.stroke(path2)

canvas.addeventlistener('click', function (e) )

如上圖所示,我們點選了左邊圖形,列印true,false;點選右邊圖形,列印false,true。列印的結果表明是沒有問題的,不過由於其相容性還有待加強,所以目前建議還是使用重繪方式來監聽事件。

資源搜尋**大全

廣州vi設計公司

自己寫的乙個demo

const canvas = document.getelementbyid('canvas')

class rectangular

) painting ()

adjust (left, top)

} class circle

) painting ()

adjust (left, top)

} class demo )

this.addrenderlist(target)

return this

}this.circle = (config) => )

this.addrenderlist(target)

return this

}this.addevent()

}addrenderlist (target)

itemtolast (index)

painting ()

addevent ()

})if (choosedindex !== null)

document.addeventlistener('mousemove', mousemoveevent)

document.addeventlistener('mouseup', mouseupevent)

this.painting()

})function mousemoveevent (e)

function mouseupevent (e)

}} const yes = new demo(canvas)

.rectangular({})

.rectangular()

.rectangular()

.circle()

.circle()

.painting()

如何在ie8中新增事件控制代碼?

ie 8 及更早 ie 版本,opera 7.0及其更早版本不支援 addeventlistener 和 removeeventlistener 方法。但是,對於這類瀏覽器版本可以使用 attachevent detachevent 方法來新增 移除事件控制代碼。跨瀏覽器解決方法 var x doc...

說說在 Canvas 中如何新增陰影

canvas 的 context 中有四個引數可以用於設定陰影相關屬性。方法名說明 shadowoffsetx 陰影 x 軸偏移量。可以為正值或負值 負值表示在左側和上方建立陰影,正值表示在底部和右側建立陰影。shadowoffsety 陰影 y 軸偏移量。其它特性與陰影 x 軸偏移量相同。shad...

如何在dll中新增資源

在dll中使用資源 現在最常看見的關於dll的問題 就是如何在dll中使用對話方塊,這是乙個很普遍的關於如何在dl l中使用資源的問題。這裡我們從win32 dll和mfc d ll兩個方面來分析並解決這個問題。1 wi n32 dll 在win32 dll中使 用對話方塊很簡單,你只需要在你的dl...