Анимация продавливания плитки в стиле Windows 8

92
14 февраля 2022, 10:20

Подскажите пожалуйста, как реализовать подобную анимацию без сторонних библиотек или jQuery. Гифку изъял отсюда из следующего раздела:

Раздел "Created with PixiJS" по ссылке

Answer 1

Вот моя попытка:

UPD: Сделал эффект для плитки из нескольких изображений (адаптивненько) + тень

let limit = a => Math.sign(a) * Math.min(15, Math.abs(a)); 
 
let imgs = [...document.querySelectorAll('img')].map(img => { 
 
  let container = document.createElement('div'); 
  container.classList.add('card-3d'); 
  img.parentNode.insertBefore(container, img); 
  container.append(img); 
  let reqId, tx = 0, ty = 0, x = 0, y = 0; 
 
  function upd() { 
      animate(); 
      x += (tx - x)/9; 
      y += (ty - y)/9; 
      img.style.transform = `rotatex(${-y}deg) rotatey(${x}deg)`; 
      img.style.boxShadow = `${-x/4}px ${-y/4}px 5px 0 #0006`; 
  } 
   
  function animate() { 
      if (Math.abs(tx - x) > 0.01 && Math.abs(ty - y) > 0.01) 
        reqId = requestAnimationFrame(upd); 
  } 
   
  return function(x, y) { 
      tx = ty = 0;  
      let r = container.getBoundingClientRect(); 
      if (r.x < x && r.y < y && r.x + r.width > x && r.y + r.height > y) { 
          tx = limit((x - r.x - r.width/2)/4); 
          ty = limit((y - r.y - r.height/2)/3); 
      }  
      cancelAnimationFrame(reqId); 
      animate(); 
  } 
}); 
 
addEventListener('mousemove', e => imgs.forEach(i => i(e.x, e.y)));
.card-3d { 
    perspective: 1000px; 
    padding: 5px; 
    display: inline-block; 
}
<img src="https://picsum.photos/id/44/200/150" > 
<img src="https://picsum.photos/id/45/200/150" > 
<img src="https://picsum.photos/id/46/200/150" > 
<img src="https://picsum.photos/id/47/200/150" ><br> 
<img src="https://picsum.photos/id/48/415/305" > 
<img src="https://picsum.photos/id/49/415/305" ><br> 
<img src="https://picsum.photos/id/43/415/305" > 
<img src="https://picsum.photos/id/42/415/305" >

Answer 2

var wrapper = document.querySelector('.box-wrapper') 
var box = document.querySelector('.box') 
var wrapperRect, elementLeftPlusElementHalfWidth, elementLeftPlusElementHalfHeight, 
    elementLeft, elementRight, elementTop, elementBottom, x, y 
 
init() 
 
wrapper.addEventListener('mousemove', mouseMoveHandler) 
wrapper.addEventListener('mouseleave', mouseleaveHandler) 
 
function mouseMoveHandler({ 
  pageX, 
  pageY 
}) { 
  if (pageX > elementLeft && pageX < elementRight) 
    x = (pageX - elementLeftPlusElementHalfWidth) * 0.04 
 
  if (pageY > elementTop && pageY < elementBottom) 
    y = -(pageY - elementLeftPlusElementHalfHeight) * 0.04 
 
  box.style.transform = `rotateX(${Math.round(y)}deg) rotateY(${Math.round(x)}deg)` 
} 
 
function mouseleaveHandler() { 
  box.style.transform = 'rotateX(0) rotateY(0)' 
} 
 
function init() { 
  wrapperRect = wrapper.getBoundingClientRect(); 
  ({ 
    left: elementLeft, 
    right: elementRight, 
    top: elementTop, 
    bottom: elementBottom 
  } = wrapperRect) 
 
  elementLeftPlusElementHalfWidth = elementLeft + wrapperRect.width / 2 
  elementLeftPlusElementHalfHeight = elementTop + wrapperRect.height / 2 
} 
 
addEventListener('resize', () => init())
body { 
  margin: 0; 
  height: 100vh; 
  display: flex; 
  align-items: center; 
  justify-content: center; 
  perspective: 1000px; 
  background-color: #38404e; 
  overflow: hidden; 
} 
 
.box-wrapper { 
  padding: 1.3rem; 
} 
 
.box { 
  width: 490px; 
  height: 390px; 
  background-color: #465162; 
  box-shadow: 10px 10px 0px -2px rgba(0, 0, 0, 0.35); 
  transition: 0.2s linear; 
} 
 
.box__cover { 
  background-image: url('https://www.pixijs.com/wp/wp-content/uploads/HeinekenGoplaces-540x312.jpg'); 
  height: 75%; 
  width: 100%; 
} 
 
.box__footer { 
  height: 25%; 
  padding-left: 2rem; 
  display: grid; 
  grid-gap: 0.5rem; 
  align-content: center; 
  color: white; 
  font-family: sans-serif; 
} 
 
.text-2 { 
  color: #BDBDBD; 
}
<div class="box-wrapper"> 
  <div class="box"> 
    <div class="box__cover"></div> 
    <footer class="box__footer"> 
      <div class="text-1 ">Heineken Go Places</div> 
      <div class="text-2">Cloud Factory</div> 
    </footer> 
  </div> 
</div>

READ ALSO
vue событие клавиатуры

vue событие клавиатуры

Есть такой небольшой vue проект: codesandbox

132
Парсинг данных из angular

Парсинг данных из angular

Заранее извиняюсь за возможно банальный и туповатый вопрос - никогда прежде не имел ничего общего с angular

95
Почему длина числа равна undefined?

Почему длина числа равна undefined?

Может кто-то объяснить, почему такой код

110
Web Audio API, periodic wave

Web Audio API, periodic wave

Как создать волну нужной формы, как работает функция создания, причем здесь преобразование Фурье, как влияет параметр нормализации(включенный...

259