Tempwave Demonstration

The sinusoidal temperature wave demo is quite similar in terms of animation to Lessons 6 and 7 in that it is some relatively simple static SVG and some somewhat more complex JavaScript to handle the interactivity and animation.

The demo a simple animation of the transmission of temperature from the air into the ground. Heat is conducted from the air into the ground and diffuses downward. As the heat diffuses downwards, the amplitude of the wave decreases until at some depth there is no perceptible variation over the time period being examined. The physics of this are quite complex but can be evaluated by this approximation:

td = Ta + At * e-d / D * cos( t * ω - d / D)

where

td the temperature at depth d
Ta air temperature at the surface (i.e. d = 0)
At daily temperature amplitude, in degrees
D the "damping depth" of the material being heated
t time
ω time period cycle expressed in radians

The interesting aspects of this demo are how the temperatures are stored and hence rendered and the use of buttons to control the animation. The temperatures are calculated and stored at ten depths, down to 10 metres. The time period is 200 steps with each step being 3600 seconds (one hour) long. So the demo runs for 8.33 days. Then it has to roll over to the beginning of the storage, which it does through a simple ring-buffer approach.

For the time-line display of the temperatures, it simply builds up a new points array for each iteration for each depth.

function UpdateTempAtDepth ( depthNum, depthID ) {
    dampingDepth    = Depth[depthNum] / damping;
    dampedAmplitude = diurnalAmplitude * Math.exp(-Depth[depthNum] / damping);
    Temps[depthNum][nCurTemp] = airTemperature + dampedAmplitude * Math.cos(curTime * omegaDayRad - dampingDepth);

    Times[depthNum][nCurTemp] = curTime / 3600.0;   

    // find the first index in our ring buffer
    index = nCurTemp - nMaxTemp;
    if (index < 0) {
        if ((nTotTemp < nMaxTemp) || (nTotTemp % nMaxTemp) == (nMaxTemp - 1))
            index = 0;
        else
            index += nMaxTemp + 1;
    }

    // now build the string from the values in the buffer
    var     pointStr = '';
    for ( k=0; k<nMaxTemp && k<=nTotTemp; k++ ) {
        var dTime = Times[depthNum][index] - timeOffset;
        pointStr += dTime + ',' + Temps[depthNum][index] + ' ';

        // increment the index and wrap around in the ring buffer, if need be
        index++;
        if (index >= nMaxTemp)
            index = 0;
    }

    UpdatePolyline( depthID, pointStr );
}

Displaying the profile is very similar:

function UpdateProfile () {
    var pointStr = '';
    for ( j=0; j<nDepth; j++ ) {
       dampingDepth    = Depth[j] / damping;
       dampedAmplitude = diurnalAmplitude * Math.exp(-Depth[j] / damping);
       temperature     = airTemperature + dampedAmplitude * Math.cos(curTime * omegaDayRad - dampingDepth);

       pointStr += temperature + ',' + Depth[j] + ' ';
    }

    UpdatePolyline( profileID, pointStr );
}

The date info displayed is calculated on the fly by using some JavaScript functions that convert from seconds to actual month and day values which are then displayed by updating the text-node child, just as in the previous demos.

Finally, the buttons which control the demo are very straightforward JavaScript. The buttons are just plain SVG round rects

<g id="playbutton" transform="matrix(1 0 0 1 408 236)" onmousedown="OnPlayButton(evt)">
    <rect width="55" height="31" rx="4" style="fill:green;stroke:black" />
    <text  transform="matrix(1 0 0 1 27.5 15.5)" style="font-family:'Verdana'; 
        font-size:12;fill:black;dominant-baseline:central;" text-anchor="middle">Play</text>
</g>
    
<g id="pausebutton" transform="matrix(1 0 0 1 484 236)" onmousedown="OnPauseButton(evt)">
    <rect width="55" height="31" rx="4" style="fill:yellow;stroke:black" />
    <text  transform="matrix(1 0 0 1 27.5 15.5)" style="font-family:'Verdana'; font-size:12;
        fill:black;dominant-baseline:central;" text-anchor="middle">Pause</text>
</g>
    
<g id="stopbutton" transform="matrix(1 0 0 1 561 236)" onmousedown="OnStopButton(evt)">
    <rect width="55" height="31" rx="4" style="fill:red;stroke:black" />
    <text  transform="matrix(1 0 0 1 27.5 15.5)" style="font-family:'Verdana'; font-size:12;
        fill:black;dominant-baseline:central;pointer-events:none;" text-anchor="middle">Stop</text>
</g>
    
<g id="restartbutton" transform="matrix(1 0 0 1 639 236)" onmousedown="OnRestartButton(evt)">
    <rect width="55" height="31" rx="4" style="fill:magenta;stroke:black" />
    <text  transform="matrix(1 0 0 1 27.5 15.5)" style="font-family:'Verdana'; font-size:12;fill:black;
        dominant-baseline:central;" text-anchor="middle">Restart</text>
</g>

And the handlers are straightforward too.

function OnStopButton(evt) {
    window.clearInterval( intervalID );
    curTime  = 0;
    nCurTemp = 0;
    nTotTemp = 0;
}

function OnPauseButton(evt) {
    window.clearInterval( intervalID );
}

function OnPlayButton(evt) {
    intervalID = window.setInterval('next_update()', 50);
}

function OnRestartButton(evt) {
    OnStopButton(evt);
    OnPlayButton(evt);
}

And that's it. Click on this link to see the demo in all its sinusoidal glory!



About Us | Contact Us | ©2017 Geo-F/X