首页 > 特效插件 > 鼠标键盘特效 >  跟随鼠标流动的Canvas星空特效正文

跟随鼠标流动的Canvas星空特效

特效介绍


这是一个跟随鼠标流动的Canvas星空特效,刚打开,会看到很多圆点星星一闪一闪的向您飞来,仿佛您置身于宇宙飞船之中。当您稍微移动鼠标,幅度很小,就会发现星星滑动的轨迹被拉长,鼠标幅度越大,星星轨迹越长,仿佛飞船非得越来越快,当鼠标移动相当快时,星星都被拉长成线条了。而且,鼠标的位置也决定了星星滑动的方向。很适合做为网页背景使用。
本特效支持:360、FireFox、Chrome等浏览器,不支持Safari、IE8等不兼容canvas的浏览器。
使用方法
1、加入css(建议装canvas的容器背景色为深色,否则可能看不清“星星”)
canvas {
  position: fixed;
  width: 100%;
  height: 100%;
}
2、html代码
<canvas></canvas>
3、js代码:
const STAR_COUNT = ( window.innerWidth + window.innerHeight ) / 8,
      STAR_SIZE = 3,
      STAR_MIN_SCALE = 0.2,
      OVERFLOW_THRESHOLD = 50;
const canvas = document.querySelector( 'canvas' ),
      context = canvas.getContext( '2d' );
let scale = 1, // device pixel ratio
    width,
    height;
let stars = [];
let pointerX,
    pointerY;
let velocity = { x: 0, y: 0, tx: 0, ty: 0, z: 0.0005 };
let touchInput = false;

generate();
resize();
step();

window.onresize = resize;
canvas.onmousemove = onMouseMove;
canvas.ontouchmove = onTouchMove;
canvas.ontouchend = onMouseLeave;
document.onmouseleave = onMouseLeave;

function generate() {
   for( let i = 0; i < STAR_COUNT; i++ ) {
    stars.push({
      x: 0,
      y: 0,
      z: STAR_MIN_SCALE + Math.random() * ( 1 - STAR_MIN_SCALE )
    });
   }
}
function placeStar( star ) {
  star.x = Math.random() * width;
  star.y = Math.random() * height;
}
function recycleStar( star ) {
  let direction = 'z';
  let vx = Math.abs( velocity.x ),
        vy = Math.abs( velocity.y );
  if( vx > 1 || vy > 1 ) {
    let axis;
    if( vx > vy ) {
      axis = Math.random() < vx / ( vx + vy ) ? 'h' : 'v';
    }else {
      axis = Math.random() < vy / ( vx + vy ) ? 'v' : 'h';
    }
    if( axis === 'h' ) {
      direction = velocity.x > 0 ? 'l' : 'r';
    }else {
      direction = velocity.y > 0 ? 't' : 'b';
    }
  }
  star.z = STAR_MIN_SCALE + Math.random() * ( 1 - STAR_MIN_SCALE );
  if( direction === 'z' ) {
    star.z = 0.1;
    star.x = Math.random() * width;
    star.y = Math.random() * height;
  }
  else if( direction === 'l' ) {
    star.x = -OVERFLOW_THRESHOLD;
    star.y = height * Math.random();
  }
  else if( direction === 'r' ) {
    star.x = width + OVERFLOW_THRESHOLD;
    star.y = height * Math.random();
  }
  else if( direction === 't' ) {
    star.x = width * Math.random();
    star.y = -OVERFLOW_THRESHOLD;
  }
  else if( direction === 'b' ) {
    star.x = width * Math.random();
    star.y = height + OVERFLOW_THRESHOLD;
  }
}
function resize() {
  scale = window.devicePixelRatio || 1;
  width = window.innerWidth * scale;
  height = window.innerHeight * scale;
  canvas.width = width;
  canvas.height = height;
  stars.forEach( placeStar );
}
function step() {
  context.clearRect( 0, 0, width, height );
  update();
  render();
  requestAnimationFrame( step );
}
function update() {
  velocity.tx *= 0.96;
  velocity.ty *= 0.96;
  velocity.x += ( velocity.tx - velocity.x ) * 0.8;
  velocity.y += ( velocity.ty - velocity.y ) * 0.8;
  stars.forEach( ( star ) => {
    star.x += velocity.x * star.z;
    star.y += velocity.y * star.z;
    star.x += ( star.x - width/2 ) * velocity.z * star.z;
    star.y += ( star.y - height/2 ) * velocity.z * star.z;
    star.z += velocity.z;
    // recycle when out of bounds
    if( star.x < -OVERFLOW_THRESHOLD || star.x > width + OVERFLOW_THRESHOLD || star.y < -OVERFLOW_THRESHOLD || star.y > height + OVERFLOW_THRESHOLD ) {
      recycleStar( star );
    }
  });
}
function render() {
  stars.forEach( ( star ) => {
    context.beginPath();
    context.lineCap = 'round';
    context.lineWidth = STAR_SIZE * star.z * scale;
    context.strokeStyle = 'rgba(255,255,255,'+(0.5 + 0.5*Math.random())+')';
    context.beginPath();
    context.moveTo( star.x, star.y );
    var tailX = velocity.x * 2,
        tailY = velocity.y * 2;
    // stroke() wont work on an invisible line
    if( Math.abs( tailX ) < 0.1 ) tailX = 0.5;
    if( Math.abs( tailY ) < 0.1 ) tailY = 0.5;
    context.lineTo( star.x + tailX, star.y + tailY );
    context.stroke();
  });
}
function movePointer( x, y ) {
  if( typeof pointerX === 'number' && typeof pointerY === 'number' ) {
    let ox = x - pointerX,
        oy = y - pointerY;
    velocity.tx = velocity.tx + ( ox / 8*scale ) * ( touchInput ? 1 : -1 );
    velocity.ty = velocity.ty + ( oy / 8*scale ) * ( touchInput ? 1 : -1 );
  }
  pointerX = x;
  pointerY = y;
}
function onMouseMove( event ) {
  touchInput = false;
  movePointer( event.clientX, event.clientY );
}
function onTouchMove( event ) {
  touchInput = true;
  movePointer( event.touches[0].clientX, event.touches[0].clientY, true );
  event.preventDefault();
}
function onMouseLeave() {
  pointerX = null;
  pointerY = null;
}
     由于使用方法太简单了,这里就不提供下载了。