JavaScript DHTML/Page Components/Rotating globe — различия между версиями

Материал из Web эксперт
Перейти к: навигация, поиск
м (1 версия)
 
(нет различий)

Текущая версия на 07:26, 26 мая 2010

Rotating globe in JavaScript

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>rotating globe</title>
<!-- misc.js -->
<script language="JavaScript" >
/*------------------------------------------------------------------------------
   Copyright (c) 2005 Tyrell Corporation.
    This file is part of the Locative Blog project.
    http://locblog.sourceforge.net/
   Author   : $Author: darkeye $
   Version  : $Revision: 1.1.1.1 $
   Location : $Source: /cvsroot/locblog/rotatingGlobe/var/public_html/misc.js,v $
   Abstract : 
    Utility functions.
   Copyright notice:
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License  
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
   
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
   
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
------------------------------------------------------------------------------*/
/**
 *  Constructor to reate an object, based on a named element from the document,
 *  browser-independently.
 *  The created object will have two properties:
 *  obj   - the named object itself
 *  style - the stylesheet object for the named object.
 *
 *  based on http://www.quirksmode.org/js/dhtmloptions.html
 *
 *  @param name the name of the element to create this object upon.
 */
function getObj(name)
{
    if (document.getElementById) {
        this.obj   = document.getElementById(name);
        this.style = document.getElementById(name).style;
    } else if (document.all) {
        this.obj   = document.all[name];
        this.style = document.all[name].style;
    } else if (document.layers) {
        this.obj   = document.layers[name];
        this.style = document.layers[name];
    }
}
/**
 *  Find the X coordinate of an element in the document.
 *  based on http://www.quirksmode.org/js/findpos.html
 *
 *  @param obj the element in the document.
 *  @return the x coordinate for this element.
 */
function findPosX(obj)
{
    var curleft = 0;
    if (obj.offsetParent) {
        while (obj.offsetParent) {
            curleft += obj.offsetLeft
            obj = obj.offsetParent;
        }
    } else if (obj.x) {
        curleft += obj.x;
    }
    return curleft;
}
/**
 *  Find the Y coordinate of an element in the document.
 *  based on http://www.quirksmode.org/js/findpos.html
 *
 *  @param obj the element in the document.
 *  @return the x coordinate for this element.
 */
function findPosY(obj)
{
    var curtop = 0;
    if (obj.offsetParent) {
        while (obj.offsetParent) {
            curtop += obj.offsetTop
            obj = obj.offsetParent;
        }
    } else if (obj.y) {
        curtop += obj.y;
    }
    return curtop;
}
/**
 *  Replace the contenst of a DOM element.
 *  based on http://www.quirksmode.org/js/layerwrite.html
 *
 *  @param id the id of the element.
 *  @param text the new text of the element.
 */
function replaceContent(id, text)
{
    if (document.getElementById) {
        x = document.getElementById(id);
        x.innerHTML = "";
        x.innerHTML = text;
    } else if (document.all) {
        x = document.all[id];
        x.innerHTML = text;
    } else if (document.layers) {
        x = document.layers[id];
        text2 = "<P CLASS="testclass">" + text + "</P>";
        x.document.open();
        x.document.write(text2);
        x.document.close();
    }
}

/**
 *  Function to calculate the X coordinate of an orthographic projection.
 *  based on http://mathworld.wolfram.ru/OrthographicProjection.html
 *
 *  @param phi the lattitude of the point on the sphere
 *  @param lambda the longitude of the point on the sphere
 *  @param phi1 the lattitude of the viewpoint
 *  @param lambda1 the longitued of the viewpoint
 *  @return the x coordinate of the specified point.
 */
function orthographicX(phi, lambda, phi1, lambda1)
{
    var x = Math.cos(phi) * Math.sin(lambda - lambda1);
    return x;
}
/**
 *  Function to calculate the Y coordinate of an orthographic projection
 *  based on http://mathworld.wolfram.ru/OrthographicProjection.html
 *
 *  @param phi the lattitude of the point on the sphere
 *  @param lambda the longitude of the point on the sphere
 *  @param phi1 the lattitude of the viewpoint
 *  @param lambda1 the longitued of the viewpoint
 *  @return the y coordinate of the specified point.
 */
