<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="style.css">
  <script src="image.js"></script>
  <title>Document</title>
</head>

<body>
  <button class="triangle-btn">triangle</button>
  <button class="sector-btn">sector</button>
  <button class="pacman-btn">pacman</button>
  <div class="scanimation">
    <div class="image-wrapper"></div>
    <div class="film-container">
      <div class="film-wrapper">
        <div class="film"></div>
      </div>
    </div>
  </div>
</body>
<script src="script.js"></script>

</html>
body {
  min-height: 3000px;
  background-color: gray;
}

.scanimation {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 700px;
  position: relative;
}

.image-wrapper {
  background-color: rgb(255, 131, 131);
  
  border-radius: 10px;
}

.image-row {
  width: 100%;
  display: flex;
}

.image-block {
  display: flex;
}

.film-container {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  overflow: auto;
}

.film-wrapper {
  width: 300vw;
  height: 100%;
  overflow: hidden;
  display: flex;
  justify-content: center;
}

.film {
  width: 100dvw;
  height: 100%;
  display: flex;
}

.bar {
  background-color: black;
  height: 100%;
}
function createTriangle(size, angle) {
  // 角度をラジアンに変換
  const radians = (angle * Math.PI) / 180;

  // タンジェントを計算(0度と90度の場合は特別に処理)
  const tan = angle === 0 ? 0 : (angle === 90 ? Infinity : Math.tan(radians));

  // 2次元配列を初期化
  const triangle = Array(size).fill().map(() => Array(size).fill(0));

  for (let y = 0; y < size; y++) {
    const width = Math.min(Math.round(y / tan), size);
    for (let x = 0; x < width; x++) {
      triangle[y][x] = 1;
    }
  }

  return triangle;
}

function createSector(size, angle, startAngle = 0) {
  // 角度をラジアンに変換
  const startRad = (startAngle * Math.PI) / 180;
  const endRad = ((startAngle + angle) * Math.PI) / 180;

  // 2次元配列を初期化
  const sector = Array(size).fill().map(() => Array(size).fill(0));

  const center = Math.floor(size / 2);
  const radius = center;

  for (let y = 0; y < size; y++) {
    for (let x = 0; x < size; x++) {
      // 中心からの相対座標を計算
      const dx = x - center;
      const dy = center - y;  // y軸は上下反転

      // 点と中心の距離を計算
      const distance = Math.sqrt(dx * dx + dy * dy);

      if (distance <= radius) {
        // 点の角度を計算(アークタンジェントを使用)
        let angle = Math.atan2(dy, dx);
        if (angle < 0) angle += 2 * Math.PI;  // 角度を0~2πの範囲に調整

        // 点が扇形の範囲内にあるかチェック
        if (angle >= startRad && angle <= endRad) {
          sector[y][x] = 1;
        }
      }
    }
  }

  return sector;
}


const numberOfBlock = 50

// 三角
const triangle = [
  createTriangle(numberOfBlock, 10),
  createTriangle(numberOfBlock, 20),
  createTriangle(numberOfBlock, 30),
  createTriangle(numberOfBlock, 40),
  createTriangle(numberOfBlock, 50),
  createTriangle(numberOfBlock, 60),
  createTriangle(numberOfBlock, 70),
  createTriangle(numberOfBlock, 80),
  createTriangle(numberOfBlock, 90),
]

// 円
const sector = [
  createSector(numberOfBlock, 30),
  createSector(numberOfBlock, 60),
  createSector(numberOfBlock, 90),
  createSector(numberOfBlock, 120),
  createSector(numberOfBlock, 150),
  createSector(numberOfBlock, 180),
  createSector(numberOfBlock, 210),
  createSector(numberOfBlock, 240),
  createSector(numberOfBlock, 270),
  createSector(numberOfBlock, 300),
  createSector(numberOfBlock, 330),
  createSector(numberOfBlock, 360),
]


// パックマン
const pacman = [
  createSector(numberOfBlock, 335, 15),
  createSector(numberOfBlock, 315, 25),
  createSector(numberOfBlock, 295, 35),
  createSector(numberOfBlock, 285, 45),
  createSector(numberOfBlock, 275, 55),
  createSector(numberOfBlock, 285, 45),
  createSector(numberOfBlock, 295, 35),
  createSector(numberOfBlock, 315, 25),
  createSector(numberOfBlock, 335, 15),
]



const film = document.querySelector(".film")
const showFilmBtn = document.querySelector(".show-film-btn")
const scanimation = document.querySelector(".scanimation")
const imageWrapper = document.querySelector(".image-wrapper")
const filmWrapper = document.querySelector(".film-wrapper")
let isShowFilmBtn = true

const imageMargin = 60

const barSize = 20
let numberOfImage = triangle.length
const gapSize = barSize / numberOfImage - 1
const imageSize = 800
scanimation.style.height = imageSize + "px"
const imageBlockSize = imageSize / numberOfBlock

film.style.width = imageSize * 2
film.style.height = imageSize


imageWrapper.style.height = imageSize + "px"
imageWrapper.style.width = imageSize + "px"

filmWrapper.style.width = (imageSize * 7) + "px"

// スキャニメーション生成
const createScanimation = (image) => {
  imageWrapper.innerHTML = ""
  const contentElWidth = (imageBlockSize / numberOfImage)
  for (let i = 0; i < numberOfBlock; i++) {
    const row = document.createElement("div")
    row.classList.add("image-row")
    row.style.height = imageBlockSize + "px"
    for (let j = 0; j < numberOfBlock; j++) {
      const block = document.createElement("div")
      block.classList.add("image-block")
      block.style.height = "100%"
      // block.style.width = imageBlockSize + "px"
      image.forEach(content => {
        const imageContentEl = document.createElement("div")
        imageContentEl.style.width = contentElWidth + "px"
        imageContentEl.style.height = "100%"
        if (content[i][j] === 1) {
          imageContentEl.style.background = "black"
        } else {
          imageContentEl.style.background = "transparent"
        }
        block.appendChild(imageContentEl)
      })
      row.appendChild(block)
    }

    imageWrapper.appendChild(row)
  }
  // film追加処理
  film.innerHTML = ""
  for (let i = 0; i < (imageSize / imageBlockSize) * 2; i++) {
    const blackBar = document.createElement("div")
    const bar = document.createElement("div")
    blackBar.classList.add("bar")
    blackBar.style.minWidth = (imageBlockSize - contentElWidth) + "px"
    blackBar.style.width = (imageBlockSize - contentElWidth) + "px"

    bar.style.minWidth = contentElWidth + "px"
    film.appendChild(blackBar)
    film.appendChild(bar)
  }

}
// showFilmBtnが押された時の処理
const handleClickShowFilmBtn = () => {
  if (isShowFilmBtn) {
    film.style.display = "none"
  } else {
    film.style.display = "flex"
  }

  isShowFilmBtn = !isShowFilmBtn
}
createScanimation(triangle)


const triangleBtn = document.querySelector(".triangle-btn")
const sectorBtn = document.querySelector(".sector-btn")
const pacmanBtn = document.querySelector(".pacman-btn")


triangleBtn.addEventListener("click", () => {
  numberOfImage = triangle.length
  createScanimation(triangle)
})
sectorBtn.addEventListener("click", () => {
  numberOfImage = sector.length
  createScanimation(sector)
})
pacmanBtn.addEventListener("click", () => {
  numberOfImage = pacman.length
  createScanimation(pacman)
})
showFilmBtn.addEventListener("click", handleClickShowFilmBtn)

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.