daodaoronron.hatenablog.com/

view source

JavaScript

/*
ろんろんブログをよろしくだおだお★
https://daodaoronron.hatenablog.com/
*/

//埋め込み先 <div id="demo"></div>
const demo = document.getElementById("demo");

// ✅ Canvasを生成&埋め込み
const canvas = document.createElement("canvas");
canvas.width = demo.clientWidth;
canvas.height = demo.clientHeight;
demo.appendChild(canvas);
const ctx = canvas.getContext("2d");

//
const imgPaths = [
  "dao1.png",
  "dao2.png",
  "dao3.png",
  "dao4.png",
  "dao5.png",
  "dao6.png",
];

const particles = [];

function loadImage(src) {
  return new Promise((res) => {
    const img = new Image();
    img.onload = () => res(img);
    img.src = src;
  });
}

// createParticle に index を渡して遅延演出に
function createParticle(img, index = 0) {
  const imgSplit = imgPaths.length/8; // 最大サイズ調整
  const maxSize = Math.min(canvas.width, canvas.height) / imgSplit;
  const scale = Math.min(maxSize / img.width, maxSize / img.height, 1);
  const w = img.width * scale;
  const h = img.height * scale;

  const particle = {
    img,
    x: Math.random() * canvas.width,
    y: Math.random() * canvas.height,
    vx: 0,
    vy: 0,
    radius: Math.max(w, h) / 2,
    alpha: 0,
    w,
    h,
    startTime: Date.now() + index * 2000, // ← msずつずらして登場
    targetAlpha: 1
  };
  particles.push(particle);
}

function updateParticles() {
  const now = Date.now();
  for (let i = 0; i < particles.length; i++) {
    const p1 = particles[i];

    if (now >= p1.startTime) {
      // フェードイン開始
      p1.alpha += (p1.targetAlpha - p1.alpha) * 0.05;
    }
    // やわらかい衝突回避
    for (let j = i + 1; j < particles.length; j++) {
      const p2 = particles[j];
      const dx = p2.x - p1.x;
      const dy = p2.y - p1.y;
      const dist = Math.sqrt(dx * dx + dy * dy);
      const minDist = p1.radius + p2.radius ;
      const minDistFix = minDist * 0.4 ;//重なり具合

      if (dist < minDistFix && dist > 0.1) {
        const overlap = (minDist - dist) / 2;
        const nx = dx / dist;
        const ny = dy / dist;

        p1.x -= nx * overlap;
        p1.y -= ny * overlap;
        p2.x += nx * overlap;
        p2.y += ny * overlap;
      }
    }

    // ゆるく壁の中に留める
    p1.x = Math.max(p1.radius, Math.min(canvas.width - p1.radius, p1.x));
    p1.y = Math.max(p1.radius, Math.min(canvas.height - p1.radius, p1.y));
  }
}

function drawParticles() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for (const p of particles) {
    ctx.save();
    ctx.globalAlpha = p.alpha;
    ctx.drawImage(p.img, p.x - p.w / 2, p.y - p.h / 2, p.w, p.h);
    ctx.restore();
  }
}

function animate() {
  updateParticles();
  drawParticles();
  requestAnimationFrame(animate);
}


(async function () {
  const loadedImgs = [];
  for (let path of imgPaths) {
    const img = await loadImage(path);
    loadedImgs.push(img);
  }

  // 一括で particle 作成、ただし登場は時間差
  loadedImgs.forEach((img, i) => {
    createParticle(img, i); // ← indexでスタートタイミング管理
  });

  animate();
})();

CSS

HTML

ページのソースを表示 : Ctrl+U , DevTools : F12

view-source:https://hi0a.com/demo/-js/js-img-pop/

ABOUT

hi0a.com 「ひまあそび」は無料で遊べるミニゲームや便利ツールを公開しています。

プログラミング言語の動作デモやWEBデザイン、ソースコード、フロントエンド等の開発者のための技術を公開しています。

必要な機能の関数をコピペ利用したり勉強に活用できます。

プログラムの動作サンプル結果は画面上部に出力表示されています。

環境:最新のブラウザ GoogleChrome / Windows / Android / iPhone 等の端末で動作確認しています。

画像素材や音素材は半分自作でフリー素材配布サイトも利用しています。LINK参照。

仕様変更、API廃止等、実験途中で動かないページもあります。