This is a discussion on Virtual Earth as Gadget for Windows Vista Sidebar within the Virtual Earth Blogs forums, part of the Blogs category; Introduction If you are using Windows Vista you probably had a look at the Sidebar Gadgets as well. There is ...
If you are using Windows Vista you probably had a look at the Sidebar Gadgets as well.
There is a already pretty big gallery available on the web but since the Gadgets are basically small HTML-documents automated through JavaScript everybody can build his own Gadgets as well. I like the idea of having some condensed information in one place and open a Flyout which get's you full functionality in a bigger window. Of course I was aware that there are already Gadgets which implement some of the Virtual Earth functions so I wanted to demonstrate how easy it can be to implement your own existing Virtual Earth applications in the Sidebar. As a starting point we use the tracking application which I described in a previous posting. The idea is to have a small Gadget as shown above in the Sidebar and then to create a Flyout in which I have advanced functionality like replaying previous days.
Getting Started
If you are new to the Vista Gadgets this might be a good starting point but don't worry it is pretty easy and the following steps will be explained in detail. As mentioned before, we will build upon the code for that simple tracking application which I have described here. In the meantime I had modified that sample so that we have a replay-function as well. You will find the source code here:
The Gadget
Particularly for development and testing it is a good idea to create a folder directly in your personal Gadget-folder (e.g. C:\Users\jkebeck\AppData\Local\Microsoft\Windows Sidebar\Gadgets) rather than in the standard repository for your Visual Studio project. The folder shall follow the naming convention "SomeName.gadget". In my case it is "MyTracking.gadget".
The Manifest (gadget.xml)
The first piece of the Gadget is the XML-Manifest which describes where everything is. The name of this file must always be gadget.xml. A detailed description of the manifest can be found here and my manifest looks like this:
As you can see the source of the gadget has to be a HTML-file and I called it gadget.html but you can choose any other name as well.
The HTML-document for the Gadget (gadget.html)
As you can see the source of the gadget is a very basic HTML-document. It contains references to a style-sheet, the Virtual Earth MapControl and our own JavaScript-file which we have still to create. In the body we have a DIV-element for the title as well as another DIV-element which will host the Virtual Earth MapControl. The DIV-element for the title also contains a link to a JavaScript-function which will be discussed later.
Docked gadgets must be at least 60 pixels high and anywhere from 25 pixels to 130 pixels wide to fit within the maximum width of the Sidebar. The size of the gadget is defined by the height and width of the HTML-body. As you can see in the CSS below I override the styles for scalebar, copyrights and logo. This is something that you should normally never do and in fact it violates the Terms of Use but since the map in my sidebar is so small that the attribution would obstruct the map completely and since my flyout will have the complete attribution anyway, I hope that it is OK. My Style-sheet looks like this.
/* Removing the Microsoft logo, scalebar, and copyright logos off of the map */ #divMap .MSVE_PoweredByLogo { display:none;
} #divMap .MSVE_ScaleBar { display:none;
} #divMap .MSVE_ScaleBarLabel { display:none;
} #divMap .MSVE_Copyright { display:none;
}
The JavaScript for the Gadget (gadget.js)
The first difference you see is the reference to the flyout-document. The rest is pretty much the same as the original website for my tracking application which was explained in my previous posting with a few exceptions:
The default size of the dashboard would be too big for the gadget so I choose a smaller size: * map.SetDashboardSize(VEDashboardSize.Tiny); Alternatively you could switch of the interactivity of the map completely which would remove the dashboard and disable all mouse- and keyboard-events: * map.LoadMap(new VELatLong(51.461962075378054, -0.9260702133178665), 13, VEMapStyle.Shaded, true);
I added a function showFlyout(). This function is being executed when you click on the link in the title of the gadget and will basically open the flyout windows.
function GetMap()
{
map = new VEMap('divMap');
map.SetDashboardSize(VEDashboardSize.Tiny);
map.LoadMap(new VELatLong(51.461962075378054, -0.9260702133178665), 13, VEMapStyle.Shaded);
map.AddShapeLayer(slTracks); //Start Tracking and Set Intervall to 5 minutes showtime=setInterval("Track()", 300000);
Track();
}
//Tracking function Track()
{ //Delete previous tracks slTracks.DeleteAllShapes();
//Build the URL
//The random URL-parameter avoids caching var url="http://YourServer/Tracking.ashx?" + Math.random();
//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);
}
}
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;
}
function showFlyout()
{
System.Gadget.Flyout.show = true;
}
All right that's already the first part. Click in the "+" symbol in the sidebar to bring up the "Gadget Gallery".
Your new gadget should be visible. Double-click to add it to the sidebar or just drag-and-drop it onto the sidebar.
The Flyout
The flyout is a bigger window which will appear when you set the property "System.Gadget.Flyout.show = true;" It will be attached to the docked gadget in the sidebar and is often used to configure the content of the docked gadget or - as in my example - to provide additional information and functions. The approach is very similar to the docked gadget mentioned above and I will use the main web site for the tracking application which I described previously a a template.
The HTML-document for Flyout (flyout.html)
Well the original posting was just providing the tracking functionality and not the function to replay a day so we will have to make some modifications to provide a replay of previous days. In the header we reference the Virtual Earth MapControl as well as our own CSS and JavaScript.
Please note: even though we did define the style for background-colour in the external CSS this would not be applied to the flyout. Apparently this is a bug in the sidebar. The workaround is to define the style in the HTML-document directly.
The body contains a first DIV-element which is basically a header. The second DIV-element contains some checkboxes to start and stop live tracking as well as a replay of a previous day. The days which are available for replay - i.e. the days when I had my GPS switched on - will be displayed in an HTML-SELECT-element. And finally there is a DIV-element which will host our Virtual Earth map.
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
The live-tracking part is the same as in the docked gadget with the exception that I use the default dashboard-size for the map and that I provide a checkbox which allows me to start and stop tracking.
I also call a function GetDates(). This function creates an AJAX-call to a new web-handler (GetDates.ashx). The source for that web handler is included in the sample code linked above and also listed at the end of this posting. It basically connects to the database and executes a "SELECT DISTINCT GPSdate FROM Tracks ORDER BY GPSdate DESC". The result will be used to create a JavaScript which populates my HTML-SELECT-element in the flyout.html site with the available days for replay. The general approach to integrate Virtual Earth with a database is described in one of my previous posting.
Another AJAX-call will be executed when the checkbox for the replay is activated. It calls my web handler Replay.ashx. This web handler is as well included the sample code linked above and listed at the end of this posting.
Finally there is also a JavaScript hideFlyout() which allows us to close the Flyout-window but in fact the flyout would be closed anyway when the flyout-window looses it's focus.
window.onload = GetMap;
//Map var map = null;
//VEShapeLayer var slTracks = new VEShapeLayer();
function GetMap()
{ //Populate Dropdown-List GetDates();
//Start/Stop Tracking function StartStopTracking(control)
{ if (document.getElementById(control).checked == false) {
clearInterval(showtime);
slTracks.DeleteAllShapes();
} else { //Start Tracking and Set Intervall to 5 minutes showtime=setInterval("Track()", 300000);
Track();
}
}
//Tracking function Track()
{ //Delete previous tracks slTracks.DeleteAllShapes();
//Build the URL
//The random URL-parameter avoids caching var url="http://YourServer/Tracking.ashx?" + Math.random();
//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);
}
}
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;
}
//Fill DropDownList function GetDates()
{ //Build the URL
//The random URL-parameter avoids caching var url="http://YourServer/GetDates.ashx?" + Math.random();
//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);
}
}
//Start/Stop Replay function StartStopReplay(control)
{ if (document.getElementById(control).checked == false) {
slTracks.DeleteAllShapes();
} else {
Replay();
}
}
//Replay function Replay()
{ //Build the URL var url="http://YourServer/Replay.ashx?myDate=" + document.getElementById("ddReplayDate").value;
//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"
//execute using eval() var result = xmlhttp.responseText
eval(result);
}
}
xmlhttp.send(null);
}
}
function hideFlyout()
{
System.Gadget.Flyout.show = false;
}
That's it. Now my boss can always see where the "Virtual Hannes" is without even opening his browser.
The complete source code for the web application is linked here. The code for the gadget is here:
Other Listing
GetDates.ashx
<%@ WebHandler Language="VB" Class="GetDates" %>
Imports System Imports System.Web Imports System.Data.SqlClient
Public Class GetDates : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest '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")
'Retrieve Dates Dim settings As ConnectionStringSettings = ConfigurationManager.ConnectionStrings("Tracking") Dim sb As StringBuilder = New StringBuilder
sb.Append("var sOpts = " + """" + "+ """" + ";") ' Dim myDates As String = "" Dim myConn As New SqlConnection(settings.ConnectionString) Dim myQuery As String = "SELECT DISTINCT GPSdate FROM Tracks ORDER BY GPSdate DESC" Dim myCMD As New SqlCommand(myQuery, myConn)
myConn.Open() Dim myReader As SqlDataReader = myCMD.ExecuteReader() While myReader.Read()
myDates = myDates + _ "sOpts += " + """" + "+ myReader(0).ToString + "\n" + """" + ";" End While myReader.Close()
myConn.Close()
sb.Append(myDates)
sb.Append("ddReplayDate.outerHTML = sOpts + " + """" + "" + """" + ";")
context.Response.Write(sb.ToString()) End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable Get
Return False
End Get
End Property
End Class
Replay.ashx
<%@ WebHandler Language="VB" Class="Replay" %>
Imports System Imports System.Web Imports System.Data.SqlClient
Public Class Replay : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest '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")
'Fetch the URL-parameter Dim myDate As String = context.Request.Params("myDate")
'Retrieve GPS-Positions Dim settings As ConnectionStringSettings = ConfigurationManager.ConnectionStrings("Tracking") Dim sb As StringBuilder = New StringBuilder Dim myPins As String = "" Dim myIcon As String = "" Dim myConn As New SqlConnection(settings.ConnectionString) Dim myQuery As String = "SELECT Lat, Long, DevName, GPSdate, GPStime, Speed, Heading FROM Tracks WHERE GPSdate LIKE '" + myDate + "' ORDER BY GPStime" Dim myCMD As New SqlCommand(myQuery, myConn)
myConn.Open() Dim i As Integer = 0 Dim myReader As SqlDataReader = myCMD.ExecuteReader() While myReader.Read()
i = i + 1 'Determine the CustomIcon based on the heading and speed If myReader(5).ToString = "0" Then myIcon = "stationary.png" Else
Select Case myReader(6) Case 0 To 22
myIcon = "n.png" Case 23 To 57
myIcon = "ne.png" Case 58 To 112
myIcon = "e.png" Case 113 To 147
myIcon = "se.png" Case 148 To 202
myIcon = "s.png" Case 203 To 247
myIcon = "sw.png" Case 248 To 292
myIcon = "w.png" Case 293 To 337
myIcon = "nw.png" Case 338 To 360
myIcon = "n.png" End Select
End If
Cheap Ski Looking for a cheap ski? Holiday Hypermarket uses the UK's leading tour operators to provide you with fantastic low prices. Book a cheap ski holiday online today.
Spain Holidays Find great Spain Holidays with Travel Counsellors. A personal Travel Counsellor can help you plan the perfect holiday to Spain.
Holidays to Cuba Situated between Jamaica and the Bahamas, Cuba has a delightful tropical climate and warm, clear waters with beaches of white sand. Check for cheap holidays to Cuba.
Holidays to Jamaica Holidays to Jamaica are about taking things easy. Forget your watch and chill out beneath the clear Jamaican sky.
Cheap Morocco Holidays Cheap Morocco holidays may be the answer to your cheap holiday search. With sunshine throughout most of the year it can be great value if you avoid the peak season. Why not include a trip to the small tranquil town of Chefchaouen Tangier in your visit?
Holiday Packages Spoil yourself and your loved ones with one of the great Holiday Packages from Travel.co.uk.
Cyprus Holidays Fancy a Mediterranean holiday? Get information on Cyprus holidays at On The Beach.