Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

Javascript: Kan je tekenen op een canvas zonder preload

Pagina: 1
Acties:

  • Alnitak
  • Registratie: September 2001
  • Laatst online: 20-12-2021
Ik was bezig met een klein projectje om mijn wiskunde weer een beetje op te halen en heb onderstaande code geschreven om een mooi spiraal te genereren. Nu loop ik alleen tegen een probleem aan als ik de rotations hoger zet als 13 en de browser het erg zwaar heeft om het weer te geven. Nu klopt de code zelf volgens mij wel maar ik heb het gevoel dat hij alles wil uitwerken tijdens het laden van de pagina en dan in 1 keer de spiraal wil tekenen. Weet iemand of het mogelijk is om het tekenen direct te doen zodat als ik hem heel hoog zet hij gewoon klein begint en gewoon door blijft tekenen zonder dat m'n browser over de zeik gaat ?


HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html>
    <head>
        <title>Spiral test</title>
        <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
        <script type="text/javascript">
            $(document).ready(function() {
                var rotations = 10;
                var spread = 5;
                var c = document.getElementById("myCanvas");
                var ctx = c.getContext("2d");
                ctx.moveTo(300,200);
                
                for(var c = 1; c <= rotations; c++) {
                    var steps = Math.pow(2,c);
                    var step = 0;
                    for (var n = Math.pow(2, c); n < Math.pow(2,c+1); n++ ) {
                        var radius = ( (c - 1) * spread) + ( (spread / steps) * step);
                        var radian = ( ( Math.PI * 2) / steps) * step *-1;
                        
                        var x = Math.round(radius * Math.cos(radian), 0);
                        var y = Math.round(radius * Math.sin(radian), 0 );
                        
                        ctx.lineTo(x+300, y+200);
                        ctx.stroke();
                        
                        step++;
                    }
                }
            });
        </script>
    </head>
    <body>
        <canvas id="myCanvas" width="600" height="400" style="border:1px solid #c3c3c3;"></canvas>
    </body>
</html>

Little known fact about Middle Earth: The Hobbits had a very sophisticated computer network! It was a Tolkien Ring...


  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06 13:31

drm

f0pc0dert

Mag ik allereerst opmerken dat als de enige aanleiding is om jquery te includen de dom-ready listener te registreren dat je iets aan je JS skills moet doen? ;) [/ot]

In principe gun je de browser geen rust op deze manier. Dat betekent waarschijnlijk dat de thread die bezig is je canvas te updaten elke keer achter de feiten aanloopt. Wat ik zou proberen is met timeouts te werken, dus je forloop ongeveer zo herschrijven

JavaScript:
1
2
3
4
5
6
7
8
function go(c) {
   // for body

   if (c < rotations) {
       setTimeout(function() { go(c + 1); }, 20);
   }
}
go(0);

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


  • klinz
  • Registratie: Maart 2002
  • Laatst online: 18-11 14:59

klinz

weet van NIETS

Voor tekengerelateerde zaken kan je daarvoor beter requestAnimationFrame gebruiken.

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
klinz schreef op maandag 12 augustus 2013 @ 16:09:
Voor tekengerelateerde zaken kan je daarvoor beter requestAnimationFrame gebruiken.
Het gaat er nog even om of je de tekenoperaties wilt partitioneren over de tijd om de CPU te ontlasten (time-slicing dus, bij gebrek aan echte threading) of echt een vloeiende animatie wilt produceren. Je hebt voor het eerste geval nl. helemaal geen high-performance animatie timer nodig.

Het echte probleem hier lijkt er meer in te schuilen dat de TS een exponentiële for loop heeft weten te produceren voor het uittekenen v/e spiraal en het dan vreemd vindt dat dit langzaam is. 8)7

Toegegeven; je zult meer stappen nodig hebben om naarmate je verder naar buiten op de boog komt een vloeiende lijn te behouden, maar het is wellicht iets effectiever om niet te proberen de hoek linear op te laten lopen, maar om de booglengte linear op te laten lopen en de bijhorende hoek te approximeren met een degelijke formule.

Zie bijvoorbeeld dit stukje sample code:

HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!DOCTYPE html>
<html>
  <head>
    <title>Spiral test</title>
    <script type="text/javascript">
      (function() {
        var
          NUMBER_OF_ROTATIONS = 60,
          BRANCH_DISTANCE = .75,
          ARC_LENGTH = .1;

        window.onload = function() {
          var
            canvas    = document.getElementById( "myCanvas" ),
            context   = canvas.getContext( "2d" ),
            halted    = false,
            t_end     = 2 * Math.PI * NUMBER_OF_ROTATIONS,
            s         = 0,
            t;

          context.translate( .5 * canvas.width , .5 * canvas.height );
          context.moveTo( 0, 0 );

          while ( !halted ) {
            /* Aproximate the angle `t` for arc length `s` and given branch distance;
             * This allows a (near)constant increase in arc length for smooth drawing 
             * as we travel outwards on the spiral.
             * See : http://fiji.sc/downloads/snapshots/arc_length.pdf
             */
            s += ARC_LENGTH;
            t = 2 * Math.PI * Math.sqrt( 2 * s / BRANCH_DISTANCE );

            if ( t > t_end ) {
              t = Math.min( t, t_end );
              halted = true;
            }

            context.lineTo( 
              BRANCH_DISTANCE * t * Math.cos( t ),
              BRANCH_DISTANCE * t * Math.sin( t )
            );                        
          }
          
          context.stroke();
        };
      })();
    </script>
  </head>
  <body>
    <canvas id="myCanvas" width="600" height="400" style="border:1px solid #c3c3c3;"></canvas>
  </body>
</html>


Da's toch wel een flink stukje sneller, of niet?
En doordat je de penseelstrook uitstelt totdat alle punten gezet zijn en ze in één keer allemaal passeert krijg je ook een stuk betere performance en een veel mooiere lijn (dankzij de ingebouwde antialiasing).

Mocht je echt een animatie willen, dan is deze implementatie misschien zelfs snel genoeg om de hele spiraal in increments te hertekenen om de nette antialiasing te behouden. Zo niet, dan kun je altijd nog partial results cachen en terug blitten voordat je door tekent.

[ Voor 87% gewijzigd door R4gnax op 16-08-2013 09:01 ]