MapPoint Forums

MapForums

Community of VE/MapPoint Users and Developers




How to bring your own content to Virtual Earth (Part 4)

This is a discussion on How to bring your own content to Virtual Earth (Part 4) within the Virtual Earth Blogs forums, part of the Blogs category; In the previous parts we added individual VEShape-objects to a layer and*we imported collections from Live Search Maps as well ...


Go Back   MapPoint Forums > Blogs > Virtual Earth Blogs

Register Blogs FAQ Members List Calendar Search Today's Posts Mark Forums Read



Click here to register

Reply

 

LinkBack (4) Thread Tools Display Modes
  4 links from elsewhere to this Post. Click to view. #1 (permalink)  
Old 09-26-2007
Member
Green Belt
 
Join Date: Sep 2007
Posts: 54
How to bring your own content to Virtual Earth (Part 4)

In the previous parts we added individual VEShape-objects to a layer and*we imported collections from Live Search Maps as well as GeoRSS-feeds. These are quick and simple methods to add information to your map but they are limited to some hundred VEShape-objects. There is no hard cut in Virtual Earth but you will experience a degradation in performance when you have more than let's say 300 points. A good solution would be to not*load all available information but only those which are in the current MapView. Our approach will be to determine the bounding box of the current MapView whenever it changes, use this information to query points of interest from a database and dynamically populate a VEShapeLayer with these points.

Dynamically populating*VEShapeLayer from a Database

The Virtual Earth API provides a number of events which we can attach to the map. Amongst these events are such which fire when we finish zooming*or*finish panning. We will capture these events and determine the latitude and longitude of the upper left and the lower right corner*of*our MapView. With these values we will build and execute a SQL-query against a database table with our points of interest (POI) and retrieve only those records which are within our bounding box. To make this as secure as possible we create an AJAX-call*to a WebHandler. The WebHandler in turn will build and execute the SQL Query. While it runs through a SqlDataReader it uses a StringBuilder to dynamically create a JavaScript or JSON-objects. The script is now returned in the response to the AJAX-call and executed there using the eval-command.

image

Don't worry, if that was to fast, we will walk through it in slow motion. First we add a new AccordionPane to our web site. Again we have HTML-controls of type checkbox in it and again we will capture the onclick-event and execute a parameterized JavaScript. There are 2 POI-categories we offer so far and that means we have to add 2 checkboxes.

<ajaxToolkit:AccordionPane ID="panePOI" runat="server">
<Header>POI from DatabaseHeader>
<Content>
<input id="cbBP" type="checkbox" onclick="AddPOILayer('cbBP',pplBP)" /><a href='javascript:ShowLocation(51.46160111471333, -0.9252655506134102, 19);'>BPa><br />
<input id="cbRailway" type="checkbox" onclick="AddPOILayer('cbRailway',pplRailway)" /><a href='javascript:ShowLocation(51.46160111471333, -0.9252655506134102, 19);'>Railwaya><br />
Content>
ajaxToolkit:AccordionPane>

Now lets move on to the JavaScript-part. In the global section we define an array which holds the activated POI-layers so that we can switch on and off various POI-categories. We also define a VEShapeLayer for each category.

var activePushPinLayer = new Array()
var pplBP = new VEShapeLayer();
var pplRailway = new VEShapeLayer();

In the GetMap-function which is being executed when we load the page we set titles for each layer so that we can easily address them later in our functions.

pplBP.SetTitle('pplBP');
pplRailway.SetTitle('pplRailway');

The function that is being executed when we click on one of the checkboxes is AddPOILayer and it takes 2 parameters as input.


  • the name of the control that has been clicked and
  • the name of the layer we want to populate.

If*the checkbox has been activated we add the relevant layer to the map and to the array which holds the active VEShapeLayers. Then we attach the events onendpan and onendzoom to the map and make sure that the function LoadData is executed whenever these events occur. Finally we call the function LoadData for the first time.

If the checkbox has been deactivated we leave the layer on the map but we delete all*VEShape-objects from it. Then we remove the VEShapeLayer from the array of active layers and detach the events from the map.

