摘要:鼠標按住繪制軌跡需求在一塊畫布上,初始狀態畫布什么都沒有,現在,我想給畫布加一點鼠標事件,用鼠標在畫布上寫字。獲取當前鼠標相對于的坐標。的解構賦值繪制起點。但是由于瀏覽器會自動幫你判斷并且移交事件處理,所以完全不用擔心。
概要
工作以來,寫過vue、react、正則、算法、小程序等知識,唯獨沒有寫過canvas,因為實在不會啊!
2018年,給自己設定一個小目標:學會canvas,達到的效果是能用canvas實現一些css3不容易實現的動畫。
本文作為學習canvas的第一篇收獲,很多人初學canvas做的第一個demo是實現一個“鐘”,當然,我也實現了一個,不過不講這個,而是講講一個更有趣、也更簡單的玩意。
鼠標按住繪制軌跡 需求在一塊canvas畫布上,初始狀態畫布什么都沒有,現在,我想給畫布加一點鼠標事件,用鼠標在畫布上寫字。具體的效果是鼠標移動到畫布上任意一點,然后按住鼠標,移動鼠標的位置,就可以開始寫字啦!
原理先簡單分析下思路,首先我們需要一個canvas畫布,然后計算鼠標在畫布上的位置,給鼠標綁定onmousedown事件和onmousemove事件,在移動過程中繪制出路徑,松開鼠標的時候,繪制結束。
這個思路雖然很簡單,但是里面有些地方需要小技巧實現。
1、需要一個html文件,包含canvas元素。
這是一個寬度800,高度400的畫布。為什么沒有寫px呢?哦,暫時沒搞懂,canvas文檔推薦的。
canvas學習
2、判斷當前環境是否支持canvas。
在main.js中,我們寫一個自執行函數,下面是兼容性判斷的代碼片段,“代碼主體”中將會是實現需求的核心。
(function() { let theCanvas = document.querySelector("#theCanvas") if (!theCanvas || !theCanvas.getContext) { //不兼容canvas return false } else { //代碼主體 } })()
3、獲取2d對象。
let context = theCanvas.getContext("2d")
4、獲取當前鼠標相對于canvas的坐標。
為什么要獲取這個坐標呢?因為鼠標默認是獲取當前窗口的相對坐標,而canvas可以位于頁面上的任何位置,所以需要通過計算才能得到真實的鼠標坐標。
將獲取鼠標相對于canvas的真實坐標封裝成了一個函數,如果你覺得抽象,可以在草稿紙上畫圖來理解為什么要這么運算。
通常情況下,可以是x - rect.left和y - rect.top。但為什么實際上卻是x - rect.left * (canvas.width/rect.width)呢?
canvas.width/rect.width表示判斷canvas中存在的縮放行為,求出縮放的倍數。
const windowToCanvas = (canvas, x, y) => { //獲取canvas元素距離窗口的一些屬性,MDN上有解釋 let rect = canvas.getBoundingClientRect() //x和y參數分別傳入的是鼠標距離窗口的坐標,然后減去canvas距離窗口左邊和頂部的距離。 return { x: x - rect.left * (canvas.width/rect.width), y: y - rect.top * (canvas.height/rect.height) } }
5、有了第4步的利器函數,我們可以給canvas加上鼠標事件了!
先給鼠標綁定按下onmousedown事件,用moveTo繪制坐標起點。
theCanvas.onmousedown = function(e) { //獲得鼠標按下的點相對canvas的坐標。 let ele = windowToCanvas(theCanvas, e.clientX, e.clientY) //es6的解構賦值 let { x, y } = ele //繪制起點。 context.moveTo(x, y) }
6、移動鼠標的時候,沒有鼠標長按事件,又該怎么監聽呢?
這里用到的小技巧是在onmousedown內部再執行一個onmousemove(鼠標移動)事件,這樣就能監聽按住鼠標并且移動了。
theCanvas.onmousedown = function(e) { //獲得鼠標按下的點相對canvas的坐標。 let ele = windowToCanvas(theCanvas, e.clientX, e.clientY) //es6的解構賦值 let { x, y } = ele //繪制起點。 context.moveTo(x, y) //鼠標移動事件 theCanvas.onmousemove = (e) => { //移動時獲取新的坐標位置,用lineTo記錄當前的坐標,然后stroke繪制上一個點到當前點的路徑 let ele = windowToCanvas(theCanvas, e.clientX, e.clientY) let { x, y } = ele context.lineTo(x, y) context.stroke() } }
7、鼠標松開的時候,不再繪制路徑。
有什么辦法可以讓onmouseup事件中阻止掉上面監聽的2種事件呢?方法挺多的,設置onmousedown和onmousemove為null算是一種,我這里用到了“開關”。isAllowDrawLine設置為bool值,來控制函數是否執行,具體代碼可以看下面完整的源碼。
源碼分為3個文件,index.html、main.js、utils.js,這里用到了es6的語法,我是使用parcle配置好了開發環境,所以不會有報錯,如果你直接復制代碼,運行的時候出現錯誤,在無法升級瀏覽器的情況下,可以將es6語法改成es5.
1、index.html
上面已經展示了,不再復述。
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
/* * 獲取鼠標在canvas上的坐標 * */ 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 }總結
這里有個誤區,我用的是canvas對象綁定事件 theCanvas.onmouseup,其實canvas不能綁定事件,真正綁定的是document和window。但是由于瀏覽器會自動幫你判斷并且移交事件處理,所以完全不用擔心。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107157.html
摘要:支持動畫狀態的,在動畫開始,執行中,結束時提供回調函數支持動畫可以自定義貝塞爾曲線任何包含數值的屬性都可以設置動畫倉庫文檔演示功能介紹一定程度上,也是一個動畫庫,適用所有的屬性,并且實現的能更方便的實現幀動畫,替代復雜的定義方式。 動畫調研-V1 前言:動畫從用途上可以分為兩種,一種是展示型的動畫,類似于一張GIF圖,或者一段視頻,另一種就是交互性的動畫。這兩種都有具體的應用場景,比如...
摘要:表示不一定是原生形式的數據。接口基于,繼承了的功能并將其擴展使其支持用戶系統上的文件。讀取操作完成的時候,會變成已完成,并觸發事件,同時屬性將包含一個格式的字符串編碼以表示所讀取文件的內容。 溫馨提示:這里除了一些幼稚的小組件啥也沒有溫馨提示-續:這是一個新的系列,寫一些實際開發中遇到的一些常用的功能,想法笨拙,代碼亂套 寫在前面 圖片上傳,作為web端一個常用的功能,在不同的項目中有...
閱讀 2529·2021-07-26 23:38
閱讀 3430·2019-08-30 13:10
閱讀 2316·2019-08-29 18:33
閱讀 2321·2019-08-29 16:12
閱讀 987·2019-08-29 10:59
閱讀 1798·2019-08-26 17:40
閱讀 766·2019-08-26 11:59
閱讀 812·2019-08-26 11:41