[英]how can i optimize this javascript code for canvas html5 to make it run smooth in firefox?
我有一個很大的問題,當我在Firefox中的畫布html5中運行此javascript代碼時,它嚴重滯后並且圖像閃爍,但是在谷歌瀏覽器和Internet Explorer中,性能會更好。 我真的需要該程序,所以我不會迷路。 該代碼是關於彈丸運動的。 我需要提及的是我需要即時通訊所使用的條件。 (注意:我制作的javascript中有一個fence函數,使Firefox滯后到凍結的程度)
這是我的html:
<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html>
<head>
<link href="img/logo-ute.ico" type="image/x-icon" rel="shortcut icon" />
<title>Simulacion</title>
<meta charset="windows-1252">
<link href="css/estilo.css" rel="stylesheet" type="text/css"/>
<link href="css/style.css" rel="stylesheet" type="text/css"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="js/mp2.js"></script>
<script type="text/javascript" src="js/jquery-2.1.4.min.js"></script>
</head>
<body>
<div class="contenedor">
<div class="encabezado">
<div class="contenedor2">
<div id="imagenes">
<img id="img" src="img/logo_facu.png" width="500" height="200"/>
<img id="img2" src="img/logo-ute.jpg" width="200" height="200"/>
</div>
</div>
<div class="contenedor3">
<h2>SIMULACIÓN</h2>
<section id="cajalienzo">
<canvas id="lienzo" width=1000 height=500>
El navegador no soporta canvas
</canvas>
</section>
<div id="seccion">
<div id="simular">
<form id="inicio_sim">
<div>
<label>Angulo de Elevación: </label><input id="angulo" type="number" name="angulo" min="1" max="90" value="45" style="width:50px" maxlength="10" onkeypress="return justNumbers(event);"><span> º</span>
<label> Velocidad Inicial: </label><input id="velocidadin" type="number" name="velocidad" min="20" max="100" value="50" step="0.5" style="width:50px" maxlength="10" onkeypress="return justNumbers2(event);"><span> m/s</span></br>
</div>
<div id="botones_sim">
<button id="pausar" name="btnpausar" type="button" value="pausar" onclick="fun_pausar()"><span class="iconic icon-pause2"></span> PAUSAR </button>
<button id="iniciar" name="btniniciar" type="button" value="iniciar" onclick="fun_simular()"><span class="iconic icon-play3"></span> INICIAR </button>
<button id="reiniciar" name="btnReiniciar" type="button" value="reiniciar" onclick="fun_reiniciar()"><span class="iconic icon-spinner11"></span> REINICIAR </button>
</div>
</form>
</div>
</div>
<div id="mostrar">
<form id="resultado">
<div>
<label>Posicion-x: </label><input id="posx" type="text" readonly name="distancia-horizontal" value="0.00"><span> m</span>
<label> Velocidad-x: </label><input id="vx" type="text" readonly name="velocidad en x" value="0.00" autocomplete="off"><span> m/s</span>
</div>
<div>
<label>Posicion-y: </label><input id="posy" type="text" readonly name="distancia-vertical" value="0.00"><span> m</span>
<label> Velocidad-y: </label><input id="vy" type="text" readonly name="velocidad en y" value="0.00"><span> m/s</span>
<label>Tiempo: </label><input id="tiempo" type="text" readonly name="tiempo" value="0.00"><span> s</span>
</div>
</form>
<h1></h1>
<div id="botones">
<ul>
<li><a id="regresar" href="Teoria.html"><span class="iconic icon-circle-left"></span> ANTERIOR PAGINA</a></li>
<li><a id="seguir" href="Bibliografia.html"><span class="iconic icon-circle-right"></span> SIGUIENTE PAGINA</a></li>
</ul>
<h1></h1>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
這是我的javascript:
var canvas;
var context;
var tiempo = 0;
var tiempo2 = 999999;
var temp;
var temp2;
var x2;
var y2;
var angulogrados;
var x;
var y;
//Detects the browswer to skip the fence function in firefox
function navegador(){
c=navigator.userAgent.search("Chrome");
f=navigator.userAgent.search("Firefox");
m8=navigator.userAgent.search("MSIE 8.0");
m9=navigator.userAgent.search("MSIE 9.0");
if (c>-1){
brwsr = "Chrome";
context.save();
sombras2();
cerca();
context.restore();
}
else if(f>-1){
if(temp2==true)
{
brwsr = "Firefox";
temp2=false;
}
}else if (m9>-1){
brwsr ="MSIE 9.0";
context.save();
sombras2();
cerca();
context.restore();
}else if (m8>-1){
brwsr ="MSIE 8.0";
context.save();
sombras2();
cerca();
context.restore();
}
else
{
context.save();
sombras2();
cerca();
context.restore();
}
}
//loads this functions first
window.onload=fun_iniciar;
function fun_iniciar(){
//objeto canvas
canvas = document.getElementById("lienzo");
//crea un conexto del objeto canvas
context = canvas.getContext("2d");
temp2=true;
//llama a la funcion que dibuja el fondo del canvas
fondo();
// puntos de iniclizacion del proyectil
x=25;
y=canvas.height-20;
//calls the functions to draw the vectors and calculate the proyectile speed and position
dibupun(0,0);
//inicializa los valores
angulogrados=0;
velocidad=0;
//tiempo real
intervalo=50;
tiempo=intervalo/1000;
y1=0;
vx=0;
vxy=0;
vy=0;
x2=20;
y2=80;
document.getElementById("reiniciar").disabled = true;
}
//se activa cuando el boton inicar se aplasta
function fun_simular(){
document.getElementById("reiniciar").disabled = false;
// se hace una repetecion de la funcion fun_play
interval=setInterval(fun_play,intervalo);
}
// aqui se va a dar todos los calculos para dibujar el proyectil
function fun_play(){
//llama a la funcion que dibuja el fondo del canvas
fondo();
//desavilita los comando de insertar un ganulo y la velocidad a que no cambie la trayectoria durante la simulacion
document.getElementById("angulo").setAttribute("disabled","true");
document.getElementById("velocidadin").setAttribute("disabled","true");
//extrae el angulo y la velocidad
angulogrados=document.getElementById("angulo").value;
anguloradianes=angulogrados*Math.PI/180;
velocidadi=document.getElementById("velocidadin").value;
//calcula las velocidades iniciales en x,y
velocidadiy=velocidadi*Math.sin(anguloradianes);
velocidadix=velocidadi*Math.cos(anguloradianes);
//calcula las pox- y la pos-y
x=(velocidadi*Math.cos(anguloradianes)*tiempo)+25;
y1=((velocidadiy*tiempo)+((0.5)*(-9.81)*(Math.pow(tiempo,2))));
//calcula la pos-y para ubicarla en el canvas
y=(-y1-25)+canvas.height;
//calcula la velocidad final en y la velocidad final en x es la velocidad inicial en x
velocidadfy=velocidadiy+((-9.81)*tiempo);
// devuelve los resultados de la posicion y la velocidad
document.getElementById("posx").value=((x-25.00).toFixed(2));
if(y1<0)
{
document.getElementById("posy").value=((0).toFixed(2));
}
else
{
document.getElementById("posy").value=((y1).toFixed(2));
}
document.getElementById("vx").value=velocidadix.toFixed(2);
document.getElementById("vy").value=velocidadfy.toFixed(2);
document.getElementById("tiempo").value =(tiempo).toFixed(2);
// la animacion se detiene cuando la altura es negativa o 0
if(y1<=0)
{
document.getElementById("angulo").removeAttribute("disabled");
document.getElementById("velocidadin").removeAttribute("disabled");
window.clearInterval(interval);
tiempo2=tiempo;
temp=true;
}
document.getElementById("iniciar").disabled = true;
//adds the time
tiempo=tiempo+0.05;
//manda a dibujar con los valores calculados
dibupun(velocidadix,velocidadfy);
}
//draws the background
function fondo()
{
var imageObj2 = new Image();
imageObj2.onload = function() {
context.moveTo(0, 0);
context.drawImage(imageObj2, 0, 0, canvas.width, canvas.height);
};
imageObj2.src = 'https://i.ytimg.com/vi/aErlwl1hEHw/sddefault.jpg';
var cloud = new Image();
cloud.onload = function(){
context.moveTo(0, 0);
context.drawImage(cloud, 0, 0, canvas.width/2.1, canvas.height/2);
};
cloud.src = 'http://silveiraneto.net/wp-content/uploads/2011/06/cloud.png';
}
function sombras()
{
context.shadowOffsetY = 25;
context.shadowOffsetX = 20;
context.shadowBlur = 0.5;
context.shadowBlur = 0.5;
context.shadowColor = 'rgba(50, 50, 50, 0.6)';
}
function sombras2()
{
context.shadowOffsetY = 25;
context.shadowOffsetX = 20;
context.shadowBlur = 0.5;
context.shadowBlur = 0.5;
context.shadowColor = 'rgba(50, 50, 50, 0.1)';
}
function sombras3()
{
context.shadowOffsetY = 25;
context.shadowOffsetX = 20;
context.shadowBlur = 0.5;
context.shadowBlur = 0.5;
context.shadowColor = 'rgba(50, 50, 50, 0)';
}
function dibujar_calc()
{
context.beginPath();
context.font = "15pt Calibri";
context.fillStyle = "white";
context.textAlign = "center";
context.textBaseline = "middle";
}
//pausa la animacion
function fun_pausar(){
window.clearInterval(interval);
document.getElementById("iniciar").disabled = false;
}
//draws the vectors
function dibupun(vx,vy){
context.clearRect(0, 0, canvas.width, canvas.height);
var imageObj = new Image();
imageObj.onload = function() {
context.moveTo(x, y);
context.save();
trazaraltura(vy);
context.restore();
context.save();
sombras3();
velocidadx(vx, vy);
context.restore();
context.save();
sombras3();
velocidady(vy);
context.restore();
navegador();
context.save();
context.beginPath();
flechay(vy);
flechax(vx, vy);
flechaxy(vx, vy);
context.fillStyle = "white";
context.fill();
context.lineWidth = 2;
context.strokeStyle = "blue";
context.stroke();
context.restore();
if((x>900 && tiempo>11) || (x>900))
{
context.drawImage(imageObj, canvas.width-100-14, y-14, 30, 30);
}
else
{
context.drawImage(imageObj, x-14, y-14, 30, 30);
}
};
imageObj.src = 'http://www.dpcdsb.org/NR/rdonlyres/132B2859-0F1F-42F6-BE18-A151ABF439BE/105710/basketball.png';
sombras();
}
//draws the arrow in x
function flechax(vx, vy){
context.lineWidth = 5;
if((x>canvas.width-100 && tiempo>11) || (x>canvas.width-100))
{
context.moveTo(canvas.width-100, y);
context.lineTo(canvas.width-100+vx, y);
context.lineTo(canvas.width-100+vx-10, -5+y);
context.lineTo(canvas.width-100+vx-10, 5+y);
context.lineTo(canvas.width-100+vx, y);
context.fill();
}
else
{
context.moveTo(x, y);
context.lineTo(x+vx, y);
context.lineTo(x+vx-10, -5+y);
context.lineTo(x+vx-10, 5+y);
context.lineTo(x+vx, y);
context.fill();
}
}
//draws arrow in y
function flechay(vy){
context.lineWidth = 5;
if((x>canvas.width-100 && tiempo>11) || (x>canvas.width-100))
{
context.moveTo(canvas.width-100, y);
}
else
{
context.moveTo(x, y);
}
if((x>canvas.width-100 && tiempo>11) || (x>canvas.width-100))
{
if(vy>0)
{
context.lineTo(canvas.width-100, y-vy);
context.lineTo(-5+canvas.width-100, y-vy+10);
context.lineTo(5+canvas.width-100, y-vy+10);
context.lineTo(canvas.width-100, y-vy);
}
else if(vy<0)
{
context.lineTo(canvas.height+400, y-vy);
context.lineTo(-5+canvas.height+400, y-vy-10);
context.lineTo(5+canvas.height+400, y-vy-10);
context.lineTo(canvas.height+400, y-vy);
}
}
else
{
if(vy>0)
{
context.lineTo(x, canvas.height-vy-y1-25);
context.lineTo(-5+x, canvas.height-vy-y1-15);
context.lineTo(5+x, canvas.height-vy-y1-15);
context.lineTo(x, canvas.height-vy-y1-25);
}
else if(vy<0)
{
context.lineTo(x, y-vy);
context.lineTo(-5+x, y-vy-10);
context.lineTo(5+x, y-vy-10);
context.lineTo(x, y-vy);
}
}
context.fill();
}
//draws an arrow in xy(I cant make it work correctly)
function flechaxy(vx, vy){
context.lineWidth = 5;
if((x>canvas.width-100 && tiempo>11) || (x>canvas.width-100))
{
context.moveTo(canvas.width-100, y);
context.lineTo(canvas.width-100+vx, y);
context.lineTo(canvas.width-100+vx-10, -5+y);
context.lineTo(canvas.width-100+vx-10, 5+y);
context.lineTo(canvas.width-100+vx, y);
context.fill();
}
else
{
if(vy>0)
{
if(y>0)
{
context.moveTo(x, y);
context.lineTo(x+x2, y-vx+5-y2+vy);
context.lineTo(x+x2-5, y-vx-5-y2+vy);
context.lineTo(x+x2+5, y-vx-5-y2+vy);
context.lineTo(x+x2, y-vx+5-y2+vy);
context.fill();
x2=x2+0.35;
y2=y2-1.5;
}
}
else if(vy<0)
{
if(y>0)
{
context.moveTo(x, y);
context.lineTo(x+x2, y+vx+y2-vy);
context.lineTo(x+x2+5, y+vx-10+y2-vy);
context.lineTo(x+x2-5, y+vx-10+y2-vy);
context.lineTo(x+x2, y+vx+y2-vy);
context.fill();
x2=x2-0.35;
y2=y2+1.5;
}
}
}
}
//draws the fences (in firefox this gets ignored because the code lags so much that it doesnt run)
function cerca(){
context.lineWidth = 5;
context.beginPath();
if((x>canvas.width-100 && tiempo>11) || (x>canvas.width-100))
{
context.moveTo(canvas.width, y);
}
else
{
context.moveTo(x, y);
}
if((x>canvas.width-100 && tiempo>11) || (x>canvas.width-100))
{
for(i=0;i<canvas.width-199;i+=200)
{
context.fillStyle = "#A4A4A4";
context.fill();
context.lineWidth = 2;
context.strokeStyle = "#A4A4A4";
context.rect(-x+i+canvas.width+90, 420, 10, 80);
if(i>canvas.width-200)
{
context.globalAlpha=0;
context.rect(-x+i+canvas.width+90, 420, 10, 80);
}
}
context.beginPath();
for(i=0;i<canvas.width-399;i+=200)
{
context.fillStyle = "#0B614B";
context.fill();
context.lineWidth = 2;
context.strokeStyle = "#0B614B";
context.rect(-x+i+canvas.width+100, 430, 190, 5);
context.rect(-x+i+canvas.width+100, 450, 190, 5);
context.rect(-x+i+canvas.width+100, 470, 190, 5);
if(i>=canvas.width-400)
{
context.globalAlpha=0;
context.fillRect(-x+i+canvas.width+100, 430, 190, 5);
context.fillRect(-x+i+canvas.width+10, 450, 190, 5);
context.fillRect(-x+i+canvas.width+10, 470, 190, 5);
}
}
}
else
{
for(i=0;i<canvas.width-199;i+=200)
{
context.fillStyle = "#A4A4A4";
context.fill();
context.lineWidth = 2;
context.strokeStyle = "#A4A4A4";
context.rect(i+210, 420, 10, 80);
if(i>canvas.width-200)
{
context.globalAlpha=0;
context.rect(i+210, 420, 10, 80);
}
}
context.beginPath();
for(i=0;i<canvas.width-399;i+=200)
{
context.fillStyle = "#0B614B";
context.fill();
context.lineWidth = 2;
context.strokeStyle = "#0B614B";
context.rect(i+220, 430, 190, 5);
context.rect(i+220, 450, 190, 5);
context.rect(i+220, 470, 190, 5);
if(i>=canvas.width-400)
{
context.globalAlpha=0;
context.fillRect(i+220, 430, 190, 5);
context.fillRect(i+220, 450, 190, 5);
context.fillRect(i+220, 470, 190, 5);
}
}
}
context.stroke();
}
//shows the x velocity along with y position and x position in the canvas
function velocidadx(vx, vy){
if(tiempo > 0.1)
{
dibujar_calc();
ancho2=x-25.00;
altura2=canvas.height-y-20.00;
if((x>canvas.width-200 && tiempo>11) || (x>canvas.width-200))
{
if(tiempo > tiempo2-0.001)
{
trazaraltura(vy);
context.fillText("Posicion-y: "+(0).toFixed(2)+" m", canvas.width-210+100, y-100);
}
else
{
trazaraltura(vy);
context.fillText("Posicion-y: "+altura2.toFixed(2)+" m", canvas.width-210+100, y-100);
}
context.fillText("Posicion-x: "+ancho2.toFixed(2)+" m", canvas.width-210+100, y-130);
context.fillText("Vx: "+vx.toFixed(2)+" m/s", canvas.width-210+100, y-40)
}
else
{
if(temp==true)
{
trazaraltura(vy);
context.fillText("Posicion-y: "+(0).toFixed(2)+" m", x+100, y-100);
}
else
{
context.fillText("Posicion-y: "+altura2.toFixed(2)+" m", x+100, y-100);
}
context.fillText("Posicion-x: "+ancho2.toFixed(2)+" m", x+100, y-130);
context.fillText("Vx: "+vx.toFixed(2)+" m/s", x+100, y-40)
}
}
}
//shows the y velocity in the canvas
function velocidady(vy){
if(tiempo > 0.1)
{
dibujar_calc();
if((x>canvas.width-200 && tiempo>11) || (x>canvas.width-200))
{
context.fillText("Vy: "+vy.toFixed(2)+" m/s", canvas.width-210+100, y-70);
}
else
{
context.fillText("Vy: "+vy.toFixed(2)+" m/s", x+100, y-70);
}
}
}
//draws the red lines that follow the projectile
function trazaraltura(vy){
context.beginPath();
context.lineWidth = 1;
context.strokeStyle = "red";
context.moveTo(x, y);
altura=parseInt(y);
alcance=parseInt(x);
if(tiempo > 0.1)
{
if((x>canvas.width-100 && tiempo>11) || (x>canvas.width-100))
{
for (i=altura;i<canvas.height;i+=5)
{
if((i%2)!==0)
{
context.lineTo(canvas.width-100,i);
}
else
{
context.moveTo(canvas.width-100,i+10);
}
}
for (i=0;i<alcance;i+=5)
{
if((i%2)!==0)
{
context.lineTo(i,y);
}
else
{
context.moveTo(i+10,y);
}
}
}
else
{
for (i=altura;i<canvas.height;i+=5)
{
if((i%2)!==0)
{
context.lineTo(x,i);
}
else
{
context.moveTo(x,i+10);
}
}
for (i=0;i<alcance;i+=5){
if((i%2)!==0)
{
context.lineTo(i,y);
}
else
{
context.moveTo(i+10,y);
}
}
}
}
context.stroke();
}
//hace que solo se pueda meter numeros en el campo de angulo y velocidad
function justNumbers(e)
{
var keynum = window.event ? window.event.keyCode : e.which;
if ((keynum == 8) || (keynum == 46))
return true;
return /\d/.test(String.fromCharCode(keynum));
}
// reinicia la animacion cuando aplasta el boton reinciar
function fun_reiniciar(){
document.getElementById("angulo").removeAttribute("disabled");
document.getElementById("velocidadin").removeAttribute("disabled");
document.getElementById("posx").value ="";
document.getElementById("posy").value ="";
document.getElementById("vx").value ="";
document.getElementById("vy").value ="";
document.getElementById("tiempo").value ="";
context.clearRect(0, 0, canvas.width, canvas.height);
window.clearInterval(interval);
temp=false;
document.getElementById("iniciar").disabled = false;
fun_iniciar();
}
使用諸如rect,arc,moveTo,lineTo等繪圖功能總是很慢。 您需要做的是將所有不會改變形狀和顏色的位繪制到圖像上,然后繪制圖像,而不要使用繪制功能。
創建可繪制的圖像。
創建可以繪制的圖像很容易。 只需創建畫布並將上下文附加到畫布即可。 這樣創建的圖像與圖像一樣快,並且可以非常快速地繪制到主畫布上
var createImage = function(width, height){ // create a drawable image
var image = document.createElement("canvas");
image.width = width;
image.height = height;
image.ctx = image.getContext("2d"); // create the context and attach it to the image
return image;
}
渲染到圖像
要渲染圖像,就像處理任何畫布一樣
var fencePost = createImage(100,400);
fencePost.ctx.fillStyle ="White";
fencePost.ctx.strokeStyle ="Black";
fencePost.ctx.beginPath();
// the drawing stuff
fencePost.ctx.fill();
fencePost.ctx.stroke();
要將圖像繪制到主畫布上,只需像其他圖像一樣進行即可。
var fenceWidth = 400;
// ctx is the main canvas.
for(var i = 0; i < ctx.canvas.width; i += fenceWidth){
ctx.drawImage(fencePost, i , 400);
}
您還具有僅更改一張圖像的優點,並且由於多次繪制,您可以使用一張繪制功能更改所有圖像。
函數fillRect()
與函數drawImage()
大約具有相同的速度(如果保持圖像大小適合GPU RAM)。 通過將詳細圖形卸載到一開始,並在需要時僅渲染圖像,可以顯着提高速度。
requestAnimationFrame
要更新動畫,請使用requestAnimationFrame(functionName)
因為它可以通過與顯示參考保持同步來更好地保持幀速率恆定,並避免閃爍(如果可以的話)。
function mainLoop(){
// your code for the main loop
requestAnimationFrame(mainLoop); // request the next animation frame
// and call mainLoop when available.
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.