Our Friends

MP2K Mag

Recent Blog Posts RSS

ViaWindowsLive on Via Virtual Earth Blog

The new ViaWindowsLive community site has launched and features not only a definitive set of resources on all Live Services from Microsoft but also a special section on Virtual Earth including a new site gallery for you to upload your sites, new articles on Version 6, including getting started guide, an interactive quick guide, location finder and more. Subscribe to the VWL aggregated blog to stay in touch with everything Live Services related. Find all the great content from this site and much, much more. Explore how other Live Services can compliment Virtual Earth and your applications.

Version 5 URL changed - Error: 'VEMap' is undefined on Via Virtual Earth Blog

It has been reported that the old url to access the Version5 javascript for Virtual Earth no longer works. This is effecting sites worldwide.

The correct way to reference the Version 5 javascript is:

<script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=5"></script>

If you have been effected a forum thread has been started here

Silverlight Virtual Earth viewer on Via Virtual Earth Blog

With the launch of silverlight yesterday I was digging around and found this viewer for Virtual Earth by Greg Schechter. It does use the 1.1 alpha of silverlight. It gives some interesting ideas for where Virtual Earth could be headed. Certainly the demo of the performance of silverlight compared to javascript for processing showed a significant increase. This could be very useful.

And of course on the gamer front check this out by Andy Beaulieu and shoot down some UFO's over Birdseye images.

John.

So much new Virtual Earth Imagery Worldwide. on Via Virtual Earth Blog

I subscribe to all the VE blogs and recently the posts about updated imagery has been more and more frequent.

The latest is here and for myself downunder we saw three updates, Canberra, Newcastle and Uluru:

CanberraAUUluruAUNewcastleAU

Derek Chan posts 3 Articles in a month! on Via Virtual Earth Blog

A big thank you to the efforts of Derek Chan who posted his third VE article today (he actually had it ready weeks ago but had to wait for Mr Bottleneck here at VVE ;) )

The 3 articles are all relivant to Version 5 of Virtual Earth and deal with the Mini Map, debugging javascript and now custom pins in routes.

All these can now be found in our articles section.

If you have something to contribute send us an email.

John (The bottleneck)

The building of mygeoland.com RSS

mygeoland.com is a minimalist location search for Australia. By offloading everything to the power of Virtual Earth it provides a simple, fast and fun way to find a street, suburb or place in Australia. In this article I explain how simple it really is as we build the site from the ground up with a few div tags and a handful of JavaScript. I will then touch on some really simply ways we can optimise such a site using free third party tools and server options.

MyGeoLand 3D

Go check it out: mygeoland.com

Simply double click the state, type the street name and extension e.g. ‘smith st’ and press enter.

Because you centred the map on the state, the search box automatically populates the state and country. So what have we done to put this together? Isn’t it just a stock Virtual earth control with a textbox. Well guess what? Pretty much it is, with a few tricks to make it work well and no crap put in.

Stage 1 – Stock map control

This is the basic html page that displays a road map over east coast Australia.

<!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>
    <title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script type="text/javascript" 
    src="http://dev.virtualearth.net/mapcontrol/v4/mapcontrol.js"></script>
    <script type="text/javascript">
     var map = null;
     
     function GetMap()
     {
      map = new VEMap('myMap');
      map.LoadMap(new VELatLong(-29, 152),5,'r',false);
      map.SetScaleBarDistanceUnit(VEDistanceUnit.Kilometers);      
     }   
    </script>
   </head>
   <body onload="GetMap();">
    <div id="myMap" style="position:relative; width:400px; height:400px;"></div>
   </body>
</html>

View Page.

Stage 2 – Full screen and dispose

We set the map div to 100% height and 100% width but we also need to hook the body onresize to tell the VE control we have resized to a specific size, I utilise some cross-browser javascript to calculate the new size.

<body onload="GetMap();" onresize="ResizeMap();" onunload="UnloadMap();">
<div id="myMap" style="width:100%;height:100%;position:relative;"></div>
</body>

While we are here we also want to hook the body onunload event and dispose of the map object.

function ResizeMap() //resize
{
  if (map != null)
  {  
    if( typeof( window.innerWidth ) == 'number' )
    {
    //Non-IE
    map.Resize(window.innerWidth,window.innerHeight);
    } 
    else if( document.documentElement && ( document.documentElement.clientWidth
       || document.documentElement.clientHeight ) )
    {
    //IE 6+ in 'standards compliant mode'
    map.Resize(document.documentElement.clientWidth
      ,document.documentElement.clientHeight);
    }
  }
}