function orthographicY(phi, lambda, phi1, lambda1)
{
    var y = Math.cos(phi1) * Math.sin(phi)
          - Math.sin(phi1) * Math.cos(phi) * Math.cos(lambda - lambda1);
    return y;
}
/**
 *  Helper function to convert a latitude or longitued into radii.
 *
 *  @param degrees the latitude or longitude
 *  @return the same value, in radii
 */
function toRadii(degrees)
{
    return (degrees / 180.0) * Math.PI;
}

</script>
<!-- GeoLocation.js -->
<script language="JavaScript">
/*------------------------------------------------------------------------------
   Copyright (c) 2005 Tyrell Corporation.
    This file is part of the Locative Blog project.
    http://locblog.sourceforge.net/
   Author   : $Author: darkeye $
   Version  : $Revision: 1.1.1.1 $
   Location : $Source: /cvsroot/locblog/rotatingGlobe/var/public_html/GeoLocation.js,v $
   Abstract : 
    A class representing a geogpraphical location.
   Copyright notice:
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License  
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
   
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
   
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
------------------------------------------------------------------------------*/
/**
 *  Constructor for a geographic location, with a link.
 *
 *  @param id the id of the location (no spaces, etc.)
 *  @param name the name of the location
 *  @param longitude the longitude coordinate of the location
 *  @param latitude the latitude coordinate of the location
 *  @param url the url for more info on the location
 */
function GeoLocation(id,
                     name,
                     longitude,
                     latitude,
                     url)
{
    // the id of the location
    this.id = id;
    // the name of the location
    this.name = name;
    // the longitude coordinate of the location
    this.longitude = longitude < 0 ? 360 + longitude : longitude;
    // the latitude coordinate of the location
    this.latitude = latitude;
    // the url for more info on the location
    this.url = url;
    // the image used to mark the location visually
    this.markerImage = "globeImages/5x5.png";
    // the width of the marker image
    this.markerWidth = 5;
    // the height of the marker image
    this.markerHeight = 5;
    // the x coordinate of this location, relative to the page window
    this.x = 0;
    // the y coordinate of this location, relative to the page window
    this.y = 0;
    // create the CSS definition for this location
    this.styleDefinition = geoLocationStyleDefinition;
    // create the HTML element source for this location
    this.htmlDefinition = geoLocationHtmlDefinition;
    // display the location object on a RotatingGlobe object
    this.display = geoLocationDisplay;
    // move the marker depiciting the location to the specified position
    this.moveMarker = geoLocationMoveMarker;
    // hide the marker depiciting the location
    this.hideMarker = geoLocationHideMarker;
    // show the location popup near the geo location
    this.showPopup = geoLocationShowPopup;
    // hide the location popup near the geo location
    this.hidePopup = geoLocationHidePopup;
    // Tell if the longitude coordinate of the GeoLocation object is visible
    // from a reference viewpoint.
    this.longitudeVisible = geoLocationLongitudeVisible;
}
/**
 *  Create the CSS definition for this location
 *
 *  @return the CSS definition for this location, as a string
 */
function geoLocationStyleDefinition()
{
    return "#" + this.id + "{"
         + " position: absolute; "
         + " top:      0px; "
         + " left:     0px; "
         + "}\n";
}
/**
 *  Create the HTML element source for this location
 *
 *  @return the HTML element source for this location, as a string.
 */
function geoLocationHtmlDefinition()
{
    return "<a id="" + this.id + "" href="" + this.url + "">"
         + "<img name="" + this.id + "" alt="" + this.name + "" "
            + "src="" + this.markerImage + "" "
            + "width="" + this.markerWidth + "" "
            + "height="" + this.markerHeight + "" border="0"/>"
         + "</a>\n";
}
/**
 *  Move the marker depicting the location to the specified coordinates.
 */
function geoLocationMoveMarker()
{
    var locationObject = new getObj(this.id);
    locationObject.style.top        = this.y + "px";
    locationObject.style.left       = this.x + "px";
    locationObject.style.visibility = "visible";
}
/**
 *  Hide the Marker depicting the location.
 */
function geoLocationHideMarker()
{
    var locationObject = new getObj(this.id);
    locationObject.style.visibility = "hidden";
}
/**
 *  Show the popup text near the location.
 */
function geoLocationShowPopup()
{
    replaceContent("locationPopup", this.name);
    var popup = new getObj("locationPopup");
    // display a bit to the right and above
    popup.style.left       = (this.x + 10) + "px";
    popup.style.top        = (this.y - 15) + "px";
    popup.style.visibility = "visible";
}
/**
 *  Hide the popup near the location.
 */
