admin管理员组

文章数量:1313006

I am looking for a way to wrap a bitmap image around the canvas, for an infinite scrolling effect. I'm looking at EaselJS but clean javascript code will also suffice.

Right now I am displacing an image to the left, and when it reaches a certain mark, it resets itself.

Coming from actionscript, there was an option to "wrap" the pixels of a bitmap around to the other side, thereby never really displacing the image, instead you were wrapping the pixels inside the image. Is this possible in javascript with canvas?

My current code:

this.update = function() {
    // super large graphic  
    _roadContainer.x -= 9;
    if(_roadContainer.x < -291) _roadContainer.x = 0;
}

I am looking for a way to wrap a bitmap image around the canvas, for an infinite scrolling effect. I'm looking at EaselJS but clean javascript code will also suffice.

Right now I am displacing an image to the left, and when it reaches a certain mark, it resets itself.

Coming from actionscript, there was an option to "wrap" the pixels of a bitmap around to the other side, thereby never really displacing the image, instead you were wrapping the pixels inside the image. Is this possible in javascript with canvas?

My current code:

this.update = function() {
    // super large graphic  
    _roadContainer.x -= 9;
    if(_roadContainer.x < -291) _roadContainer.x = 0;
}
Share Improve this question asked Nov 28, 2013 at 10:45 KokodokoKokodoko 28.2k36 gold badges132 silver badges205 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 5

Start with a good landscape image.

Flip the image horizontally using context.scale(-1,1).

Combine the flipped image to the right side of the original image.

Because we have exactly mirrored the images, the far left and right sides of the bined image are exactly the same.

Therefore, as we pan across the bined image and “run out of image”, we can just add another copy of the bined image to the right side and we have infinite + seamless panning.

Here's code and a Fiddle: http://jsfiddle/m1erickson/ywDp5/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery./jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>

<script>
$(function(){

    // thanks Paul Irish for this RAF fallback shim
    window.requestAnimFrame = (function(callback) {
      return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
      function(callback) {
        window.setTimeout(callback, 1000 / 60);
      };
    })();


    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./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() {
            requestAnimFrame(pan);
        }, 1000 / fps);
    }

}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=500 height=143></canvas><br>
</body>
</html>

You can achieve this quite easily with the html5 canvas.
Look at the drawImage specification here :
http://www.whatwg/specs/web-apps/current-work/multipage/the-canvas-element.html#drawing-images

drawImage es in 3 flavors, the first being a simple copy of the image, the second allowing to scale the image, and the third is the one you seek, it allows to perform clipping in a single call.

What you have to do :
- have a counter that will move from zero to the width of your image, then loop to zero again.
- each frame, draw the maximum of the image that you can on the canvas.
- If there is still some part of the canvas not drawn, draw again the image starting from zero to fill the canvas.

i made a fiddle, the only part that matters is in the animate function (other things are tools i often use in my fiddles).
(Rq : I assumed in this example that two images would be enough to fill the canvas.)

http://jsfiddle/gamealchemist/5VJhp/

var startx = Math.round(startPos);
var clippedWidth = Math.min(landscape.width - startx, canvasWidth);

// fill left part of canvas with (clipped) image.
ctx.drawImage(landscape, startx, 0, clippedWidth, landscape.height,
0, 0, clippedWidth, landscape.height);

if (clippedWidth < canvasWidth) {
    // if we do not fill the canvas
    var remaining = canvasWidth - clippedWidth;
    ctx.drawImage(landscape, 0, 0, remaining, landscape.height,
    clippedWidth, 0, remaining, landscape.height);
}
// have the start position move and loop
startPos += dt * rotSpeed;
startPos %= landscape.width;

To answer my own question: I found a way to achieve this effect with EaselJS. The great benefit of this method is that you don't have to check for the position of your bitmap. It will scroll infinitely - without ever resetting the position to 0.

The trick is to fill a shape with a bitmapfill. You can set a bitmapfill to repeat infinitely. Then you use a Matrix2D to decide the offset of the bitmapfill. Since it repeats automatically, this will generate a scrolling effect.

function.createRoad() {
    // road has a matrix, shape and image
    _m = new createjs.Matrix2D();
    // this gets the image from the preloader - but this can be any image
    _r = queue.getResult("road");
    // this creates a shape that will hold the repeating bitmap
     _roadshape = new createjs.Shape();
    // put the shape on the canvas
    addChild(_roadshape);
}
//
// the draw code gets repeatedly called, for example by requestanimationframe
//
function.drawRoad() {
    // var _speed = 4;
    _m.translate(-_speed, 0);
    _roadshape.graphics.clear().beginBitmapFill(_r, "repeat", _m).rect(0, 0, 900, 400);
}

本文标签: javascriptMake a bitmap wrap around the canvas for infinite scrollingStack Overflow