function UnloadMap() //dispose map etc
{
  if (map != null)
  {
    map.Dispose();
  }
} 

View Page.

Stage 3 – Custom search box and disambiguation box

For the search box I add a simply div to the page containing a textbox and a go hyperlink with some css styles. For the disambiguation box I add another div, again with some css styles.

<div id="mySearch" style="position:absolute;top:12px;left:100px;font: bold 10px arial;">
  <input tabindex="0" id="SearchInput" style="width:280px;font:bold 14px arial;
  filter:Alpha(Opacity=80);opacity:0.8;" type="text" onkeydown="Keypress(event);" 
  autocomplete="off" size="20" /> <a 
  href="javascript:Search(document.getElementById('SearchInput').value);"
   >GO</a></div>
<div id="myDisambiguation" style="display:none;position:absolute;width:400px;top:34px;
  left:100px;z-index:1000;background-color:White;font:bold 14px arial;
  border: solid 1px black;"></div>   

We have to add the following JavaScript to wire it up, we accept a key press of enter to search, put a pin at the right location of the result – DO NOT USE map.GetCenter() - and  produce the html for the disambiguation box.

function Keypress(e) //keypress
{
  if (e.keyCode == 13) {
    Search(document.getElementById('SearchInput').value);
  }
}  
function Search(s) //search
{
  DisambiguationClose();
  if (s != '')
  { 
    map.Find(null,s,1,SearchResults);
  }
}
function SearchResults(results) //search returned
{
  map.Clear();
  map.AddPushpin(new VEPushpin("sPin",  results[0].LatLong));
}  
function Disambiguation(e) //Disambiguation Callback
{
  var r="<div style='float:left'>Multiple results. 
    Choose or refine search.</div><div
    style='float:right;cursor:pointer;' 
    onclick='DisambiguationClose();'>X</div><br />";
  for (x=0; x<e.length; x++)
  {
    r+="<a onclick='Search(\""+e[x].ID+"\");' href='#'>"+e[x].ID+"</a><br>";
  }
  document.getElementById('myDisambiguation').innerHTML=r;
  document.getElementById('myDisambiguation').style.display = "block";
}   
function DisambiguationClose() //close DisambiguationCallback
{
  document.getElementById("myDisambiguation").style.display = "none";
}  

View Page.

Stage 4 – Support for controls in 3D mode

In order for our search box and disambiguation box to appear in 3D mode we have to generate a “shim”. The shim is an iframe that allows the control to be placed on top of the 3D layer.

We add some generic add and remove functions and then call the function when the map changes to 3D mode. This is achieved by hooking the “oninitmode” event.

function GetMap()
{
  map = new VEMap('myMap');
  map.LoadMap(new VELatLong(-29, 152),5,'r',false);
  map.SetScaleBarDistanceUnit(VEDistanceUnit.Kilometers);      
  map.DisambiguationCallback = Disambiguation;
  map.ShowDisambiguationDialog(false);   
  map.AttachEvent('oninitmode', ModeChange);  
  map.AddControl(document.getElementById("mySearch"));   
  map.AddControl(document.getElementById("myDisambiguation")); 
  AddShim(document.getElementById("mySearch"),"mySearchShim");         
} 

function AddShim(el,sid)  //add iframe shim     
{   
  if (map.GetMapMode() == VEMapMode.Mode3D)  
  {   
    var s = document.createElement("iframe");      
    s.id = sid;      
    s.frameBorder = "0";      
    s.style.position = "absolute";      
    s.style.zIndex = "1";      
    s.style.top  = el.offsetTop;      
    s.style.left = el.offsetLeft;      
    s.width  = el.offsetWidth;      
    s.height = el.offsetHeight;
    s.scrolling="no";
    s.className="Shim";
    el.shimElement = s;      
    el.parentNode.insertBefore(s, el);   
  }    
}
function RemoveShim(sid) //remove iframe shim      
{             
  var msh = document.getElementById(sid);     
  if (msh!=null) msh.parentNode.removeChild(msh);      
  msh = null;     
} 
function ModeChange() //Change from 2d to 3d etc
{
  if (map.GetMapMode() == VEMapMode.Mode3D)   
  {
    AddShim(document.getElementById("mySearch"),"mySearchShim");
    if (document.getElementById("myDisambiguation").style.display == "block")
    {
      AddShim(document.getElementById("myDisambiguation"),"myDisambiguationShim");
    }
  }else
  {
    RemoveShim("mySearchShim");
    RemoveShim("myDisambiguationShim");
  }
}  

View Page.

Stage 5 – Some hard coded reverse geocoding

