JavaScript:1枚の画像をブロック単位に分割してランダムに置き換え10秒で元に戻る

スポンサーリンク
JavaScript

画像は、600×600ピクセルの正方形画像を使用した。
1ブロックのサイズは100×100ピクセル。合計36個のブロックをランダムで置き換えて表示している。

ブロックの置き換えは100回行う。
ただランダムに置き換えてしまうと元の画像に戻らなくなるので、前半50回の置き換え順序を後半50回では、下から順にして元に戻るようにしている。

イメージ

  1回目 1番 2番 を置き換え
  2回目 5番 6番 を置き換え
  3回目 9番 3番 を置き換え
      :
 98回目 9番 3番 を置き換え
 99回目 5番 6番 を置き換え
100回目 1番 2番 を置き換え

ソースコード

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <script src="main.js"></script>
    <title>画像がブロック単位で置き換わり元に戻る</title>
</head>
<body>
    <main>
        <canvas id="canvas" width="600" height="600"></canvas>
    </main>
</body>
</html>

style.css

/* style.css */
@charset "utf-8";

*{
    margin: 0;
    padding: 0;
}

body{
    display: grid;                  /* CSSグリッドを適用 */
    grid-template-columns: 100vw;   /* ビューポート幅最大 */
    grid-template-rows: 100vh;      /* ビューポート高さ最大 */
}

main{
    justify-self: center;   /* 横方向中央揃え */
    align-self: center;     /* 縦方向中央揃え */
}

main.js

// main.js

let canvas = null;      // キャンバス
let g = null;           // コンテキスト
let image;              // 読み込む画像
let blocks = [];        // 画像ブロック表示位置
let cells = [];         // 画像切り出し位置
let currentNo = 0;      // 現在のブロック番号(表示用)
let timeLine = [];      // 位置交換するセルの順番

const $id = (id) => { return document.getElementById(id); };    // DOM取得用
const IMG_FILE = "majo024.jpg";
const IMG_SIZE = 600;   // 画像サイズ
const BLK_SIZE = 100;   // 1ブロックのサイズ
const BUNKATU = IMG_SIZE / BLK_SIZE;

// 表示処理
function mainLoop(){
    const [x, y] = [ timeLine[currentNo][0], timeLine[currentNo][1] ];
    swapBlock(x, y);
    drawBlock(x);
    drawBlock(y);

    currentNo++;
    if(currentNo >= timeLine.length){
        currentNo = 0;
        g.fillStyle = "rgba(200, 200, 200, 128)";
        g.fillText("©スタジオジブリ 魔女の宅急便", 440, 580);
        setTimeline();
        setTimeout(mainLoop, 10000);    // 完成後10秒間待つ
    }
    else{
        setTimeout(mainLoop, 100);
    }
}

// 全体を描画
function drawAll(){
    for(let block of blocks){
        g.drawImage(image, block.dx, block.dy, BLK_SIZE, BLK_SIZE,
            block.dx, block.dy, BLK_SIZE, BLK_SIZE);
    }
}

// 位置交換
function swapBlock(x, y){
    [ blocks[x].value, blocks[y].value ] = [ blocks[y].value, blocks[x].value ];
}

// ブロックを描画
function drawBlock(n){
    const x = blocks[n].value;
    g.drawImage(image, cells[x].sx, cells[x].sy, BLK_SIZE, BLK_SIZE,
        blocks[n].dx, blocks[n].dy, BLK_SIZE, BLK_SIZE);
}

// タイムライン生成
function setTimeline(){
    timeLine = [];
    let half = [];
    // 前半部分
    for(let i=0; i<50; i++){
        const r1 = Math.floor(Math.random()*BUNKATU*BUNKATU);
        const r2 = Math.floor(Math.random()*BUNKATU*BUNKATU);
        half.push( [r1, r2] );
        timeLine.push( [r1, r2] );
    }
    // 後半部分
    while(true){
        const obj = half.pop();
        if(obj === undefined) break;
        const [x, y] = [obj[0], obj[1]];
        timeLine.push([y, x]);
    }
}

/*
 * 起動時の処理
 */
window.addEventListener("load", function(){
    // キャンバス情報取得
    canvas = $id("canvas");
    g = canvas.getContext("2d");

    // 画像情報取得
    image = new Image();
    image.src = IMG_FILE;

    image.addEventListener("load", ()=>{
        console.log("image loaded.");
        // 画像を分割する
        let i = 0;
        for(let y=0; y<BUNKATU; y++){
            for(let x=0; x<BUNKATU; x++){
                const block = { value: i, dx: x*BLK_SIZE, dy: y*BLK_SIZE };
                blocks.push(block);

                const cell = { sx: x*BLK_SIZE, sy: y*BLK_SIZE };
                cells.push(cell);
                i++;
            }
        }

        setTimeline();
        drawAll();
        mainLoop();

    });

});

参考

使った魔女の宅急便の画像は、スタジオジブリが常識の範囲内での利用に限り提供してくれているもの。

今月から、スタジオジブリ作品の場面写真の提供を開始します - スタジオジブリ|STUDIO GHIBLI
今月から、スタジオジブリ作品の場面写真の提供を開始します。 今月からスタジオジブリ全作品の場面写真を順次提供することになりました。今月は、新しい作品を中心に 8作品、合計400枚提供します。 常識の範囲でご自由にお使いください。 思い出のマーニー50枚 かぐや姫の物語50枚 風立ちぬ50枚 コクリ
スポンサーリンク

コメント

タイトルとURLをコピーしました