iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0

大家好,我是Karin。
因為鐵人賽挑戰也快告一段落了,所以想藉由實作一個簡單的東西來當作是這系列的一個小成果。
還不確定能不能成功完成,總之就先來試試看。


安排

首先我請chatGPT幫我把要做的事情分成三天份,並引導我一步步開始練習。

第一天:準備工作與圖片切割
目標:理解如何將圖片切割並動態顯示在頁面上。

這一天的重點是確保你熟悉如何動態生成HTML元素並操作CSS樣式,成功實現圖片切割和隨機打亂圖片塊的功能。

  • 選擇圖片並設置HTML結構:
    選擇一張你想要用來拼圖的圖片。
    在HTML中準備一個容器(如)來存放圖片拼圖的碎片。
  • 將圖片切割成方塊:
    使用CSS將圖片分成多個方塊(例如3x3的9塊)。
    可以透過JavaScript動態生成這些方塊並加到puzzle-container中。記得每個方塊都應有獨立的div元素,並使用CSS背景圖片來顯示圖片的一部分。
  • 隨機打亂圖片塊的位置:
    將生成的方塊隨機排序,你可以用JavaScript將圖片的方塊順序隨機打亂。
    這可以簡單地用一個陣列來存儲所有圖片塊的位置信息,然後使用Array.sort()配合隨機數進行打亂。
  • 測試與調整:
    確認圖片方塊已經正確切割並隨機排列在頁面上。如果需要,可以調整CSS樣式來美化圖片塊的排列。

實作

首先先把檔案開好。
https://ithelp.ithome.com.tw/upload/images/20240927/20168967PUDmF3Xe34.png
接著要讓讓使用者上傳圖片後,切割圖片,製作成拼圖,之後隨機打亂拼圖塊。

HTML

<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>圖片拼圖遊戲</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <input type="file" id="imageUpload" accept="image/*">
  <div id="puzzle-container"></div>
  <script src="script.js"></script>
</body>
</html>

創建一個名為 puzzle-container 的 div區塊,用來放置拼圖。
input:添加文件上傳的功能,並限制上傳的文件類型只能是圖片(accept="image/*")。

CSS

#puzzle-container {
    display: grid;
    gap: 2px;
    max-width: 80vw; /* 設定容器最大寬度為視窗寬度的80% */
    max-height: 80vh; /* 設定容器為視窗高度的80% */
    aspect-ratio: 1 / 1; /* 保持容器為正方形 */
    margin: 0 auto; /* 讓容器在頁面中央 */
  }
  
  .puzzle-tile {
    background-size: cover;
    background-repeat: no-repeat;
    cursor: pointer;
    border: 1px solid #ccc;
  }
  

CSS Grid:是一種CSS佈局系統,用來設計網頁中的2D格狀佈局。它可以把網頁內容分割成行(rows)和列(columns),並且可以精確控制每個元素的排列方式和大小。

Javascript

