# 可觸控畫板Canvas ### **撰寫程式:HTML | CSS(SASS) | JS(jQuery ∕ 原生JS)** ###### codepen:https://codepen.io/liu_0821/pen/RwMGWoo ![](https://i.imgur.com/wCkiU5W.jpg) ## HTML > ###### 主要分成兩個部分,canvas就是畫板呈現的區域,上方則是功能按鈕。 ``` <article> <div class="paint-container"> <div class="paint-wrap"> <div class="paint-button"> <!--按鈕--> <div class="paint-button-container"> <button class="button brush1" id="brush1" onclick="brush1()"> <i class="fas fa-pencil-alt"></i> </button> </div> <div class="paint-button-container"> <button class="button brush2" id="brush2" onclick="brush2()"> <i class="fas"></i> </button> </div> <div class="paint-button-container"> <button class="button brush3" id="brush3" onclick="brush3()" > <i class="fas fa-paint-brush"></i> </button> </div> <div class="paint-button-container"> <button class="color" > <input type="color" name="color" id = "color"> </button> </div> <div class="paint-button-container"> <button class="button erase" id="eraser" onclick="checkeraser()" > <i class="fas fa-eraser"></i> </button> </div> <div class="paint-button-container"> <button class="button delete" id="clear" onclick="clear()"> <i class="fas fa-trash-alt"></i> </button> </div> <div class="paint-button-container"> <button class="button save" id="save" onclick="save()"> <i class="fas fa-save"></i> </button> </div> <div class="paint-button-container-size"> <input class="brush-size" type="number" id = "number" placeholder="10" min ="1" max ="50" > </div> </div> </div> </div> <div class = "paint-canvas"> <canvas class="canvas" id="canvas" > 畫畫白色區域 <span>瀏覽器不支持畫布,請換瀏覽器使用或升級瀏覽器</span> </canvas> </div> </article> ``` ## CSS(SASS) > ###### 與原生CSS不同之處,原生CSS使用大括弧{}套用CSS特性,SASS則利用縮排區分HTML之間的層級關係。 ``` @import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css") * //border: 2px solid black /*----顏色----*/ $colorbgc :#D25565 $colorpink :#fad3cf $colorred :#ea7070 $colorR :#e59572 /*---Css變數---*/ @mixin flexCenter display: flex flex-wrap: wrap justify-content: center align-items: center @mixin flexArrangement display: flex flex-direction: row justify-content: center html,body margin: 0 padding: 0 background-color: $colorbgc article width: 100% height: 100% +flexCenter .paint-container width: 90% margin-top: 5px margin-bottom: 5px .paint-wrap background-color: $colorbgc border-radius: 12px .paint-button +flexArrangement margin-top: 1px margin-bottom: 1px .paint-button-container margin-left: 5px overflow: hidden .button background-color: $colorpink border:0px border-radius: 25px width: 40px height: 40px overflow: hidden cursor: pointer .fas color: #fff width: 40px height: 40px font-size: 20px margin-left: -6px margin-top: 8px .color background-color: $colorpink border-radius: 25px width: 40px height: 40px overflow: hidden border: 0 input border: 0 background-color: $colorpink width: 40px height: 40px border-radius: 25px margin-left: -6px margin-top: -1px /*-調整顏色區塊-*/ &::-webkit-color-swatch border:none border-radius: 50% padding: 0 .paint-button-container-size margin-left: 5px overflow: hidden .brush-size border: 0 width: 50px height: 35px margin-top: 2px border-radius: 25% font-size: 14px text-align: center /*----------畫布-----------*/ .paint-canvas width: 90% height: auto overflow: hidden border-radius: 25px 25px 25px 25px background-color: #fff margin-bottom: 15px .canvas background-color: rgb(255, 255, 255) border-radius: 0 0 45px 45px ``` ## JS > ###### 控制螢幕對畫面的影響 ``` //關閉原本瀏覽器的兩指縮放、拖拉捲動操作的干擾 document.body.addEventListener('touchmove',function(e){e.preventDefault(); },false); //隨著螢幕大小更動畫布大小 canvas.width = (document.body.clientWidth); canvas.height = (window.innerHeight); ``` >###### 基本設定 ``` var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var imgs =[]; var lastpoint; var back = false; var drawing = false; var density = 50; var eraserbtn = false; var X1 = undefined; // 後續要放座標 var Y1 = undefined; var X2 = undefined; var Y2 = undefined; ``` > ###### 滑鼠的控制(三種筆刷) ``` function brush1() { canvas.onmousedown=function(e){ drawing = true ; X1 = e.offsetX; Y1 = e.offsetY; ctx.strokeStyle = color.value; ctx.lineCap ='round'; ctx.lineJoin ='round'; ctx.lineWidth =size.value; } canvas.onmousemove=function(e) { if(!drawing){ return; } // 取得終點座標 X2 = e.offsetX; Y2 = e.offsetY; // 開始繪圖 ctx.beginPath(); ctx.moveTo(X1, Y1); ctx.lineTo(X2, Y2); ctx.stroke(); // 更新起始點座標 X1 = X2; Y1 = Y2; } canvas.onmouseup=function(e) { ctx.closePath(); drawing = false; } var ccc= $("#canvas").offset() canvas.ontouchstart=function(e){ e.preventDefault(); drawing = true ; X1 = e.touches[0].pageX-ccc.left; Y1 = e.touches[0].pageY-ccc.top; ctx.strokeStyle = color.value; ctx.lineCap ='round'; ctx.lineJoin ='round'; ctx.lineWidth =size.value; } canvas.ontouchmove=function(e){ e.preventDefault(); if(!drawing){ return; } drawing = true ; // 取得終點座標 X2 = e.touches[0].pageX-ccc.left; Y2 = e.touches[0].pageY-ccc.top; // 開始繪圖 ctx.beginPath(); ctx.moveTo(X1, Y1); ctx.lineTo(X2, Y2); ctx.stroke(); // 更新起始點座標 X1 = X2; Y1 = Y2; } canvas.ontouchend=function(e) { ctx.closePath(); drawing = false; } }; function brush2() //噴槍滑鼠操控 { document.body.addEventListener('touchmove',function(e){e.preventDefault(); },false); var ccc= $("#canvas").offset() function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } canvas.onmousedown=function(e){ drawing = true ; X1 = e.offsetX; Y1 = e.offsetY; ctx.lineCap ='round'; ctx.lineJoin ='round'; ctx.lineWidth =size.value; ctx.beginPath(); ctx.moveTo(X1, Y1); } canvas.onmousemove=function(e) { if (drawing) { X2 = e.offsetX; Y2 = e.offsetY; for (var i = density; i--; ) { var radius =size.value; var xx = getRandomInt(-radius, radius); var yy = getRandomInt(-radius, radius); ctx.fillRect(xx+X2,yy+Y2, 1, 1); ctx.fillStyle = ctx.strokeStyle; } } } canvas.onmouseup=function(e) { ctx.closePath(); drawing = false; } //觸控 canvas.ontouchstart=function(e){ drawing = true ; X1 = e.touches[0].pageX-ccc.left; Y1 = e.touches[0].pageY-ccc.top; ctx.strokeStyle = color.value; ctx.lineCap ='round'; ctx.lineJoin ='round'; ctx.lineWidth =size.value; ctx.beginPath(); ctx.moveTo(X1, Y1); } canvas.ontouchmove=function(e){ if (drawing) { X2 = e.touches[0].pageX-ccc.left; Y2 = e.touches[0].pageY-ccc.top; for (var i = density; i--; ) { var radius =size.value; var xx = getRandomInt(-radius, radius); var yy = getRandomInt(-radius, radius); ctx.fillRect(xx+X2,yy+Y2, 1, 1); ctx.fillStyle = ctx.strokeStyle; } } } canvas.ontouchend=function(e) { console.log('1') ctx.closePath(); drawing = false; } }; function brush3() { document.body.addEventListener('touchmove',function(e){e.preventDefault(); },false); var ccc= $("#canvas").offset() if(drawing!=false){ canvas.removeEventListener('click',drawing) } //獲取 0 ~ num的隨機數(閉區間) function randomNum(num) { return Math.floor(Math.random()*(num+1)); }; //獲取範圍隨機數 (閉區間) function randomRange(start,end) { return Math.floor(Math.random()*(end-start+1))+start; }; var ColorBall = function(){} ColorBall.prototype.left = 0; //X軸 ColorBall.prototype.top = 0; //y軸 ColorBall.prototype.r = 10; //半徑 //RainbowBrush 球噴槍 RainbowBrush = function(){} //生產小球陣列的方法 RainbowBrush.prototype.getBalls = function(num) { var colorBalls = []; for(var i = 0; i < num; i++) { var ball = new ColorBall(); colorBalls.push(ball); } return colorBalls; } //噴刷球 RainbowBrush.prototype.brush = function(ctx,balls,x,y) { balls.forEach(function(ballIem){ ballIem.x = randomRange(x - 8,x + 8); ballIem.y = randomRange(y - 8,y + 8); ballIem.r = size.value; ctx.beginPath(); ctx.fillStyle=ctx.strokeStyle; ctx.arc(ballIem.x,ballIem.y,ballIem.r,0,Math.PI*2); ctx.fill(); }) } var rainbowBrush = new RainbowBrush(); var balls = rainbowBrush.getBalls(1); //當滑鼠按下 canvas.onmousedown=function(e){ drawing = true ; canvas.onmousemove=function(e) { X2 = e.offsetX; Y2 = e.offsetY; if (drawing) rainbowBrush.brush(ctx,balls,X2,Y2); } canvas.onmouseup=function(e) { ctx.closePath(); drawing = false; } } //觸控 canvas.ontouchstart=function(e){ drawing = true ; ctx.strokeStyle = color.value; canvas.ontouchmove=function(e){ X2 = e.touches[0].pageX-ccc.left; Y2 = e.touches[0].pageY-ccc.top; if (drawing) rainbowBrush.brush(ctx,balls,X2,Y2); } } canvas.ontouchend=function(e) { ctx.closePath(); drawing = false; } }; function checkeraser () { canvas.onmousedown=function(e){ drawing = true ; X1 = e.offsetX; Y1 = e.offsetY; ctx.strokeStyle ='white' ctx.lineCap ='round'; ctx.lineJoin ='round'; ctx.lineWidth =size.value; } canvas.onmousemove=function(e) { if(!drawing){ return; } // 取得終點座標 X2 = e.offsetX; Y2 = e.offsetY; // 開始繪圖 ctx.beginPath(); ctx.moveTo(X1, Y1); ctx.lineTo(X2, Y2); ctx.stroke(); // 更新起始點座標 X1 = X2; Y1 = Y2; } canvas.onmouseup=function(e) { ctx.closePath(); drawing = false; } var ccc= $("#canvas").offset() var ccc= $("#canvas").offset() canvas.ontouchstart=function(e){ e.preventDefault(); drawing = true ; X1 = e.touches[0].pageX-ccc.left; Y1 = e.touches[0].pageY-ccc.top; ctx.strokeStyle ='white' ctx.lineCap ='round'; ctx.lineJoin ='round'; ctx.lineWidth =size.value; } canvas.ontouchmove=function(e){ e.preventDefault(); if(!drawing){ return; } drawing = true ; // 取得終點座標 X2 = e.touches[0].pageX-ccc.left; Y2 = e.touches[0].pageY-ccc.top; // 開始繪圖 ctx.beginPath(); ctx.moveTo(X1, Y1); ctx.lineTo(X2, Y2); ctx.stroke(); // 更新起始點座標 X1 = X2; Y1 = Y2; } canvas.ontouchend=function(e) { ctx.closePath(); drawing = false; } }; ``` > ###### 其他功能 ``` //改變顏色 var color= document.getElementById('color'); ctx.strokeStyle = color.value; color.addEventListener ('input', function(){ ctx.strokeStyle = color.value; }) //改筆畫大小 var size = document.getElementById('number'); size.onchange = function() { ctx.lineWidth = size.value; } //畫板清空 clear.onclick = function() { ctx.clearRect(0,0,canvas.width,canvas.height); } ``` > ###### 儲存到本地端 ``` function save(){ var url = canvas.toDataURL("image/jpg"); var a=document.createElement('a'); document.body.appendChild(a); a.href=url; a.download='mydraw'; a.target='_blank'; a.click() ; } ``` --- ##### ヽ(∀゚ )人(゚∀)人( ゚∀)人(∀゚ )人(゚∀)人( ゚∀)ノヽ(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人( ゚∀)人 ##### 以上 如果註解哪裡有錯誤或有問題,歡迎提出來一起討論~~~~