画布动画无法正常工作

时间:2016-03-30 00:08:23

标签: javascript canvas html5-canvas

如果您运行下面的代码,您会注意到y值在控制台中按预期增加。但是,画布上的圆圈不会按预期沿y轴移动。任何人都知道为什么?

如果向下滚动到render()功能,您会看到我用y += 5;增加y。

'use strict';

(function () {

  const canvas = document.getElementsByClassName('canvas')[0],
        c = canvas.getContext('2d');

  // Circle
  var circleRadius = 50,
      x = (canvas.width/2) - circleRadius, // inital x position of the ball
      y = (canvas.height/2) - circleRadius, // inital y position of the ball
      segments = 4,
      bezieCircleFormula = (4/3)*Math.tan(Math.PI/(2*segments)), // http://stackoverflow.com/a/27863181/2040509
      pointOffset = {
        positive: bezieCircleFormula*circleRadius,
        negative: circleRadius-(bezieCircleFormula*circleRadius)
      },
      // Each side has 3 points, bezier 1, circle point, bezier 2
      // These are listed below in clockwise order.
      // So top has: left bezier, circle point, right bezier
      // Right has: top bezier, circle point, bottom bezier
      circlePoints = {
        top: [
          [x+pointOffset.negative, y],
          [x+circleRadius, y],
          [x+pointOffset.positive+circleRadius, y]
        ],
        right: [
          [x+circleRadius*2, y+pointOffset.negative],
          [x+circleRadius*2, y+circleRadius],
          [x+circleRadius*2, y+pointOffset.positive+circleRadius]
        ],
        bottom: [
          [x+pointOffset.positive+circleRadius, y+circleRadius*2],
          [x+circleRadius, y+circleRadius*2],
          [x+pointOffset.negative, y+circleRadius*2]
        ],
        left: [
          [x, y+pointOffset.positive+circleRadius],
          [x, y+circleRadius],
          [x, y+pointOffset.negative]
        ]
      };

  // For `side` you can pass `top`, `right`, `bottom`, `left`
  // For `amount` use an interger
  function squish (side, squishAmount) {
    for (let i = 0; i < circlePoints[side].length; i++) {
      if (side === 'top') {
        circlePoints[side][i][1] += squishAmount;
      } else if (side === 'right') {
        circlePoints[side][i][0] -= squishAmount;
      } else if (side === 'bottom') {
        circlePoints[side][i][1] -= squishAmount;
      } else if (side === 'left') {
        circlePoints[side][i][0] += squishAmount;
      }
    }
  }

  function render () {

    // Clear the canvas
    c.clearRect(0, 0, canvas.width, canvas.height);

    // Draw a circle using bezier curves
    c.beginPath();
    c.moveTo(circlePoints.left[1][0], circlePoints.left[1][1]);
    c.bezierCurveTo(circlePoints.left[2][0], circlePoints.left[2][1], circlePoints.top[0][0], circlePoints.top[0][1], circlePoints.top[1][0], circlePoints.top[1][1]);
    c.bezierCurveTo(circlePoints.top[2][0], circlePoints.top[2][1], circlePoints.right[0][0], circlePoints.right[0][1], circlePoints.right[1][0], circlePoints.right[1][1]);
    c.bezierCurveTo(circlePoints.right[2][0], circlePoints.right[2][1], circlePoints.bottom[0][0], circlePoints.bottom[0][1], circlePoints.bottom[1][0], circlePoints.bottom[1][1]);
    c.bezierCurveTo(circlePoints.bottom[2][0], circlePoints.bottom[2][1], circlePoints.left[0][0], circlePoints.left[0][1], circlePoints.left[1][0], circlePoints.left[1][1]);
    c.stroke();
    c.closePath();

    // Doing this for animation
    y += 5;

    console.log(y);

    requestAnimationFrame(render);
  }

  render();

})();
<canvas class="canvas" width="200" height="200"></canvas>

1 个答案:

答案 0 :(得分:2)

因为y不会以任何方式影响圈子。它曾用于生成circlePoints,因为此时y的值是按值传递的,因此对y所做的任何更改都不会反映在circlePoints中。如果您想要查看这些更改,则需要更新circlePoints,因为它不会动态更新,因为y是基元,因此通过值传递:

&#13;
&#13;
'use strict';

