<?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.com/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.com/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].complete) { 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>
|