在HTML5画布上围绕一个点旋转一颗星

Rotating a star around one of its points on an HTML5 canvas

本文关键字:一个 旋转 一颗 HTML5      更新时间:2023-09-26

我正在将flash动画转换为javascript/html5。我的动画看起来很相似,然而,我正在努力完成我在html5画布上绘制的星星的旋转。我正在使用此网站的代码变体:http://programmingthomas.wordpress.com/2012/05/16/drawing-stars-with-html5-canvas/为了参考,我粘贴了下面的相关代码。

function star(ctx, x, y, r, p, m)
{
    ctx.save();
    ctx.beginPath();
    ctx.translate(x, y);
    ctx.moveTo(0,0-r);
    for (var i = 0; i < p; i++)
    {
        ctx.rotate(Math.PI / p);
        ctx.lineTo(0, 0 - (r*m));
        ctx.rotate(Math.PI / p);
        ctx.lineTo(0, 0 - r);
    }
    ctx.fill();
    ctx.restore();
}

我已经找到了如何通过插入ctx.rotate()调用使恒星围绕其中心旋转的方法,如下所示:

    ...beginPath();
    ctx.translate(x, y);
    ctx.rotate(radianOffset);
    ctx.moveTo(0,0-r);
    for (var i = 0...

有人知道如何围绕恒星的一个点旋转恒星吗?我一直在读关于旋转函数的文章,但不知道如何使它与我的星形函数一起工作。

只需平移到要旋转的点,旋转,然后再平移回来,继续绘制星形。

然而,对于你正在使用的函数,这可能会比这更复杂一点,因为你需要恒星"尖峰"点的绝对位置。

这是我写的一个替代实现,用来处理这个问题。在这里,我们调用一个函数来获得一个带有点的数组,以便构建一个星。

然后,我们可以使用该点阵列来选择用于旋转的轴心点,以及渲染恒星本身。功能如下:

// cx = center x
// cy = center y
// r1 = outer radius
// r2 = inner radius
// spikes = number of star "spikes"
function getStarPoints(cx, cy, r1, r2, spikes) {
  var i = 0,
      deltaAngle = (2 * Math.PI) / spikes,
      x, y,
      points = [];
  // calc rest of points
  for (; i < spikes; i++) {
    points.push(
      {
        x: cx + r2 * Math.cos(deltaAngle * i),               // calc inner point
        y: cy + r2 * Math.sin(deltaAngle * i)
      }, {
        x: cx + r1 * Math.cos(deltaAngle * i + deltaAngle * 0.5), // outer point
        y: cy + r1 * Math.sin(deltaAngle * i + deltaAngle * 0.5)
      }
    );
  }
  return points;
}

现在我们所需要做的就是从数组中选择一个点,它将是一个点对象,并将其用于旋转中心,这里是点索引1:

ctx.translate(points[1].x, points[1].y);   // translate to origin for rotation
ctx.rotate(angle);                         // rotate angle (radians)
ctx.translate(-points[1].x, -points[1].y); // translate back

然后渲染星形

ctx.beginPath();                           // start a new path
ctx.moveTo(points[0].x, points[0].y);      // starting point
for(var i = 1, p; p = points[i++];)
    ctx.lineTo(p.x, p.y);                  // add points to path
ctx.fill();                                // close and fill

注意:如果你想划星星,在划之前需要一个closePath()

就是这样。请参阅下面的片段,了解它的动画版本以及完整的来源。

就性能而言,这将更快,因为我们只计算一次星形,而且在这种情况下,我们不使用保存/恢复(这是一种成本较高的操作)来制作动画。

希望这能有所帮助!

var ctx = document.getElementById('canvas').getContext('2d'),
    points = [],
    angleStep = 0.025;
ctx.fillStyle = 'orange';
// draw first star at angle 0 and get point array
points = getStarPoints(150, 90, 80, 40, 5);
// now that we know the point for each part, lets animate
loop();
function loop() {
  // clear canvas
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  // rotate around one of the points (or anywhere if wanted..)
  ctx.translate(points[1].x, points[1].y);
  ctx.rotate(angleStep);
  ctx.translate(-points[1].x, -points[1].y);
  // draw start
  ctx.beginPath();
  ctx.moveTo(points[0].x, points[0].y);
  for(var i = 1, p; p = points[i++];) ctx.lineTo(p.x, p.y);
  ctx.fill();
  requestAnimationFrame(loop);
}
// Star by Ken Fyrstenberg/CC3.0-Attr
// cx = center x
// cy = center y
// r1 = outer radius
// r2 = inner radius
// spikes = number of star "spikes"
function getStarPoints(cx, cy, r1, r2, spikes) {
  var i = 0,
      deltaAngle = (2 * Math.PI) / spikes,
      x, y,
      points = [];
  // calc rest of points
  for (; i < spikes; i++) {
    points.push(
      {
        x: cx + r2 * Math.cos(deltaAngle * i),
        y: cy + r2 * Math.sin(deltaAngle * i)
      }, {
        x: cx + r1 * Math.cos(deltaAngle * i + deltaAngle * 0.5),
        y: cy + r1 * Math.sin(deltaAngle * i + deltaAngle * 0.5)
      }
    );
  }
  return points;
}
<canvas id="canvas" width=350 height=180></canvas>