HTML5 -- Canvas

weixin_34337265發表於2016-12-14

利用 HTML5 中的 Canvas,我們可以做很多很棒的事情,下面來看看我做的一個 Demo

2849764-db2b89fdef62be1b.png
mydemo.png

下面就針對這個例子介紹一下 Canvas 的基礎使用。


HTML & CSS

當然 Canvas 的繪製需要藉助 JavaScript, 首先讓我們利用 HTMLCSS 將結構層和表現層搭建好,然後我們才可以大展身手。

你可以利用自己高超的 CSS 水平將頁面寫的十分炫酷,當然我只是簡單的利用 CSS 對頁面進行了佈局,沒有寫其它用來表現的特性。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" type="text/css" href="demo05.css">
    </head>
    <body>
        <article>
            <canvas width="680" height="320" id="myCanvas"></canvas>
            <form>
                <section>
                    <label for="backgroundColor">Select background :</label>
                    <select id="backgroundColor">
                        <option value="white" selected>White</option>
                        <option value="black">Black</option>
                    </select>
                </section>
                <section>
                    <label for="foregroundColor">Select ForegroundColor:</label>
                    <select id="foregroundColor">
                        <option value="white">White</option>
                        <option value="black" selected>Black</option>
                    </select>
                </section>
                <section>
                    <label for="shape">Select shape:</label>
                    <select id="shape">
                        <option value="circles" selected>Circles</option>
                        <option value="squares">Squares</option>
                    </select>
                </section>
                <section>
                    <label for="message">Input text:</label>
                    <input type="text" name="message" id="message" maxlength="48">
                </section>
                <input type="button" value="preview" id="previewButton">
            </form>
        </article>
        <script src="demo05.js"></script>
    </body>
</html>

其實大部分內容都是關於書寫表單控制元件的,這些程式碼千篇一律,十分好懂,不過唯一值得注意的是,我在輸入控制元件中加入了 maxlength, 對輸入的長度進行了控制,如果輸入的字串太多,繪製文字的時候會出現文字溢位。

上述程式碼中最珍貴的一行是定義 canvas 元素的那一行,將畫布定義為 680px 寬,320px 高。

下面利用 CSS 對頁面進行稍微的修改。

*,
*::before,
*::after {
    -moz-box-sizing: border-box;
         box-sizing: border-box;
    margin: 0;
    padding: 0;
}

article {
    width: 680px;
    height: 320px;
    margin: 32px auto;

    text-align: center;
}

canvas {
    border: 1px solid #ccc;
}

form section {
    margin-bottom: 16px;
}

這裡,為畫布設定了一個邊框,是為了更清楚的看到畫布的位置。


Canvas 繪圖

為了繪製圖形,我們首先要得到畫布元素,並要求得到它的 2d 繪製上下文。像下面這樣。

var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");

有了這個 context, 我們就可以肆意的畫圖了,首先,讓我們來畫個矩形吧,需要哪些條件呢?事實上,我們只需要指定 x,y 座標(矩形左上角的座標)並且設定寬高就可以畫出這個圖形。

function drawSquare(canvas, context) {
    var width = Math.floor(Math.random() * 64);

    var x = Math.floor(Math.random() * canvas.width);
    var y = Math.floor(Math.random() * canvas.height);

    context.fillStyle = "lightblue";
    context.fillRect(x, y, width, width);
}

上面我們使用了隨機值,這樣我們就可以繪製出不同寬高分佈在不同位置的矩形了。利用上面的程式碼,我們就可以看到下面這樣的結果啦。

2849764-2aa77e7b97c4c024.png
square.png

可以看到,有的矩形已經超出邊界了,為什麼呢?自己好好想想總會相處答案的吧!

既然已經知道怎麼繪製矩形了,那麼該怎麼繪製圓形呢?我已經迫不及待的去畫個圓了,因為我感覺圓比矩形好看,這也就是為什麼我們在很多 app 中看到的是圓形頭像。

不過,事情進展的不是很順利,因為我們已經沒有類似 fillCircle() 這樣的函式可用了。所以我們不得不動筆去畫一個,實際上利用 Canvas 你可以畫出可以用筆畫出的任何效果。在現實生活中,如果你想畫畫,那麼你需要拿起一支筆,但是在畫布上,你只需要呼叫 contextbeginPath() 方法就可以了,這相當於告訴畫布:我要開始畫些東西了,你準備好吧!

如果你想在指定的一個點開始你的筆跡,那麼你可以使用 moveTo(x, y) 方法,如果你想從畫筆的當前位置畫線,可以使用 lineTo(x, y)方法。

