簡體   English   中英

我如何優化畫布html5的此javascript代碼,使其在Firefox中順利運行?

[英]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: &nbsp;</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>&nbsp;Velocidad Inicial: &nbsp;</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>&nbsp; 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>&nbsp; m</span>
                                <label>&nbsp; Velocidad-x: </label><input id="vx" type="text" readonly name="velocidad en x" value="0.00" autocomplete="off"><span>&nbsp; m/s</span>
                            </div>
                            <div>
                                <label>Posicion-y: &nbsp;</label><input id="posy" type="text" readonly name="distancia-vertical" value="0.00"><span>&nbsp; m</span>
                                <label>&nbsp; Velocidad-y: </label><input id="vy" type="text" readonly name="velocidad en y" value="0.00"><span>&nbsp; m/s</span>
                                <label>Tiempo: &nbsp;</label><input id="tiempo" type="text" readonly name="tiempo" value="0.00"><span>&nbsp; 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM