html5 canvas圆形的泡沫动画特效



75 299 100



特效描述:html5 canvas圆形的泡沫 动画特效,html5 canvas绘制圆形泡沫动画,鼠标点击会变颜色效果。

代码结构

1. HTML代码

<div class="container">
  <canvas class="canvas" id="canvas"></canvas>
</div>
<script>
'use strict';
(function() {
  var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    mouseX = 0, mouseY = -100,
    width = window.innerWidth, height = window.innerHeight,
    isMouseMove = false;
  var TAU = 2 * Math.PI;
  var generates = 0;
  var attempts = 300;
  var mainCirlce = {
    x: width / 2,
    y: height / 2,
    rds: 220
  };
  var maxCirlcesCount = 700;
  var circles = [];
  var maxCircleSize = mainCirlce.rds / 7;
  var colors = [
    ['#0F4155', '#F5C03E'],
    ['#D63826', '#0F4155'],
    ['#0F4155', '#D63826'],
    ['#152A3B', '#158ca7'],
    ['#e4a50a', '#D63826'],
    ['#D63826', '#e4a50a'],
    ['#3a7b30', '#F5C03E'],
    ['#0F4155', '#7ec873']
  ];
  var mouseCircle = {
    currX: width / 2,
    currY: -100,
    targX: width / 2,
    targY: -100,
    rds: maxCircleSize * .85,
    easingCircle: .15,
    easingRect: .13,
    angle: random(360),
    rectCurrX: width / 2,
    rectCurrY: -100,
  };
  var activeDistanceRadius = maxCircleSize * 2;
  var isRectPosOfsset = false;
  var isRectWidthOfsset = false;
  var isDrawBubbles = true;
  var isDrawRects = true;
  var rndWidthFactor = 1;
  var rndXOffsetFactor = .5;
  var rndYOffsetFactor = .5;
  var sintId;
  function start() {
    setup();
  }
  function setup() {
    canvas.width  = width;
    canvas.height = height;
    ctx.lineWidth = 1;
    sintId = setInterval(function () {
      generateNewWorld();
    }, 500);
    setEventListeners();
    draw();
  }
  function generateNewWorld() {
    if (generates === 3) {  clearInterval(sintId);  }
    isRectPosOfsset = false;
    isRectWidthOfsset = false;
    isDrawBubbles = true;
    isDrawRects = true;
    rndWidthFactor = 1;
    rndXOffsetFactor = .5;
    rndYOffsetFactor = .5;
    mouseCircle.angle = random(360);
    var clrSetIdx = ~~random(colors.length);
    ctx.strokeStyle = colors[clrSetIdx][0];
    ctx.fillStyle   = colors[clrSetIdx][1];
    if (generates === 0) {
      isDrawRects = false;
    }
    if (generates === 1) {
      isRectPosOfsset = true;
      rndXOffsetFactor = random(-.5, 1);
      rndYOffsetFactor = random(-.5, 1);
    }
    if (generates === 2) {
      isRectWidthOfsset = true;
      rndWidthFactor = random(4, 5);
    }
    if (generates > 3) {
      if (Math.random() >= .8) {
        isRectWidthOfsset = true;
        rndWidthFactor = random(3, 5);
      }
      if (Math.random() >= .7) {
        isRectPosOfsset = true;
        rndXOffsetFactor = random(-.5, 1);
        rndYOffsetFactor = random(-.5, 1);
      }
      if (Math.random() >= .85) {
        isDrawBubbles = false;
      }
      if (isDrawBubbles) {
        if (Math.random() >= .85) {
          isDrawRects = false;
        }
      }
    }
    generateCirclesInCircle();
    ++generates;
  }
  function draw() {
    background('#fff');
    drawFoamBubbles();
    drawMouseCircle();
    window.requestAnimationFrame(draw);
  }
  function drawFoamBubbles() {
    updateCirclesPos(circles);
    circles.forEach(function (p) {
      p.updateAnimationValues();
    });
    if (isDrawRects) {
      circles.forEach(function (p) {
        p.drawRect();
      });
    }
    if (isDrawBubbles) {
      circles.forEach(function (p) {
        p.drawCircle();
      });
    }
  }
  function drawMouseCircle() {
    mouseCircle.currX += (mouseX - mouseCircle.currX) * mouseCircle.easingCircle;
    mouseCircle.currY += (mouseY - mouseCircle.currY) * mouseCircle.easingCircle;
    mouseCircle.rectCurrX += (mouseX - mouseCircle.rectCurrX) * mouseCircle.easingRect;
    mouseCircle.rectCurrY += (mouseY - mouseCircle.rectCurrY) * mouseCircle.easingRect;
    ctx.beginPath();
    ctx.arc(mouseCircle.currX, mouseCircle.currY, mouseCircle.rds, 0, Math.PI * 2, false);
    ctx.arc(mouseCircle.currX, mouseCircle.currY, mouseCircle.rds + .3, 0, Math.PI * 2, false);
    ctx.stroke();
    ctx.save();
    ctx.translate(mouseCircle.rectCurrX, mouseCircle.rectCurrY);
    ctx.rotate(mouseCircle.angle);
    ctx.fillRect(-mouseCircle.rds * rndXOffsetFactor, -mouseCircle.rds * rndYOffsetFactor, mouseCircle.rds / rndWidthFactor, mouseCircle.rds);
    ctx.restore();
  }
  function generateCirclesInCircle() {
    circles = [];
    var newCircleCenter, tmpDistance, cDist, idx, itr, i;
    for (idx = 0; idx < maxCirlcesCount; idx++) {
      for (i = 0; i < attempts; ++i) {
        newCircleCenter = genNewPosition(mainCirlce);
        if (isPointInsideCircle(newCircleCenter, mainCirlce) && !isIntersectWithCircles(newCircleCenter, circles)) {
          break;
        }
      }
      // distance to main circle border;
      var newCircleSize = (mainCirlce.rds - dist(newCircleCenter.x, newCircleCenter.y, mainCirlce.x, mainCirlce.y)) * 2;
      newCircleSize = newCircleSize > maxCircleSize ? maxCircleSize : newCircleSize;
      for (itr = 0; itr < circles.length; itr++) {
        cDist = dist(circles[itr].x, circles[itr].y, newCircleCenter.x, newCircleCenter.y);
        tmpDistance = Math.abs(circles[itr].rds - cDist);
        if (tmpDistance < newCircleSize) {
          newCircleSize = tmpDistance + 3;
        }
      }
      if (newCircleSize >= 3) {
        circles.push(new Circle(newCircleCenter.x, newCircleCenter.y, newCircleSize, idx));
      }
    }
    if (isRectWidthOfsset) {
      circles.forEach(function (circleItem) {
        circleItem.rectWidthDivideFactor = rndWidthFactor;
      });
    }
    if (isRectPosOfsset) {
      circles.forEach(function (circleItem) {
        circleItem.rectXOffsetFactor = rndXOffsetFactor;
        circleItem.rectYOffsetFactor = rndYOffsetFactor;
      });
    }
  }
  function updateCirclesPos() {
    var i, circleItem, theta, distance;
    for (i = 0; i < circles.length; i++) {
      circleItem = circles[i];
      theta = Math.atan2(circleItem.y - mouseY, circleItem.x - mouseX);
      distance = activeDistanceRadius / dist(mouseX, mouseY, circleItem.x, circleItem.y);
      circleItem.x += Math.cos(theta) * distance + (circleItem.origX - circleItem.x) * 0.075;
      circleItem.y += Math.sin(theta) * distance + (circleItem.origY - circleItem.y) * 0.075;
    }
  }
  // Circle class
  function Circle (x, y, r, idx) {
    this.x = x;
    this.y = y;
    this.origX = x;
    this.origY = y;
    this.rds = r;
    this.currRds = 0;
    this.idx = idx;
    this.durAnimation = random(1.7, 2.7);
    this.durProgress = 0;
    this.currAngle = random(1, 7);
    this.targetAngle = this.currAngle + random(1, 7) * (Math.random() > .5 ? 1 : -1);
    this.rectWidth = 0;
    this.rectX = 0;
    this.rectY = 0;
    this.rectXOffsetFactor = .5;
    this.rectYOffsetFactor = .5;
    this.rectWidthDivideFactor = 1;
    this.drawCircle = function () {
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.currRds, 0, Math.PI * 2, false);
      ctx.arc(this.x, this.y, this.currRds + .3, 0, Math.PI * 2, false);
      ctx.stroke();
    };
    this.drawRect = function () {
      ctx.save();
      ctx.translate(this.x, this.y);
      ctx.rotate(this.currAngle);
      ctx.fillRect(this.rectX, this.rectY, this.rectWidth, this.currRds);
      ctx.restore();
    };
    this.updateAnimationValues = function () {
      if (this.durProgress < this.durAnimation) {
        if (this.currRds !== this.rds) {
          this.currRds = easeOutElastic(this.durProgress, this.currRds, this.rds, this.durAnimation);
          this.rectWidth = this.currRds / this.rectWidthDivideFactor;
          this.rectX = -this.currRds * this.rectXOffsetFactor;
          this.rectY = -this.currRds * this.rectYOffsetFactor;
        }
        if (this.currAngle !== this.targetAngle) {
          this.currAngle = easeOutElastic(this.durProgress, this.currAngle, this.targetAngle, this.durAnimation);
        }
        this.durProgress += .008;
      }
    };
    this.drawWithAnimate = function () {
      this.updateAnimationValues();
      this.drawCircle();
    };
  }
  function genNewPosition(mainCirlce) {
    return {
      x: random(10, width  - 20),
      y: random(10, height - 10)
    };
    // // different way: perfect for creating point inside circle but having some slight differences in result
    // var angle = random(TAU);
    // var scalar = random(1, mainCirlce.rds);
    // return {
    //   x: Math.cos(angle) * scalar + mainCirlce.x,
    //   y: Math.sin(angle) * scalar + mainCirlce.y
    // };
  }
  function isPointInsideCircle(pos, circle) {
    return  dist (pos.x, pos.y, circle.x, circle.y) < circle.rds;
  }
  function isIntersectWithCircles(pos, circles) {
    if (circles.length > 0) {
      for (var i = 0; i < circles.length; i++) {
        if (isPointInsideCircle(pos, circles[i])) {
          return true;
        }
        // return isPointInsideCircle(pos, circles[i]);
      }
    }
    return false;
  }
  function setEventListeners() {
    document.addEventListener('mousedown', mouseDown);
    document.addEventListener('mouseout',  mouseOut );
    document.addEventListener('mousemove', mouseMove);
    document.addEventListener('keypress',  keyTyped );
    window.addEventListener('resize',  function() {
      width = window.innerWidth; height = window.innerHeight;
    } );
  }
  function keyTyped(evt) {
    var eventKey = evt.key.toLowerCase();
    switch (eventKey){
      case 'g': generateNewWorld(); break;
    }
  }
  function mouseDown(evt) {
    if (evt.button === 0) { generateNewWorld(); }
  }
  function mouseOut (evt) {
    isMouseMove = false;
  }
  function mouseMove(evt) {
    var mousePos = getMousePos(canvas, evt);
    mouseX = mousePos.x;
    mouseY = mousePos.y;
    isMouseMove = true;
  }
  function getMousePos(block, evt) {
    block = block || document.getElementsByTagName('body')[0];
    var rect = block.getBoundingClientRect();
    return {
      x: evt.clientX - rect.left,
      y: evt.clientY - rect.top
    };
  }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Helper Functions //////////////////////////////////////////////////////////////////////////////////////////
  function random (min, max){
    if (!min && min !== 0) {
      return Math.random();
    } else if (!max) {
      return Math.random() * min;
    }
    return Math.random() * (max - min) + min;
  }
  function dist (x1, y1, x2, y2) {
    var a = x1 - x2;
    var b = y1 - y2;
    return Math.sqrt(a * a + b * b);
  }
  function background(clr) {
    ctx.save();
    ctx.fillStyle = clr || "#fff";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.restore();
  }
  // t: curr time, b: start val, c: change In value, d: duration
  function easeOutElastic(t, b, c, d) {
    var s = 1.70158;
    var a = c;
    if (t === 0) { return 0; }
    t /= d;
    if (t === 1) { return c; }
    var p = d * 0.3;
    if (a < Math.abs(c)) {
      a = c;
      s = p / 4;
    } else {
      s = p / (2 * Math.PI) * Math.asin(c / a);
    }
    return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c;
  }
  start();
})();
</script>



用户评论
大牛,别默默的看了,快登录帮我点评一下吧!:)      登录 | 注册


热门标签: 滑动选项卡 滑动切换 加载动画 滚动切换 滚动条切换 滑动手风琴 选项卡切换 选项卡 切换 tab切换 页面切换 选项卡插件 切换插件 滑动星星打分 h5弹窗动画 html5弹窗动画 旋转翻转 旋转 翻转 h5动画 h5背景动画 h5场景动画 h53D动画 h5界面动画 html5动画 其他 h5按钮动画 html5按钮动画 旋转木马 图片旋转木马 文字旋转木马 旋转木马插件 背景切换 大图切换 h5线条动画 html5线条动画 鼠标滑过 鼠标悬停 跟随鼠标移动

×
×

注册

官方QQ群

扫描上面二维码加微信群

官方QQ群

jQuery/js讨论群
群号:642649996
Css3+Html5讨论群
群号:322131262

加群请备注:从官网了解到