Скорост на анимацията на платното

Съставям симулация на градска транспортна система и се опитвам да подобря уменията си за Javascript и Canvas. Предоставих гола версия тук: https://jsfiddle.net/ftmzm9vp/

Два въпроса:

1) Искам „шушулките“ да работят с еднаква скорост. В момента всички те пристигат до дестинациите си по едно и също време, което означава, че пътуват с различна скорост. Как да коригирам това?

2) Очевидно има още нещо, което трябва да направя -- да накарам капсулите да пътуват по съществуващите линии, да измисля най-добрия път до местоназначението си, да разширя броя на линиите и станциите -- всичко това ще увеличи изчислителните разходи. Точно сега, с 500-те капсули, които искам да използвам, анимацията започва да пълзи. Пренаписах цялото нещо, за да използвам requestAnimFrame, тъй като мислех, че ще бъде по-бързо, но изглежда не е толкова гладко, колкото би трябвало. Какво мога да направя, за да подобря това? Благодаря!

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<title>Pod Stations Lines Test</title>
<body>
    <canvas id="layer1" style="z-index: 2;  
                position:absolute;
                left:0px;
                top:0px;
                " height="600px" width="1000">This text is displayed if your browser does not support HTML5 Canvas.</canvas>
    <canvas id="layer2" style="z-index: 3;
                position:absolute;
                left:0px;
                top:0px;
                " height="600px" width="1000">This text is displayed if your browser does not support HTML5 Canvas.</canvas>
    <canvas id="layer3" style="z-index: 1;
                position:absolute;
                left:0px;
                top:0px;
                " height="600px" width="1000">This text is displayed if your browser does not support HTML5 Canvas.</canvas>
    <script>
        //Modified Source: http://jsfiddle.net/m1erickson/HAbfm/
        //
        layer1 = document.getElementById("layer1");
        ctx1 = layer1.getContext("2d");
        layer2 = document.getElementById("layer2");
        ctx2 = layer2.getContext("2d");
        layer3 = document.getElementById("layer3");
        ctx3 = layer3.getContext("2d");

        window.requestAnimFrame = (function(callback) {
            return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
                window.setTimeout(callback, 1000 / 60);
            };
        })();

        //STATION LIST
        var station = [
            ['A', 100, 50],
            ['B', 300, 50],
            ['C', 200, 150],
            ['D', 100, 250],
            ['E', 300, 250],
            ['F', 400, 250]
        ];


        //DRAW LINES
        function drawLines() {

            ctx1.clearRect(0, 0, layer3.width, layer3.height);

            var linkAB = ctx1.beginPath();
            ctx1.moveTo(station[0][1], station[0][2]);
            ctx1.lineTo(station[1][1], station[1][2]);
            ctx1.stroke();
            var linkBC = ctx1.beginPath();
            ctx1.moveTo(station[1][1], station[1][2]);
            ctx1.lineTo(station[2][1], station[2][2]);
            ctx1.stroke();
            var linkCD = ctx1.beginPath();
            ctx1.moveTo(station[2][1], station[2][2]);
            ctx1.lineTo(station[3][1], station[3][2]);
            ctx1.stroke();
            var linkDE = ctx1.beginPath();
            ctx1.moveTo(station[3][1], station[3][2]);
            ctx1.lineTo(station[4][1], station[4][2]);
            ctx1.stroke();
            var linkCE = ctx1.beginPath();
            ctx1.moveTo(station[2][1], station[2][2]);
            ctx1.lineTo(station[4][1], station[4][2]);
            ctx1.stroke();
            var linkEF = ctx1.beginPath();
            ctx1.moveTo(station[4][1], station[4][2]);
            ctx1.lineTo(station[5][1], station[5][2]);
            ctx1.stroke();

        }


        //CREATE PODS

        var podArray = [];

        function Pod(startX, startY, endX, endY, riders, color) {
            this.startX = startX;
            this.startY = startY;
            this.endX = endX;
            this.endY = endY;
            this.riders = riders;
            this.color = color;
        }

        var colorArray = ["gold", "orange", "red", "green", "blue", "black"];

        function randomPass() {
            occ = 1 + Math.floor(Math.random() * 6);
            return occ;
            console.log("Riders " + occ);
        }


        for (i = 0; i < 500; i++) {
            var origNum = Math.floor(Math.random() * station.length);
            var origin = {
                x: station[origNum][1],
                y: station[origNum][2]
            }
            var destNum = Math.floor(Math.random() * station.length);
            while (origNum == destNum) {
                destNum = Math.floor(Math.random() * station.length);
            }
            var destination = {
                x: station[destNum][1],
                y: station[destNum][2]
            }

            podArray.push(new Pod(
            startX = origin.x,
            startY = origin.y,
            endX = destination.x,
            endY = destination.y,
            riders = randomPass(),
            color = colorArray[riders - 1]

            ));
        }

        var pct = 0.00;
        var fps = 60;

        //CALL DRAWING AND ANIMATION
        drawLines();
        animate();

        function animate() {
            setTimeout(function() {

                if (pct <= 1.00) {
                    requestAnimFrame(animate)
                };

                // increment the percent (from 0.00 to 1.00)
                pct += .01;

                // clear the canvas
                ctx3.clearRect(0, 0, layer3.width, layer3.height);

                // draw all podArray
                for (var i = 0; i < podArray.length; i++) {

                    // get reference to next aPod
                    var aPod = podArray[i];

                    var dx = aPod.endX - aPod.startX;
                    var dy = aPod.endY - aPod.startY;
                    var nextX = aPod.startX + dx * pct;
                    var nextY = aPod.startY + dy * pct;

                    //create pod on screen
                    ctx3.fillStyle = aPod.color;
                    ctx3.beginPath();
                    ctx3.arc(nextX, nextY, 5, 0, Math.PI * 2, true);
                    ctx3.fillStyle = aPod.color;
                    ctx3.fill();
                    ctx3.closePath();

                    //STATION LETTERS

                    for (s = 0; s < station.length; s++) {
                        ctx2.font = '12pt Calibri';
                        ctx2.fillStyle = 'red';
                        ctx2.textAlign = 'center';
                        ctx2.fillText(station[s][0], station[s][1], (station[s][2]) + 4);
                    }

                }

            }, 1000 / fps);
        }
    </script>
