這篇文章主要介紹怎么利用canvas實現(xiàn)按住鼠標(biāo)移動繪制出軌跡,文中介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們一定要看完!
創(chuàng)新互聯(lián)2013年開創(chuàng)至今,先為勃利等服務(wù)建站,勃利等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為勃利企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
概要
工作以來,寫過vue、react、正則、算法、小程序等知識,唯獨(dú)沒有寫過canvas,因為實在不會??!
2018年,給自己設(shè)定一個小目標(biāo):學(xué)會canvas,達(dá)到的效果是能用canvas實現(xiàn)一些css3不容易實現(xiàn)的動畫。
本文作為學(xué)習(xí)canvas的第一篇收獲,很多人初學(xué)canvas做的第一個demo是實現(xiàn)一個“鐘”,當(dāng)然,我也實現(xiàn)了一個,不過不講這個,而是講講一個更有趣、也更簡單的玩意。
鼠標(biāo)按住繪制軌跡
需求
在一塊canvas畫布上,初始狀態(tài)畫布什么都沒有,現(xiàn)在,我想給畫布加一點鼠標(biāo)事件,用鼠標(biāo)在畫布上寫字。具體的效果是鼠標(biāo)移動到畫布上任意一點,然后按住鼠標(biāo),移動鼠標(biāo)的位置,就可以開始寫字啦!
原理
先簡單分析下思路,首先我們需要一個canvas畫布,然后計算鼠標(biāo)在畫布上的位置,給鼠標(biāo)綁定onmousedown事件和onmousemove事件,在移動過程中繪制出路徑,松開鼠標(biāo)的時候,繪制結(jié)束。
這個思路雖然很簡單,但是里面有些地方需要小技巧實現(xiàn)。
1、需要一個html文件,包含canvas元素。
這是一個寬度800,高度400的畫布。為什么沒有寫px呢?哦,暫時沒搞懂,canvas文檔推薦的。
<!doctype html> <html class="no-js" lang="zh"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>canvas學(xué)習(xí)</title> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="manifest" href="site.webmanifest"> <link rel="apple-touch-icon" href="icon.png"> <link rel="stylesheet" href="css/main.css"> </head> <body> <canvas id="theCanvas" width="800" height="400"></canvas> <script src="js/main.js"></script> </body> </html>
2、判斷當(dāng)前環(huán)境是否支持canvas。
在main.js中,我們寫一個自執(zhí)行函數(shù),下面是兼容性判斷的代碼片段,“代碼主體”中將會是實現(xiàn)需求的核心。
(function() { let theCanvas = document.querySelector('#theCanvas') if (!theCanvas || !theCanvas.getContext) { //不兼容canvas return false } else { //代碼主體 } })()
3、獲取2d對象。
let context = theCanvas.getContext('2d')
4、獲取當(dāng)前鼠標(biāo)相對于canvas的坐標(biāo)。
為什么要獲取這個坐標(biāo)呢?因為鼠標(biāo)默認(rèn)是獲取當(dāng)前窗口的相對坐標(biāo),而canvas可以位于頁面上的任何位置,所以需要通過計算才能得到真實的鼠標(biāo)坐標(biāo)。
將獲取鼠標(biāo)相對于canvas的真實坐標(biāo)封裝成了一個函數(shù),如果你覺得抽象,可以在草稿紙上畫圖來理解為什么要這么運(yùn)算。
通常情況下,可以是x - rect.left和y - rect.top。但為什么實際上卻是x - rect.left * (canvas.width/rect.width)呢?
canvas.width/rect.width表示判斷canvas中存在的縮放行為,求出縮放的倍數(shù)。
const windowToCanvas = (canvas, x, y) => { //獲取canvas元素距離窗口的一些屬性,MDN上有解釋 let rect = canvas.getBoundingClientRect() //x和y參數(shù)分別傳入的是鼠標(biāo)距離窗口的坐標(biāo),然后減去canvas距離窗口左邊和頂部的距離。 return { x: x - rect.left * (canvas.width/rect.width), y: y - rect.top * (canvas.height/rect.height) } }
5、有了第4步的利器函數(shù),我們可以給canvas加上鼠標(biāo)事件了!
先給鼠標(biāo)綁定按下onmousedown事件,用moveTo繪制坐標(biāo)起點。
theCanvas.onmousedown = function(e) { //獲得鼠標(biāo)按下的點相對canvas的坐標(biāo)。 let ele = windowToCanvas(theCanvas, e.clientX, e.clientY) //es6的解構(gòu)賦值 let { x, y } = ele //繪制起點。 context.moveTo(x, y) }
6、移動鼠標(biāo)的時候,沒有鼠標(biāo)長按事件,又該怎么監(jiān)聽呢?
這里用到的小技巧是在onmousedown內(nèi)部再執(zhí)行一個onmousemove(鼠標(biāo)移動)事件,這樣就能監(jiān)聽按住鼠標(biāo)并且移動了。
theCanvas.onmousedown = function(e) { //獲得鼠標(biāo)按下的點相對canvas的坐標(biāo)。 let ele = windowToCanvas(theCanvas, e.clientX, e.clientY) //es6的解構(gòu)賦值 let { x, y } = ele //繪制起點。 context.moveTo(x, y) //鼠標(biāo)移動事件 theCanvas.onmousemove = (e) => { //移動時獲取新的坐標(biāo)位置,用lineTo記錄當(dāng)前的坐標(biāo),然后stroke繪制上一個點到當(dāng)前點的路徑 let ele = windowToCanvas(theCanvas, e.clientX, e.clientY) let { x, y } = ele context.lineTo(x, y) context.stroke() } }
7、鼠標(biāo)松開的時候,不再繪制路徑。
有什么辦法可以讓onmouseup事件中阻止掉上面監(jiān)聽的2種事件呢?方法挺多的,設(shè)置onmousedown和onmousemove為null算是一種,我這里用到了“開關(guān)”。isAllowDrawLine設(shè)置為bool值,來控制函數(shù)是否執(zhí)行,具體代碼可以看下面完整的源碼。
源碼
分為3個文件,index.html、main.js、utils.js,這里用到了es6的語法,我是使用parcle配置好了開發(fā)環(huán)境,所以不會有報錯,如果你直接復(fù)制代碼,運(yùn)行的時候出現(xiàn)錯誤,在無法升級瀏覽器的情況下,可以將es6語法改成es5.
1、index.html
上面已經(jīng)展示了,不再復(fù)述。
2、main.js
import { windowToCanvas } from './utils' (function() { let theCanvas = document.querySelector('#theCanvas') if (!theCanvas || !theCanvas.getContext) { return false } else { let context = theCanvas.getContext('2d') let isAllowDrawLine = false theCanvas.onmousedown = function(e) { isAllowDrawLine = true let ele = windowToCanvas(theCanvas, e.clientX, e.clientY) let { x, y } = ele context.moveTo(x, y) theCanvas.onmousemove = (e) => { if (isAllowDrawLine) { let ele = windowToCanvas(theCanvas, e.clientX, e.clientY) let { x, y } = ele context.lineTo(x, y) context.stroke() } } } theCanvas.onmouseup = function() { isAllowDrawLine = false } } })()
3、utils.js
/* * 獲取鼠標(biāo)在canvas上的坐標(biāo) * */ const windowToCanvas = (canvas, x, y) => { let rect = canvas.getBoundingClientRect() return { x: x - rect.left * (canvas.width/rect.width), y: y - rect.top * (canvas.height/rect.height) } } export { windowToCanvas }
這里有個誤區(qū),我用的是canvas對象綁定事件 theCanvas.onmouseup,其實canvas不能綁定事件,真正綁定的是document和window。但是由于瀏覽器會自動幫你判斷并且移交事件處理,所以完全不用擔(dān)心。
以上是怎么利用canvas實現(xiàn)按住鼠標(biāo)移動繪制出軌跡的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
文章名稱:怎么利用canvas實現(xiàn)按住鼠標(biāo)移動繪制出軌跡
本文地址:http://muchs.cn/article2/gphdoc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導(dǎo)航、網(wǎng)站建設(shè)、品牌網(wǎng)站設(shè)計、外貿(mào)建站、服務(wù)器托管、電子商務(wù)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)