iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 29
0
Modern Web

重新學習網頁設計系列 第 29

DAY 29. JavaScript Canvas 處理

DAY 29. JavaScript Canvas 處理

canvas有關的處理,時常在最後我們需要預覽、上傳、下載影像
這個單元就來說說這些動作該如何實現。

預覽

當我們有input允許使用者上傳檔案時,可以設定該inputaccept影像檔案。
確保使用者使用這個input只能上傳影像,就能確保這個檔案可以用於canvas
JSbin Demo
HTML

<div class="container">
  <input type="file" name="images" accept="image/*" multiple>
</div>

JavaScript

// 取得input
const input = document.querySelector('input')

// 當使用者修改內容(選擇檔案)
input.addEventListener('change', function(event){
  const files = this.files  // 取得所有 file
  const container = this.parentNode // 設定一個preview容器
  
  // 處理每一個檔案
  Array.prototype.forEach.call(files, file => {
    filePreview(file, container)
  })
})

// 這個將會把file的預覽圖加入指定container
function filePreview(file, container) {
    const url = URL.createObjectURL(file)   // 建立檔案url
    const image = new Image
    image.style.width = '150px'
    image.style.height = 'auto'
    image.alt = file.name
    image.addEventListener('load', function(event) {
        container.appendChild(this)
    })
    image.src = url
}

下載

下載很簡單,首先將canvas轉成一個ObjectURL接著定於連結即可
JSbin Demo

// 這裡首先建立並繪製一個canvas
// 這個 canvas 可以是任何你想指定的canvas
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = 150
canvas.height = 150
ctx.strokeStyle = 'rgba(255, 0, 0, .5)'
ctx.arc(75, 75, 50, 0, Math.PI*2, false)
ctx.lineWidth = '5'
ctx.stroke()
document.body.appendChild(canvas)

// 使用canvas的toBlob方法將其轉為blob
const blob = canvas.toBlob(blob => {
    // 有了blob我們就可以使三 URL.createObjectURL建立url
    const url = URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.innerText = 'Download'
    link.href = url // 將url 設定給 a tage 的 href
    link.download = 'circle.png'    // 設定 download name
    document.body.appendChild(link) // 加到指定元素之中,即可點擊下載
})

上傳

比起預覽、下載,上傳動作相對複雜,但也不算太困難

這裡的上傳是指,將一個canvas轉為檔案,之後使用Ajax(fetch)將該檔送至後端

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Canvas Demo</title>
</head>

<body>
    <script>
        // 建立一個範例用圖
        const canvas = document.createElement('canvas')
        const ctx = canvas.getContext('2d')
        canvas.width = 150
        canvas.height = 150
        ctx.strokeStyle = 'rgba(255, 0, 0, .5)'
        ctx.arc(75, 75, 50, 0, Math.PI * 2, false)
        ctx.lineWidth = '5'
        ctx.stroke()

        // 建立 file
        const dataURL = canvas.toDataURL('image/png')
        const blobBin = atob(dataURL.split(',')[1])
        const array = []
        for (let i = 0; i < blobBin.length; i++) {
            array.push(blobBin.charCodeAt(i))
        }
        const file = new Blob([new Uint8Array(array)], { type: 'image/png' })

        // 將file 加至 formData
        const formData = new FormData()
        formData.append('file', file, 'test.png')

        // send ajax request 
        fetch('/upload.php', {
            method: 'POST',
            body: formData
        }).then(res => res.text())
            .then(resText => console.log(resText))
    </script>
</body>

</html>
// upload.php
<?php
if (isset($_FILES["file"])) {
    $file = $_FILES["file"];
    $name = $file["name"];
    $tmp_name = $file['tmp_name'];
    $error = $file['error'];
    move_uploaded_file($tmp_name, './' . $name);
    echo 'file uploaded';
} else {
    echo 'no file upload.';
}

而這個範例直接展示了如何將瀏覽器中的canvas轉為file上傳到伺服器
而不用透過使用者下載然後點選input在上傳檔案。

由於最後個範例牽扯到一點點的php code,所以不方便上Demo
有興趣測試的朋友請複製程式到local測試
將html部分直接取名為index.php 或 index.html
php部分取名為upload.php,執行index.html後便會在跟專案得到一張圖片

不是直接執行index.html
而示開一個local php server執行


上一篇
DAY 28. JavaScript Canvas 動畫
下一篇
DAY 30. JavaScript Blob, Buffer
系列文
重新學習網頁設計30

尚未有邦友留言

立即登入留言