Kendall
Kendall

Reputation: 5255

content scrolling on canvas via mousemovement

I'm trying to implement an infinite background scene scroll that is controlled by the mousemove on a canvas

I have the following in a requestAnimationFrame working almost right

 y1 = y1 >= h? y1 - h : y1; // y1 is the current mouse position on('drag') less the offset  if the position is greater than height of canvas reset with offset
 c.font="20px Georgia";
 c.clearRect(0,0, w, h); // w, h is the width and height of canvas
 c.save();
 //c.translate(0, y1);
 for (var i = 0; i < numImages; i++) { // number of images to be drawn to fill area
    var y = y1 + (i * im.height); // reposition the images relative to mouse position
    y = y >= h? - im.height + y1 : y; // if the image position is off screen then re position to top relative to mouse
    c.drawImage(im, 0, y, im.width, im.height);
 }
 c.fillText("y: " + y,10,190);
 c.restore();

However the problem comes in when I have reached the end of the canvas edges and need to "loop" the image... can't figure out how to reposition the images after going out of view in relation to the mouse position

Any insight on this?

Update:

I'm able to get a continuous scroll but I believe its being messed up by an e.preventDefault on the document element while i'm running the 'touchmove' on the canvas element itself...

Is it safer to run the code on the canvas or the document?

Upvotes: 0

Views: 84

Answers (2)

GameAlchemist
GameAlchemist

Reputation: 19294

Most simple way is to do two passes : one down, one up

 y1 = y1 >= h? y1 - h : y1; // y1 is the current mouse position on('drag') less the offset  if the position is greater than height of canvas reset with offset
 c.font="20px Georgia";
 c.clearRect(0,0, w, h); // w, h is the width and height of canvas
 c.save();
 var cumulatedHeight=0;
 for (var i = 0; i < numImages; i++) { // number of images to be drawn to fill area
    var y = y1 + cumulatedHeight; // reposition the images relative to mouse position
    if (y>h) break;
    c.drawImage(im, 0, y, im.width, im.height);
    cumulatedHeight+= im.height;
 }
 cumulatedHeight=0;
 for (var i = numImage-1; i >=0; i--) { // number of images to be drawn to fill area
    cumulatedHeight+= im.height;
    var y = y1 - cumulatedHeight; // reposition the images relative to mouse position
    if (y+im.height<0) break;
    c.drawImage(im, 0, y, im.width, im.height);        
 }
 c.fillText("y: " + y,10,190);
 c.restore();

(you might notice i started the work in case you want images with different heights : just add

 var im = someImageArray[i];

in each for loop.)

Upvotes: 0

markE
markE

Reputation: 105035

Here's one way of creating an infinite panorama:

  • Create a horizontally mirrored image from your source image.

  • Create an animation loop that draws first the original & then the mirror image to the right of the original image..

  • Panning Visually Rightward: With each loop, offset the images by 1 pixel leftward (offset--). When the offset is the size of original+mirror width, then reset the offset to zero.

  • Panning Visually Leftward: Start with an offset=-(original+mirror width), With each loop, offset the images by 1 pixel rightward (offset++). When the offset is zero, then reset the offset to -(original+mirror).

  • Mouse Control: You can use the mouse-X position to determine to calculate your desired offset (which in turn determines your position within the infinite panorama).

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    
    var infiniteImage;
    var infiniteImageWidth;
    var img=document.createElement("img");
    img.onload=function(){
    
      // use a tempCanvas to create a horizontal mirror image
      // This makes the panning appear seamless when
      // transitioning to a new image on the right
      var tempCanvas=document.createElement("canvas");
      var tempCtx=tempCanvas.getContext("2d");
      tempCanvas.width=img.width*2;
      tempCanvas.height=img.height;
      tempCtx.drawImage(img,0,0);
      tempCtx.save();
      tempCtx.translate(tempCanvas.width,0);
      tempCtx.scale(-1,1);
      tempCtx.drawImage(img,0,0);
      tempCtx.restore();
      infiniteImageWidth=img.width*2;
      infiniteImage=document.createElement("img");
      infiniteImage.onload=function(){
        pan();
      }
      infiniteImage.src=tempCanvas.toDataURL();
    }
    img.crossOrigin="anonymous";
    img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/mountain.jpg";
    
    
    var fps = 60;
    var offsetLeft=0;
    function pan() {
    
      // increase the left offset
      offsetLeft+=1;
      if(offsetLeft>infiniteImageWidth){ offsetLeft=0; }
    
      ctx.drawImage(infiniteImage,-offsetLeft,0);
      ctx.drawImage(infiniteImage,infiniteImage.width-offsetLeft,0);
    
      setTimeout(function() {
        requestAnimationFrame(pan);
      }, 1000 / fps);
    }
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
    <h4>Infinite panorama using mirror image</h4>
    <canvas id="canvas" width=500 height=143></canvas>

Upvotes: 1

Related Questions