Mercurial > geoleap
changeset 0:c978fac38f18
Origination.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Fri, 08 Feb 2008 20:33:37 +0000 |
parents | |
children | 0a09525111a6 |
files | index.html locationInfo.xml map.css map.js |
diffstat | 4 files changed, 514 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/index.html Fri Feb 08 20:33:37 2008 +0000 @@ -0,0 +1,18 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"/> + <title>Atul's Map</title> + <base target="_blank" /> + <link rel="stylesheet" type="text/css" href="map.css" /> + <script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAzBIC_wxmje-aKLT3RzZx7BQqYoqieBGZ_GPQY-hbWWrY23D7qxTw2ek84-RtvWTLn318N3vg6dKmhg" + type="text/javascript"></script> + <script src="map.js" type="text/javascript"></script> + </head> + <body onload="load()" onunload="GUnload()"> + <div id="quasimode"></div> + <div id="map"></div> + <div id="selection_info"></div> + </body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/locationInfo.xml Fri Feb 08 20:33:37 2008 +0000 @@ -0,0 +1,41 @@ +<locationInfo> + <loc name="The Neo-Futurarium" + address="5153 N. Ashland, Chicago, IL"> + <![CDATA[ Home to the Neo-Futurists, a dramatic group that is + worth checking out at least once—if not over and over. + Their signature act, <a + href="http://www.neofuturists.org/index.php?option=com_content&task=view&id=20&Itemid=45">Too + Much Light Makes the Baby Go Blind</a>, is the longest-running + show in Chicago and changes frequently.<p>See <a + href="http://www.neofuturists.org">neofuturists.org</a> for more + information.]]> + </loc> + <loc name="Hopleaf" + address="5148 N. Clark, Chicago, IL"> + <![CDATA[ An excellent bar that specializes in a wide variety of + Belgian beers. Easily Atul's favorite bar in the Chicagoland + area. Find out more at <a href="http://www.hopleaf.com">hopleaf.com</a>.]]> + </loc> + <loc name="Landmark Century Centre Cinema" + address="2828 N. Clark, Chicago, IL" + lat="41.933632" long="-87.645689"> + <![CDATA[ An excellent independent theater that is used to show a + number of entries in the annual Chicago Film Festival. Take a + look at the <a + href="http://www.landmarktheatres.com/Market/Chicago/Chicago_Frameset.htm">showtimes</a>. + ]]> + </loc> + <loc name="Roscoe Hall" + address="1925 W. Newport, Chicago, IL"> + <![CDATA[ Where John, J.P., Erik, Atul, and/or Isaac used to + live.]]> + </loc> + <loc name="Mozilla, Building K" + address="1981 Landings Dr., Mountain View, CA"> + <![CDATA[ Mozilla Headquarters! ]]> + </loc> + <loc name="Mozilla, Toronto Office" + address="20 Richmond St East, Toronto, Ontario, Canada"> + <![CDATA[ Mozilla's Toronto office.]]> + </loc> +</locationInfo>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/map.css Fri Feb 08 20:33:37 2008 +0000 @@ -0,0 +1,65 @@ +a:link { +color:#990000; +text-decoration:none; +} + +a:visited { +color:#990000; +text-decoration:none; +} + +a:hover { +color:#CC3300; +text-decoration:underline; +} + +a:active { +color:#990000; +text-decoration:none; +} + +body { + font-family: lucida grande,lucida sans unicode,arial,verdana,sans serif; + font-size: 8pt; + line-height: 1.4em; +} + +.locationHeader { + font-weight: bold; +} + +.searchHighlight { + background-color: yellow; +} + +.searchSuccessful { + font-weight: bold; +} + +.searchUnsuccessful { + font-weight: bold; + color: red; +} + +#map { + width: 600px; + height: 600px; + top: 10; + left: 10; + border: 1px solid black; + position: absolute; +} + +#selection_info { + width: 200px; + top: 10; + left: 620px; + position: absolute; +} + +#quasimode { + width: 640px; + top: 620px; + left: 10; + position: absolute; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/map.js Fri Feb 08 20:33:37 2008 +0000 @@ -0,0 +1,390 @@ +/* General */ +const SITE_HOSTNAME = "labs.toolness.com" + +function load() +{ + if (GBrowserIsCompatible()) + { + Location.prototype.initMap( + document.getElementById("map"), + document.getElementById("selection_info") + ); + GDownloadUrl( "locationInfo.xml", parseLocationInfo ); + } + + theQuasimode = new Quasimode( + SHIFT_KEYCODE, + new QuasimodeDelegate( document.getElementById("quasimode") ) + ); +} + +/* Location */ +const MARKER_SELECTED_IMG = "http://labs.google.com/ridefinder/images/mm_20_red.png"; +const MARKER_UNSELECTED_IMG = "http://labs.google.com/ridefinder/images/mm_20_gray.png"; +const MARKER_SHADOW_IMG = "http://labs.google.com/ridefinder/images/mm_20_shadow.png"; + +function Location( info ) +{ + for ( key in info ) + this[key] = info[key]; + + if ( !Location.prototype.icon ) + { + var icon = new GIcon(); + + icon.image = MARKER_UNSELECTED_IMG; + icon.shadow = MARKER_SHADOW_IMG; + icon.iconSize = new GSize(12, 20); + icon.shadowSize = new GSize(22, 20); + icon.iconAnchor = new GPoint(6, 20); + icon.infoWindowAnchor = new GPoint(5, 1); + + Location.prototype.icon = icon; + } + + var i = this.locations.length; + + var point = new GLatLng( this.lat, this.long ); + + var markerOptions = { icon: Location.prototype.icon, + title: this.name }; + + this.marker = new GMarker(point, markerOptions); + + this.globalName = "Location.prototype.locations[" + i + "]"; + + this.map.addOverlay( this.marker ); + + GEvent.bind( this.marker, "click", this, this.select ); + + this.locations.push( this ); + + if ( !Location.prototype.selection ) + this.select(); +} + +Location.prototype.select = function() +{ + if ( Location.prototype.selection ) + Location.prototype.selection.unselect(); + this.marker.setImage( MARKER_SELECTED_IMG ); + this.map.panTo( new GLatLng(this.lat, this.long) ); + + var html = ( "<div class=\"locationHeader\" onclick=\"" + + this.globalName + + ".select()\">" + this.name + "</div>" + + "<p>" + this.address + "</p>" + + "<p>" + this.description + "</p>" ); + + Location.prototype.selectionInfoElement.innerHTML = html; + + Location.prototype.selection = this; +} + +Location.prototype.unselect = function() +{ + this.marker.setImage( MARKER_UNSELECTED_IMG ); + Location.prototype.selection = null; +} + +Location.prototype.initMap = function( mapElement, selectionInfoElement ) +{ + var map = new GMap2( mapElement ); + + Location.prototype.selectionInfoElement = selectionInfoElement; + Location.prototype.map = map; + Location.prototype.locations = []; + + map.setCenter(new GLatLng(0, 0), 13); + + map.enableScrollWheelZoom(); + map.enableContinuousZoom(); + map.disableInfoWindow(); +} + +Location.prototype.icon = null; +Location.prototype.selection = null; +Location.prototype.map = null; +Location.prototype.selectionInfoElement = null; +Location.prototype.locations = null; + +function findLatLong( info ) +{ + var cachedLocs = null; + + var key = "mapCache_" + info.address; + + if ( window.globalStorage != undefined ) + cachedLocs = window.globalStorage[SITE_HOSTNAME]; + else + cachedLocs = {}; + + var makeLocationFromCache = function() + { + var latAndLong = new String(cachedLocs[key]).split( "," ); + + info.lat = parseFloat( latAndLong[0] ); + info.long = parseFloat( latAndLong[1] ); + + new Location( info ); + } + + if ( cachedLocs[key] == undefined ) + { + var geocoder = new GClientGeocoder(); + var geocoderCallback = function( point ) + { + if ( !point ) + { + //console.log( "Can't get geocoding info for " + + // info.address ); + } else { + //console.log( "Fetched geocoding info for " + + // info.address ); + var pointArray = [ point.lat(), point.lng() ]; + cachedLocs[key] = pointArray.join( "," ); + makeLocationFromCache(); + } + } + + geocoder.getLatLng( info.address, geocoderCallback ); + } else + makeLocationFromCache(); +} + +function parseLocationInfo( data ) +{ + var xml = GXml.parse( data ); + var locations = xml.documentElement.getElementsByTagName( "loc" ); + + for ( var i = 0; i < locations.length; i++ ) + { + var loc = locations[i]; + + var info = { name: loc.getAttribute( "name" ), + address: loc.getAttribute( "address" ), + description: loc.textContent }; + + if ( loc.hasAttribute("lat") ) + { + info.lat = parseFloat( loc.getAttribute("lat") ); + info.long = parseFloat( loc.getAttribute("long") ); + + new Location( info ); + } else + findLatLong( info ); + } +} + +/* Quasimode Delegate */ + +QUASIMODE_HELP_MSG = ( "Press and hold down the shift key to " + + "search for a location." ); + +QUASIMODE_HELP_MSG2 = ( "Continue to hold the shift key and " + + "start typing the name of the location " + + "you want to go to." ); + +QUASIMODE_SEARCH_MSG = "Now searching for: " + +function QuasimodeDelegate( displayElement ) +{ + this.displayElement = displayElement; + this.displayElement.innerHTML = QUASIMODE_HELP_MSG; +} + +QuasimodeDelegate.prototype.onQuasimodeBegin = function() +{ + this.originalSelection = Location.prototype.selection; + this.displayElement.innerHTML = QUASIMODE_HELP_MSG2; +} + +QuasimodeDelegate.prototype.onQuasimodeEnd = function() +{ + this.displayElement.innerHTML = QUASIMODE_HELP_MSG; + this.originalSelection = null; + this.resetSelectionInfoHighlighting(); +} + +QuasimodeDelegate.prototype.resetSelectionInfoHighlighting = function() +{ + if ( !this.pristineSelInfoElement ) + return; + + this.pristineSelInfoElement.innerHTML = this.pristineSelInfo; + this.pristineSelInfoElement = null; + this.pristineSelInfo = null; +} + +QuasimodeDelegate.prototype.onSearch = function( searchString ) +{ + var locs = Location.prototype.locations; + var bestMatchLoc = null; + var bestMatchIndex = Infinity; + var spanClass = "searchUnsuccessful" + + if ( searchString.length > 0 ) + { + for ( var i = 0; i < locs.length; i++ ) + { + var searchText = ( locs[i].name + locs[i].address + + locs[i].description ); + + searchText = searchText.toLowerCase(); + + var matchIndex = searchText.search( searchString ); + + if ( matchIndex != -1 && matchIndex < bestMatchIndex ) + { + bestMatchIndex = matchIndex; + bestMatchLoc = locs[i]; + } + } + } + + this.resetSelectionInfoHighlighting(); + + if ( bestMatchLoc ) + { + bestMatchLoc.select(); + + this.pristineSelInfoElement = bestMatchLoc.selectionInfoElement; + this.pristineSelInfo = this.pristineSelInfoElement.innerHTML; + this.pristineSelInfoElement.innerHTML = doHighlight( + this.pristineSelInfo, + searchString, + "<span class=\"searchHighlight\">", + "</span>" + ); + spanClass = "searchSuccessful"; + } else + this.originalSelection.select(); + + this.displayElement.innerHTML = ( QUASIMODE_SEARCH_MSG + + "<span class=\"" + spanClass + "\">" + + searchString + + "</span>" ); +} + +/* Quasimode */ + +var theQuasimode = null; + +SHIFT_KEYCODE = 16; +BACKSPACE_KEYCODE = 8; + +function Quasimode( quasimodeKeycode, delegate ) +{ + this.quasimodeKeycode = quasimodeKeycode; + this.searchString = ""; + this.inQuasimode = false; + this.delegate = delegate; + + self = this; + + window.addEventListener( "keydown", + function(evt) { self.onKeyDown(evt) }, + false ); + window.addEventListener( "keyup", + function(evt) { self.onKeyUp(evt) }, + false ); + window.addEventListener( "keypress", + function(evt) { self.onKeypress(evt) }, + false ); +} + +Quasimode.prototype.onKeypress = function( evt ) +{ + if ( this.inQuasimode ) + { + //console.log( evt ); + /* Originally I used evt.isChar here, but according to bug + * 312552 it always returns false. It appears to be fixed in + * Firefox 3, but not in earlier versions. */ + if ( evt.charCode ) + { + var newChar = String.fromCharCode( evt.charCode ); + this.searchString += newChar.toLowerCase(); + //console.log( "char" ); + } else { + //console.log( "not a char" ); + if ( evt.keyCode == BACKSPACE_KEYCODE && + this.searchString.length > 0 ) + this.searchString = this.searchString.slice( + 0, + this.searchString.length - 1 + ) + } + this.delegate.onSearch( this.searchString ); + } +} + +Quasimode.prototype.onKeyDown = function( evt ) +{ + if ( (!this.inQuasimode) && evt.keyCode == this.quasimodeKeycode ) + { + this.inQuasimode = true; + this.searchString = ""; + this.delegate.onQuasimodeBegin(); + } +} + +Quasimode.prototype.onKeyUp = function( evt ) +{ + if ( this.inQuasimode && evt.keyCode == this.quasimodeKeycode ) + { + this.inQuasimode = false; + this.searchString = ""; + this.delegate.onQuasimodeEnd(); + } +} + +/* Text highlighting code, taken from: + * http://www.nsftools.com/misc/SearchAndHighlight.htm */ + +/* + * This is the function that actually highlights a text string by + * adding HTML tags before and after all occurrences of the search + * term. You can pass your own tags if you'd like, or if the + * highlightStartTag or highlightEndTag parameters are omitted or + * are empty strings then the default <font> tags will be used. + */ +function doHighlight(bodyText, searchTerm, highlightStartTag, highlightEndTag) +{ + // the highlightStartTag and highlightEndTag parameters are optional + if ((!highlightStartTag) || (!highlightEndTag)) { + highlightStartTag = "<font style='color:blue; background-color:yellow;'>"; + highlightEndTag = "</font>"; + } + + // find all occurences of the search term in the given text, + // and add some "highlight" tags to them (we're not using a + // regular expression search, because we want to filter out + // matches that occur within HTML tags and script blocks, so + // we have to do a little extra validation) + var newText = ""; + var i = -1; + var lcSearchTerm = searchTerm.toLowerCase(); + var lcBodyText = bodyText.toLowerCase(); + + while (bodyText.length > 0) { + i = lcBodyText.indexOf(lcSearchTerm, i+1); + if (i < 0) { + newText += bodyText; + bodyText = ""; + } else { + // skip anything inside an HTML tag + if (bodyText.lastIndexOf(">", i) >= bodyText.lastIndexOf("<", i)) { + // skip anything inside a <script> block + if (lcBodyText.lastIndexOf("/script>", i) >= lcBodyText.lastIndexOf("<script", i)) { + newText += bodyText.substring(0, i) + highlightStartTag + bodyText.substr(i, searchTerm.length) + highlightEndTag; + bodyText = bodyText.substr(i + searchTerm.length); + lcBodyText = bodyText.toLowerCase(); + i = -1; + } + } + } + } + + return newText; +}