好了,下面就讓我們開始畫圓吧!實際上,還有一個 arc() 方法,可以讓我們去畫圓,不過在這之前,我們需要呼叫 beginPath() 方法。

function drawCircle(canvas, context) {
    var radius = Math.floor(Math.random() * 48);

    var x = Math.floor(Math.random() * canvas.width);
    var y = Math.floor(Math.random() * canvas.height);

    context.beginPath();
    context.arc(x, y, radius, 0, Math.PI * 2, true);
    context.fillStyle = "lightblue";
    context.fill();
}

值得一提的是,arc() 方法中第四和第五個引數使用的都是弧度值,不過我們一般喜歡使用角度,比如 360 度,而不是 2 PI,所以我們可以寫一個轉換函式,然後你就可以盡情的使用熟悉的角度值了。

function degreesToRadians(degrees) {
    return (degrees * Math.PI) / 180;
}

下面,你就可以畫出下面這樣的效果。

2849764-43af4481a4334bcc.png
circle.png

圖形已經繪製完畢了,我們就去看看如何繪製文字,首先我們的獲取輸入控制元件中輸入的文字,然後我們需要使用 contextmeasureText() 測量文字的寬度,因為我們想讓文字居中。

function drawText(canvas, context) {
    var selectObj = document.getElementById("foregroundColor");
    var index = selectObj.selectedIndex;
    var fgColor = selectObj[index].value;
    var fontSize = "24";

    context.fillStyle = fgColor;
    context.font = "bold " + fontSize + "px sans-serif";
    context.textAlign = "left";

    var message = document.getElementById("message").value;
    var messageWidth = context.measureText(message).width;
    var x = Math.floor(canvas.width / 2 - messageWidth / 2);
    var y = Math.floor(canvas.height / 2 - fontSize / 2);
    context.fillText(message, x, y);
}

可以使用 context.font 設定文字相關的資訊,第一個引數是 font style, 可以設定為 bold 或者 italic,第二個引數是文字的大小,第三個引數是 font family,這裡我指定為 sans-serif

你可能還有疑問的是,context.textAlign 是什麼玩意?這個就是設定 fillText() 中 x 座標指定的是文字哪個部位的座標,如果你設定為 center,那麼這個 x 就是文字中間的 x 座標。當然我們這裡設定為 left 就是文字最左邊的 x 座標。

那麼問題來了,我們為什麼還要使用 measureText() 這麼費勁的測試文字的寬度使文字居中呢?的確如此,我們可以使用 textAlign 輕易的實現文字居中,下面是對上述函式的改寫。

function drawText(canvas, context) {
    var selectObj = document.getElementById("foregroundColor");
    var index = selectObj.selectedIndex;
    var fgColor = selectObj[index].value;
    var fontSize = "24";

    context.fillStyle = fgColor;
    context.font = "bold " + fontSize + "px sans-serif";
    context.textAlign = "center"; // change

    var x = Math.floor(canvas.width / 2); // change
    var y = Math.floor(canvas.height / 2 - fontSize / 2);

    var message = document.getElementById("message").value;
    context.fillText(message, x, y);
}

文字也繪製完畢了,下面就繪製圖形右下角的笑臉圖片,當然這是個圖片,不是一筆一筆畫出來的。

function drawImage(canvas, context) {
    var smileImage = new Image();
    smileImage.src = "smile.png";

    smileImage.onload = function() {
        context.drawImage(smileImage, 632, 272, 24, 24);
    }
}

drawImage() 的第二個引數是圖形的左上角的 x 座標,第三個引數是左上角的 y 座標,第四個引數是圖形的寬度,第五個引數是圖形的高度。

這裡為什麼還是用一個 onload 呢?因為圖片總是需要載入的,如果圖片還沒有載入完畢,就開始去繪製圖片,肯定會繪製失敗,所以我們利用一個回撥,當圖片載入完畢,再去繪製圖片。

最後再來介紹一個目前瀏覽器支援不是很好的屬性,我們可以將這個 Canvas 轉化為一個圖片,怎麼樣?聽上去是不是很心動,其實寫起來很容易。

function makeImage() {
    var canvas = document.getElementById("myCanvas");
    canvas.onclick = function() {
        window.location = canvas.toDataURL("image/png");
    }
}

這個時候,如果你的瀏覽器支援的話,只要你點選一些畫布,那麼就會有一個圖片版本彈出來,供你儲存到本地。

我在我的電腦上做了測試,只有 Firefox 支援這個功能,我喜歡的 Google Chrome, Opera, Yandex 在這方面的支援還不盡如人意。


如果你想要專案的原始碼,你可以到 我的 Github 下載原始碼。

Ending...

相關文章