function AddPOILayer(control,layer)
{
if (document.getElementById(control).checked == false) {
//Delete Shape-Layer
layer.DeleteAllShapes();

//Remove the layer from the array of active layers
for (var i = 0; i < activePushPinLayer.length; ++i)
{
if (activePushPinLayer[i] == layer.GetTitle())
{
activePushPinLayer.splice(i,1);
}
}

//Detach Map-Events
if (activePushPinLayer.length == 1) {
map.DetachEvent("onendpan", LoadData);
map.DetachEvent("onendzoom", LoadData);
}
}
else{
//Create a new Shape-Layer
try
{
map.AddShapeLayer(layer);
}
catch(e)
{
}

//Add the layer to the array of active layers
activePushPinLayer.push(layer.GetTitle());

//Attach Map-Events
map.AttachEvent("onendpan", LoadData);
map.AttachEvent("onendzoom", LoadData);
LoadData();
}
}

The function LoadData prepares and executes our AJAX-call. First we delete all VEShape-objects from the map. Then we calculate the latitude and longitudes of the upper left and lower right corner of our MapView. Virtual Earth supports us here with a function PixelToLatLong. This function takes as input an VEPixel-object and this again is defined by 2 pixel coordinates relative to the MapView. Thus the upper left corner is always (0, 0) and the lower right corner is defined by the width and the height of our

-element. The output of the PixelToLatLong*function is always a VELatLong-object and we need to break it into its properties latitude and longitude.

Now we can start building our AJAX-call. The call goes to a WebHandler DBAccess.ashx which we still have to create and it will hand over a few URL-parameters. The first 4 are always the latitudes and longitudes of the upper left and lower right corner of our MapView. The fifth is the total number of active layers and the next ones are the names of the active layers.

Before we execute the call we first have to determine*what the appropriate XMLHTTP-object for the clients browser is and we do that by calling the function GetXmlHttp. With this object we execute the XMLHTTP Get-Request to our WebHandler and then the call waits until it receives the response from the WehHandler. As mentioned earlier this response is a JavaScript and it will be executed using the eval-command.

function LoadData()
{
map.DeleteAllShapes();

//Retrieve the boundaries of the mapview
var ulPixel = new VEPixel(0, 0);
var brPixel = new VEPixel(mapWidth, mapHeight);
var ulLatLon = map.PixelToLatcLong(ulPixel);
var ulLat = ulLatLon.Latitude;
var ulLon = ulLatLon.Longitude;
var brLatLon = map.PixelToLatLong(brPixel);
var brLat = brLatLon.Latitude;
var brLon = brLatLon.Longitude;

//Build URL to call the server
var url="DBAccess.ashx?";
url += "&ulLat=" + ulLat;
url += "&ulLon=" + ulLon;
url += "&brLat=" + brLat;
url += "&brLon=" + brLon;

//In this part we check how many and which layers are active
url += "&layerCount=" + activePushPinLayer.length;
for (var i = 0; i < activePushPinLayer.length; ++i)
{
url += "&layer" + i + "=" + activePushPinLayer[i];
}

//Get the appropriate XMLHTTP object for the browser
var xmlhttp = GetXmlHttp();

//if we have a valid XMLHTTP object
if (xmlhttp)
{
xmlhttp.Open("GET", url, true); // varAsynx = true

//set the callback
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readystate ==4) //4 is a success
{
//server code creates JavaScript "on the fly" for us to
//execute using eval()
var result = xmlhttp.responseText
eval(result);
}
}
xmlhttp.send(null);
}
}

This is our function to determine the appropriate XMLHTTP-object as mentioned above:

function GetXmlHttp()
{
var x = null;
try
{
x = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
x = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
x = null;
}
}
if (!x && typeof XMLHttpRequest != "undefined")
{
x = new XMLHttpRequest();
}
return x;
}

That's all on the JavaScript side. Now we move on to our WebHandler but before we do that let's have a quick look at our database. We have 2 tables for the POI with a total of more than 4,000 records. The tables contain columns for the latitude and longitude and one with the same. This is of course just a sample and there could be many more information in it. How did we get the latitudes and longitudes in the first place? Well, that may be an issue for another blog-posting but the Virtual Earth platform can support you here as well.

CREATE TABLE [BP]">(
[Latitude] [float]">,
[Longitude] [float]">,
[Name] [nvarchar]">(255">))

We define the connection string to our database in the web.config

<connectionStrings>
<
add name="MyDB"
connectionString="
Data Source=MyServer;
Initial Catalog=MyDatabase;
uid=MyUID; pwd=MyPWD;
"
providerName="System.Data.SqlClient"/>
connectionStrings>

Now we create a new WebHandler DBAccess.ashx and import the namespace

