I was tasked with a dual problem the other day and with the help of the Virtual Earth interactive SDK, managed to complete the task in only a matter of a couple of hours.
The first thing to do was to try and get the Virtual Earth map displayed within a web part. That should be easy enough, just get a Site Viewer web part and point to local.live.com. Unfortunately this doesn't actually work, all you get is a blank web part.
OK so what now? Well since we want to eventually manipulate the map ourselves, we really want to host the Virtual Earth map on our own server (kindof), so the next thing I tried was to simply create a new website on the MOSS (Microsoft Office Server Systems – the new name for Sharepoint Server) server, assign it a unique port number and then create a new web application in there that simply uses the VE SDK and displays a map onto an aspx page.
This was no problem to create. Went back into my MOSS server and pointed the Site Viewer webpart to my now internally hosted page and the Virtual Earth map displayed.
Onto Stage 2. Virtual Earth is a great technology and database however there are certain things that it obviously doesn't hold. Things like local people will call buildings perhaps by a name rather than the street address and the VE database won't hold the local name. This is the same situation my problem falls under, if we want a map of the university I work for with all the local building names so that students/faculty etc. can simply type in the local building names to get directions then we need to create our own database holding the names of the local buildings along with the latitude and longitude of those buildings.
So off to SQL Server to create a very simple database that simply lists the local names of the buildings and the latitude and longitude of each building.
Now back in our web app, we simply add a couple of text boxes below the VE Map for people to type the names of the buildings in and a submit button to show the directions. Once the submit button is clicked, it should go off to the database, retrieve the longitude and latitude of the two buildings and create a new VELatLong object for each. This can then be used with the GetRoute function to display the route. In the spirit of VE the calls to the backend to retrive the information from the database was done using XMLHttp so that the page wouldn't need to refresh.
The first thing to do was to try and get the Virtual Earth map displayed within a web part. That should be easy enough, just get a Site Viewer web part and point to local.live.com. Unfortunately this doesn't actually work, all you get is a blank web part.
OK so what now? Well since we want to eventually manipulate the map ourselves, we really want to host the Virtual Earth map on our own server (kindof), so the next thing I tried was to simply create a new website on the MOSS (Microsoft Office Server Systems – the new name for Sharepoint Server) server, assign it a unique port number and then create a new web application in there that simply uses the VE SDK and displays a map onto an aspx page.
This was no problem to create. Went back into my MOSS server and pointed the Site Viewer webpart to my now internally hosted page and the Virtual Earth map displayed.
Onto Stage 2. Virtual Earth is a great technology and database however there are certain things that it obviously doesn't hold. Things like local people will call buildings perhaps by a name rather than the street address and the VE database won't hold the local name. This is the same situation my problem falls under, if we want a map of the university I work for with all the local building names so that students/faculty etc. can simply type in the local building names to get directions then we need to create our own database holding the names of the local buildings along with the latitude and longitude of those buildings.
So off to SQL Server to create a very simple database that simply lists the local names of the buildings and the latitude and longitude of each building.
Now back in our web app, we simply add a couple of text boxes below the VE Map for people to type the names of the buildings in and a submit button to show the directions. Once the submit button is clicked, it should go off to the database, retrieve the longitude and latitude of the two buildings and create a new VELatLong object for each. This can then be used with the GetRoute function to display the route. In the spirit of VE the calls to the backend to retrive the information from the database was done using XMLHttp so that the page wouldn't need to refresh.
Here's the code for the Virtual Earth WebPart page.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!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 runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Map</title>
<script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js"></script>
<script type="text/javascript" language="javascript">
var map = null;
var XMLHttp = null;
var BuildingCoords = null;
function GetMap()
{
map = new VEMap('map');
map.LoadMap(new VELatLong(33.504114945297374, -86.79941654205322), 17 ,'h' , false);
}
function GetCoords()
{
var coords = document.getElementById("Buildng1");
coords.value = map.GetCenter();
}
function GetDirs()
{
var build1 = document.getElementById("txtFrom");
var build2 = document.getElementById("txtTo");
var url = "GetCoords.aspx?Building1=" + build1.value + "&Building2=" + build2.value;
getXMLHttp();
if(XMLHttp != null)
{
XMLHttp.open("GET", url);
XMLHttp.onreadystatechange = stateChanged;
XMLHttp.send(null);
}
}
function stateChanged()
{
if(XMLHttp.readyState == 4 && XMLHttp.status == 200)
{
BuildingCoords = XMLHttp.responseText;
var brk = BuildingCoords.indexOf("|");
var Building1 = BuildingCoords.substr(0, brk);
var Building2 = BuildingCoords.substr(brk + 1);
/* var bld1 = document.getElementById("Buildng1");
bld1.value = Building1;
var bld2 = document.getElementById("Buildng2");
bld2.value = Building2; */
var bld1brk = Building1.indexOf(", ");
var bld1lat = Building1.substr(0, bld1brk);
var bld1lon = Building1.substr(bld1brk + 2);
var bld2brk = Building2.indexOf(", ");
var bld2lat = Building2.substr(0, bld2brk);
var bld2lon = Building2.substr(bld2brk + 2);
var point1 = new VELatLong(bld1lat, bld1lon);
var point2 = new VELatLong(bld2lat, bld2lon);
map.GetRoute(point1, point2);
}
}
function getXMLHttp()
{
if(window.ActiveXObject)
{
try
{
XMLHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch(e)
{
try
{
XMLHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e)
{
}
}
}
else if(window.XMLHttpRequest)
{
try
{
XMLHttp = new XMLHttpRequest();
}
catch(e)
{
}
}
}
</script>
<style type="text/css">
.map {
position: absolute;
top: 20;
left: 10;
width: 400px;
height: 400px;
border:#555555 2px solid;
}
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Map</title>
<script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js"></script>
<script type="text/javascript" language="javascript">
var map = null;
var XMLHttp = null;
var BuildingCoords = null;
function GetMap()
{
map = new VEMap('map');
map.LoadMap(new VELatLong(33.504114945297374, -86.79941654205322), 17 ,'h' , false);
}
function GetCoords()
{
var coords = document.getElementById("Buildng1");
coords.value = map.GetCenter();
}
function GetDirs()
{
var build1 = document.getElementById("txtFrom");
var build2 = document.getElementById("txtTo");
var url = "GetCoords.aspx?Building1=" + build1.value + "&Building2=" + build2.value;
getXMLHttp();
if(XMLHttp != null)
{
XMLHttp.open("GET", url);
XMLHttp.onreadystatechange = stateChanged;
XMLHttp.send(null);
}
}
function stateChanged()
{
if(XMLHttp.readyState == 4 && XMLHttp.status == 200)
{
BuildingCoords = XMLHttp.responseText;
var brk = BuildingCoords.indexOf("|");
var Building1 = BuildingCoords.substr(0, brk);
var Building2 = BuildingCoords.substr(brk + 1);
/* var bld1 = document.getElementById("Buildng1");
bld1.value = Building1;
var bld2 = document.getElementById("Buildng2");
bld2.value = Building2; */
var bld1brk = Building1.indexOf(", ");
var bld1lat = Building1.substr(0, bld1brk);
var bld1lon = Building1.substr(bld1brk + 2);
var bld2brk = Building2.indexOf(", ");
var bld2lat = Building2.substr(0, bld2brk);
var bld2lon = Building2.substr(bld2brk + 2);
var point1 = new VELatLong(bld1lat, bld1lon);
var point2 = new VELatLong(bld2lat, bld2lon);
map.GetRoute(point1, point2);
}
}
function getXMLHttp()
{
if(window.ActiveXObject)
{
try
{
XMLHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch(e)
{
try
{
XMLHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e)
{
}
}
}
else if(window.XMLHttpRequest)
{
try
{
XMLHttp = new XMLHttpRequest();
}
catch(e)
{
}
}
}
</script>
<style type="text/css">
.map {
position: absolute;
top: 20;
left: 10;
width: 400px;
height: 400px;
border:#555555 2px solid;
}
</style>
</head>
<body onload="GetMap();">
<div id="map" class="map" onclick="GetCoords();"></div>
<br />
<div id="coords" style=’position:absolute; top:420px;’>
From : <input type="text" id="txtFrom" value="" size="20" />
<br />
To : <input type="text" id="txtTo" value="" size="20" />
<br />
<input type="submit" onclick="GetDirs();" value="Get Directions" />
<!– <input type="submit" onclick="GetCoords();" value="Get Coords" />
<br /><br />
Build1: <input type="text" id="Buildng1" value="" size="20" />
<br />
Build2: <input type="text" id="Buildng2" value="" size="20" /> –>
</div>
</body>
</html>
</head>
<body onload="GetMap();">
<div id="map" class="map" onclick="GetCoords();"></div>
<br />
<div id="coords" style=’position:absolute; top:420px;’>
From : <input type="text" id="txtFrom" value="" size="20" />
<br />
To : <input type="text" id="txtTo" value="" size="20" />
<br />
<input type="submit" onclick="GetDirs();" value="Get Directions" />
<!– <input type="submit" onclick="GetCoords();" value="Get Coords" />
<br /><br />
Build1: <input type="text" id="Buildng1" value="" size="20" />
<br />
Build2: <input type="text" id="Buildng2" value="" size="20" /> –>
</div>
</body>
</html>
The commented out sections were simply used to get the latitude and longitude co-ordinates of the various places to store in the database alongside the local name.
And here is the web page that the XMLHttp request calls to return the co-ordinates of the places.
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;
public partial class GetCoords : System.Web.UI.Page
{
private string connString = "your connection string goes here";
{
private string connString = "your connection string goes here";
protected void Page_Load(object sender, EventArgs e)
{
string Building1 = Request["Building1"].ToString();
string Building2 = Request["Building2"].ToString();
string latlong1 = GetLatLong(Building1);
string latlong2 = GetLatLong(Building2);
string latlong = latlong1 + "|" + latlong2;
Response.Write(latlong);
Response.End();
}
{
string Building1 = Request["Building1"].ToString();
string Building2 = Request["Building2"].ToString();
string latlong1 = GetLatLong(Building1);
string latlong2 = GetLatLong(Building2);
string latlong = latlong1 + "|" + latlong2;
Response.Write(latlong);
Response.End();
}
public string GetLatLong(string Building)
{
string latlong = string.Empty;
SqlConnection conn = new SqlConnection(connString);
string sql = "SELECT * FROM Campus WHERE Building LIKE '" + Building + "';";
SqlCommand cmdSQL = new SqlCommand(sql, conn);
SqlDataReader dr;
try
{
conn.Open();
dr = cmdSQL.ExecuteReader();
while (dr.Read())
{
latlong = dr["Latitude"].ToString();
latlong += ", ";
latlong += dr["Longitude"].ToString();
}
dr.Dispose();
}
catch
{
return String.Empty;
}
finally
{
conn.Close();
}
return latlong;
}
{
string latlong = string.Empty;
SqlConnection conn = new SqlConnection(connString);
string sql = "SELECT * FROM Campus WHERE Building LIKE '" + Building + "';";
SqlCommand cmdSQL = new SqlCommand(sql, conn);
SqlDataReader dr;
try
{
conn.Open();
dr = cmdSQL.ExecuteReader();
while (dr.Read())
{
latlong = dr["Latitude"].ToString();
latlong += ", ";
latlong += dr["Longitude"].ToString();
}
dr.Dispose();
}
catch
{
return String.Empty;
}
finally
{
conn.Close();
}
return latlong;
}
}
The first page (default.aspx – the one that actually displays the map) has no code behind.
The second page (GetCoords.aspx) really only has code behind. I didn't touch the .aspx page itself.
And that's it. Compile the pages, publish them off to your site on the MOSS server and simply use the Page Viewer webpart within MOSS to point to your site.