function geoLocationHidePopup()
{
    var popup = new getObj("locationPopup");
    popup.style.visibility = "hidden";
}

/**
 *  Display the location on the map.
 *
 *  @param globe a RotatingGlobe object, on which to display the location
 */
function geoLocationDisplay(globe)
{
    longStepSize  = 360.0 / globe.maxPosition;
    viewLongitude = globe.position * longStepSize;
    if (!this.longitudeVisible(viewLongitude)) {
        this.hideMarker();
        return;
    }
    lambda  = toRadii(this.longitude);
    phi     = toRadii(this.latitude);
    lambda1 = toRadii(viewLongitude);
    phi1    = toRadii(0);
    x = (orthographicX(phi, lambda, phi1, lambda1) * (globe.realGlobeWidth/2))
      + (globe.globeImage.width / 2);
    y = globe.globeImage.height
      - ((orthographicY(phi, lambda, phi1, lambda1) * (globe.realGlobeHeight/2))
         + (globe.globeImage.height / 2) );
    this.x = globe.globeImageX + x;
    this.y = globe.globeImageY + y;
    this.moveMarker();
}
/**
 *  Tell if the longitude coordinate of the GeoLocation object is visible
 *  from a reference viewpoint.
 *  It"s not visible if it would be "on the other side of the planet"
 *
 *  @param refLongitude the reference view point, to check from.
 *  @return true if longitude is visible, false otherwise
 */
function geoLocationLongitudeVisible(refLongitude)
{
    var westEdge = refLongitude - 90;
    var eastEdge = refLongitude + 90;
    if (westEdge >= 0 && eastEdge < 360) {
        return westEdge <= this.longitude && this.longitude <= eastEdge;
    } else if (eastEdge >= 360) {
        eastEdge -= 360;
        return westEdge <= this.longitude || this.longitude <= eastEdge;
    } else {
        westEdge += 360;
        return westEdge <= this.longitude || this.longitude <= eastEdge;
    }
}

</script>
<!-- RotatingGlobe.js -->
<script language="JavaScript">
/*------------------------------------------------------------------------------
   Copyright (c) 2005 Tyrell Corporation.
    This file is part of the Locative Blog project.
    http://locblog.sourceforge.net/
   Author   : $Author: darkeye $
   Version  : $Revision: 1.1.1.1 $
   Location : $Source: /cvsroot/locblog/rotatingGlobe/var/public_html/RotatingGlobe.js,v $
   Abstract : 
    A rotating globe JavaScript object.
   Copyright notice:
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License  
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
   
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
   
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
------------------------------------------------------------------------------*/
/**
 *  Event handler for a preloaded image finishing loading.
 *  This function expects the rotating globe, for which preloaded images
 *  are checked, being available at the global variable named "globe".
 *
 *  @return true if all images are loaded, false otherwise.
 */
function globeImageLoaded()
{
    if (globe.imagesLoaded()) {
        globe.init();
        return true;
    }
    return false;
}
/**
 *  Start dragging the image by the mouse move.
 *  This function expects the rotating globe at a global variable named "globe"
 */
function globeDragImage()
{
    globe.startDragImage();
    document.globe.onmousemove = globeTrackMouseMove;
}
/**
 *  Stop dragging the image by the mouse move.
 *  This function expects the rotating globe at a global variable named "globe"
 */
function globeUndragImage()
{
    document.globe.onmousemove = null;
    globe.stopDragImage();
}
/**
 *  Track the mouse movement, and change the globe view if necessary.
 *  This function expects the rotating globe at a global variable named "globe"
 *
 *  @param event the mouse movement event.
 */
function globeTrackMouseMove(event)
{
    // first tell the current mouse position, possibly in all browsers
    // thanks to http://www.quirksmode.org/js/events_properties.html
    var posx = 0;
    var posy = 0;
    if (!event) {
        var event = window.event;
    }
    if (event.pageX || event.pageY) {
        posx = event.pageX;
        posy = event.pageY;
    } else if (event.clientX || event.clientY) {
        posx = event.clientX + document.body.scrollLeft;
        posy = event.clientY + document.body.scrollTop;
    }
    // display the detected coordinates, for debug reasons
    document.test.x.value = posx;
    document.test.y.value = posy;
    globe.updateView(posx, posy);
}


