我想在函数 draw1()中保存画布的状态,并在另一个函数 draw2()中恢复它。所以我写了下面的代码。但它不起作用。
<canvas id="canvas" style="width:500px; height:500px;" height="500" width="500"></canvas>
ctx = document.querySelector('#canvas').getContext('2d');
function draw1(){
ctx.save();
ctx.fillRect(25,25,100,100);
}
function draw2(){
ctx.restore();
}
draw1();
draw2();
我猜原因是状态保存在调用堆栈中。因此,在函数返回后,还会清除保存状态。
还有其他方法可以实现我的需求吗?
UPD:背景是我想要实现一个简单的动画,其中大部分都是静态的。我希望使用 setInterval()来执行绘图函数 draw()。在 draw()中,首先恢复画布并绘制剩余的动态部分。
答案 0 :(得分:5)
如果我理解正确你只需要绘制一些静态对象,然后每帧绘制动画对象。
首先,你完全误解了save
和restore
方法,Michael Geary告诉你原因。此外,markE会教您toDataURL
方法,以便随时拍摄画布的快照并保存到图像对象中。这是一个强大的功能,但不是你真正想要的简单动画。
那么,如何使用静态和动态对象创建动画?
有两个主要选择:
我认为最好的选择是2.好的,但我们如何设置这些画布?
使用CSS将所有画布设置为父div
标签内的绝对位置(0,0)。
还可以使用CSS来设置画布的z-index。 z-index属性指定元素的堆栈顺序。具有较低z-index值的项目将落后于具有较高z-index值的项目。
现在我们正确定义了我们的画布,让我们玩吧!
我制作了一个jsFiddle来向您展示如何完成所需的动画。
和那个小提琴中使用的代码:
HTML:
<div id="canvasesdiv">
<canvas id="static" width=400 height=400>This text is displayed if your browser does not support HTML5 Canvas</canvas>
<canvas id="dynamic" width=400 height=400>This text is displayed if your browser does not support HTML5 Canvas</canvas>
</div>
CSS:
#canvasesdiv {
position:relative;
width:400px;
height:300px;
}
#static {
position: absolute;
left: 0;
top: 0;
z-index: 1;
}
#dynamic {
position: absolute;
left: 0;
top: 0;
z-index: 2;
}
使用Javascript:
// static canvas
var static = document.getElementById("static");
var staticCtx = static.getContext("2d");
// dynamic canvas
var dynamic = document.getElementById("dynamic");
var dynamicCtx = dynamic.getContext("2d");
// animation status
var FPS = 30;
var INTERVAL = 1000 / FPS;
// our background
var myStaticObject = {
x: 0,
y: 0,
width: static.width,
height: static.height,
draw: function () {
staticCtx.fillStyle = "rgb(100, 100, 0)";
staticCtx.fillRect(0, 0, static.width, static.height);
}
};
// our bouncing rectangle
var myDynamicObject = {
x: 30,
y: 30,
width: 50,
height: 50,
gravity: 0.98,
elasticity: 0.90,
friction: 0.1,
velX: 10,
velY: 0,
bouncingY: false,
bouncingX: false,
draw: function () { // example of dynamic animation code
// clear the last draw of this object
dynamicCtx.clearRect(this.x - 1, this.y - 1, this.width + 2, this.height + 2);
// compute gravity
this.velY += this.gravity;
// bounce Y
if (!this.bouncingY && this.y >= dynamic.height - this.height) {
this.bouncingY = true;
this.y = dynamic.height - this.height;
this.velY = -(this.velY * this.elasticity);
} else {
this.bouncingY = false;
}
// bounce X
if (!this.bouncingX && (this.x >= dynamic.width - this.width) || this.x <= 0) {
this.bouncingX = true;
this.x = (this.x < 0 ? 0 : dynamic.width - this.width);
this.velX = -(this.velX * this.elasticity);
} else {
this.bouncingX = false;
}
// compute new position
this.x += this.velX;
this.y += this.velY;
// render the object
dynamicCtx.fillStyle = "rgb(150, 100, 170)";
dynamicCtx.fillRect(this.x, this.y, this.width, this.height);
}
};
function drawStatic() {
myStaticObject.draw();
// you can add more static objects and draw here
}
function drawDynamic() {
myDynamicObject.draw();
// you can add more dynamic objects and draw here
}
function animate() {
setInterval(function () {
// only need to redraw dynamic objects
drawDynamic();
}, INTERVAL);
}
drawStatic(); // draw the static objects
animate(); // entry point for animated (dynamic) objects
答案 1 :(得分:2)
您可以使用canvas.toDataURL()
在画布上保存和重新加载像素这是保存:
dataURL=canvas.toDataURL();
这是重装:
var image=new Image();
image.onload=function(){
ctx.drawImage(image,0,0);
}
image.src=dataURL;
如果您需要保存上下文属性(fillStyle等),则必须将它们保存在对象中,并在重新加载像素时将它们重新加载到上下文中。
如果需要保存变换,则必须创建变换矩阵(由6个数字组成的数组)然后,您需要通过操纵变换矩阵来跟踪每个变换。 请参阅此博文:http://blog.safaribooksonline.com/2012/04/26/html5-canvas-games-tracking-transformation-matrices/
此处的代码和小提琴:http://jsfiddle.net/m1erickson/btmLE/
<!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(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.fillRect(25,25,100,100);
var dataURL;
$("#save").click(function(){
dataURL=canvas.toDataURL();
ctx.clearRect(0,0,canvas.width,canvas.height);
});
$("#reload").click(function(){
var image=new Image();
image.onload=function(){
ctx.drawImage(image,0,0);
}
image.src=dataURL;
});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas><br>
<button id="save">Save</button>
<button id="reload">Reload</button>
</body>
</html>
答案 2 :(得分:1)
不,.save()
和.restore()
不会将画布状态保存在JavaScript调用堆栈中。从JavaScript函数返回不会影响该状态 - 它在画布本身中完全保存在该世界之外。
但我认为你可能期望这些功能可以做他们实际做的事情。
它有一个黑色矩形,正如.fillRect()
调用所预期的那样。
您是否认为.restore()
调用会使黑色矩形消失?这不是功能的作用。它不会将画布位图恢复到以前的状态,只会将剪裁区域,笔触和填充样式等其他画布设置恢复。
这是an article that explains some of this。
如果你想保存实际的位图,你需要使用其他方法来做到这一点,也许使用.getImageDataHD()
和.setImageDataHD()
- 我不确定是什么意思最好。