ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Canvas] 버튼 Particle 이펙트
    CSS 2019. 1. 30. 22:46

    [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, 11).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, 11).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(00window.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(00, 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
Designed by Tistory.