# 可觸控畫板Canvas
### **撰寫程式:HTML | CSS(SASS) | JS(jQuery ∕ 原生JS)**
###### codepen:https://codepen.io/liu_0821/pen/RwMGWoo

## 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() ;
}
```
---
##### ヽ(∀゚ )人(゚∀)人( ゚∀)人(∀゚ )人(゚∀)人( ゚∀)ノヽ(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人( ゚∀)人
##### 以上 如果註解哪裡有錯誤或有問題,歡迎提出來一起討論~~~~