To make the site auto-populate the state and country for Australia we hook the onfocus event for the text box and work out the centre location of the map with a set of if..else statements.

function GetLocation() //GetLocation
  {
  //don't change if the Disambiguation box is up.
  if (document.getElementById('myDisambiguation').style.display == "none")
  {
  var mc = map.GetCenter();
  var mla = mc.Latitude;
  var mlo = mc.Longitude;
  var s = "";
  
  if (mla < -8.67 && mla > -45.34 && mlo > 110.92 && mlo < 158.20) //AUS
  {
  if (mlo < 129) //WA
  {
  if (s.indexOf("WA") == -1)
  s = s + ", WA";
  }else if (mlo < 138 && mla > -26) //NT
  {
  if (s.indexOf("NT") == -1)
  s = s + ", NT";    
  }else if (mlo < 141 && mla < -26) //SA
  {
  if (s.indexOf("SA") == -1)
  s = s + ", SA" ;   
  }else if (mla > -28.23) //QLD
  {
  if (s.indexOf("QLD") == -1)
  s = s + ", QLD" ;   
  }else if (mla > -36.8)  //NSW
  {
  if (mla < -35.16 && mla > -35.93 && mlo > 148.8 && mlo < 149.21)  //ACT
  {
  if (s.indexOf("ACT") == -1)
  s = s + ", ACT";
  }else  //NSW
  {
  if (s.indexOf("NSW") == -1)
  s = s + ", NSW";
  }
  }else if (mla > -40)  //VIC
  {
  if (s.indexOf("VIC") == -1)
  s = s + ", VIC";
  }else  //TAS
  {
  if (s.indexOf("TAS") == -1)
  s = s + ", TAS";
  }
  //add AUS suffix
  if (s.indexOf("AUS") == -1)
  s = s + ", AUS";
  }
  document.getElementById("SearchInput").value = s;
  SetFocus();
  }
  }  
  function SetFocus() //setfocus
  {
  var elm = document.getElementById("SearchInput");
  if (elm.setSelectionRange) {
  elm.focus();
  elm.setSelectionRange(0, 0);
  }
  else if (elm.createTextRange) {
  var r = elm.createTextRange();
  r.collapse(true);
  r.moveEnd('character', 0);
  r.moveStart('character', 0);
  r.select();
  }
  }
  function SetDelayedFocus() //delayed focus
  {
  if (map.GetMapMode() != VEMapMode.Mode3D)
  {
  setTimeout("SetFocus()",100);
  }
  }

View Page.

Clearly this technique is error prone around the boundaries and doesn’t scale but it is a simple demo and is very fast. To make this more accurate and support the entire world you make an AJAX call to reverse geocode the position using one of the many services available such as:

http://www.geonames.org/export/#ws

Stage 6 – Hide the VE message boxes

To suppress some of the VE message boxes we add some css to override the visibility of the divs created. These are bound to change in the future so use at your own peril.

<style type="text/css">#a_vemessagepanel, #threeDNotification {visibility:hidden;}</style> 

View Page.

Stage 7 – Firefox 2 support

At the time of writing VE4 didn’t support Firefox 2.0. This simple snippet of js will get around that.


function GetMap()
{
    // START FIX FOR FF2.0
    var ffv = 0;
    var ffn = "Firefox/"
    var ffp = navigator.userAgent.indexOf(ffn);
    if (ffp != -1) ffv = parseFloat(navigator.userAgent.substring(ffp + ffn.length));
    // If we're using Firefox 1.5 or above override 
    // the Virtual Earth drawing functions to use SVG
    if (ffv >= 1.5) {
      Msn.Drawing.Graphic.CreateGraphic=function(f,b) 
        { return new Msn.Drawing.SVGGraphic(f,b) }
    }
    // END FIX FOR FF2.0            
    map = new VEMap('myMap');
    map.LoadMap(new VELatLong(-29, 152),5,'r',false);
    map.SetScaleBarDistanceUnit(VEDistanceUnit.Kilometers);          
    map.DisambiguationCallback = Disambiguation;
    map.ShowDisambiguationDialog(false);     
    map.AttachEvent('oninitmode', ModeChange);  
    map.AttachEvent('onclick', SetDelayedFocus);                
    map.AddControl(document.getElementById("mySearch"));     
    map.AddControl(document.getElementById("myDisambiguation")); 
    AddShim(document.getElementById("mySearch"),"mySearchShim"); 
    SetFocus();
} 

View Page.

Stage 8 – preloading message for VE JavaScript

The aim here is to make a really fast site. Later we will optimise your code but we will always face the overhead of the VE JavaScript. Rather than having to wait for the JavaScript to load before the page is shown what we do here is remove the link and dynamically load the JavaScript after the page is loaded. This way the site will load very quickly and show the loading and usage instructions.

