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

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

style.css

1/* style.css */
2@charset "utf-8";
3 
4*{
5    margin: 0;
6    padding: 0;
7}
8 
9body{
10    display: grid;                  /* CSSグリッドを適用 */
11    grid-template-columns: 100vw;   /* ビューポート幅最大 */
12    grid-template-rows: 100vh;      /* ビューポート高さ最大 */
13}
14 
15main{
16    justify-self: center;   /* 横方向中央揃え */
17    align-self: center;     /* 縦方向中央揃え */
18}

main.js

1// main.js
2 
3let canvas = null;      // キャンバス
4let g = null;           // コンテキスト
5let image;              // 読み込む画像
6let blocks = [];        // 画像ブロック表示位置
7let cells = [];         // 画像切り出し位置
8let currentNo = 0;      // 現在のブロック番号(表示用)
9let timeLine = [];      // 位置交換するセルの順番
10 
11const $id = (id) => { return document.getElementById(id); };    // DOM取得用
12const IMG_FILE = "majo024.jpg";
13const IMG_SIZE = 600;   // 画像サイズ
14const BLK_SIZE = 100;   // 1ブロックのサイズ
15const BUNKATU = IMG_SIZE / BLK_SIZE;
16 
17// 表示処理
18function mainLoop(){
19    const [x, y] = [ timeLine[currentNo][0], timeLine[currentNo][1] ];
20    swapBlock(x, y);
21    drawBlock(x);
22    drawBlock(y);
23 
24    currentNo++;
25    if(currentNo >= timeLine.length){
26        currentNo = 0;
27        g.fillStyle = "rgba(200, 200, 200, 128)";
28        g.fillText("©スタジオジブリ 魔女の宅急便", 440, 580);
29        setTimeline();
30        setTimeout(mainLoop, 10000);    // 完成後10秒間待つ
31    }
32    else{
33        setTimeout(mainLoop, 100);
34    }
35}
36 
37// 全体を描画
38function drawAll(){
39    for(let block of blocks){
40        g.drawImage(image, block.dx, block.dy, BLK_SIZE, BLK_SIZE,
41            block.dx, block.dy, BLK_SIZE, BLK_SIZE);
42    }
43}
44 
45// 位置交換
46function swapBlock(x, y){
47    [ blocks[x].value, blocks[y].value ] = [ blocks[y].value, blocks[x].value ];
48}
49 
50// ブロックを描画
51function drawBlock(n){
52    const x = blocks[n].value;
53    g.drawImage(image, cells[x].sx, cells[x].sy, BLK_SIZE, BLK_SIZE,
54        blocks[n].dx, blocks[n].dy, BLK_SIZE, BLK_SIZE);
55}
56 
57// タイムライン生成
58function setTimeline(){
59    timeLine = [];
60    let half = [];
61    // 前半部分
62    for(let i=0; i<50; i++){
63        const r1 = Math.floor(Math.random()*BUNKATU*BUNKATU);
64        const r2 = Math.floor(Math.random()*BUNKATU*BUNKATU);
65        half.push( [r1, r2] );
66        timeLine.push( [r1, r2] );
67    }
68    // 後半部分
69    while(true){
70        const obj = half.pop();
71        if(obj === undefined) break;
72        const [x, y] = [obj[0], obj[1]];
73        timeLine.push([y, x]);
74    }
75}
76 
77/*
78 * 起動時の処理
79 */
80window.addEventListener("load", function(){
81    // キャンバス情報取得
82    canvas = $id("canvas");
83    g = canvas.getContext("2d");
84 
85    // 画像情報取得
86    image = new Image();
87    image.src = IMG_FILE;
88 
89    image.addEventListener("load", ()=>{
90        console.log("image loaded.");
91        // 画像を分割する
92        let i = 0;
93        for(let y=0; y<BUNKATU; y++){
94            for(let x=0; x<BUNKATU; x++){
95                const block = { value: i, dx: x*BLK_SIZE, dy: y*BLK_SIZE };
96                blocks.push(block);
97 
98                const cell = { sx: x*BLK_SIZE, sy: y*BLK_SIZE };
99                cells.push(cell);
100                i++;
101            }
102        }
103 
104        setTimeline();
105        drawAll();
106        mainLoop();
107 
108    });
109 
110});

参考

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

今月から、スタジオジブリ作品の場面写真の提供を開始します - スタジオジブリ|STUDIO GHIBLI
今月から、スタジオジブリ作品の場面写真の提供を開始します。 今月からスタジオジブリ全作品の場面写真を順次提供することになりました。今月は、新しい作品を中心に 8作品、合計400枚提供します。 常識の範囲でご自由にお使いください。 思い出のマ...

コメント

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