Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / Javascript

Implementation of Touring Feature for Virtual Earth

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
2 Aug 2009CPOL3 min read 10.2K   4  
Implementation of touring feature for virtual earth

If you have ever used Google Earth, you will probably be familiar with the touring feature, which plays back a series of points, i.e., putting a point on the map center, opening its balloon which may contain photos and/or text, staying for a fixed time period, and then moving on to the next point. It is almost like a slide show, but at the same time shows the location of current point on the map. Virtual Earth does not have the touring feature built-in. However, we can implement the feature ourselves using Virtual Earth SDK. Please first visit this link to see a demo of the touring feature in Virtual Earth, and then read the rest of the post to see how it is implemented.

In the demo, there are 5 pushpins and their data is defined by the following 2D array:

C#
var data = new Array(
    new Array(34.042182, -118.232889, "homer0.jpg", 289, 300, "Homer screaming"),
    new Array(34.045917, -118.239462, "homer1.gif", 290, 267, "D'OH!"),
    new Array(34.049360, -118.245736, "homer2.jpg", 210, 210, "Homer having a donut"),
    new Array(34.051448, -118.252511, "homer3.jpg", 300, 400, "Homer having a beer"),
    new Array(34.057442, -118.259504, "homer4.jpg", 219, 167, "Homer choking Bart") );

where each pushpin has these fields: latitude, longitude, image name, image width, image height and caption. Of course, in a real application, the data will probably come from a back end database. The data is loaded to the map with this script:

JavaScript
function LoadData()
{
    var layer = new VEShapeLayer();
    map.AddShapeLayer(layer);
    //create array of VEShape and bulk add to the layer
    var shapes = new Array();
    for (var i = 0; i < data.length; i++)
    {
        var shape = new VEShape(VEShapeType.Pushpin, new VELatLong(data[i][0], data[i][1]));
        shape.SetTitle(data[i][2]);
        var desc = "<div style=\"width:200px\"><img src=\"photos/" +
                    data[i][2] + "\" width=\"200\" height=\"" +
                    Math.round(200 * data[i][4]/data[i][3],0) + "\" border=\"0\"></div>
                    <div style=\"width:200px\">" + data[i][5] + "</div>";
        shape.SetDescription(desc);
        shapes[i] = shape;
    }
    layer.AddShape(shapes);
    AdjustView(layer);
}

This script first creates a layer, then creates an array of shapes (pushpins) based on the data, and then adds the pushpins to the layer in bulk. Notice that an image width is fixed to 200 pixels and the infobox width is fixed to 233 pixels accordingly. This is to prevent a too big infobox from showing. In other words, images may be dynamically resized to fit the infobox.

Once the data is loaded, the following script is used to adjust the map view so that all the pushpins in the layer are visible on the map:

JavaScript
function AdjustView(layer)
{
    var rect = layer.GetBoundingRectangle();
    var count = layer.GetShapeCount();
    map.SetMapView(rect);
    if (count <= 1)
    {
        map.SetZoomLevel(7);
    }
}

The following script and variables are directly related to playing a tour:

JavaScript
var currShapeIdx = -1;
var theShape = null;
var pause = true;
var customBehavior = false;

function Start()
{
    currShapeIdx = 0;
    pause = false;
    Play();
}

function Stop()
{
    currShapeIdx = -1;
    pause = true;
}

function Pause()
{
    pause = true;
}

function Restart()
{
    pause = false;
    Play();
}

function Play()
{
    var layer = map.GetShapeLayerByIndex(1);
    var n = layer.GetShapeCount();
    var img = document.getElementById("currImg");
    if (currShapeIdx >= 0 && currShapeIdx < n && !pause)
    {
        var sideWidth = (typeof( window.innerWidth ) == 'number' )?
                    Math.round(window.innerWidth * 0.2) :
                    Math.round(document.documentElement.clientWidth * 0.2);
        sideWidth -= 10;
        img.src = "photos/" + data[currShapeIdx][2];
        img.width = (data[currShapeIdx][3] > sideWidth)? sideWidth : data[currShapeIdx][3];
        img.style.visibility = "visible";
        theShape = layer.GetShapeByIndex(currShapeIdx);
        var pts = theShape.GetPoints();
        customBehavior = true;
        map.PanToLatLong(pts[0]);
        //map.SetCenter(pts[0]);
        currShapeIdx++;
        var chkLoop = document.getElementById("loop");
        if (currShapeIdx == n && chkLoop.checked)
            currShapeIdx = 0;
        var selInterval = document.getElementById("interval");
        var i = selInterval.options[selInterval.selectedIndex].value;
        window.setTimeout("Play()", 1000 * i);
    }
    else
    {
        img.style.visibility = "hidden";
        theShape = null;
    }
}

function OnMapMoved()
{
    if (customBehavior)
        window.setTimeout("map.ShowInfoBox(theShape)", 10);
    customBehavior = false;
}

Here are some key points about this script. First, the Play() function is called recursively via the JavaScript function window.setTimeout(). The calling interval is specified by the user. Second, each time the Play() function is called, the current pushpin is retrieved and the map is moved via the VE method PanToLatLong() so that the current pushpin is at the map center. The current pushpin is tracked by the variables currShapeIdx and theShape. Third, when the map is moved in position, the OnEndPan event is fired and the event handler OnMapMoved() is executed, which opens the infobox of the current pushpin. It is important to call the ShowInfoBox() method via the JavaScript function window.setTimeout(), and only call it once right after the Play() function is called. Fourth, the pause/restart status is tracked by the boolean variable pause. Once the touring is started, pressing the pause/restart button toggles the call between Pause() and Restart() functions. Finally, the width of the image on the sidebar is determined by the width of the sidebar or the original image width, whichever is smaller. The width of the sidebar is 20% of the width of the browser window.

Again, to see the touring feature in action and the complete JavaScript code, click here.

Note if you set the interval too small while the points are too far apart, you may find that some points are skipped during touring because it takes too long time to pan from one point to the next. In this case, you will have to either increase the playback interval or zoom out the map a few notches.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Pharos
United States United States
I work as a Principal Software Engineer for Pharos. I develop location-based services and applications using Microsoft .Net Technologies. I am a Microsoft Certified Application Developer (MCAD) and Microsoft Certified Solution Developer (MCSD). I have more than 20 years of experience in computer programming and software development. I'm currently interested in topics related to C#, APS.Net, SQL Server, Windows Programming, Web Programming, AJAX, Bing Maps, Google Maps, and e-Commerce.
My blog site: http://www.tofuculture.com

Comments and Discussions

 
-- There are no messages in this forum --