/**
 *  The contructor class depicting the rotating globe.
 *
 *  @param globeImage the globe <img/> tag in the page,
 *         that holds the globe images.
 *  @param globeBorder the number of pixels the image has a border around
 *         the enclosed globe. it is expected that the image has a globe at
 *         its center, which is surrounded by a border on each side with
 *         this many pixels. thus the actual globe is
 *         globeImage.width - (2 * globeBorder) wide, and
 *         globeImage.height - (2 * globeBorder) in height.
 *  @param locations an array holding GeoLocation object, the list of
 *         interesting locations.
 */
function RotatingGlobe(globeImage, globeBorder, locations)
{
    // the <img/> element in the page, holding the globe images
    this.globeImage = globeImage;
    // the size of the border around the globe in the image
    this.globeBorder = globeBorder;
    // the interesting locations on the globe
    this.locations = locations;
    // the X coordinate of the upper-left corner of the globe image
    // in the browser window
    this.globeImageX = findPosX(document.globe);
    // the Y coordinate of the upper-left corner of the globe image
    // in the browser window
    this.globeImageY = findPosY(document.globe);
    // the real height of the globe itself, inside the image
    this.realGlobeHeight = this.globeImage.width - (2 * this.globeBorder);
    // the real width of the globe itself, inside the image
    this.realGlobeWidth  = this.globeImage.height - (2 * this.globeBorder);
    // the number of view positions available
    this.maxPosition = 36;
    // the current view position
    this.position = 0;
    // the prefix for each globe image
    // the image names are: imagePrefix + position + imagePostfix
    this.imagePrefix = "globeImages/globe";
    // the postfix for each globe image
    // the image names are: imagePrefix + position + imagePostfix
    this.imagePostfix = ".jpg";
    // the globe images, as an array
    this.images = Array(this.maxPosition);
    // the x coordinate, which if passed by the mouse, triggers a move to east
    this.eastThreshold = 0;
    // the x coordinate, which if passed by the mouse, triggers a move to west
    this.westThreshold = 0;
    // the size of the x coordinate window to trigger a move to east or west
    // by the mouse movement
    this.thresholdStep = 20;
    // a flag indicating if this object has already been initialized
    this.initialized = false;
    // preload all the images for the globe
    this.preloadImages = rotatingGlobePreloadImages;
    // tell if all images that are to be preloaded have completed loading.
    this.imagesLoaded = rotatingGlobeImagesLoaded;
    // initialize the globe, after all the images have been loaded
    this.init = rotatingGlobeInit;
    // start mouse dragging
    this.startDragImage = rotatingGlobeStartDragImage;
    // stop mouse dragging
    this.stopDragImage = rotatingGlobeStopDragImage;
    // update the view point according to the new mouse coordinates, if needed
    this.updateView = rotatingGlobeUpdateView;
    // function to return the name of an image for a specified position
    this.imageName = rotatingGlobeImageName;
    // rotate the viewpoint one step to the east
    this.rotateEast = rotatingGlobeRotateEast;
    // rotate the viewpoint one step to the west
    this.rotateWest = rotatingGlobeRotateWest;
    // reset the mouse movement thresholds triggering view point change
    this.resetThreshold = rotatingGlobeResetThreshold;
    // display the locations
    this.displayLocations = rotatingGlobeDisplayLocations;
}
/**
 *  Function returning the name of an image for a specified position
 *
 *  @param position the view position to get the image for, must be
 *         in the interval [0:maxPosition[
 *  @return the name of the appropariate globe image, as a string
 */
function rotatingGlobeImageName(position)
{
    return this.imagePrefix + position + this.imagePostfix;
}
/**
 *  Rotate the current viewpoint one step to the east.
 */
function rotatingGlobeRotateEast()
{
    this.position = (++this.position) % this.maxPosition;
    this.globeImage.src = this.images[this.position].src;
    this.displayLocations();
}
/**
 *  Rotate the current viewpoint one step to the east.
 */
function rotatingGlobeRotateWest()
{
    this.position = (--this.position) % this.maxPosition;
    if (this.position < 0) {
        this.position += this.maxPosition;
    }
    this.globeImage.src = this.images[this.position].src;
    this.displayLocations();
}
/**
 *  Preload all the images, so that they are in the browsers cache.
 */