document.addEventListener('DOMContentLoaded', function() { // 等待 DOM 內容加載完成後才執行內部的程式碼
  const imageUpload = document.getElementById('imageUpload'); // 取得上傳圖片的 input 元素
  const puzzleContainer = document.getElementById('puzzle-container'); // 取得拼圖容器的 div 元素

  imageUpload.addEventListener('change', function(event) { // 監測 input 元素的 change 事件,當使用者上傳圖片時觸發
    const file = event.target.files[0]; // 取得上傳的圖片檔案
    if (file) { // 確認是否有上傳圖片
      const reader = new FileReader(); // 建立 FileReader 物件來讀取上傳的檔案

      reader.onload = function(e) { // 當 FileReader 成功讀取檔案後,觸發 onload 事件
        const img = new Image(); // 建立一個新的 Image 物件,用來保存上傳的圖片
        img.src = e.target.result; // 設定 Image 物件的 src 為讀取到的圖片資料(Data URL)

        img.onload = function() { // 當圖片成功載入後,執行以下程式碼
          const rows = 3; // 固定拼圖的行數為3
          const cols = 3; // 固定拼圖的列數為3
          const containerWidth = puzzleContainer.clientWidth; // 取得拼圖容器的寬度
          const containerHeight = puzzleContainer.clientHeight; // 取得拼圖容器的高度

          // 根據容器大小計算每塊拼圖的寬度(容器寬度除以列數)
          const tileWidth = containerWidth / cols;
          const tileHeight = containerHeight / rows; // 根據容器大小計算每塊拼圖的高度(容器高度除以行數)

          puzzleContainer.innerHTML = ''; // 清除之前的拼圖內容,準備生成新的拼圖

          // 設置拼圖容器的 CSS 樣式,使其使用 grid 佈局,行數和列數均為 3
          puzzleContainer.style.gridTemplateColumns = `repeat(${cols}, 1fr)`; // 設置每列的寬度分配為 1fr,根據列數分佈
          puzzleContainer.style.gridTemplateRows = `repeat(${rows}, 1fr)`; // 設置每行的高度分配為 1fr,根據行數分佈

          const positions = []; // 建立一個陣列來儲存每塊拼圖的背景圖片位置

          for (let i = 0; i < rows * cols; i++) { 
            positions.push({ // 根據拼圖塊的位置計算其對應的背景位置,儲存到陣列中
              backgroundPosition: `${-(i % cols) * tileWidth}px ${-Math.floor(i / cols) * tileHeight}px`
            });
          }

          positions.sort(() => Math.random() - 0.5); // 隨機打亂陣列中的背景圖片位置,讓拼圖呈現隨機順序

          // 根據打亂後的背景位置生成拼圖塊
          for (let i = 0; i < rows * cols; i++) { // 為每塊拼圖生成對應的 div
            const tile = document.createElement('div'); // 建立一個新的 div 元素,代表一塊拼圖
            tile.classList.add('puzzle-tile'); // 為拼圖塊添加 CSS 類別,方便樣式控制
            tile.style.width = `${tileWidth}px`; // 設置拼圖塊的寬度
            tile.style.height = `${tileHeight}px`; // 設置拼圖塊的高度
            tile.style.backgroundImage = `url(${img.src})`; // 設定拼圖塊的背景圖片為上傳的圖片
            tile.style.backgroundSize = `${containerWidth}px ${containerHeight}px`; // 設置背景圖片大小與拼圖容器匹配
            tile.style.backgroundPosition = positions[i].backgroundPosition; // 設定每塊拼圖的背景位置為打亂後的順序

            puzzleContainer.appendChild(tile); // 將拼圖塊添加到拼圖容器中
          }
        };
      };

      reader.readAsDataURL(file); // 使用 FileReader 讀取圖片檔案,並將其轉換成 Data URL 格式
    }
  });
});

整理一下我丟給它的指令:
1.開始實作圖片拼圖遊戲

  • 要求:剛學習完基礎的JavaScript,想要一步步開始實作圖片拼圖遊戲。
  • 方法:創建專案環境,包括設置 index.htmlstyle.cssscript.js 檔案,並讓你動態生成3x3的圖片拼圖。圖片被切割成9塊後,排列在一個網格中。

2.讓使用者可以上傳圖片

  • 要求:希望使用者能隨機上傳圖片,圖片的寬高不限。
  • 方法:添加了一個圖片上傳的 input 元素,並使用 JavaScript 來處理圖片上傳,動態切割圖片成3x3的拼圖塊。這段過程中,圖片大小會根據容器的寬高進行調整,以適應視窗大小。

3.讓拼圖適應螢幕視窗大小

  • 要求:希望拼圖範圍限制在螢幕的可視範圍內。
  • 方法:調整了 puzzle-container 的CSS樣式,將容器的大小限制為視窗寬度的80%,並使用 aspect-ratio 保持圖片拼圖的比例不變。同時,在JavaScript中根據容器的寬高動態調整拼圖塊的大小,確保拼圖適應螢幕範圍。

4.隨機打亂拼圖塊

  • 要求:希望能打亂圖片拼圖塊的順序。
  • 方法:使用JavaScript中的 Array.sort() 來隨機打亂圖片塊的順序,並將打亂後的圖片塊重新排列在網格中,保持遊戲的隨機性。

5.修改拼圖塊的排列方式

  • 要求:希望打亂圖片塊順序時,保持圖片的形狀,只是順序打亂。
  • 方法:修改了代碼,確保每個圖片塊保持在它原本的格子位置上,但顯示的圖片部分隨機打亂。這樣圖片塊仍保持在3x3的網格中,只是每個圖片塊顯示的圖片部分會隨機變換。

6.不需要選擇行列數,固定為3x3拼圖

  • 要求:希望不需要讓使用者選擇行列數,保持拼圖為3x3格式即可。
  • 方法:簡化了代碼,移除了行列數的選擇功能,並將拼圖固定為3x3的網格格式。這樣每次上傳圖片時,系統都會自動生成3x3的拼圖塊,並隨機打亂順序。

今日結果

https://ithelp.ithome.com.tw/upload/images/20240927/20168967r5dv256bOx.png

突然看到了一大堆沒看過的func.,要再整理消化一下......還有一些想優化的地方明天繼續(˘・_・˘)


上一篇
Day 26 Git & GitHub 版本控制的方法
下一篇
Day 28 實作練習-拼圖小遊戲-2
系列文
每天都進步一點!從零開始的JavaScript 與基礎網路知識學習30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言