</body>

person Tyler330    schedule 17.08.2015    source източник


Отговори (2)


Всичките ви превозни средства достигат дестинацията си едновременно, защото променяте позицията им въз основа на процент. Така че, когато pct==1,00, всички превозни средства пристигат едновременно до собствените си крайни точки, независимо от разстоянието, което трябва да изминат, за да стигнат до там.

// increment the percent (from 0.00 to 1.00)
pct += .01;

За да накарате превозно средство да пристигне въз основа на изминато разстояние

Въпрос №1: Можете да изчислите всяка точка (пътна точка==уникален пиксел), която превозното средство трябва да измине, за да завърши своя маршрут. Придвижете автомобила до следващата му точка с всеки нов анимационен кадър. Това кара всяко превозно средство да пристига въз основа на дължината на своя маршрут, а не на единен процент.

Въпрос №2: За всяко превозно средство, ако предварително изчислите и запазите точките му в масив, можете лесно да получите 500 превозни средства, нарисувани върху платното по време на всеки анимационен кадър.

Ето анотация и демонстрация:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

ctx.lineWidth=2;

// define routes
var routes=[];
routes.push({
  points:linePoints({x:10,y:10},{x:150,y:10}),
  currentPoint:0,
  color:'red',
});
routes.push({
  points:linePoints({x:10,y:50},{x:250,y:65}),
  currentPoint:0,
  color:'green',
});
routes.push({
  points:linePoints({x:10,y:90},{x:325,y:105}),
  currentPoint:0,
  color:'blue',
});