function rotatingGlobePreloadImages()
{
    this.initialized = false;
    for (i = 0; i < this.maxPosition; ++i) {
        this.images[i] = new Image(this.globeImage.width,
                                   this.globeImage.height);
        this.images[i].onload = globeImageLoaded;
        this.images[i].src    = this.imageName(i);
    }
}
/**
 *  Tell if all images that are to be preloaded have completed loading.
 *
 *  @return true if all images have been loaded, false otherwise
 */
function rotatingGlobeImagesLoaded()
{
    var   allCompleted = true;
    for (i = 0; i < this.maxPosition; ++i) {
        if (!this.images[i].ruplete) {
            allCompleted = false;
            break;
        }
    }
    return allCompleted;
}
/**
 *  Initialize the globe, after all the images have been loaded.
 *  This means grabbing event handlers, etc.
 */
function rotatingGlobeInit()
{
    if (this.initialized) {
        return;
    }
    this.thresholdStep        = this.globeImage.width / (this.maxPosition + 1);
    this.globeImage.onmousedown = globeDragImage;
    this.globeImage.onmouseup   = globeUndragImage;
    this.globeImage.src         = this.images[0].src;
    this.initialized            = true;
    for (i = 0; i < locations.length; ++i) {
        var obj = new getObj(locations[i].id);
        obj.obj.onmouseover = locationShowPopup;
        obj.obj.onmouseout  = locationHidePopup;
    }
    this.displayLocations();
}
/**
 *  Find a location in an array of locations, by its id.
 *
 *  @param locations an array of GeoLocation objects.
 *  @param id the id of the location to look for
 *  @return the requested GeoLocation object, or null if not found.
 */
function getLocationById(locations, id) {
    for (i = 0; i < locations.length; ++i) {
        if (locations[i].id == id) {
            return locations[i];
        }
    }
    return null;
}
/**
 *  Event hanlder for showing the popup near a location.
 *
 *  @param event the event triggering this call. it is expected that the event
 *         target name is a valid GeoLocation id in the locations array.
 */
function locationShowPopup(event) {
    geoLocation = getLocationById(locations, event.target.name);
    if (geoLocation != null ) {
        geoLocation.showPopup();
    }
}
/**
 *  Event hanlder for hiding the popup near a location.
 *
 *  @param event the event triggering this call. it is expected that the event
 *         target name is a valid GeoLocation id in the locations array.
 */
function locationHidePopup(event) {
    geoLocation = getLocationById(locations, event.target.name);
    if (geoLocation != null ) {
        geoLocation.hidePopup();
    }
}
/**
 *  Reset the mouse movement thresholds. Set the new limits for when
 *  to change the view point, if the mouse move beyonds these limints.
 *
 *  @param posx the current position, from where the relative thresholds
 *         have to be set up.
 */
function rotatingGlobeResetThreshold(posx)
{
    this.eastThreshold = posx - this.thresholdStep;
    this.westThreshold = posx + this.thresholdStep;
}
/**
 *  Start mouse dragging
 */
function rotatingGlobeStartDragImage()
{
    this.eastThreshold = 0;
    this.westThreshold = 0;
}
/**
 *  Stop mouse dragging.
 */
function rotatingGlobeStopDragImage()
{
    this.eastThreshold = 0;
    this.westThreshold = 0;
}
/**
 *  Update the view point according to the new mouse coordinates, if needed.
 *
 *  @param x the new x coordinate for the mouse
 *  @param y the new y coordinate for the mouse
 */
function rotatingGlobeUpdateView(x, y)
{
    // if this is the first event after started dragging, initialize
    // the appropriate thresholds
    if (this.eastThreshold == 0 && this.westThreshold == 0) {
        this.resetThreshold(x);
    }
    // change the view point, if needed
    if (x > this.westThreshold) {
        this.rotateWest();
        this.resetThreshold(x);
    } else if (x < this.eastThreshold) {
        this.rotateEast();
        this.resetThreshold(x);
    }
}
/**
 *  Display all interesting locations on the map.
 */
function rotatingGlobeDisplayLocations()
{
    for (i = 0; i < locations.length; ++i) {
        this.locations[i].display(this);
    }
}

</script>

<script language="JavaScript">
/**
 *  The global rotating globe object, the event handlers depend on this.
 */
var globe;
/**
 *  The locations.
 */
