비전공자 개발일기

3D Gallery 본문

Javascript

3D Gallery

HiroDaegu 2022. 5. 14. 00:26
728x90
SMALL

 

<!DOCTYPE html>
<html lang="ko">
<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">
  <title>3D GALLERY</title>
  <link rel="stylesheet" href="style.css">
  <script defer src="main.js"></script>
</head>
<body>
  <main></main>
</body>
</html>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  height: 100vh;
  perspective: 800px;
  overflow: hidden;
  display: grid;
  place-items: center;
  background:linear-gradient(#3a4149, #111722);
}

main {
  position: relative;
  transform-style: preserve-3d;
  width: 50vmin;
  height: 75vmin;
  transition: all 500ms cubic-bezier(0.4, 0, 0.2, 1);
}

img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
}

article {
  position: absolute;
  inset: 0;
  -webkit-box-reflect: below 50px linear-gradient(transparent, rgba(255, 255, 255, 0.15));
}

article button {
  border: 0;
  outline: 0;
  cursor: pointer;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 5%;
  transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
}

article button:focus-visible {
  box-shadow: 0 0 0 3px cyan;
}

article button:focus {
  box-shadow: 0 0 0 3px cyan;
}

article button:focus:not(:focus-visible) {
  box-shadow: none;
}

article button:hover, article button:focus, article button:hover img, article button:focus img {
  transform: scale(1.07);
}
const articles = new Map([
  ["6392322", {tx: "-90%", tz: "-70vmin", ry: "60deg"}],
  ["1761279", {tz: "-110vmin"}],
  ["1679772", {tx: "90%", tz: "-70vmin", ry: "-60deg"}]
])

window.addEventListener("load", () => {
  const main = document.querySelector("main");
  for(const [id, {tx, tz, ry}] of articles.entries()) {
    main.appendChild(makeArticleElement(id, tx, tz, ry))
  }
  document.addEventListener("click", ({target}) => {
    const targetId = target.closest("article")?.id;
    let [itx, itz, iry] = [0, 0, 0];
    if(targetId && main.dataset.focus !== targetId) {
      const {tx, tz, ry} = articles.get(targetId) || {};
      [itx, itz, iry] = [tx, tz, ry].map(inverseTransformation);
      main.setAttribute("data-focus", targetId);
    } else {
      main.removeAttribute("data-focus");
    }
    main.style.transform = `rotateY(${iry}) translate3d(${itx}, 0, ${itz})`;
  })
})

function inverseTransformation(transform) {
  if(!transform) return 0;
  const [_, value, unit] = transform.match(/(-?\d+)(.*)/);
  return `${-Number(value)}${unit}`;
}

function makeArticleElement(id, tx = 0, tz = 0, ry = 0) {
  const img = document.createElement("img");
  img.src = `https://images.pexels.com/photos/${id}/pexels-photo-${id}.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500`
  const button = document.createElement("button");
  button.appendChild(img);
  const element = document.createElement("article");
  element.id = id;
  element.style.transform = `translate3d(${tx}, 0, ${tz}) rotateY(${ry})`
  element.appendChild(button);
  return element;
}
728x90
LIST

'Javascript' 카테고리의 다른 글

Light AND Dark Mode Toggle  (0) 2022.05.16
Random Color Generator  (0) 2022.05.15
Draggable DIV  (0) 2022.05.12
Animated Submit BUTTON  (0) 2022.05.10
Lock Animation  (0) 2022.05.05