4m1r
4m1r

Reputation: 12542

Drawing a repeating sinusoidal wave with canvas api

I'm trying to get an image to flow horizontally in a sinusoidal fashion, and repeat seamlessly when it gets to the end of its own width in relation to its canvas size.

So far, I've got the image repeating and waving, but there is a significant jump when the x axis needs to be reset.

I think the problem is here:

 if (x > canvasX) {
            console.log('reset!!');
            x = canvasX-imgW;
            y = sineY(x);
        }
        //draw aditional image
        if (x > (canvasX-imgW)) {
            var ax = x-imgW+dx;
            y =  sineY(ax);
            ctx.drawImage(img,ax,y,imgW,imgH);
        }

Ultimately, what happens is that the sineY of the reset x value is about 19 degrees off of what it should be at the end of its regular period where the x value is highest. However, I can't really figure out how to adjust the bounds to make the movement seamless through the multiple periods.

Here's the fiddle: http://jsfiddle.net/3L7Dp/

Upvotes: 2

Views: 467

Answers (2)

ErikE
ErikE

Reputation: 50201

One way is to declare an offset by which x will be adjusted, such as var xOffset = 0. When calculating the sine, use x + xOffset. Every time you do x -= imgW, update the offset based on the current offset and the image width, so that the sin at the new position will equal the sin at the current position.

Doing this will allow you to have any period, even one unrelated to the width of your image.

I made my own version of your page with many simplifications, you can see it in this JsFiddle. The sine wave is seamless. My implementation also supports images much narrower than the canvas--they will be repeated all the way across, always filling the canvas (try img.width = 100 in my JsFiddle to see what I mean). In my function, since I based the period on a certain number of x-pixels, my xOffset recalculation is simplified and I can simply use modulus to calculate the new offset after subtracting from x.

Some style considerations I would like to suggest are:

  • Use more consistent variable names (such as context vs. ctx--if both are truly needed, give them prefixes such as baseContext, canvasContext so that context is consistent throughout the code).
  • Name variables closer to what they represent (for example, canvasX is not a good variable name for canvas.Width.
  • Don't be afraid of slightly longer variable names. imgW is less clear than imageWidth. W doesn't always mean width.
  • Put spaces after commas and the word function, and around operators.
  • Using parameter x in your sineY function is confusing as x is already declared outside.

Parameterizing your animation function is fine, but just as good is to wrap the entire script in a SEAF (self-executing anonymous function), as that properly gives all the variables a scope (keeping them out of global scope), thus simplifying your code by not having to pass around the variables.

Upvotes: 1

user1693593
user1693593

Reputation:

The period variable needs to be normalized based on the total distance x will move.

In this case x will go image.width so period must be:

var period = x / imgW;  //period must be a value in the range [0.0, 1.0]

This should give an usable value for cycling the image.

Modified fiddle

Hope this helps!

Upvotes: 2

Related Questions