---
# System prepended metadata

title: 可觸控畫板Canvas
tags: [jquery, SASS, HTML & CSS, JavaScript]

---


# 可觸控畫板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() ;
}
```


---

##### ヽ(∀ﾟ )人(ﾟ∀)人( ﾟ∀)人(∀ﾟ )人(ﾟ∀)人( ﾟ∀)ﾉヽ(∀ﾟ )人(ﾟ∀ﾟ)人( ﾟ∀)人(∀ﾟ )人(ﾟ∀ﾟ)人( ﾟ∀)人(∀ﾟ )人( ﾟ∀)人

##### 以上 如果註解哪裡有錯誤或有問題，歡迎提出來一起討論~~~~