In this post we take a look at a small interactive animation made using p5* graphic library for JavaScript, that shows pressure waves generated by a point travelling at different speeds relative to the speed of sound in the medium. You can select the Mach number using the slider and see the resulting effect.

The code

In this post I’m not getting into detail about how JavaScript or p5* work, but you can think of JavaScript as the C++ for web development. In fact, the syntax is very similar to C/C++, so if you know any of these languages you can start programming in JavaScript relatively easily. You don’t need any specific environment to execute the JS scripts, they are executed directly in your favorite browser. Without further delays, here goes the code:

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<div id="simple-sketch-holder" style="position: relative"></div>
<script src="https://cdn.jsdelivr.net/npm/p5@1.0.0/lib/p5.js"></script>

<script>
    let waves = [];
    let next;
    let speed;
    let mSlider;
    let checkbox;
    let angle;
    let mach;

    function setup() {
        let canvasDiv = document.getElementById('simple-sketch-holder');
        let width = canvasDiv.offsetWidth;
        canvas = createCanvas(width, 400);
        canvas.parent('simple-sketch-holder');
        mSlider = createSlider(0, 200, 0);
        mSlider.position(40, 20);
        mSlider.style('width', '80px');
        mSlider.parent('simple-sketch-holder');
        checkbox = createCheckbox('', false);
        checkbox.parent('simple-sketch-holder');
        checkbox.position(215,20);
        speed = 0.4;
        next = 0;
    }

    function draw() {
        background(200);
        if (millis() > next) {

            // Add new particle
            waves.push(new Wave());
            
            // Schedule next circle
            next = millis() + 500;
        }

        // Draw all paths
        for( let i = 0; i < waves.length; i++) {
            waves[i].update();
            waves[i].display();
            if(waves[i].lifespan <= 0){
                waves.splice(i,1);
            }
        }
        
        mach = mSlider.value()/100;
      
        noStroke();
        fill(0);
        text('Mach', mSlider.x + mSlider.width + 20, 35);
        text(mach, mSlider.x + mSlider.width + 55, 35);
        
        if(mach >= 1){
          angle = degrees(asin(1/mach));
          checkbox.removeAttribute('disabled');
          if(checkbox.checked()){
            text(nf(angle,0,2), mSlider.x + mSlider.width + 185, 35);
          }
        }
        else{
          checkbox.attribute('disabled', ''); 
          noStroke();
          fill(150);
          if(checkbox.checked()){
            text('-', mSlider.x + mSlider.width + 185, 35);
          }
        }
        text('Mach angle', mSlider.x + mSlider.width + 115, 35);
    }

    class Wave {
        constructor() {
            this.x = width/4;
            this.y = height/2;
            this.diameter = 0;
            this.lifespan = 255;
        }
        
        update() {
            this.diameter += speed*2;
            this.lifespan -= 0.5;
            this.x = this.x + speed * mSlider.value()/100;
        }
        
        display() {
            stroke(0, this.lifespan);
            fill(0,0);
            ellipse(this.x, this.y, this.diameter, this.diameter);
        }
    }
</script>