摘要:本文同步于個人博客前些天學(xué)習(xí)了的元素,今天就來實(shí)踐一下,用做一個畫板。實(shí)現(xiàn)一個簡單的畫板實(shí)現(xiàn)思路監(jiān)聽鼠標(biāo)事件,用方法把記錄的數(shù)據(jù)畫出來。為時,移動鼠標(biāo)使用剪裁擦除畫布。
本文同步于個人博客:https://zhoushuo.me/blog/2018/03/11/drawing-borad/
前些天學(xué)習(xí)了HTML5的元素,今天就來實(shí)踐一下,用canvas做一個畫板。
首先說一下要實(shí)現(xiàn)的功能:
切換畫筆顏色
調(diào)整筆刷粗細(xì)
清空畫布
橡皮擦擦除
撤銷操作
保存成圖片
兼容移動端(支持觸摸)
好了,廢話少說,先看最終效果:https://zhoushuozh.github.io/drawingborad
準(zhǔn)備工作首先,準(zhǔn)備個容器,也就是畫板了。
然后初始化js:
let canvas = document.getElementById("drawing-board"); let ctx = canvas.getContext("2d");
我想把畫板做成全屏的,所以接下來設(shè)置一下canvas的寬高。
let pageWidth = document.documentElement.clientWidth; let pageHeight = document.documentElement.clientHeight; canvas.width = pageWidth; canvas.height = pageHeight;
由于部分IE不支持canvas,如果要兼容IE,我們可以創(chuàng)建一個canvas,然后使用excanvas初始化,針對IE加上exCanvas.js,這里我們暫時先不考慮IE。
實(shí)現(xiàn)一個簡單的畫板實(shí)現(xiàn)思路:監(jiān)聽鼠標(biāo)事件,用drawCircle()方法把記錄的數(shù)據(jù)畫出來。
設(shè)置初始化當(dāng)前畫布功能為畫筆狀態(tài),painting = false,
當(dāng)鼠標(biāo)按下時(mousedown),把painting設(shè)為true,表示正在畫,鼠標(biāo)沒松開。把鼠標(biāo)點(diǎn)記錄下來。
當(dāng)按下鼠標(biāo)的時候,鼠標(biāo)移動(mousemove)就把點(diǎn)記錄下來并畫出來。
如果鼠標(biāo)移動過快,瀏覽器跟不上繪畫速度,點(diǎn)與點(diǎn)之間會產(chǎn)品間隙,所以我們需要將畫出的點(diǎn)用線連起來(lineTo())。
鼠標(biāo)松開的時候(mouseup),把painting設(shè)為false。
代碼:
let painting = false; let lastPoint = {x: undefined, y: undefined}; //鼠標(biāo)按下事件 canvas.onmousedown = function (e) { painting = true; let x = e.clientX; let y = e.clientY; lastPoint = {"x": x, "y": y}; drawCircle(x, y, 5); }; //鼠標(biāo)移動事件 canvas.onmousemove = function (e) { if (painting) { let x = e.clientX; let y = e.clientY; let newPoint = {"x": x, "y": y}; drawLine(lastPoint.x, lastPoint.y, newPoint.x, newPoint.y,clear); lastPoint = newPoint; } }; //鼠標(biāo)松開事件 canvas.onmouseup = function () { painting = false; } // 畫點(diǎn)函數(shù) function drawCircle(x, y, radius) { ctx.save(); ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI * 2); ctx.fill(); } // 劃線函數(shù) function drawLine(x1, y1, x2, y2) { ctx.lineWidth = 3; ctx.lineCap = "round"; ctx.lineJoin = "round"; ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); ctx.closePath(); }橡皮擦功能
實(shí)現(xiàn)思路
獲取橡皮擦元素
設(shè)置橡皮擦初始狀態(tài),clear = false。
監(jiān)聽橡皮擦click事件,點(diǎn)擊橡皮擦,改變橡皮擦狀態(tài),clear = true。
clear為true時,移動鼠標(biāo)使用canvas剪裁(clip())擦除畫布。
let eraser = document.getElementById("eraser"); let clear = false; eraser.onclick = function () { clear = true; }; ... if (clear) { ctx.save(); ctx.globalCompositeOperation = "destination-out"; ctx.stroke(); ctx.closePath(); ctx.clip(); ctx.clearRect(0,0,canvas.width,canvas.height); ctx.restore(); } ...
注意,在canvas中的裁剪和平時的裁剪功能不一樣在這里,裁剪是指在裁剪區(qū)域去顯示我們所畫的圖
兼容移動端實(shí)現(xiàn)思路:
判斷設(shè)備是否支持觸摸
true,則使用touch事件;false,則使用mouse事件
代碼:
... if (document.body.ontouchstart !== undefined) { // 使用touch事件 anvas.ontouchstart = function (e) { // 開始觸摸 } canvas.ontouchmove = function (e) { // 開始滑動 } canvas.ontouchend = function () { // 滑動結(jié)束 } }else{ // 使用mouse事件 ... } ...
這里需要注意的一點(diǎn)是,在touch事件里,是通過.touches[0].clientX和.touches[0].clientY來獲取坐標(biāo)的,這點(diǎn)要和mouse事件區(qū)別開。
切換畫筆顏色實(shí)現(xiàn)思路:
獲取顏色元素節(jié)點(diǎn)。
點(diǎn)擊顏色返回其顏色值,并賦給畫布的ctx.strokeStyle。
代碼:
let aColorBtn = document.getElementsByClassName("color-item"); for (let i = 0; i < aColorBtn.length; i++) { aColorBtn[i].onclick = function () { for (let i = 0; i < aColorBtn.length; i++) { activeColor = this.style.backgroundColor; ctx.strokeStyle = activeColor; } }清空畫布
實(shí)現(xiàn)思路:
獲取元素節(jié)點(diǎn)。
點(diǎn)擊清空按鈕清空canvas畫布。
代碼:
let reSetCanvas = document.getElementById("clear"); reSetCanvas.onclick = function () { ctx.clearRect(0, 0, canvas.width, canvas.height); };調(diào)整筆刷粗細(xì)
實(shí)現(xiàn)思路:
創(chuàng)建input[type=range]
滑動range獲取其value值,并賦給ctx.lineWidth
代碼:
let range = document.getElementById("range"); range.onchange = function(){ lWidth = this.value; };保存成圖片
實(shí)現(xiàn)思路:
獲取canvas.toDateURL
在頁面里創(chuàng)建并插入一個a標(biāo)簽
a標(biāo)簽href等于canvas.toDateURL,并添加download屬性
點(diǎn)擊保存按鈕,a標(biāo)簽觸發(fā)click事件
代碼:
let save = document.getElementById("save"); save.onclick = function () { let imgUrl = canvas.toDataURL("image/png"); let saveA = document.createElement("a"); document.body.appendChild(saveA); saveA.href = imgUrl; saveA.download = "zspic" + (new Date).getTime(); saveA.target = "_blank"; saveA.click(); };撤銷
實(shí)現(xiàn)思路:
準(zhǔn)備一個數(shù)組記錄歷史操作
每次使用畫筆前將當(dāng)前繪圖表面儲存進(jìn)數(shù)組
點(diǎn)擊撤銷時,恢復(fù)到上一步的繪圖表面
代碼:
canvas.ontouchstart = function (e) { // 在這里儲存繪圖表面 this.firstDot = ctx.getImageData(0, 0, canvas.width, canvas.height); saveData(this.firstDot); ... } let undo = document.getElementById("undo"); let historyDeta = []; function saveData (data) { (historyDeta.length === 10) && (historyDeta.shift()); // 上限為儲存10步,太多了怕掛掉 historyDeta.push(data); } undo.onclick = function(){ if(historyDeta.length < 1) return false; ctx.putImageData(historyDeta[historyDeta.length - 1], 0, 0); historyDeta.pop() };
因?yàn)槊看蝺Υ娑际菍⒁粡垐D片存入內(nèi)存,對性能影響較大,所以在這里設(shè)置了儲存上限。
總結(jié)這里用的知識點(diǎn)主要有:監(jiān)聽mouse、touch事件,以及canvas的moveTo()、lineTo()、stroke()、clip()、clearRect()等方法。其實(shí)還有很多效果可以實(shí)現(xiàn),比如說噴霧效果,蠟筆效果,藝術(shù)畫效果等等。日后有時間我會繼續(xù)對這個畫板進(jìn)行優(yōu)化,增加一些新的功能,同時歡迎大家留言提問或者提出批評建議。
最終代碼:https://github.com/zhoushuozh/drawingborad
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93455.html
摘要:中的圖片處理與合成一引言圖片處理現(xiàn)在已經(jīng)成為了我們生活中的剛需,想必大家也經(jīng)常有這方面的需求。實(shí)際前端業(yè)務(wù)中,也經(jīng)常會有很多的項目需要用到圖片加工和處理。 JavaScript中的圖片處理與合成(一) 引言: 圖片處理現(xiàn)在已經(jīng)成為了我們生活中的剛需,想必大家也經(jīng)常有這方面的需求。實(shí)際前端業(yè)務(wù)中,也經(jīng)常會有很多的項目需要用到圖片加工和處理。由于過去一段時間公司的業(yè)務(wù)需求,讓我在這方面積累...
摘要:實(shí)現(xiàn)彩虹畫筆繪畫板指南作者簡介是推出的一個天挑戰(zhàn)。這部分不涉及內(nèi)容,全部由來實(shí)現(xiàn)。實(shí)現(xiàn)彩虹畫筆繪畫板效果圖項目源碼分析源碼獲取節(jié)點(diǎn)支持不支持彩虹效控制筆觸大小控制繪制路徑源碼分析寬高設(shè)置屬性筆觸的形狀,有圓平方三種。 Day08 - HTML5 Canvas 實(shí)現(xiàn)彩虹畫筆繪畫板指南 作者:?liyuechun 簡介:JavaScript30 是 Wes Bos 推出的一個 30 天挑...
閱讀 2397·2021-11-22 14:56
閱讀 1205·2019-08-30 15:55
閱讀 3234·2019-08-29 13:29
閱讀 1384·2019-08-26 13:56
閱讀 3547·2019-08-26 13:37
閱讀 589·2019-08-26 13:33
閱讀 3377·2019-08-26 13:33
閱讀 2255·2019-08-26 13:33