本篇文章主要介紹了canvas實作按住滑鼠移動繪製出軌跡的範例程式碼,內容挺不錯的,現在分享給大家,也給大家做個參考。
概要
工作以來,寫過vue、react、正規、演算法、小程式等知識,唯獨沒有寫過canvas,因為實在不會啊!
2018年,為自己設定一個小目標:學會canvas,達到的效果是能用canvas實現一些css3不容易實現的動畫。
本文作為學習canvas的第一篇收穫,許多人初學canvas做的第一個demo是實現一個“鐘”,當然,我也實現了一個,不過不講這個,而是講講一個更有趣、也更簡單的玩意。
滑鼠按住繪製軌跡
需求
在一塊canvas畫布上,初始狀態畫布什麼都沒有,現在,我想為畫布加一點滑鼠事件,用滑鼠在畫布上寫字。具體的效果是滑鼠移動到畫布上任意一點,然後按住滑鼠,移動滑鼠的位置,就可以開始寫字囉!
原理
先簡單分析下思路,首先我們需要一個canvas畫布,然後計算滑鼠在畫布上的位置,給滑鼠綁定onmousedown事件和onmousemove事件,在移動過程中繪製出路徑,放開滑鼠的時候,繪製結束。
這個想法雖然很簡單,但裡面有些地方需要小技巧實作。
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学习</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、判斷目前環境是否支援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 。但由於瀏覽器會自動幫你判斷並且移交事件處理,所以完全不用擔心。
以上就是本文的全部內容,希望對大家的學習有所幫助,更多相關內容請關注PHP中文網!
相關推薦:
#
以上是如何利用canvas實作按住滑鼠移動繪製出軌跡的詳細內容。更多資訊請關注PHP中文網其他相關文章!