使用Canvas和JavaScript作一個畫板

本文同步於我的博客:https://zhoushuo.me/blog/2018/03/11/drawing-borad/git

前些天學習了HTML5<canvas>元素,今天就來實踐一下,用canvas作一個畫板。github

alt

首先說一下要實現的功能:canvas

  • 切換畫筆顏色
  • 調整筆刷粗細
  • 清空畫布
  • 橡皮擦擦除
  • 撤銷操做
  • 保存成圖片
  • 兼容移動端(支持觸摸)

好了,廢話少說,先看最終效果:https://zhoushuozh.github.io/drawingborad數組

準備工做

首先,準備個容器,也就是畫板了。瀏覽器

<canvas id="drawing-board"></canvas>

而後初始化js:app

let canvas = document.getElementById("drawing-board");
let ctx = 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。性能

實現一個簡單的畫板

實現思路:監聽鼠標事件,用drawCircle()方法把記錄的數據畫出來。學習

  1. 設置初始化當前畫布功能爲畫筆狀態,painting = false
  2. 當鼠標按下時(mousedown),把painting設爲true,表示正在畫,鼠標沒鬆開。把鼠標點記錄下來。
  3. 當按下鼠標的時候,鼠標移動(mousemove)就把點記錄下來並畫出來。
  4. 若是鼠標移動過快,瀏覽器跟不上繪畫速度,點與點之間會產品間隙,因此咱們須要將畫出的點用線連起來(lineTo())。
  5. 鼠標鬆開的時候(mouseup),把painting設爲false

代碼:優化

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,clear);
        lastPoint = newPoint;
    }
};

//鼠標鬆開事件
canvas.onmouseup = function () {
    painting = false;
}

// 畫點函數
function drawCircle(x, y, radius) {
    ctx.save();
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, Math.PI * 2);
    ctx.fill();
}

// 劃線函數
function drawLine(x1, y1, x2, y2) {
    ctx.lineWidth = 3;
    ctx.lineCap = "round";
    ctx.lineJoin = "round";
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.stroke();
    ctx.closePath();
}

橡皮擦功能

實現思路

  1. 獲取橡皮擦元素
  2. 設置橡皮擦初始狀態,clear = false
  3. 監聽橡皮擦click事件,點擊橡皮擦,改變橡皮擦狀態,clear = true
  4. cleartrue時,移動鼠標使用canvas剪裁(clip())擦除畫布。
let eraser = document.getElementById("eraser");
let clear = false;

eraser.onclick = function () {
    clear = true;
};

...
if (clear) {
    ctx.save();
    ctx.globalCompositeOperation = "destination-out";
    ctx.stroke();
    ctx.closePath();
    ctx.clip();
    ctx.clearRect(0,0,canvas.width,canvas.height);
    ctx.restore();
}
...

注意,在canvas中的裁剪和平時的裁剪功能不同在這裏,裁剪是指在裁剪區域去顯示咱們所畫的圖

兼容移動端

實現思路:

  1. 判斷設備是否支持觸摸
  2. true,則使用touch事件;false,則使用mouse事件

代碼:

...
if (document.body.ontouchstart !== undefined) {
    // 使用touch事件
    anvas.ontouchstart = function (e) {
        // 開始觸摸
    }
    canvas.ontouchmove = function (e) {
        // 開始滑動
    }
    canvas.ontouchend = function () {
        // 滑動結束
    }
}else{
    // 使用mouse事件
    ...
}
...

這裏須要注意的一點是,在touch事件裏,是經過.touches[0].clientX.touches[0].clientY來獲取座標的,這點要和mouse事件區別開。

切換畫筆顏色

實現思路:

  1. 獲取顏色元素節點。
  2. 點擊顏色返回其顏色值,並賦給畫布的ctx.strokeStyle

代碼:

let aColorBtn = document.getElementsByClassName("color-item");

for (let i = 0; i < aColorBtn.length; i++) {
    aColorBtn[i].onclick = function () {
    for (let i = 0; i < aColorBtn.length; i++) {
        activeColor = this.style.backgroundColor;
        ctx.strokeStyle = activeColor;
    }
}

清空畫布

實現思路:

  1. 獲取元素節點。
  2. 點擊清空按鈕清空canvas畫布。

代碼:

let reSetCanvas = document.getElementById("clear");

reSetCanvas.onclick = function () {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
};

調整筆刷粗細

實現思路:

  1. 建立input[type=range]
  2. 滑動range獲取其value值,並賦給ctx.lineWidth

代碼:

let range = document.getElementById("range");

range.onchange = function(){
    lWidth = this.value;
};

保存成圖片

實現思路:

  1. 獲取canvas.toDateURL
  2. 在頁面裏建立並插入一個a標籤
  3. a標籤href等於canvas.toDateURL,並添加download屬性
  4. 點擊保存按鈕,a標籤觸發click事件

代碼:

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 = "zspic" + (new Date).getTime();
    saveA.target = "_blank";
    saveA.click();
};

撤銷

實現思路:

  1. 準備一個數組記錄歷史操做
  2. 每次使用畫筆前將當前繪圖表面儲存進數組
  3. 點擊撤銷時,恢復到上一步的繪圖表面

代碼:

canvas.ontouchstart = function (e) {
     // 在這裏儲存繪圖表面
    this.firstDot = ctx.getImageData(0, 0, canvas.width, canvas.height);
    saveData(this.firstDot);
    ...
}

let undo = document.getElementById("undo");
let historyDeta = [];

function saveData (data) {
    (historyDeta.length === 10) && (historyDeta.shift()); // 上限爲儲存10步,太多了怕掛掉
    historyDeta.push(data);
}
undo.onclick = function(){
    if(historyDeta.length < 1) return false;
    ctx.putImageData(historyDeta[historyDeta.length - 1], 0, 0);
    historyDeta.pop()
};

由於每次儲存都是將一張圖片存入內存,對性能影響較大,因此在這裏設置了儲存上限。

總結

這裏用的知識點主要有:監聽mousetouch事件,以及canvasmoveTo()lineTo()stroke()clip()clearRect()等方法。其實還有不少效果能夠實現,好比說噴霧效果,蠟筆效果,藝術畫效果等等。往後有時間我會繼續對這個畫板進行優化,增長一些新的功能,同時歡迎你們留言提問或者提出批評建議。

最終代碼:https://github.com/zhoushuozh/drawingborad

相關文章
相關標籤/搜索