Javascript Canvas 内容随着时间的推移变慢
Javascript Canvas Content Get Slow Over Time
这项工作需要一些帮助。基本上我使用 Javascript canvas 来模拟高速公路的道路。请注意,最初一切都很顺利且状况良好。然而,随着时间的推移,内容将不再是顺畅的。
有人知道这里的问题是什么吗?我注意到刷新浏览器确实解决了问题。在那种情况下,我可以知道如何在没有可见刷新的情况下刷新内容吗?
window.requestAnimationFrame = window.requestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.msRequestAnimationFrame
|| function (f) { return setTimeout(f, 1000 / 50) }
window.cancelAnimationFrame = window.cancelAnimationFrame
|| window.mozCancelAnimationFrame
var canvas = document.getElementById("canV"); //obtain the content
var ctx = canvas.getContext("2d");
var angle = 0;
var rect = []; //initialize for predefined width purposes.
var mouse = {
x: 0,
y: 0,
w: 0,
alt: false,
shift: false,
ctrl: false,
buttonLastRaw: 0, // user modified value
buttonRaw: 0,
over: false,
buttons: [1, 2, 4, 6, 5, 3], // masks for setting and clearing button raw bits;
};
function mouseMove(event) {
mouse.x = event.offsetX;
mouse.y = event.offsetY;
if (mouse.x === undefined) {
mouse.x = event.clientX;
mouse.y = event.clientY;
}
mouse.alt = event.altKey;
mouse.shift = event.shiftKey;
mouse.ctrl = event.ctrlKey;
if (event.type === "mousedown") {
event.preventDefault();
//console.log("this is mouse.buttonRaw before (mousedown): " + mouse.buttonRaw);
console.log("this is event.which (mousedown): " + event.which);
var valu = mouse.buttonRaw |= mouse.buttons[event.which - 1]; //bitwise AND operator (convert to binary and do the operation)
//console.log("this is value value: " + value);
} else if (event.type === "mouseup") {
//console.log("this is mouse.buttonRaw before (mouseup): " + mouse.buttonRaw);
//console.log("this is event.which (mouseup): " + event.which);
mouse.buttonRaw &= mouse.buttons[event.which + 2]; //bitwise OR operator (convert to binary and do the operation)
} else if (event.type === "mouseout") {
mouse.buttonRaw = 0;
mouse.over = false;
} else if (event.type === "mouseover") {
mouse.over = true;
} else if (event.type === "mousewheel") {
event.preventDefault();
mouse.w = event.wheelDelta;
} else if (event.type === "DOMMouseScroll") { // FF you pedantic doffus
mouse.w = -event.detail;
}
}
function setupMouse(e) {
//syntax addEventListener (event, function, useCapture)
e.addEventListener('mousemove', mouseMove);
e.addEventListener('mousedown', mouseMove);
e.addEventListener('mouseup', mouseMove);
e.addEventListener('mouseout', mouseMove);
e.addEventListener('mouseover', mouseMove);
e.addEventListener('mousewheel', mouseMove);
e.addEventListener('DOMMouseScroll', mouseMove); // fire fox
e.addEventListener("contextmenu", function(e) {
e.preventDefault();
}, false);
}
setupMouse(canvas);
// terms.
// Real space, real, r (prefix) refers to the transformed canvas space.
// c (prefix), chase is the value that chases a required value
var displayTransform = {
x: 0,
y: 0,
ox: 0,
oy: 0,
scale: 6,
rotate: 0,
cx: 0, // chase values Hold the actual display
cy: 0,
cox: 0,
coy: 0,
cscale: 1,
crotate: 0,
dx: 0, // deltat values
dy: 0,
dox: 0,
doy: 0,
dscale: 1,
drotate: 0,
drag: 0.2, // drag for movements
accel: 0.5, // acceleration
matrix: [0, 0, 0, 0, 0, 0], // main matrix
invMatrix: [0, 0, 0, 0, 0, 0], // invers matrix;
mouseX: 0,
mouseY: 0,
ctx: ctx,
setTransform: function() {
var m = this.matrix;
var i = 0;
this.ctx.setTransform(m[i++], m[i++], m[i++], m[i++], m[i++], m[i++]);
},
setHome: function() {
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
},
update: function() {
// smooth all movement out. drag and accel control how this moves
// acceleration
this.dx += (this.x - this.cx) * this.accel;
console.log("this is dx: " + this.dx);
this.dy += (this.y - this.cy) * this.accel;
this.dox += (this.ox - this.cox) * this.accel;
this.doy += (this.oy - this.coy) * this.accel;
this.dscale += (this.scale - this.cscale) * this.accel;
// drag
this.dx *= this.drag;
this.dy *= this.drag;
this.dox *= this.drag;
this.doy *= this.drag;
this.dscale *= this.drag;
// set the chase values. Chase chases the requiered values
this.cx += this.dx;
this.cy += this.dy;
this.cox += this.dox;
this.coy += this.doy;
this.cscale += this.dscale;
// create the display matrix
this.matrix[0] = Math.cos(this.crotate) * this.cscale;
this.matrix[1] = Math.sin(this.crotate) * this.cscale;
this.matrix[2] = -this.matrix[1];
this.matrix[3] = this.matrix[0];
// set the coords relative to the origin
this.matrix[4] = -(this.cx * this.matrix[0] + this.cy * this.matrix[2]) + this.cox;
this.matrix[5] = -(this.cx * this.matrix[1] + this.cy * this.matrix[3]) + this.coy;
// create invers matrix
var det = (this.matrix[0] * this.matrix[3] - this.matrix[1] * this.matrix[2]);
this.invMatrix[0] = this.matrix[3] / det;
this.invMatrix[1] = -this.matrix[1] / det;
this.invMatrix[2] = -this.matrix[2] / det;
this.invMatrix[3] = this.matrix[0] / det;
// check for mouse. Do controls and get real position of mouse.
if (mouse !== undefined) { // if there is a mouse get the real canvas coordinates of the mouse
if (mouse.oldX !== undefined && (mouse.buttonRaw & 1) === 1) { // check if panning (middle button)
var mdx = mouse.x - mouse.oldX; // get the mouse movement
var mdy = mouse.y - mouse.oldY;
// get the movement in real space
var mrx = (mdx * this.invMatrix[0] + mdy * this.invMatrix[2]);
var mry = (mdx * this.invMatrix[1] + mdy * this.invMatrix[3]);
this.x -= mrx;
this.y -= mry;
}
// do the zoom with mouse wheel
if (mouse.w !== undefined && mouse.w !== 0) {
//this.ox = mouse.x;
//this.oy = mouse.y;
//this.x = this.mouseX;
//this.y = this.mouseY;
/* Special note from answer */
// comment out the following is you change drag and accel
// and the zoom does not feel right (lagging and not
// zooming around the mouse
/*
this.cox = mouse.x;
this.coy = mouse.y;
this.cx = this.mouseX;
this.cy = this.mouseY;
*/
if (mouse.w > 0) { // zoom in
this.scale *= 1.1;
console.log(this.scale);
mouse.w -= 20;
if (mouse.w < 0) {
mouse.w = 0;
}
}
if (mouse.w < 0) { // zoom out
this.scale *= 1/1.1;
mouse.w += 20;
if(this.scale <=0.5){
this.scale = 0.5;
}
if (mouse.w > 0) {
mouse.w = 0;
}
}
}
// get the real mouse position
var screenX = (mouse.x - this.cox);
var screenY = (mouse.y - this.coy);
this.mouseX = this.cx + (screenX * this.invMatrix[0] + screenY * this.invMatrix[2]);
this.mouseY = this.cy + (screenX * this.invMatrix[1] + screenY * this.invMatrix[3]);
mouse.rx = this.mouseX; // add the coordinates to the mouse. r is for real
mouse.ry = this.mouseY;
// save old mouse position
mouse.oldX = mouse.x;
mouse.oldY = mouse.y;
}
}
}
// set up font
ctx.font = "14px verdana";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
// timer for stuff
var timer = 0;
var w = 1000,
h = 500;
setInterval(update, 6);
//requestAnimationFrame(update);
function update() {
timer += 1; // update timer
console.log("this is timer" + timer);
if(timer > 1000){
timer = 0;
console.log("clear");
clearInterval(update);
}
// update the transform
displayTransform.update();
ctx.clearRect(0, 0, canvas.width, canvas.height);
// set home transform to clear the screen
displayTransform.setHome();
ctx.clearRect(0, 0, canvas.width, canvas.height);
displayTransform.setTransform();
ctx.clearRect(0, 0, canvas.width, canvas.height);
//first segment
this.width = 23300;
this.height = 150;
this.x = 0;
this.y = 150;
this.color = "#605A4C"; //light grey (road)
ctx.save(); //save the unrotated context of the canvas
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width / 8, this.height);
ctx.fillStyle = "#DCDCDC"; //white grey
ctx.fillRect(this.x, this.y + ((this.height / 2) - 1), this.width / 8, 2); //middle white line
ctx.fillStyle = "ffffff";
ctx.beginPath();
ctx.setLineDash([2, 6]);
ctx.moveTo(this.x, this.y + ((this.height / 4) - 1));
ctx.lineTo((this.x + this.width / 8), this.y + ((this.height / 4) - 1));
ctx.closePath();
ctx.strokeStyle = "#A09383"; //lighter grey
ctx.lineWidth = 1;
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.setLineDash([2, 6]);
ctx.moveTo(this.x, this.y + ((this.height / (4 / 3)) - 1));
ctx.lineTo((this.x + this.width / 8), this.y + ((this.height / (4 / 3)) - 1));
ctx.closePath();
ctx.strokeStyle = "#A09383"; //lighter grey
ctx.lineWidth = 1;
ctx.fill();
ctx.stroke();
ctx.fillStyle = "#A09383"; //lighter grey
ctx.fillRect(this.x, this.y - 10, this.width / 8, 10);
ctx.fillStyle = "#A09383"; //lighter grey
ctx.fillRect(this.x, this.y + this.height, this.width / 8 + 2 /*a little long to cover up white region)*/ , 10);
//requestAnimationFrame(update);
}
.canC {
width: 100%;
height: 100%;
background-color: rgba(87, 80, 86, 0.5);
}
<div>
<canvas class="canC" id="canV" width="3840" height="2160">
</canvas>
</div>
正如 Ryan 所建议的那样。在更新函数末尾添加 ctx.restore()
解决了我的问题。为了更好地理解此类问题。凯多提供了参考linkHow to delete the state stack for a JavaScript canvas rendering context。
再次感谢您对我的帮助。
这项工作需要一些帮助。基本上我使用 Javascript canvas 来模拟高速公路的道路。请注意,最初一切都很顺利且状况良好。然而,随着时间的推移,内容将不再是顺畅的。
有人知道这里的问题是什么吗?我注意到刷新浏览器确实解决了问题。在那种情况下,我可以知道如何在没有可见刷新的情况下刷新内容吗?
window.requestAnimationFrame = window.requestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.msRequestAnimationFrame
|| function (f) { return setTimeout(f, 1000 / 50) }
window.cancelAnimationFrame = window.cancelAnimationFrame
|| window.mozCancelAnimationFrame
var canvas = document.getElementById("canV"); //obtain the content
var ctx = canvas.getContext("2d");
var angle = 0;
var rect = []; //initialize for predefined width purposes.
var mouse = {
x: 0,
y: 0,
w: 0,
alt: false,
shift: false,
ctrl: false,
buttonLastRaw: 0, // user modified value
buttonRaw: 0,
over: false,
buttons: [1, 2, 4, 6, 5, 3], // masks for setting and clearing button raw bits;
};
function mouseMove(event) {
mouse.x = event.offsetX;
mouse.y = event.offsetY;
if (mouse.x === undefined) {
mouse.x = event.clientX;
mouse.y = event.clientY;
}
mouse.alt = event.altKey;
mouse.shift = event.shiftKey;
mouse.ctrl = event.ctrlKey;
if (event.type === "mousedown") {
event.preventDefault();
//console.log("this is mouse.buttonRaw before (mousedown): " + mouse.buttonRaw);
console.log("this is event.which (mousedown): " + event.which);
var valu = mouse.buttonRaw |= mouse.buttons[event.which - 1]; //bitwise AND operator (convert to binary and do the operation)
//console.log("this is value value: " + value);
} else if (event.type === "mouseup") {
//console.log("this is mouse.buttonRaw before (mouseup): " + mouse.buttonRaw);
//console.log("this is event.which (mouseup): " + event.which);
mouse.buttonRaw &= mouse.buttons[event.which + 2]; //bitwise OR operator (convert to binary and do the operation)
} else if (event.type === "mouseout") {
mouse.buttonRaw = 0;
mouse.over = false;
} else if (event.type === "mouseover") {
mouse.over = true;
} else if (event.type === "mousewheel") {
event.preventDefault();
mouse.w = event.wheelDelta;
} else if (event.type === "DOMMouseScroll") { // FF you pedantic doffus
mouse.w = -event.detail;
}
}
function setupMouse(e) {
//syntax addEventListener (event, function, useCapture)
e.addEventListener('mousemove', mouseMove);
e.addEventListener('mousedown', mouseMove);
e.addEventListener('mouseup', mouseMove);
e.addEventListener('mouseout', mouseMove);
e.addEventListener('mouseover', mouseMove);
e.addEventListener('mousewheel', mouseMove);
e.addEventListener('DOMMouseScroll', mouseMove); // fire fox
e.addEventListener("contextmenu", function(e) {
e.preventDefault();
}, false);
}
setupMouse(canvas);
// terms.
// Real space, real, r (prefix) refers to the transformed canvas space.
// c (prefix), chase is the value that chases a required value
var displayTransform = {
x: 0,
y: 0,
ox: 0,
oy: 0,
scale: 6,
rotate: 0,
cx: 0, // chase values Hold the actual display
cy: 0,
cox: 0,
coy: 0,
cscale: 1,
crotate: 0,
dx: 0, // deltat values
dy: 0,
dox: 0,
doy: 0,
dscale: 1,
drotate: 0,
drag: 0.2, // drag for movements
accel: 0.5, // acceleration
matrix: [0, 0, 0, 0, 0, 0], // main matrix
invMatrix: [0, 0, 0, 0, 0, 0], // invers matrix;
mouseX: 0,
mouseY: 0,
ctx: ctx,
setTransform: function() {
var m = this.matrix;
var i = 0;
this.ctx.setTransform(m[i++], m[i++], m[i++], m[i++], m[i++], m[i++]);
},
setHome: function() {
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
},
update: function() {
// smooth all movement out. drag and accel control how this moves
// acceleration
this.dx += (this.x - this.cx) * this.accel;
console.log("this is dx: " + this.dx);
this.dy += (this.y - this.cy) * this.accel;
this.dox += (this.ox - this.cox) * this.accel;
this.doy += (this.oy - this.coy) * this.accel;
this.dscale += (this.scale - this.cscale) * this.accel;
// drag
this.dx *= this.drag;
this.dy *= this.drag;
this.dox *= this.drag;
this.doy *= this.drag;
this.dscale *= this.drag;
// set the chase values. Chase chases the requiered values
this.cx += this.dx;
this.cy += this.dy;
this.cox += this.dox;
this.coy += this.doy;
this.cscale += this.dscale;
// create the display matrix
this.matrix[0] = Math.cos(this.crotate) * this.cscale;
this.matrix[1] = Math.sin(this.crotate) * this.cscale;
this.matrix[2] = -this.matrix[1];
this.matrix[3] = this.matrix[0];
// set the coords relative to the origin
this.matrix[4] = -(this.cx * this.matrix[0] + this.cy * this.matrix[2]) + this.cox;
this.matrix[5] = -(this.cx * this.matrix[1] + this.cy * this.matrix[3]) + this.coy;
// create invers matrix
var det = (this.matrix[0] * this.matrix[3] - this.matrix[1] * this.matrix[2]);
this.invMatrix[0] = this.matrix[3] / det;
this.invMatrix[1] = -this.matrix[1] / det;
this.invMatrix[2] = -this.matrix[2] / det;
this.invMatrix[3] = this.matrix[0] / det;
// check for mouse. Do controls and get real position of mouse.
if (mouse !== undefined) { // if there is a mouse get the real canvas coordinates of the mouse
if (mouse.oldX !== undefined && (mouse.buttonRaw & 1) === 1) { // check if panning (middle button)
var mdx = mouse.x - mouse.oldX; // get the mouse movement
var mdy = mouse.y - mouse.oldY;
// get the movement in real space
var mrx = (mdx * this.invMatrix[0] + mdy * this.invMatrix[2]);
var mry = (mdx * this.invMatrix[1] + mdy * this.invMatrix[3]);
this.x -= mrx;
this.y -= mry;
}
// do the zoom with mouse wheel
if (mouse.w !== undefined && mouse.w !== 0) {
//this.ox = mouse.x;
//this.oy = mouse.y;
//this.x = this.mouseX;
//this.y = this.mouseY;
/* Special note from answer */
// comment out the following is you change drag and accel
// and the zoom does not feel right (lagging and not
// zooming around the mouse
/*
this.cox = mouse.x;
this.coy = mouse.y;
this.cx = this.mouseX;
this.cy = this.mouseY;
*/
if (mouse.w > 0) { // zoom in
this.scale *= 1.1;
console.log(this.scale);
mouse.w -= 20;
if (mouse.w < 0) {
mouse.w = 0;
}
}
if (mouse.w < 0) { // zoom out
this.scale *= 1/1.1;
mouse.w += 20;
if(this.scale <=0.5){
this.scale = 0.5;
}
if (mouse.w > 0) {
mouse.w = 0;
}
}
}
// get the real mouse position
var screenX = (mouse.x - this.cox);
var screenY = (mouse.y - this.coy);
this.mouseX = this.cx + (screenX * this.invMatrix[0] + screenY * this.invMatrix[2]);
this.mouseY = this.cy + (screenX * this.invMatrix[1] + screenY * this.invMatrix[3]);
mouse.rx = this.mouseX; // add the coordinates to the mouse. r is for real
mouse.ry = this.mouseY;
// save old mouse position
mouse.oldX = mouse.x;
mouse.oldY = mouse.y;
}
}
}
// set up font
ctx.font = "14px verdana";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
// timer for stuff
var timer = 0;
var w = 1000,
h = 500;
setInterval(update, 6);
//requestAnimationFrame(update);
function update() {
timer += 1; // update timer
console.log("this is timer" + timer);
if(timer > 1000){
timer = 0;
console.log("clear");
clearInterval(update);
}
// update the transform
displayTransform.update();
ctx.clearRect(0, 0, canvas.width, canvas.height);
// set home transform to clear the screen
displayTransform.setHome();
ctx.clearRect(0, 0, canvas.width, canvas.height);
displayTransform.setTransform();
ctx.clearRect(0, 0, canvas.width, canvas.height);
//first segment
this.width = 23300;
this.height = 150;
this.x = 0;
this.y = 150;
this.color = "#605A4C"; //light grey (road)
ctx.save(); //save the unrotated context of the canvas
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width / 8, this.height);
ctx.fillStyle = "#DCDCDC"; //white grey
ctx.fillRect(this.x, this.y + ((this.height / 2) - 1), this.width / 8, 2); //middle white line
ctx.fillStyle = "ffffff";
ctx.beginPath();
ctx.setLineDash([2, 6]);
ctx.moveTo(this.x, this.y + ((this.height / 4) - 1));
ctx.lineTo((this.x + this.width / 8), this.y + ((this.height / 4) - 1));
ctx.closePath();
ctx.strokeStyle = "#A09383"; //lighter grey
ctx.lineWidth = 1;
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.setLineDash([2, 6]);
ctx.moveTo(this.x, this.y + ((this.height / (4 / 3)) - 1));
ctx.lineTo((this.x + this.width / 8), this.y + ((this.height / (4 / 3)) - 1));
ctx.closePath();
ctx.strokeStyle = "#A09383"; //lighter grey
ctx.lineWidth = 1;
ctx.fill();
ctx.stroke();
ctx.fillStyle = "#A09383"; //lighter grey
ctx.fillRect(this.x, this.y - 10, this.width / 8, 10);
ctx.fillStyle = "#A09383"; //lighter grey
ctx.fillRect(this.x, this.y + this.height, this.width / 8 + 2 /*a little long to cover up white region)*/ , 10);
//requestAnimationFrame(update);
}
.canC {
width: 100%;
height: 100%;
background-color: rgba(87, 80, 86, 0.5);
}
<div>
<canvas class="canC" id="canV" width="3840" height="2160">
</canvas>
</div>
正如 Ryan 所建议的那样。在更新函数末尾添加 ctx.restore()
解决了我的问题。为了更好地理解此类问题。凯多提供了参考linkHow to delete the state stack for a JavaScript canvas rendering context。
再次感谢您对我的帮助。