A word of caution: I was unable to successfully dynamically include the proper “http://dev.virtualearth.net/mapcontrol/v4/mapcontrol.js” file. Instead I added the direct “http://local.live.com/veapi.asjx”. What this means it the site could break as the versions changes. Keep an eye on the VE wiki for updates or make a suggestion.

var map = null;
var le = 0;

function GetMap()
{
  var head = document.getElementsByTagName("head")[0];
  var s = document.createElement('script');
  s.id = 'VEScript';
  s.type = 'text/javascript';
  s.src = "http://local.live.com/veapi.asjx";
  head.appendChild(s);
  DelayGetMap();
}
function DelayGetMap()
{
  try {
    // START FIX FOR FF2.0
    var ffv = 0;
    var ffn = "Firefox/"
    var ffp = navigator.userAgent.indexOf(ffn);
    if (ffp != -1) ffv = parseFloat(navigator.userAgent.substring(ffp + ffn.length));
    // If we're using Firefox 1.5 or above override 
    // the Virtual Earth drawing functions to use SVG
    if (ffv >= 1.5) {
      Msn.Drawing.Graphic.CreateGraphic=function(f,b) 
      { return new Msn.Drawing.SVGGraphic(f,b) }
    }
    // END FIX FOR FF2.0      
    map = new VEMap('myMap');
    document.getElementById("myLoading").style.display = "none";
    document.getElementById("myMap").style.display = "block"; 
    document.getElementById("mySearch").style.display = "block"; 
    map.LoadMap(new VELatLong(-29, 152),5,'r',false);
    map.SetScaleBarDistanceUnit(VEDistanceUnit.Kilometers);      
    map.DisambiguationCallback = Disambiguation;
    map.ShowDisambiguationDialog(false);   
    map.AttachEvent('oninitmode', ModeChange);  
    map.AttachEvent('onclick', SetDelayedFocus);        
    map.AddControl(document.getElementById("mySearch"));   
    map.AddControl(document.getElementById("myDisambiguation")); 
    AddShim(document.getElementById("mySearch"),"mySearchShim"); 
    SetFocus();
  }catch(err)
  {
      if (le < 30)
      {
          le++;
          setTimeout("DelayGetMap()",1000);
      }else
      {
          alert("Site is busy.");
      }
  }           
}  

View Page.

Stage 9 – optimisation

We have no server side code! What we have is a static file the user downloads. Once they have this file all the work is done by Virtual Earth, her farm of servers and the clients broswser. So if we can reduce what the user needs to download from our site we can improve their experience. Unless you have some serious web farm infrastructure I bet we are the weakest link here.

Put into a separate js file

By moving the JavaScript into its own file it will be downloaded separately from the html file and cached.

Replace variable names.

Although our code was nice and readable the browser doesn’t care. By changing the variables and ID to several letters we vastly reduce the number of characters in the code.

Run through optimiser to remove comments and whitespace

I used: http://www.xtreeme.com/javascript-optimizer

To remove my comments and whitespace. We now have a JavaScript file that is 4.1KB compared to 10KB, that’s 2.4 times smaller!

Stage 10 – IIS6 settings

If you have access to your IIS settings there a couple of things that can make a big difference to serving static files.

Firstly, turn on IIS compression. This using gzip to compress the textual files. For our JavaScript and html page it makes a huge difference. Since the files are static the compression only occurs once. IIS serves less data and the client gets it faster. Html page is now 0.88KB and the JavaScript file is 1.59KB. If the browser supports it the user will download only 2.47KB the first time (Plus the VE JavaScript) and then only 880 Bytes on future requests!

Secondly enable kernel mode caching. See here for more information: http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/webapp/iis/iis6perf.mspx

Put simply this cache is accessed very early on in the processing logic of IIS. It means your server can serve the page with less effort and therefore can serve more pages/sec with little cpu usage.

Conclusion.

Here is the final product: mygeoland.com

In this article I hope you picked up a few tips on how to put together a simple VE page and get it serving up quick. Your homework is to go a build a local street search site for your country!

Virtual Earth is free for non-commercial use for sites serving less than 100,000 “transaction” per day.

So keep it local and find a decent host for your 2.47KB website! Then start adding some really cool stuff like webcams, traffic reports, weather, favourite places etc.

Article contributed by John O'Brien (www.soulsolutions.com.au). Have you got something to contribute?

Rating

What did you think?

Not signed in. Sign in or sign up?

Others thought...

         

Average: 5 / 5