How to scale a canvas image larger and smaller in a continuous loop?

I created a cloud shape in canvas, and I'm wondering how I can scale the shape back and forth between larger and smaller. Like I want the cloud to get bigger, than smaller, then bigger then smaller, etc.

I was able to be able to move a separate canvas image up and down using a when-then method, but I don't think that method will work by increasing the canvas size because the actual image stays to scale.

Here is my canvas code:

<script>
var canvas = document.getElementById('hardware-cloud');
var context = canvas.getContext('2d');

// begin cloud shape-Hardware
context.beginPath();
context.moveTo(180, 80);
context.bezierCurveTo(150, 132, 143, 165, 203, 154);
context.bezierCurveTo(203, 154, 180, 200, 260, 175);
context.bezierCurveTo(297, 231, 352, 198, 344, 185);
context.bezierCurveTo(344, 185, 372, 215, 374, 175);
context.bezierCurveTo(473, 165, 462, 132, 429, 110);
context.bezierCurveTo(473, 44, 407, 33, 374, 55);
context.bezierCurveTo(352, 10, 275, 22, 275, 55);
context.bezierCurveTo(210, 20, 165, 22, 180, 80);

// complete cloud shape-Hardware
context.closePath();
context.lineWidth = 5;
context.strokeStyle = 'navy';
context.stroke();
context.fillStyle = 'white';
context.fill();

//font inside hardware cloud
context.beginPath();
context.font = 'bold 15pt Calibri';
context.textAlign = 'center';
context.fillStyle ="navy";  // <-- Text colour here
context.fillText('Why not the electronic store?', 300, 120);
context.lineWidth = 2;
context.strokeStyle = 'grey';
context.stroke();
context.closePath();

//top  hardware circle
context.beginPath();
context.arc(380, 220, 13, 0, Math.PI * 2, false);
context.lineWidth = 5;
context.strokeStyle = 'navy';
context.stroke();
context.fillStyle = 'white';
context.fill();
context.closePath();

//middle hardware circle
context.beginPath();
context.arc(398, 253, 10, 0, Math.PI * 2, false);
context.lineWidth = 5;
context.strokeStyle = 'navy';
context.stroke();
context.fillStyle = 'white';
context.fill();
context.closePath();

//bottom hardware circle
context.beginPath();
context.arc(425, 273, 7, 0, Math.PI * 2, false);
context.lineWidth = 5;
context.strokeStyle = 'navy';
context.stroke();
context.fillStyle = 'white';
context.fill();
context.closePath();
</script>

And here is my attempt at the jQuery. The first part of it is to get the div region to slide into view. The second part is an attempt to scale up and down.:

$(document).ready(function(){
$('#hardware').hide();
$('#hardware').show("slide", {direction: "left"}, 400 );

ani();
function ani(){
$.when(
$('#hardware-cloud').effect({
scale: "120"},700),
   $('#hardware-cloud').effect({
scale: "100"},700)
.then(ani));}
});

Answers


You can use scale and translate to change the size of the shape.

All transforms works for the next drawn shape and doesn't affect already drawn shapes.

So for it to work you'll need to clear the canvas, transform and then redraw the shape.

For example, re-factor the code so that you can call shape() to draw the cloud, then:

  • Clear canvas ctx.clearRect(0, 0, canvas.width, canvas.height);
  • Apply scale ctx.scale(scaleX, scaleY);
  • Optionally translate the shape using ctx.translate(deltaX, deltaY);
  • Redraw shape shape();
  • Repeat using for example requestAnimationFrame() in a loop.

Scale value is 1 = 1:1, 0.5 = half etc. Just remember these transforms are accumulative (you can use setTransform() to set absolute transforms each time).

Update

Here is one way you can do this:

var maxScale = 1,  // for demo, this represents "max"
    current = 0,   // angle (in radians) used to scale smoother
    step = 0.02,   // speed
    pi2 = Math.PI; // cached value

// main loop clears, transforms and redraws shape
function loop() {
    context.clearRect(0, 0, canvas.width, canvas.height);
    transform();
    drawShape();
    requestAnimationFrame(loop);
}
requestAnimationFrame(loop);

// set scale based on rotation
function transform() {
    current += step;
    current %= pi2;

    // just play around with different combinations here
    var s = (maxScale * Math.abs(Math.sin(current))) / maxScale + 0.5;

    // set absolute scale
    context.setTransform(s, 0, 0, s, 0, 0);
}

// wrap shape calls in a function so it can be reused
function drawShape() {
    // begin cloud shape-Hardware
    context.beginPath();
    ... rest goes here...
Online demo

In addition you can use translate() to re-position the shape linked to the rotation value.

Hope this helps!


Need Your Help

How to allocate memory for new structure?

c++ pointers struct linked-list structure

I'm trying to allocate the memory for a new linked list within the constructor of a class, but when I try to compile it, I get some weird message.

Setting up Git Server on Windows With git-http-backend.exe

git apache2 git-http-backend

I am in the process of setting up a Git server (1.7.2.3) on a WS 2008 machine using Apache and git-http-backend.exe. I have been following a good tut here. I have the GUI working, I can annoymously