(function () {

  const canvas = document.getElementsByClassName('canvas')[0],
        c = canvas.getContext('2d');

  // Circle
  var circleRadius = 50,
      x = (canvas.width/2) - circleRadius, // inital x position of the ball
      y = (canvas.height/2) - circleRadius, // inital y position of the ball
      segments = 4,
      bezieCircleFormula = (4/3)*Math.tan(Math.PI/(2*segments)), // http://stackoverflow.com/a/27863181/2040509
      pointOffset = {
        positive: bezieCircleFormula*circleRadius,
        negative: circleRadius-(bezieCircleFormula*circleRadius)
      },
      // Each side has 3 points, bezier 1, circle point, bezier 2
      // These are listed below in clockwise order.
      // So top has: left bezier, circle point, right bezier
      // Right has: top bezier, circle point, bottom bezier
      circlePoints = {
        top: [
          [x+pointOffset.negative, y],
          [x+circleRadius, y],
          [x+pointOffset.positive+circleRadius, y]
        ],
        right: [
          [x+circleRadius*2, y+pointOffset.negative],
          [x+circleRadius*2, y+circleRadius],
          [x+circleRadius*2, y+pointOffset.positive+circleRadius]
        ],
        bottom: [
          [x+pointOffset.positive+circleRadius, y+circleRadius*2],
          [x+circleRadius, y+circleRadius*2],
          [x+pointOffset.negative, y+circleRadius*2]
        ],
        left: [
          [x, y+pointOffset.positive+circleRadius],
          [x, y+circleRadius],
          [x, y+pointOffset.negative]
        ]
      };

  // For `side` you can pass `top`, `right`, `bottom`, `left`
  // For `amount` use an interger
  function squish (side, squishAmount) {
    for (let i = 0; i < circlePoints[side].length; i++) {
      if (side === 'top') {
        circlePoints[side][i][1] += squishAmount;
      } else if (side === 'right') {
        circlePoints[side][i][0] -= squishAmount;
      } else if (side === 'bottom') {
        circlePoints[side][i][1] -= squishAmount;
      } else if (side === 'left') {
        circlePoints[side][i][0] += squishAmount;
      }
    }
  }

  function render () {
    
    circlePoints = {
        top: [
          [x+pointOffset.negative, y],
          [x+circleRadius, y],
          [x+pointOffset.positive+circleRadius, y]
        ],
        right: [
          [x+circleRadius*2, y+pointOffset.negative],
          [x+circleRadius*2, y+circleRadius],
          [x+circleRadius*2, y+pointOffset.positive+circleRadius]
        ],
        bottom: [
          [x+pointOffset.positive+circleRadius, y+circleRadius*2],
          [x+circleRadius, y+circleRadius*2],
          [x+pointOffset.negative, y+circleRadius*2]
        ],
        left: [
          [x, y+pointOffset.positive+circleRadius],
          [x, y+circleRadius],
          [x, y+pointOffset.negative]
        ]
      };

    // Clear the canvas
    c.clearRect(0, 0, canvas.width, canvas.height);

    // Draw a circle using bezier curves
    c.beginPath();
    c.moveTo(circlePoints.left[1][0], circlePoints.left[1][1]);
    c.bezierCurveTo(circlePoints.left[2][0], circlePoints.left[2][1], circlePoints.top[0][0], circlePoints.top[0][1], circlePoints.top[1][0], circlePoints.top[1][1]);
    c.bezierCurveTo(circlePoints.top[2][0], circlePoints.top[2][1], circlePoints.right[0][0], circlePoints.right[0][1], circlePoints.right[1][0], circlePoints.right[1][1]);
    c.bezierCurveTo(circlePoints.right[2][0], circlePoints.right[2][1], circlePoints.bottom[0][0], circlePoints.bottom[0][1], circlePoints.bottom[1][0], circlePoints.bottom[1][1]);
    c.bezierCurveTo(circlePoints.bottom[2][0], circlePoints.bottom[2][1], circlePoints.left[0][0], circlePoints.left[0][1], circlePoints.left[1][0], circlePoints.left[1][1]);
    c.stroke();
    c.closePath();

    // Doing this for animation
    y += 5;

    console.log(y);

    requestAnimationFrame(render);
  }

  render();

})();
&#13;
<canvas class="canvas" width="200" height="200"></canvas>
&#13;
&#13;
&#13;