Shannon
Shannon

Reputation: 17

Pulse animation in canvas

I am trying to make various shapes have a pulse like effect in canvas and managed to do it with a circle,

function drawCircle() {

// color in the background
context.fillStyle = "#EEEEEE";
context.fillRect(0, 0, canvas.width, canvas.height);

// draw the circle
context.beginPath();

var radius = 25 + 20 * Math.abs(Math.cos(angle)); //radius of circle
context.arc(25, 25, radius, 0, Math.PI * 2, false); //position on canvas
context.closePath();

// color in the circle
context.fillStyle = "#006699";
context.fill();

//'pulse'
angle += Math.PI / 220;

requestAnimationFrame(drawCircle);
}
drawCircle();

but I'm not sure how to go about doing any other shape. What I have so far for my triangle is

function drawTriangle() {

// draw the triangle
context.beginPath();
context.moveTo(75, 50);
context.lineTo(100, 75);
context.lineTo(100, 25);
context.fill();

context.rect(215, 100, Math.PI * 2, false); //position on canvas
context.closePath();

// color in the triangle
context.fillStyle = "#3f007f";
context.fill();

//'pulse'
angle += Math.PI / 280;

requestAnimationFrame(drawTriangle);
}
drawTriangle();

Any insight would be appreciated.

Upvotes: 1

Views: 2849

Answers (1)

Kaiido
Kaiido

Reputation: 136776

This can be simply achieved by changing the scale of the context matrix.

All you need to find is the position of the scaling anchor of your shape so that you can translate the matrix to the correct position after the scale has been applied.

In following example, I'll use the center of the shape as scaling anchor, since it seems it is what you wanted.

The extended version of the matrix transformations would be

ctx.translate(anchorX, anchorY);
ctx.scale(scaleFactor, scaleFactor);
ctx.translate(-anchorX, -anchorY);

which in below example has been reduced to

ctx.setTransform(
   scale, 0, 0,
   scale, anchorX  - (anchorX * scale), anchorY  - (anchorY * scale)
);

var ctx = canvas.getContext('2d');
var angle = 0;
var scale = 1;
var img = new Image();
img.src = 'https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png';
anim();


function anim() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  updateScale();
  drawCircle();
  drawTriangle();
  drawImage();
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  requestAnimationFrame(anim);
}

function updateScale() {
  angle += Math.PI / 220;
  scale = 0.5 + Math.abs(Math.cos(angle));
}

function drawCircle() {
  ctx.beginPath();
  var cx = 75,
    cy = 50,
    radius = 25;
  // for the circle, centerX and centerY are given
  var anchorX = cx,
    anchorY = cy;
  // with these anchorX, anchorY and scale, 
  // we can determine where we need to translate our context once scaled
  var scaledX = anchorX - (anchorX * scale),
    scaledY = anchorY - (anchorY * scale);
  // then we apply the matrix in one go
  ctx.setTransform(scale, 0, 0, scale, scaledX, scaledY);
  // and we draw normally
  ctx.arc(cx, cy, radius, 0, Math.PI * 2);
  ctx.fill();
}

function drawTriangle() {
  ctx.beginPath();
  // for the triangle, we need to find the position between minX and maxX,
  // and between minY and maxY
  var anchorX = 175 + (200 - 175) / 2,
    anchorY = 25 + (75 - 25) / 2;
  var scaledX = anchorX - (anchorX * scale),
    scaledY = anchorY - (anchorY * scale);
  ctx.setTransform(scale, 0, 0, scale, scaledX, scaledY);
  ctx.moveTo(175, 50);
  ctx.lineTo(200, 75);
  ctx.lineTo(200, 25);
  ctx.fill();
}

function drawImage() {
  if (!img.naturalWidth) return;
  // for rects, it's just pos + (length / 2)
  var anchorX = 250 + img.naturalWidth / 2,
    anchorY = 25 + img.naturalHeight / 2;
  var scaledX = anchorX - (anchorX * scale),
    scaledY = anchorY - (anchorY * scale);
  ctx.setTransform(scale, 0, 0, scale, scaledX, scaledY);
  ctx.drawImage(img, 250, 25);
}
<canvas id="canvas" width="500"></canvas>

Upvotes: 1

Related Questions