Part 6: Draw Compass Arrow

In the last part, we used the device orientation plugin to create an app that shows the degrees the top of our device is relative to the North. Now we’ll use the canvas component of HTML5 to draw an arrow that always points to the North and we’ll have a much more intuitive compass.

I’ve based the drawing code on a nice example that draws a rotating arrow using canvas given here.

In the next related post, We’ll handle fine location getting GPS coordinates. When combining this with the compass, we will have the data we need to create the target application, which is an arrow that always points to a fixed destination, for example, that place where you parked your car in Disneyworld but can’t seem to remember where it was…

So now, just replace the www/index.html file with the content provided here, and then cordova build android , followed by cordova run android and enjoy the phonegap compass

<!DOCTYPE html>
<html>
  <head>
    <title>Compass Example</title>

    <script type="text/javascript" charset="utf-8" src="cordova.js"></script>
    <script type="text/javascript" charset="utf-8">

    var g_PI2 = Math.PI*2;   // 2 x Pi
    var g_toRAD = 360/g_PI2; // Divide degrees by this to get radians
    var g_watchID = null;    // the current `watchHeading`
    var g_ArrHeight = 48;

    // Wait for device API libraries to load
    //
    document.addEventListener("deviceready", onDeviceReady, false);

    // device APIs are available
    //
    function onDeviceReady() {
        var oc = document.getElementById('arrow');
        oc.width = g_ArrHeight * 4;
        oc.height = g_ArrHeight * 4;        
        startWatch();
    }

    // Start watching the compass
    //
    function startWatch() {

        // Update compass every 3 seconds
        var options = { frequency: 250 };

        g_watchID = navigator.compass.watchHeading(onSuccess, onError, options);
    }

    // Stop watching the compass
    //
    function stopWatch() {
        if (g_watchID) {
            navigator.compass.clearWatch(g_watchID);
            g_watchID = null;
        }
    }

    // onSuccess: Get the current heading
    
    function onSuccess(heading) {
        var element = document.getElementById('heading');
        element.innerHTML = 'Heading: ' + heading.magneticHeading;
        // We want the arrow to point to the same position (North) regardless
        // of the device orientation, so since the North heading is given 
        // relative to the top of the device, we'll point the arrow to
        // 2xPi (360 degrees) minus the heading of the top of the device.
        drawArrow(g_PI2-heading.magneticHeading/g_toRAD);
    }

    // onError: Failed to get the heading
    //
    function onError(compassError) {
        alert('Compass error: ' + compassError.code);
    }

    function drawArrow(r) {
        var ctx = document.getElementById('arrow').getContext('2d');
        ctx.clearRect(0, 0, g_ArrHeight*4, g_ArrHeight*4);
        var state = ctx.save();
        var fulld3 = g_ArrHeight/3;
        var fulld2 = g_ArrHeight/2;
        ctx.translate(g_ArrHeight*2, g_ArrHeight*2);
        ctx.rotate(r);

        ctx.beginPath();
        ctx.strokeStyle = '#aaaaff';
        ctx.lineWidth = 5;

        ctx.moveTo(0, -g_ArrHeight);
        ctx.lineTo(g_ArrHeight, fulld3);
        ctx.lineTo(fulld2, fulld3);
        ctx.lineTo(fulld2, g_ArrHeight);
        ctx.lineTo(-fulld2, g_ArrHeight);
        ctx.lineTo(-fulld2, fulld3);
        ctx.lineTo(-g_ArrHeight, fulld3);

        ctx.closePath();
        ctx.stroke();
        ctx.fillStyle="#33ff33";
        ctx.fill();

        ctx.restore(state);
    }
    </script>
  </head>
  <body>
    <div id="heading">Waiting for heading...</div>
    <button onclick="startWatch();">Start Watching</button>
    <button onclick="stopWatch();">Stop Watching</button>
    <br /><hr />
    <canvas id="arrow">
  </body>
</html>

Leave a Reply

Your email address will not be published. Required fields are marked *