Imports System.Data.SqlClient

Finally we replace the default code with the one shown below. It is always a good idea to set the CurrentCulture to make sure that the decimal separator for the latitudes and *longitudes are returned as a '.'. Then we fetch the URL-parameters as well as the ConnectionStrings from the web.config and set up the database connection before we build the SqlCommand. The SqlCommand is being executed with a SqlDataReader and as we read the records we use a StringBuilder to create the JavaScript which is later to be returned to the AJAX-call and executed there. If we have more than 300 records which meet the criteria we don't return a JavaScript to add the VEShape-objects but rather we return a script which pops up a message.

'set culture to en-UK to avoid potential problems with decimal-separators
System.Threading.Thread.CurrentThread.CurrentCultu re = System.Globalization.CultureInfo.CreateSpecificCul ture("en-UK")

'Get the URL-Parameters
Dim ulLat As String = context.Request.Params("ulLat")
Dim brLat As String = context.Request.Params("brLat")
Dim ulLon As String = context.Request.Params("ulLon")
Dim brLon As String = context.Request.Params("brLon")

'How many layers are active?
Dim layerCount As Integer = context.Request.Params("layerCount")

'Query database(s) and create JavaScript
Dim settings As ConnectionStringSettings
Dim sb As StringBuilder = New StringBuilder
Dim myPins As String = ""
Dim poiCounter As Integer = 0
Dim i As Integer = 0
For i = 0 To layerCount
Dim dummy As String = context.Request.Params("layer" & i)
Select Case dummy
Case "pplBP"
settings = ConfigurationManager.ConnectionStrings("MyDB")
Dim myConn As New SqlConnection(settings.ConnectionString)
Dim myQuery1 As String = "SELECT COUNT(*) FROM BP WHERE (Latitude BETWEEN " + brLat + " AND " + ulLat + ") AND (Longitude BETWEEN " + ulLon + " AND " + brLon + ")"
Dim myCMD1 As New SqlCommand(myQuery1, myConn)
myConn.Open()
Dim myReader1 As SqlDataReader = myCMD1.ExecuteReader()
myReader1.Read()
If myReader1(0) > 300 Then
myPins = myPins + _
"map.ShowMessage('There are more than 300s POI of type BP in this MapView. The Layer will not be shown.');"
sb.Append(myPins)
myReader1.Close()
Else
poiCounter = poiCounter + myReader1(0)
myReader1.Close()
Dim j As Integer = 0
Dim myQuery2 As String = "SELECT Latitude, Longitude, Name FROM BP WHERE (Latitude BETWEEN " + brLat + " AND " + ulLat + ") AND (Longitude BETWEEN " + ulLon + " AND " + brLon + ")"
Dim myCMD2 As New SqlCommand(myQuery2, myConn)
Dim myReader2 As SqlDataReader = myCMD2.ExecuteReader()
While myReader2.Read()
myPins = myPins + _
"var shape" + j.ToString + "=new VEShape(VEShapeType.Pushpin, new VELatLong(" + myReader2(0).ToString + ", " + myReader2(1).ToString + "));" + _
"shape" + j.ToString + ".SetCustomIcon('IMG/BP.bmp');" + _
"shape" + j.ToString + ".SetTitle(" + """" + myReader2(2).ToString + """" + ");" + _
"pplBP.AddShape(shape" + j.ToString + ");"
j = j + 1
End While
sb.Append(myPins)
myReader2.Close()
End If
myConn.Close()
Case "pplRailway"
settings = ConfigurationManager.ConnectionStrings("MyDB")
Dim myConn As New SqlConnection(settings.ConnectionString)
Dim myQuery1 As String = "SELECT COUNT(*) FROM Railway WHERE (Latitude BETWEEN " + brLat + " AND " + ulLat + ") AND (Longitude BETWEEN " + ulLon + " AND " + brLon + ")"
Dim myCMD1 As New SqlCommand(myQuery1, myConn)
myConn.Open()
Dim myReader1 As SqlDataReader = myCMD1.ExecuteReader()
myReader1.Read()
If myReader1(0) > 300 Then
myPins = myPins + _
"map.ShowMessage('There are more than 300s POI of type Railway in this MapView. The Layer will not be shown.');"
sb.Append(myPins)
myReader1.Close()
Else
poiCounter = poiCounter + myReader1(0)
myReader1.Close()
Dim j As Integer = 0
Dim myQuery2 As String = "SELECT Latitude, Longitude, Name FROM Railway WHERE (Latitude BETWEEN " + brLat + " AND " + ulLat + ") AND (Longitude BETWEEN " + ulLon + " AND " + brLon + ")"
Dim myCMD2 As New SqlCommand(myQuery2, myConn)
Dim myReader2 As SqlDataReader = myCMD2.ExecuteReader()
While myReader2.Read()
myPins = myPins + _
"var shape" + j.ToString + "=new VEShape(VEShapeType.Pushpin, new VELatLong(" + myReader2(0).ToString + ", " + myReader2(1).ToString + "));" + _
"shape" + j.ToString + ".SetCustomIcon('IMG/Railway.bmp');" + _
"shape" + j.ToString + ".SetTitle(" + """" + myReader2(2).ToString + """" + ");" + _
"pplRailway.AddShape(shape" + j.ToString + ");"
j = j + 1
End While
sb.Append(myPins)
myReader2.Close()
End If
myConn.Close()
End Select
Next

