정보실

웹학교

정보실

javascript 2D Canvas를 활용한 Particles 애니메이션

본문

https://codepen.io/soulwire/pen/Ffvlo


HTML

<div id='container'></div>

<div class='info'>

  <hgroup class='about'>

    <h1>30,000 Particles</h1>

    <h2>A study creating performant particles with Canvas 2D</h2>

    <h3>Use your mouse</h3>

  </hgroup>

</div>


CSS

@charset "UTF-8";

@import url(https://fonts.googleapis.com/css?family=Quantico);

html, body {

  background: #111;

}


#container {

  background: #111;

  position: absolute;

  left: 50%;

  top: 50%;

}


#stats {

  position: absolute;

  right: 10px;

  top: 10px;

}


/* Info */

@keyframes show-info {

  0% {

    transform: rotateY(120deg);

  }

  100% {

    transform: rotateY(0deg);

  }

}

.info {

  transition: all 180ms ease-out;

  transform-style: preserve-3d;

  transform: perspective(800px);

  font-family: "Quantico", sans-serif;

  position: absolute;

  font-size: 12px;

  opacity: 0.8;

  color: #fff;

  width: 220px;

  left: 0px;

  top: 20px;

}

.info:hover {

  box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.05);

  opacity: 1;

}

.info h1, .info h2, .info h3 {

  line-height: 1;

  margin: 5px 0;

}

.info a {

  transition: all 200ms ease-out;

  border-bottom: 1px dotted rgba(255, 255, 255, 0.4);

  text-decoration: none;

  opacity: 0.6;

  color: #fff;

}

.info a:hover {

  opacity: 0.99;

}

.info .about,

.info .more {

  transform-origin: 0% 50%;

  transform: rotateY(120deg);

  margin-bottom: 1px;

  background: rgba(0, 0, 0, 0.8);

  padding: 12px 15px 12px 20px;

}

.info .about {

  animation: show-info 500ms cubic-bezier(0.23, 1, 0.32, 1) 600ms 1 normal forwards;

  padding-bottom: 15px;

}

.info .about a {

  opacity: 0.9;

}

.info .about h1 {

  letter-spacing: -1px;

  font-weight: 300;

  font-size: 19px;

  opacity: 0.95;

}

.info .about h2 {

  font-weight: 300;

  font-size: 13px;

  opacity: 0.8;

}

.info .about h3 {

  text-transform: uppercase;

  margin-top: 10px;

  font-size: 11px;

}

.info .about h3:before {

  margin-right: 2px;

  font-size: 14px;

  content: "›";

}

.info .more {

  animation: show-info 500ms cubic-bezier(0.23, 1, 0.32, 1) 500ms 1 normal forwards;

  padding: 5px 15px 10px 20px;

}

.info .more a {

  text-transform: uppercase;

  margin-right: 10px;

  font-size: 10px;

}


JS


var NUM_PARTICLES = ( ( ROWS = 100 ) * ( COLS = 300 ) ),

    THICKNESS = Math.pow( 80, 2 ),

    SPACING = 3,

    MARGIN = 100,

    COLOR = 220,

    DRAG = 0.95,

    EASE = 0.25,

    

    /*

    

    used for sine approximation, but Math.sin in Chrome is still fast enough :)http://jsperf.com/math-sin-vs-sine-approximation


    B = 4 / Math.PI,

    C = -4 / Math.pow( Math.PI, 2 ),

    P = 0.225,


    */


    container,

    particle,

    canvas,

    mouse,

    stats,

    list,

    ctx,

    tog,

    man,

    dx, dy,

    mx, my,

    d, t, f,

    a, b,

    i, n,

    w, h,

    p, s,

    r, c

    ;


particle = {

  vx: 0,

  vy: 0,

  x: 0,

  y: 0

};


function init() {


  container = document.getElementById( 'container' );

  canvas = document.createElement( 'canvas' );

  

  ctx = canvas.getContext( '2d' );

  man = false;

  tog = true;

  

  list = [];

  

  w = canvas.width = COLS * SPACING + MARGIN * 2;

  h = canvas.height = ROWS * SPACING + MARGIN * 2;

  

  container.style.marginLeft = Math.round( w * -0.5 ) + 'px';

  container.style.marginTop = Math.round( h * -0.5 ) + 'px';

  

  for ( i = 0; i < NUM_PARTICLES; i++ ) {

    

    p = Object.create( particle );

    p.x = p.ox = MARGIN + SPACING * ( i % COLS );

    p.y = p.oy = MARGIN + SPACING * Math.floor( i / COLS );

    

    list[i] = p;

  }


  container.addEventListener( 'mousemove', function(e) {


    bounds = container.getBoundingClientRect();

    mx = e.clientX - bounds.left;

    my = e.clientY - bounds.top;

    man = true;

    

  });

  

  if ( typeof Stats === 'function' ) {

    document.body.appendChild( ( stats = new Stats() ).domElement );

  }

  

  container.appendChild( canvas );

}


function step() {


  if ( stats ) stats.begin();


  if ( tog = !tog ) {


    if ( !man ) {


      t = +new Date() * 0.001;

      mx = w * 0.5 + ( Math.cos( t * 2.1 ) * Math.cos( t * 0.9 ) * w * 0.45 );

      my = h * 0.5 + ( Math.sin( t * 3.2 ) * Math.tan( Math.sin( t * 0.8 ) ) * h * 0.45 );

    }

      

    for ( i = 0; i < NUM_PARTICLES; i++ ) {

      

      p = list[i];

      

      d = ( dx = mx - p.x ) * dx + ( dy = my - p.y ) * dy;

      f = -THICKNESS / d;


      if ( d < THICKNESS ) {

        t = Math.atan2( dy, dx );

        p.vx += f * Math.cos(t);

        p.vy += f * Math.sin(t);

      }


      p.x += ( p.vx *= DRAG ) + (p.ox - p.x) * EASE;

      p.y += ( p.vy *= DRAG ) + (p.oy - p.y) * EASE;


    }


  } else {


    b = ( a = ctx.createImageData( w, h ) ).data;


    for ( i = 0; i < NUM_PARTICLES; i++ ) {


      p = list[i];

      b[n = ( ~~p.x + ( ~~p.y * w ) ) * 4] = b[n+1] = b[n+2] = COLOR, b[n+3] = 255;

    }


    ctx.putImageData( a, 0, 0 );

  }


  if ( stats ) stats.end();


  requestAnimationFrame( step );

}


init();

step();


추가 링크...

https://gist.github.com/mrdoob/838785/raw/a19a753b441d6ad41707c58f06dbe17f3470423c/RequestAnimationFrame.js

https://raw.github.com/mrdoob/stats.js/master/build/stats.min.js

  • 트위터로 보내기
  • 페이스북으로 보내기
  • 구글플러스로 보내기
  • 카카오톡으로 보내기

페이지 정보

조회 46회 ]  작성일18-09-03 16:53

웹학교