0%

Canvas 繪圖 基本操作

1
<canvas id="cvs" width="800" height="600" style="border: 1px solid #000000;"></canvas>

基本用法

綁定 canvas

1
2
3
4
5
const cvs=document.querySelector('#cvs')
// 宣告 Canvas Content Object
getContext() 2d webgl
// 2D 畫面 3D 畫面
const ctx= cvs.getContext('2d')

Fill 填滿

1
2
3
4
5
6
// 填滿顏色
ctx.fillStyle="red"
// 透明度 1 為不透明 0 為完全透明
ctx.globalAlpha=0.5
// fillRect(X,Y,weight,height)
ctx.fillRect(50,50,100,100)

Stroke 描邊

1
2
3
4
// 描邊顏色
ctx.strokeStyle='blue'
// strokeRect(X,Y,weight,height)
ctx.strokeRect(100,100,100,100)

Path 路徑

1
2
3
4
5
6
7
8
9
10
// 開啟路徑
ctx.beginPath()
// 移動到當前所在位置 moveTo(X,Y)
ctx.moveTo(300,300)
// 與設定座標畫一直線 lineTo(X,Y)
ctx.lineTo(400,500)
// 關閉路徑
ctx.closePath()
// 選擇顯現方式 stoke() fill()
ctx.stroke()

繪製多邊形

1
2
3
4
5
6
ctx.beginPath()
ctx.moveTo(300,300)
ctx.lineTo(100,500)
ctx.lineTo(500,500)
ctx.closePath()
ctx.fill()

影像處理、濾鏡

影像處理

1
2
3
4
5
6
let img=new Image() 
img.src='../head.png'
img.onload=function () { // 註冊 load 事件,圖片載入完成後,入完成後,才做繪製
// drawImage(img,X,Y,width,height)
ctx.drawImage(img,0,0,cvs.width,cvs.height)
}

濾鏡

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Html
<button onclick="invertColor()">影像反轉</button>
<canvas id="cvs" width="800" height="600" style="border: 1px solid #000000;"></canvas>
// JavaScript
function invertColor(){
let pixels=ctx.getImageData(0,0,cvs.width,cvs.height)
//一個像素佔據 4 個資料 (bytes) 。 r,g,b,a(範圍 0 ~ 255)
let pixelsData=pixels.data
for (let i = 0; i < pixelsData.length; i+=4) {
pixelsData[i]=255-pixelsData[i]
pixelsData[i+1]=255-pixelsData[i+1]
pixelsData[i+2]=255-pixelsData[i+2]

}
ctx.putImageData(pixels,0,0)
}

檔案輸入、輸出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Html

<input type="file" onchange="loadFile(this)">
<button onclick="saveFile()">儲存檔案</button>
<a href="" id="download"></a>
<canvas id="cvs" width="800" height="600" style="border: 1px solid #000000;"></canvas>

// JavaScript

function loadFile(input){
// 抓取 input files
let files=input.files[0]
// 把 files 轉成網址
let url=URL.createObjectURL(files)
let img=new Image()
img.src=url
img.onload=function () {
ctx.drawImage(img,0,0,cvs.width,cvs.height)
}
}

function saveFile() {
const link=document.querySelector('#download')
// a 連結下載格式
link.download='image.jpg'
// canvas 輸出格式
link.href=cvs.toDataURL('image/jpeg')
link.click()
}

畫線

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
let painting=false
// 按下滑鼠代表開始畫畫
cvs.addEventListener('mousedown',startPosition)
// 放下滑鼠代表完成畫畫
cvs.addEventListener('mouseup',finishedPosition)
// 滑鼠移動代表正在畫畫
cvs.addEventListener('mousemove',draw)


function startPosition() {
painting=true
}
function finishedPosition(e) {
painting=false
ctx.beginPath()
}
function draw(e) {
// 如果正在畫畫就 return
if(!painting)return
if(stroke && !eraser){
ctx.lineWidth=size
ctx.strokeStyle=color
ctx.lineCap='round'
ctx.lineTo(e.clientX,e.clientY)
ctx.stroke()
ctx.beginPath()
ctx.moveTo(e.clientX,e.clientY)
}else if(!stroke && eraser){
ctx.lineWidth=size
ctx.strokeStyle='#E8E8E8'
ctx.lineCap='round'
ctx.lineTo(e.clientX,e.clientY)
ctx.stroke()
ctx.beginPath()
ctx.moveTo(e.clientX,e.clientY)
}
}

Undo、Redo

創建一個物件,每次畫完就擷取圖片存在物件裡,物件[步驟]讀取畫面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
let restore_array=[]
let step=-1


function finishedPosition(e) {
painting=false
ctx.beginPath()
console.log(e.type)
if(e.type!='mousedown'){
restore_array.push(ctx.getImageData(0,0,cvs.width,cvs.height))
step++
}
if(restore_array.length>0){
console.log(1)
domUndo.classList.add('btn-active')
}else{
domUndo.classList.remove('btn-active')
}
}

function undo(e) {
e.preventDefault()
if(step<=0){
allClear()
domUndo.classList.remove('btn-active')
}else{
console.log(restore_array)
domUndo.classList.add('btn-active')
step--
ctx.putImageData(restore_array[step],0,0)
}
if(step<restore_array.length&&step>=0){
domRedo.classList.add('btn-active')
}else{
domRedo.classList.remove('btn-active')
}
}
function redo(e) {
e.preventDefault()
console.log(step)
if(step==restore_array.length||step<0){
return
}else if(step<restore_array.length){
step++
ctx.putImageData(restore_array[step],0,0)
}
}