var locations = Array();
</script>
<!-- locations.js -->
<script language="JavaScript">
/*------------------------------------------------------------------------------
   Copyright (c) 2005 Tyrell Corporation.
    This file is part of the Locative Blog project.
    http://locblog.sourceforge.net/
   Author   : $Author: darkeye $
   Version  : $Revision: 1.1.1.1 $
   Location : $Source: /cvsroot/locblog/rotatingGlobe/var/public_html/locations.js,v $
   
   Abstract : 
    A sample location data definition file.
   Copyright notice:
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License  
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
   
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    GNU General Public License for more details.
   
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
------------------------------------------------------------------------------*/
locations.push(new GeoLocation(
    "amsterdam", "Amsterdam", 4.54, 52.23, "/amsterdam"));
locations.push(new GeoLocation(
    "bangkok", "Bangkok", 100.50, 13.73, "/bangkok"));
locations.push(new GeoLocation(
    "budapest", "Budapest", 19.05, 47.50, "/budapest"));
locations.push(new GeoLocation(
    "chiang_mai", "Chiang Mai", 99.03, 18.82, "/chiang_mai"));
locations.push(new GeoLocation(
    "linz", "Linz", 14.18, 48.19, "/linz"));
locations.push(new GeoLocation(
    "london", "London", -0.16, 51.50, "/london"));
locations.push(new GeoLocation(
    "luang_prabang", "Luang Prabang", 102.14, 19.88, "/luang_prabang"));
locations.push(new GeoLocation(
    "new_york", "New York", -74.00, 40.70, "/new_york"));
locations.push(new GeoLocation(
    "Paris", "Paris", 2.33, 48.87, "/paris"));
locations.push( new GeoLocation(
    "philadelphia", "Philadelphia", -75.12, 39.96, "/philadelphia"));
locations.push( new GeoLocation(
    "prague", "Prague", 14.43, 50.10, "/prague"));
locations.push( new GeoLocation(
    "rotterdam", "Rotterdam", 4.29, 51.55, "/rotterdam"));
locations.push( new GeoLocation(
    "taipei", "Taipei", 121.36, 25.01, "/taipei"));
locations.push( new GeoLocation(
    "tokyo", "Tokyo", 139.50, 35.75, "/tokyo"));
locations.push( new GeoLocation(
    "vienna", "Vienna", 16.36, 48.20, "/vienna"));
locations.push( new GeoLocation(
    "washington", "Washington DC", -77.03, 38.88, "/washington"));

</script>
<script language="JavaScript">
/**
 *  Initialize the page, after it has loaded.
 */
function onPageLoad()
{
    globe = new RotatingGlobe(document.globe, 30, locations);
    // this sets up event handlers for the preloaded images
    globe.preloadImages();
    // as not all event handlers are called (damn these lame browswers)
    // set a timout value and call the load image hanlder ourselves
    makeSureImagesAreLoaded()
}
/**
 *  Make sure all images are loaded, by checking on this regularly.
 */
function makeSureImagesAreLoaded()
{
    if (!globeImageLoaded()) {
        // if not ready, check a second later as well
        setTimeout("makeSureImagesAreLoaded()", 1000);
    }
}

/**
 *  Rotate the globe one step to the east.
 */
function rotateEast()
{
    globe.rotateEast();
}
/**
 *  Rotate the globe one step to the west.
 */
function rotateWest()
{
    globe.rotateWest();
}
</script>
<script language="JavaScript">
// create the style sheet definition for each geo location
document.write("<style type="text/css">");
for (i = 0; i < locations.length; ++i) {
    document.write(locations[i].styleDefinition());
}
document.write("</style>");
</script>
<style type="text/css">
#locationPopup {
    position:    absolute;
    top:         0px;
    left:        0px;
    visibility:  hidden;
    font:        14px arial;
    font-weight: bold;
    color:       yellow;
}
</style>
</head>
<body onLoad="onPageLoad();">
<a href="#" onClick="javascript:rotateWest(); return false;">west</a>
|
<a href="#" onClick="javascript:rotateEast(); return false;">east</a>
<br/>
<img name="globe" src="images/loading.png" width="650" height="650" alt="globe"/>
<br/>
<form name="test">
    X: <input type="text" name="x" size="4">
    Y: <input type="text" name="y" size="4">
</form>
<script language="JavaScript">
// create the HTML element for each geo location
for (i = 0; i < locations.length; ++i) {
    document.write(locations[i].htmlDefinition());
}
</script>
<div id="locationPopup"></div>
</body>


<A href="http://www.wbex.ru/Code/JavaScriptDownload/rotatingGlobe-0.1.zip">rotatingGlobe-0.1.zip( 4,605 k)</a>