[Canvas] 버튼 Particle 이펙트
HTML 요소의 자유를 결합하여 웹 페이지의 시각적 기능을 향상시키는 방법에 대해 살펴 보겠습니다. 최신브라우저에만 적용이 가능합니다.
초기 상태
See the Pen DOM to Canvas #1 by Zach Saucier (@Zeaklous) on CodePen.
캔버스 버전
html2canvas라는 매우 편리한 라이브러리가 도움이 됩니다.
라이브러리를 로드 한 다음 html2canvas를 호출하면 엘리먼트의 캔버스 버전과 함께 Promise가 반환됩니다.
See the Pen DOM to Canvas #2 by Zach Saucier (@Zeaklous) on CodePen.
여기에는 HTML 버전과 캔버스 버전의 버튼이 있습니다.캔버스 버전은 "screenshot"으로 사용하거나 특정 위치의 픽셀 색상과 같은 정보의 소스로 사용할 수 있습니다.
캔버스에서 데이터 가져 오기
이렇게하려면 특정 위치에서 픽셀 정보를 가져 오는 새로운 함수를 만들어 보겠습니다.
원래의 HTML 요소를 대신 보여주기 때문에 색상 데이터를 가져올 캔버스를 표시 할 필요도 없습니다.
1 2 3 4 5 6 7 8 9 10 | function getColorAtPoint(e) { // Get the coordinate of the click let x = e.offsetX; let y = e.offsetY; // Get the color data of the canvas version of our element at that location let rgbaColorArr = ctx.getImageData(x, y, 1, 1).data; // Do something with rgbaColorArr } | cs |
See the Pen DOM to Canvas #3 by Zach Saucier (@Zeaklous) on CodePen.
이제 위에 가져온 캔버스 정보를 가지고 입자를 생성합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | var particleCanvas, particleCtx; function createParticleCanvas() { // Create our canvas particleCanvas = document.createElement("canvas"); particleCtx = particleCanvas.getContext("2d"); // Size our canvas particleCanvas.width = window.innerWidth; particleCanvas.height = window.innerHeight; // Position out canvas particleCanvas.style.position = "absolute"; particleCanvas.style.top = "0"; particleCanvas.style.left = "0"; // Make sure it's on top of other elements particleCanvas.style.zIndex = "1001"; // Make sure other elements under it are clickable particleCanvas.style.pointerEvents = "none"; // Add our canvas to the page document.body.appendChild(particleCanvas); } | cs |
우리는 또한 버튼의 위와 왼쪽뿐 아니라 오른쪽에서 입자를 생성하기 위해 전역 좌표의 위치인 로컬 좌표에서 색상 데이터를 계속 가져와야합니다.
좌표 데이터 가져 오기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | btn.addEventListener("click", e => { // Get our color data like before let localX = e.offsetX; let localY = e.offsetY; let rgbaColorArr = ctx.getImageData(localX, localY, 1, 1).data; // Get the button's positioning in terms of the window let bcr = btn.getBoundingClientRect(); let globalX = bcr.left + localX; let globalY = bcr.top + localY; // Create a particle using the color we obtained at the window location // that we calculated createParticleAtPoint(globalX, globalY, rgbaColorArr); }); | cs |
파티클 프로토 타입 만들기
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | /* An "exploding" particle effect that uses circles */ var ExplodingParticle = function() { // Set how long we want our particle to animate for this.animationDuration = 1000; // in ms // Set the speed for our particle this.speed = { x: -5 + Math.random() * 10, y: -5 + Math.random() * 10 }; // Size our particle this.radius = 5 + Math.random() * 5; // Set a max time to live for our particle this.life = 30 + Math.random() * 10; this.remainingLife = this.life; // This function will be called by our animation logic later on this.draw = ctx => { let p = this; if(this.remainingLife > 0 && this.radius > 0) { // Draw a circle at the current location ctx.beginPath(); ctx.arc(p.startX, p.startY, p.radius, 0, Math.PI * 2); ctx.fillStyle = "rgba(" + this.rgbArray[0] + ',' + this.rgbArray[1] + ',' + this.rgbArray[2] + ", 1)"; ctx.fill(); // Update the particle's location and life p.remainingLife--; p.radius -= 0.25; p.startX += p.speed.x; p.startY += p.speed.y; } } } | cs |
입자 팩토리 만들기
또한 좌표와 색상 정보를 기반으로 입자를 생성하는 함수가 필요합니다. 생성 된 입자의 배열에 추가해야합니다.
1 2 3 4 5 6 7 8 9 10 | var particles = []; function createParticleAtPoint(x, y, colorData) { let particle = new ExplodingParticle(); particle.rgbArray = colorData; particle.startX = x; particle.startY = y; particle.startTime = Date.now(); particles.push(particle); } | cs |
애니메이션 논리 추가
또한 생성된 모든 입자에 애니메이션을 적용하는 방법이 필요합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function update() { // Clear out the old particles if(typeof particleCtx !== "undefined") { particleCtx.clearRect(0, 0, window.innerWidth, window.innerHeight); } // Draw all of our particles in their new location for(let i = 0; i < particles.length; i++) { particles[i].draw(particleCtx); // Simple way to clean up if the last particle is done animating if(i === particles.length - 1) { let percent = (Date.now() - particles[i].startTime) / particles[i].animationDuration[i]; if(percent > 1) { particles = []; } } } // Animate performantly window.requestAnimationFrame(update); } window.requestAnimationFrame(update); | cs |
HTML 요소를 기반으로 입자를 만들 수 있습니다!
See the Pen DOM to Canvas #4 by Zach Saucier (@Zeaklous) on CodePen.
한 픽셀 대신 클릭하여 전체 버튼을 "폭발"시키려면 클릭 기능 만 수정하면됩니다.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | let reductionFactor = 17; btn.addEventListener("click", e => { // Get the color data for our button let width = btn.offsetWidth; let height = btn.offsetHeight let colorData = ctx.getImageData(0, 0, width, height).data; // Keep track of how many times we've iterated (in order to reduce // the total number of particles create) let count = 0; // Go through every location of our button and create a particle for(let localX = 0; localX < width; localX++) { for(let localY = 0; localY < height; localY++) { if(count % reductionFactor === 0) { let index = (localY * width + localX) * 4; let rgbaColorArr = colorData.slice(index, index + 4); let bcr = btn.getBoundingClientRect(); let globalX = bcr.left + localX; let globalY = bcr.top + localY; createParticleAtPoint(globalX, globalY, rgbaColorArr); } count++; } } }); | cs |
See the Pen DOM to Canvas #5 by Zach Saucier (@Zeaklous) on CodePen.
웹은 이제 더 창조적인 자유를 행사하기 위해 캔버스와 같은 추가 기능을 사용할 수 있다는 것을 알게 되었습니다.
가장자리 감지 기능을 사용하여 요소가 컨테이너 경계 외부에 있는지 (예 :보기에서 숨겨져 있는지) 알려주고 요소가 경계 외부로 나가면 입자를 생성하여 훨씬 더 창의적으로 처리 할 수 있습니다.
출처 : https://css-tricks.com/adding-particle-effects-to-dom-elements-with-canvas/
'CSS' 카테고리의 다른 글
Bootstrap5 새소식(큰 변화 4가지) (6) | 2019.12.22 |
---|---|
[CSS] Rethinking CSS (0) | 2019.01.31 |
[Reflow] Reflow 최소화 (0) | 2019.01.29 |
Will-Change (0) | 2019.01.22 |
잘 알려지지 않은 CSS 팁 (1) | 2019.01.01 |
댓글