If poiCounter > 300 Then
context.Response.Write("map.ShowMessage('The POIs in all layers add up to more than 300. Please deselect a layer or zoom-in.');")
Else
context.Response.Write(sb.ToString())
End If

All right, that's it let's see what we have:

14-small

You will find the sample application here and as always the complete source code is available for download from this page as well.

Technorati Tags: Virtual Earth, AJAX, Database


Click here to view the article.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!Spurl this Post!Reddit! Wong this Post!
Reply With Quote
Reply

Tags
bring, content, part, virtual earth


LinkBacks (?)
LinkBack to this Thread: http://www.mapforums.com/how-bring-your-own-content-virtual-earth-part-4-a-6426.html

Posted By For Type Date
Using MapPoint from Word, Access and Excel - MapPoint Articles - MP2K Magazine This thread Refback 09-26-2007 10:37 PM
Using Autoroute 2003 Data in MapPoint 2002 - MapPoint Articles - MP2K Magazine This thread Refback 09-26-2007 10:24 PM
An API to Control MapPoint 2006 GPS Features - Part I of II - MapPoint Articles - MP2K Magazine This thread Refback 09-26-2007 05:04 PM
Programming MapPoint in .NET - MP2K Magazine This thread Refback 09-26-2007 05:04 PM

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)

 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is On
Trackbacks are On
Pingbacks are On
Refbacks are On

Similar Threads

Thread Thread Starter Forum Replies Last Post
How to bring your own content to Virtual Earth (Part 2) Johannes Kebeck's Blog Virtual Earth Blogs 1 10-16-2007 05:02 PM
How to bring your own content to Virtual Earth (Part 3) Johannes Kebeck's Blog Virtual Earth Blogs 0 09-26-2007 07:50 AM
How to bring your own content to Virtual Earth (Part 1) Johannes Kebeck's Blog Virtual Earth Blogs 0 09-15-2007 03:25 PM
Virtual Earth @ WPC VirtualEarth MSDN Blog Virtual Earth Blogs 0 09-15-2007 02:17 PM
MSN Virtual Earth. Eric Frost News and Announcements 0 11-03-2006 11:27 AM


All times are GMT -5. The time now is 10:29 PM.


Powered by vBulletin® Version 3.7.2
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.2.0
MP2K Magazine
Visitor Map

Flights Malaga
Costa Del Sol is known as a destination for the rich and famous. Don't be put off, with Holiday Hypermarket you can book cheap flights and accommodation.

European City Breaks
Find European City Breaks on Travel Counsellors. Based on holidays booked this year, these are the most popular City Breaks for 2006

Cheap Flight Canada
Making a cheap flight to Canada can become a reality when you book online with dealchecker.co.uk. Our simple search allows you to see for yourself who is the cheapest.

Holidays to Cuba
For the best offers on holidays to Cuba, visit The Holiday Place today. Find a deal to suit you and your budget online!

Cheap Turkey Holidays
The best time of year to sneak in cheap Turkey holidays is during the off-peak season. Check out the great deals available during April, May or October. For other tips on how to bag a great value holiday simply check online at ulookubook.com

Holiday
For the holiday of your life, that is easy to plan, visit Travel.co.uk to see all the options.

Cheap Holidays in Fuerteventura
Save your money! Live like royalty! Visit the Canary Islands! Get info on cheap holidays in Fuerteventura, only at On The Beach.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52