本文主要介紹:
名稱:智繪畫板
技術堆疊:HTML5,CSS3,JavaScript,行動端
功能描述:
專案地址預覽地址
預覽圖
PC端的預覽圖:
移動端的預覽圖:
看完上面的預覽圖和體驗過智繪畫板覺得還可以的,記得點個贊哦,不管你是否十分激動,反正我是挺激動的,畢竟自己實現出現的項目效果,挺自豪的,說了一堆廢話,以下就可以動起手來敲程式碼,實現自己想要的效果! ! !
註:以下實作專案效果主要是關於JavaScript方面的,以下只是提供實作想法的程式碼,並非全部程式碼。
三、一步步達成專案效果(一)分析頁面
透過用例圖,我們知道用戶進入我們這個網站有哪些功能?
使用者可以進行的操作:
(二)進行HTML佈局
我書寫html的同時,引進了css檔和js文件
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <meta name=viewport content=width=device-width, initial-scale=1.0> <meta http-equiv=X-UA -Compatible content=ie=edge> <title>智繪畫板</title> <link rel=shortcut icon href=./image/favicon.png type=image/x-icon> <link rel=stylesheet href=./css/style.css></head><body> <canvas id=canvas></canvas> < div class=bg-btn></div> <div class=color-group id=bgGroup> <h3>選擇背景顏色:</h3> <ul class=clearfix> <li class=bgcolor-item style=background-color: blue;></li> <li class=bgcolor-item style=background-color: black;></li> <li class=bgcolor-item style=background-color : #FF3333;></li> <li class=bgcolor-item style=background-color: #0066FF;></li> <li class=bgcolor-item style=background-color: #FFFF33;></li> <li class=bgcolor-item style=background-color: #33CC66;></li> <li class=bgcolor-item style=background -color: gray;></li> <li class=bgcolor-item style=background-color: #F34334;></li> <li class=bgcolor-item style=background-color: #fff;box-shadow: 0 1px 2px 0 rgba(32,33,36,0.28);></li> <li class=bgcolor-item style=background-color : #9B27AC;></li> <li class=bgcolor-item style=background-color: #4CB050;></li> <li class=bgcolor-item style=background-color: #029688;></li> </ul> <i class=closeBtn></i> </div> <div class =tools> <div class=container> <button class=save id=save <button class=brush active id=brush <button class=eraser id=eraser <button class=clear id=clear <button class=undo id=undo <button class=redo id=redo </div> </div> <div class=pen-detail id=penDetail> <i class= closeBtn></i> <p>筆大小</p> <span class=circle-box><i id=thickness></i></span> <input type=range id=range1 min=1 max=10 value=1> <p>筆顏色</p> <ul class=pen-color clearfix> <li class=color-item active style=background-color: black;></li> <li class=color-item style=background-color: #FF3333;></li> <li class=color-item style=background-color: #99CC00;></li> <li class=color-item style=background-color: #0066FF;></li> <li class=color-item style=background-color: #FFFF33 ;></li> <li class=color-item style=background-color: #33CC66;></li> </ul> <p>不透明度</p> <i class=showOpacity></i> <input type=range id=range2 min=1 max=10 value=1> </div> <script src=./js/main.js></script></body> </html>
(三)用CSS美化介面
css程式碼可以依照個人習慣來美化介面,所以這裡就不寫css的程式碼了,大家可以直接看專案程式碼或從開發者工具中審查元素觀看。如果有問題可以私聊我,我覺得問題不大。
(四)使用JS實現專案的具體功能
1.準備工作
首先,準備個容器,也就是畫板了,前面的html已經書寫好這個容器,這裡純屬是廢話。
<canvas id=canvas></canvas>
然後初始化js
let canvas = document.getElementById('canvas');let context = canvas.getContext('2d');我打算把畫板做成全螢幕的,所以接下來設定一下canvas的寬高
let pageWidth = document.documentElement.clientWidth;let pageHeight = document.documentElement.clientHeight;canvas.width = pageWidth;canvas.height = pageHeight;
由於部分IE不支援canvas ,如果要相容IE,我們可以建立一個canvas ,然後使用excanvas初始化,針對IE加上exCanvas.js,這裡我們明確地不考慮IE。
但是我在電腦上對瀏覽器的視窗進行改變,畫板不會自適應的放縮。解決辦法:
// 記得執行autoSetSize這個函數喔function autoSetSize(){ canvasSetSize(); // 當執行這個函數的時候,會先設定canvas的寬高function canvasSetSize(){ let pageWidth = document.documentElement.Widight. = document.documentElement.clientHeight; canvas.width = pageWidth; canvas.height = pageHeight; } // 在視窗大小改變之後,就會觸發resize事件,重新設定canvas的寬高window.onresize = function(){ canvasSetSize(); }}2.實現畫畫的功能
實現想法:監聽滑鼠事件, 用drawLine()方法把記錄的資料畫出來。
painting = false 。mousedown ),把painting設為true ,表示正在畫,滑鼠沒放開。把滑鼠點記錄下來。mousemove )就把點記錄下來並畫出來。 如果滑鼠移動太快,瀏覽器跟不上繪畫速度,點與點之間會出現間隙,所以我們需要將畫出的點用線連起來( lineTo() )。mouseup ),把painting設為false 。註: drawCircle這個方法其實可以不用書寫,這個只是為了讓大家能理解開始點擊的位置在哪裡?
function listenToUser() { // 定義一個變數初始化畫筆狀態let painting = false; // 記錄畫筆最後一次的位置let lastPoint = {x: undefined, y: undefined}; // 滑鼠按下事件canvas.onmousedown = function (e){ painting = true; let x = e.clientX; let y = e.clientY; lastPoint = {'x':x,'y':y}; drawCircle(x,y,5); } // 滑鼠移動事件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); lastPoint = newPoint; } } // 滑鼠放開事件canvas.onmouseup = function(){ painting = false; }}// 畫點函數function drawCircle(x,y,radius){ // 新建一條路徑,產生之後,圖形繪製指令被指向到路徑上產生路徑。 context.beginPath(); // 畫一個以(x,y)為圓心的以radius為半徑的圓弧(圓), // 從startAngle開始到endAngle結束,按照anticlockwise給定的方向(預設為順時針)來生成。 context.arc(x,y,radius,0,Math.PI*2); // 透過填滿路徑的內容區域產生實心的圖形context.fill(); // 閉合路徑之後圖形繪製指令又重新指向到上下文中。 context.closePath();}function drawLine(x1,y1,x2,y2){ // 設定線條寬度context.lineWidth = 10; // 設定線條末端樣式。 context.lineCap = round; // 設定線條與線條間接合處的樣式context.lineJoin = round; // moveTo(x,y)將筆觸移到指定的座標x以及y上context.moveTo(x1,y1 ); // lineTo(x, y) 繪製一條從目前位置到指定x以及y位置的直線context.lineTo(x2,y2); // 透過線條來繪製圖形輪廓context.stroke(); context.closePath();}3.實現橡皮擦功能
實現思路:
eraserEnabled = false 。click事件,點選橡皮擦,改變橡皮擦狀態, eraserEnabled = true ,並且切換class,實現被啟動的效果。eraserEnabled為true時,移動滑鼠以context.clearRect()實作了橡皮檫。但是我發現canvas的API中,可以清除像素的就是clearRect方法,但是clearRect方法的清除區域矩形,畢竟大部分人的習慣中的橡皮擦都是圓形的,所以就引入了剪輯區域這個強大的功能,也就是clip方法。下面的程式碼是使用context.clearRect()實作了橡皮檫。請看踩坑部分,了解如何更好的實現橡皮檫。
let eraser = document.getElementById(eraser);let eraserEnabled = false;// 記得要執行listenToUser這個函數喔function listenToUser() { // ... 代表省略了先前寫的程式碼// ... // 滑鼠按下事件canvas.onmousedown = function(e){ // ... if(eraserEnabled){//要使用eraser context.clearRect(x-5,y-5,10,10) }else{ lastPoint = {'x':x,'y':y} } } // 滑鼠移動事件canvas.onmousemove = function(e){ let x = e.clientX; let y = e.clientY; if(!painting){return} if(eraserEnabled){ context.clearRect(x-5,y-5,10,10); }else{ var newPoint = {'x':x,'y':y}; drawLine(lastPoint.x, lastPoint.y,newPoint.x , newPoint.y); lastPoint = newPoint; } } // ...}// 點選橡皮檫eraser.onclick = function(){ eraserEnabled = true; eraser.classList.add('active'); brush.classList.remove('active');}4.實現清屏功能
實現思路:
取得元素節點。
點擊清空按鈕清空canvas畫布。
let reSetCanvas = document.getElementById(clear);// 實作清屏reSetCanvas.onclick = function(){ ctx.clearRect(0,0,canvas.width,canvas.height); setvasvasBg('wCanite');}///重新設定canvas背景顏色function setCanvasBg(color) { ctx.fillStyle = color; ctx.fillRect(0, 0, canvas.width, canvas.height);}5.實現保存成圖片功能
實現思路:
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 = 'mypic'+(new Date).getTime(); saveA.target = '_blank'; saveA.click();}6.實現改變背景顏色的功能
實現思路:
let selectBg = document.querySelector('.bg-btn');let bgGroup = document.querySelector('.color-group');let bgcolorBtn = document.querySelectorAll('.bgcolor-item');let penDetail = document. getElementById(penDetail);let activeBgColor = '#fff';// 實作了切換背景顏色for (let i = 0; i < bgcolorBtn.length; i++) { bgcolorBtn[i].onclick = function (e) { // 阻止冒泡e.stopPropagation() ; for (let i = 0; i < bgcolorBtn.length; i++) { bgcolorBtn[i].classList.remove(active); this.classList.add(active); activeBgColor = this.style.backgroundColor; setCanvasBg(activeBgColor); } }}document.onclick = function(){ bgGroup.classList.remove('active');}selectB.onclick. (e){ bgGroup.classList.add('active'); e.stopPropagation();}7.實現改變畫筆粗細的功能
實現思路:
let range1 = document.getElementById('range1');let lWidth = 2;let ifPop = false;range1.onchange = function(){ console.log(range1.value); console.log(typeof range1.value) thickness. style.transform = 'scale('+ (parseInt(range1.value)) +')'; console.log(thickness.style.transform ) lWidth = parseInt(range1.value*2);}// 畫線函數function drawLine(x1,y1,x2,y2){ // ... context.lineWidth = lWidth; // ...}// 點選畫筆brush.onclick = function(){ eraserEnabled = false; brush.classList.add('active'); eraser.classList.remove('active'); if(!ifPop){ // 彈出框console.log('彈一彈') penDetail.classList.add('active '); }else{ penDetail.classList.remove('active'); } ifPop = !ifPop;}8.實現改變畫筆顏色的功能
實現想法跟改變畫板背景顏色的想法類似。
let aColorBtn = document.getElementsByClassName(color-item);getColor();function getColor(){ for (let i = 0; i < aColorBtn.length; i++) { aColorBtn[i].onclick = function (tn.length; i++) { aColorBtn[i].onclick = function (tn. let i = 0; i < aColorBtn.length; i++) { aColorBtn[i].classList.remove(active); this.classList.add(active); activeColor = this.style.backgroundColor; ctx.fillStyle = activeColor; ctx.strokeStyle = activeColor; } } }}9.實現改變撤銷和重做的功能
實現思路:
canvasHistory陣列(產生快照使用canvas 的toDataURL()方法,產生的是base64 的圖片);canvasHistory陣列中對應索引的快照使用canvas 的drawImage()方法重繪一次; let undo = document.getElementById(undo);let redo = document.getElementById(redo);// ...canvas.onmouseup = function(){ painting = false; canvasDraw();}let canvasHistory = [];let step = -1;// 繪製方法function canvasDraw(){ step++; if(step < canvasHistory.length){ canvasHistory.length = step; // 截斷數組} // 新增新的繪製到歷史記錄canvasHistory.push(canvas.toDataURL());}// 撤銷方法function canvasUndo(){ if(step > 0){ step--; // ctx.clearRect(0,0,canvas.width,canvas.height); let canvasPic = new Image(); canvasPic.src = canvasHistory[step]; canvasPic.onload = function () { ctx.drawImage(canvasPic. 0); } undo.classList.add('active'); }else{ undo.classList.remove('active'); alert('不能再繼續撤銷了'); }}// 重做方法function canvasRedo(){ if(step < canvasHistory.length - 1){ step++; let canvasPic = new Image(); canvasPic.src = canvasHistory[step]; canvasPic.onload = function () { // ctx.clearRect(0,0,canvas.width,canvas.height); ctx.drawImage(canvasPic, 0, 0); } redo.classList.add('active'); }else { redo .classList.remove('active') alert('已經是最新的記錄了'); }}undo.onclick = function(){ canvasUndo();}redo.onclick = function(){ canvasRedo();}10.相容於行動端
實現思路:
true ,則使用touch事件; false ,則使用mouse事件 // ...if (document.body.ontouchstart !== undefined) { // 使用touch事件anvas.ontouchstart = function (e) { // 開始觸碰} canvas.ontouchmove = function (e) { // 開始滑動} canvas.ontouchend = function () { // 滑動結束}}else{ // 使用mouse事件// ...}// ...四、踩坑問題1:在電腦上對瀏覽器的視窗進行改變,畫板不會自適應解決辦法:
在onresize回應事件處理中,所取得的頁面尺寸參數是變更後的參數。
當視窗大小改變之後,重新設定canvas的寬高,簡單來說,就是視窗改變之後,給canvas.width和canvas.height重新賦值。
// 記得執行autoSetSize這個函數喔function autoSetSize(){ canvasSetSize(); // 當執行這個函數的時候,會先設定canvas的寬高function canvasSetSize(){ let pageWidth = document.documentElement.Widight. = document.documentElement.clientHeight; canvas.width = pageWidth; canvas.height = pageHeight; } // 在視窗大小改變之後,就會觸發resize事件,重新設定canvas的寬高window.onresize = function(){ canvasSetSize(); }}問題2:當繪製線寬度比較小的時候還好,一旦比較粗就會出現問題解決方法:看一下文檔,得出方法,只需要簡單修改一下繪製線條的程式碼就行
// 畫線函數function drawLine(x1,y1,x2,y2){ context.beginPath(); context.lineWidth = lWidth; //-----加入----- // 設定線條末端樣式。 context.lineCap = round; // 設定線條與線條間接合處的樣式context.lineJoin = round; //-----加入----- context.moveTo(x1,y1); context.lineTo( x2,y2); context.stroke(); context.closePath();}問題3:如何實現圓形的橡皮檫?解決辦法:
在canvas的API中,可以清除像素的就是clearRect方法,但是clearRect方法的清除區域矩形,畢竟大部分人的習慣中的橡皮擦都是圓形的,所以就引入了剪輯區域這個強大的功能,也就是clip方法。用法很簡單:
ctx.save()ctx.beginPath()ctx.arc(x2,y2,a,0,2*Math.PI);ctx.clip()ctx.clearRect(0,0,canvas.width,canvas.height) ;ctx.restore();
上面那段程式碼就實現了圓形區域的擦除,也就是先實作一個圓形路徑,然後把這個路徑當作剪輯區域,再清除像素就行了。有個注意點就是需要先保存繪圖環境,清除完像素後要重置繪圖環境,如果不重置的話以後的繪圖都是會被限制在那個剪輯區域中。
問題4:如何相容於行動端?1.添加meta標籤
因為瀏覽器初始會將頁面現在手機端顯示時進行縮放,因此我們可以在meta標籤中設定meta viewport屬性,告訴瀏覽器不將頁面進行縮放,頁面寬度=用戶設備螢幕寬度
<meta name=viewport content=width=device-width,initial-scale=1,user-scalable=no,maximum-scale=1.0,minimum-scale=1.0/>/*頁寬度=移動寬度:w idth=device-width使用者無法縮放:user-scalable=no縮放比例:initial-scale=1最大縮放比例:maximum-scale=1.0最小縮放比例:minimum-scale=1.0*/
2.在行動端幾乎使用的都是touch事件,與PC端不同
由於行動端是觸控事件,所以要用到H5的屬性touchstart/touchmove/touchend,但是PC端只支援滑鼠事件,所以要進行特性檢測。
在touch事件裡,是透過.touches[0].clientX和.touches[0].clientY來取得座標的,這點要和mouse事件區分開。
這個嘛,問題不大,只不過是我漏寫context.beginPath(); ,也花了一點時間在上面解決bug,讓我想起代碼千萬行,註釋第一行;編程不規範,同事兩行淚,還是依照文檔操作規範操作好,真香! ! !
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。