---
# System prepended metadata

title: html-刮刮樂
tags: [html, js, css]

---

# html網頁

連結: [GitHub](https://github.com/yunnnzeng/scratch-off)、[GitHub Pages](https://yunnnzeng.github.io/scratch-off/)

來由
---
過年期間收到LINE很多訊息廣告，有很多刮刮樂小遊戲，想說自己是否可以也做一個，於是就來嘗試。因為太久沒寫網頁，有點不知道怎麼下手，所以問了chatgpt，一來一回完成了簡單的小遊戲。


## 程式碼
### 使用語法
* HTML、CSS、JS

### HTML
```
<div id="scratch-card">
    <canvas id="scratch-canvas" width="300" height="200"></canvas>
</div>
```
### CSS
```
#scratch-card {
    position: relative;
    width: 300px;
    height: 200px;
    background: no-repeat center center;
    background-size: cover;
}
#scratch-canvas {
    position: absolute;
    top: 0;
    left: 0;
}
```
### JS
* 底圖部分，可自行設定機率看要顯示哪張底圖
```
const scratchCard = document.getElementById('scratch-card');
let imgSrc;

// 生成 0 到 1 之間的隨機數
const randomNumber = Math.random();

// 根據機率選擇底圖
if (randomNumber < 0.1) {
    imgSrc = './images/background-o.jpg'; // 底圖一
} else {
    imgSrc = './images/background-x.jpg'; // 底圖二
}

scratchCard.style.backgroundImage = `url('${imgSrc}')`;


const canvas = document.getElementById('scratch-canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.src = './images/scratch-off.jpg'; // The scratch-off image
img.onload = function() {
    const scale = Math.max(canvas.width / img.width, canvas.height / img.height); // 計算縮放比例
    const newWidth = img.width * scale;
    const newHeight = img.height * scale;
    ctx.drawImage(img, 0, 0, newWidth, newHeight); 
};

```
* 刮刮樂部分，有設定當使用者刮到甚麼程度會全部自動清空
```
let isDrawing = false;
let pixelsFilled = 0; // 記錄刮開得像素數量
const threshold = 0.6; // 整張清空的比例


function scratchOff(e) {
    if (!isDrawing) return;
    const rect = canvas.getBoundingClientRect();
    let x, y;
    if (e.touches) { // 觸摸事件
        x = e.touches[0].clientX - rect.left;
        y = e.touches[0].clientY - rect.top;
    } else { // 滑鼠事件
        x = e.clientX - rect.left;
        y = e.clientY - rect.top;
    }
    ctx.globalCompositeOperation = 'destination-out';
    ctx.beginPath();
    ctx.arc(x, y, 20, 0, Math.PI * 2);
    ctx.fill();
    
    // 更新刮開的像素
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imageData.data;
    pixelsFilled = 0;
    for (let i = 0; i < data.length; i += 4) {
        if (data[i + 3] === 0) {
            pixelsFilled++;
        }
    }
    
    // 判斷是否達到清空設定值
    if (pixelsFilled / (canvas.width * canvas.height) >= threshold) {
        clearCanvas();
    }
}

function startDrawing(e) {
    isDrawing = true;
    scratchOff(e);
}

function stopDrawing() {
    isDrawing = false;
}

function clearCanvas() {
    ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空塗層
    pixelsFilled = 0; 
}

canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', scratchOff);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);

canvas.addEventListener('touchstart', function(e) {
    e.preventDefault();
    startDrawing(e.touches[0]);
});
canvas.addEventListener('touchmove', scratchOff);
canvas.addEventListener('touchend', stopDrawing);
canvas.addEventListener('touchcancel', stopDrawing);
```

完整程式碼: [GitHub](https://github.com/yunnnzeng/scratch-off)

後續
---
1. 頁面目前很陽春，應該可以增加一些裝飾，可嘗試仿照過年刮刮樂
3. 後續如果連接資料庫，加上python運算，可以設計更多種中獎種類


###### tags: `html` `css` `js`
