我正在寻找一种在画布周围包裹位图图像的方法,以获得无限滚动效果。我正在看EaselJS但是干净的javascript代码也足够了。
现在我正在向左移动图像,当它到达某个标记时,它会自行重置。
来自actionscript,有一个选项可以将位图的像素“包裹”到另一侧,从而永远不会真正替换图像,而是将像素包裹在图像中。这是否可以在带有画布的javascript中使用?
我目前的代码:
this.update = function() {
// super large graphic
_roadContainer.x -= 9;
if(_roadContainer.x < -291) _roadContainer.x = 0;
}
答案 0 :(得分:4)
从良好的风景图像开始。
使用context.scale(-1,1)水平翻转图像。
将翻转的图像合并到原始图像的右侧。
由于我们已完全镜像了图像,因此组合图像的最左侧和右侧完全相同。
因此,当我们平移组合图像并“用完图像”时,我们可以将组合图像的另一个副本添加到右侧,我们可以进行无限+无缝平移。
这是代码和小提琴:http://jsfiddle.net/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.com/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.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() {
requestAnimFrame(pan);
}, 1000 / fps);
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=500 height=143></canvas><br>
</body>
</html>
答案 1 :(得分:2)
使用html5画布可以很容易地实现这一点
请看这里的drawImage规范:
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#drawing-images
drawImage有3种风格,第一种是图像的简单副本,第二种是允许缩放图像,第三种是你寻找的,它允许在一次调用中执行剪切。
你需要做什么:
- 让计数器从零移动到图像的宽度,然后再循环到零
- 每个帧,在画布上绘制最大的图像
- 如果画布的某些部分仍未绘制,则从零开始再次绘制图像以填充画布。
我做了一个小提琴,唯一重要的部分是动画功能(其他东西是我经常在我的小提琴中使用的工具)。
(Rq:我在这个例子中假设两个图像足以填满画布。)
http://jsfiddle.net/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;
答案 2 :(得分:2)
回答我自己的问题:我找到了achieve this effect with EaselJS.的方法。这种方法的好处是你不必检查位图的位置。它将无限滚动 - 无需将位置重置为0。
诀窍是用bitmapfill填充形状。您可以将位图填充设置为无限重复。然后使用Matrix2D来确定bitmapfill的偏移量。由于它会自动重复,因此会产生滚动效果。
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);
}