// animation related vars
var lastTime=0;
var delay=1000/60*5;

// start animating
requestAnimationFrame(animate);

function animate(time){
  // return if the desired time hasn't elapsed
  if(time<lastTime){requestAnimationFrame(animate);return;}
  // redraw each route
  ctx.clearRect(0,0,cw,ch);
  // var used to stop animating if all routes are completed
  var isComplete=true;
  for(var i=0;i<routes.length;i++){
    var r=routes[i];
    // increase the currentPoint, but not beyond points.length-1
    if((r.currentPoint+1)<r.points.length-1){
      isComplete=false;
      r.currentPoint++;
    }
    // draw the route to its current point
    ctx.strokeStyle=r.color;
    ctx.beginPath();
    ctx.moveTo(r.points[0].x,r.points[0].y);
    ctx.lineTo(r.points[r.currentPoint].x,r.points[r.currentPoint].y);
    ctx.stroke();
    ctx.fillStyle=r.color;
    ctx.beginPath();
    ctx.arc(r.points[r.currentPoint].x,r.points[r.currentPoint].y,5,0,Math.PI*2);
    ctx.fill();
  }
  // request another frame unless all routes are completed
  if(!isComplete){
    requestAnimationFrame(animate);
  }
}

function linePoints(p1,p2){
  // start building a points array with the starting point
  var points=[p1];
  var dx=p2.x-p1.x;
  var dy=p2.y-p1.y;
  var count=Math.sqrt(dx*dx+dy*dy)*3;
  for(var pct=0;pct<count;pct++){
    // calc next waypoint on the line
    var x=p1.x+dx*pct/count;
    var y=p1.y+dy*pct/count;
    var lastPt=points[points.length-1];
    // add new waypoint if the its integer pixel value has
    // changed from last waypoint
    if(parseInt(x)!==parseInt(lastPt.x) || parseInt(y)!==parseInt(lastPt.y)){
      points.push({x:x,y:y});
    }
  }
  // force the last point to be the ending point
  points[points.length-1]=p2;
  // return a unique points[] forming a line from p1 to p2
  return(points);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=350 height=300></canvas>

person markE    schedule 17.08.2015
comment
Все още се опитвам да разбера логиката на платното. Благодаря ви за това! - person Tyler330; 20.08.2015
comment
Опитах се да адаптирам кода ви, но не мога да го накарам да рисува нищо на екрана. какво съм пропуснала [връзка]( jsfiddle.net/yL8udg9r) - person Tyler330; 03.09.2015

За да накарате вашите капсули да се движат със същата скорост, вероятно ще искате да използвате Питагоровата теорема. Хипотенузата е разстоянието, което искате да измине възелът всеки път, когато rAF се появи. След това изчислете вашите x и y от това.

Не съм съвсем сигурен дали разбирам какво прави pct.

За да ускорите rAF, ще искате да:

  1. убийте зададеното време за изчакване
  2. предварително изобразяване

Предварителното изобразяване е малко повече работа, но вместо да рисувате всеки кръг всеки път, когато рисувате, имате платна, които не са в DOM. След това по същество поставяте „скритото“ платно, където пожелаете, върху видимото DOM платно. По този начин запазва рисунката в паметта.

Освен това рисувате всеки кръг върху платното в края на for-цикъла. Издърпайте метода за запълване извън него по този начин платното може да изчертае пакетно вместо куп малки извиквания (това наистина може да убие производителността).

Настройката на шрифта всеки път може да бъде премахната.

Canvas е страхотно за изпълнение, но просто трябва да внимавате, защото една малка грешка може да доведе до огромно затруднение.

Това е добра статия: http://www.html5rocks.com/en/tutorials/canvas/performance/

Дай ми да знам, ако имаш още въпроси.

person 9TrSl9IAlaLfDmffagsw    schedule 17.08.2015
comment
Ще разгледам това. Бях го виждал и преди, но не бях опитвал да го приложа. - person Tyler330; 20.08.2015