| Johannes's profileHannes's Virtual Earth B...BlogListsSkyDrive | Help |
Hannes's Virtual Earth Blog |
|||||||||||||||||||
|
November 28 Clustering with the Bing Maps Silverlight Control – Part 3Publishing to Windows Azure In the previous 2 parts we have created a Photo-Map with the Bing Maps Silverlight Control and implemented server-side clustering. Now we are going to publish this application to Windows Azure. Let’s start with the photos. I use SpaceBlock which is available on CodePlex to upload the photos into my Windows Azure Blob Storage. In this example we don’t want to deal with access control so we just set public access rights on the root-folder: In the SQL Azure Server Administration Tool we create now a new database. We will also need to set the firewall rules. In order to allow our Windows Azure application to access the database we need at least “Allow Microsoft Services”. This can be done by simply ticking the checkbox. Since we also want to access the database from our local machine we need to grant access to our own IP address as well. In order to do that we click on “Add Rule”. The web site automatically determines our IP-address. We copy this address and paste it in the start- and end- of the IP range. Then we submit the new rule. We should now have 2 firewall rules. Now we need to create the table and populate it with our data. There are a couple of migration tools out there but if we use SQL Server 2008 R2 we already have all we need. In the SQL Server Management Studio we right-click on your database and select from the context menu “Tasks” and then “Generate Scripts”. In the wizard we select the objects that we want to script and then in the advanced options we select that we want to script for a SQL Azure database and that we want both the schemas and the data. Now we change the database connection in our SQL Server Management Studio to our SQL Azure database. We will get the details for the connection from the SQL Azure Server Administration Page. Finally we execute the script that was generated with the wizard before: All right, the data is already in the cloud now we need to do the same with our application. In the application we need to switch the baseURL in the MainPage.xaml.vb from our local machine to the Windows Azure Blob Storage: 'Public Shared baseURL As String = "http://localhost" Public Shared baseURL As String = http://hannesve.blob.core.windows.net In the web.config we need to modify the connection string. We can generate a connection string in the SQL Azure Server Administration Page but that one didn’t quite work for me. In order to make it work I had to append @ServerName to the User ID: <add name="TalkingDonkeyAzure" connectionString="Server=tcp:siljplpmxm.database.windows.net;Database=TalkingDonkey;User ID=jkebeck@siljplpmxm;Password=YOUR_PWD;Trusted_Connection=False;" providerName="System.Data.SqlClient" /> Once we have made the changes we can build our application again and create a new or open an existing Cloud Service project in Visual Studio. In my example I have an existing application with a couple of samples and I want to add this one to it. In the Solution Explorer I create a new folder under the Web Role project and add the xap-file as well as the htm- and js-files as existing items from the project that we have been working on. The web service goes into the root of this web role project since that’s where our code expects the service endpoint. Once we have tested the project we can right-click on the Azure-Project and select “Publish” from the context menu: This will package the solution, open Windows Explorer at the folder where the package was created and it will also open the Windows Azure Administration page where you can upload the package to a staging environment and test it before you swap it with the production environment. That’s it. Ciao for today :-) Technorati Tags: Bing Maps,Virtual Earth,Clustering,Windows Azure,SQL Azure,Silverlight,Custom Navigation Control Clustering with the Bing Maps Silverlight Control – Part 2Adding the Map and Extending the Navigation Control Now that we have set up the database and created the web service we can move on to the Silverlight application. First we add the Bing Maps Silverlight control as reference to our Silverlight project: Next we add a service reference pointing to the web service that we have created before. Click on discover to find the service and give it a name. Particularly when we work with Windows Azure we must be able to modify the endpoint of the service dynamically and hence we add the following code to the public sub new method of the MainPage.xaml.vb 'Reset service reference endpoint (important when port or domain changes) Dim wsURL As String = "http://" + HtmlPage.Document.DocumentUri.Host + ":" + _ In the MainPage.xaml we add the namespace for the Bing Maps Silverlight Control and the map itself. We also add a mini-map that provides an overview. In this overview-map we remove all components that might obstruct the view on the map itself. To add additional elements to the navigation control we add a handler right after we initialized the component: Public Sub New() InitializeComponent() ' Add additional controls to the navigation bar AddHandler MyMap.MapForeground.TemplateApplied, AddressOf MapForeground_TemplateApplied We are going to add 3 additional control elements
#Region "Navigation" Private Sub MapForeground_TemplateApplied(ByVal sender As Object, ByVal e As EventArgs) AddHandler MyMap.MapForeground.NavigationBar.TemplateApplied, _ The functions that are being executed when we click these control-elements are in separate classes and I have simply added them at the end of MainPage.xaml.vb #Region "Additional Commands in Dashboard" Class ToggleMiniMap Inherits NavigationBarCommandBase Public Sub New() End Sub Public Overloads Overrides Sub Execute(ByVal map As MapBase) Dim status As NavigationBarCommandStatus = Me.GetStatus(map) If status = NavigationBarCommandStatus.Checked Then MainPage.myMiniMap.Visibility = Visibility.Collapsed ElseIf status = NavigationBarCommandStatus.Normal Then MainPage.myMiniMap.Visibility = Visibility.Visible End If End Sub Public Overloads Overrides Function GetStatus(ByVal map As MapBase) _
Preparing the Photo-Viewer The Photo-Viewer is basically a ChildWindow that comes as part of the Silverlight Toolkit for Visual Studio 2008 SP1 and is out-of-the-box part of Visual Studio 2010 Beta 2. So if you are using Visual Studio 2010 Beta 2 just add a new item of type ChildWindow The basic xaml is quite simple since we add most of child-elements dynamically through code… <controls:ChildWindow x:Class="BM_SL_PhotoMap.PhotoShow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" Width="400" Height="300" Title="PhotoShow"> <Grid x:Name="LayoutRoot" Margin="2"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Image x:Name="imgCurrentPhoto" Stretch="Uniform" Grid.Column="0" Grid.Row="0" …but I have changed the style and added storyboards in Expression Blend in order to show the title and thumbnails when you mouse over the regions and hide them when you don’t:
Calling the Web Service Remember when we created the additional controls in our dashboard we also created a class to show or hide the photos. When activated this element adds a handler for the ViewChangeEnd event and queries our database for the first time. The ViewChangeEnd event calls our web service asynchronously and adds a handler that processes the result. Public Shared Sub MyMap_ViewChangeEnd(ByVal sender As Object, ByVal e As MapEventArgs) Dim map As Map = DirectCast(sender, Map) Dim bounds As LocationRect = map.TargetBoundingRectangle AddHandler svc.GetClusterInViewCompleted, AddressOf svc_GetClusterInViewCompleted svc.GetClusterInViewAsync(bounds.Northwest.Latitude, _ When we process the result we first delete all pins in the layer before we loop through the items in our list-object and create new pins. In the tag of each pin we add the name of the photo and also any other information that we want to show in the title. We also add a handler that fires whenever we click on the pin. Public Shared Sub svc_GetClusterInViewCompleted(ByVal sender As Object, _ When we click on the pin we split its tag into a string-array the element 0 and all items with an even number contain the file-name of the photo (without the extension (.jpg). All odd-number elements contain the information that we want to show in the title. Now we cycle through this string array and create child elements for our Photo-Viewer. The thumbnail images will have a handler attached that allows us to click on it in order to display a larger image in the main window and and set the title. Public Shared Sub PhotoShow(ByVal sender As Object, _ Finally we add a little bit of code to the Photo-Viewer in order to scroll through the thumbnails, display the photo in the main window and also provide a slide-show function. We won’t go into more detail here but it’s all in the sample code and you can explore it for yourself. Well that brings us to an end of part 2. The application is ready for your local environment. You can have a look at it here and download the sample code here. If you want to learn more about publishing the application to Windows Azure have a look at part 3. Technorati Tags: Bing Maps,Virtual Earth,Clustering,Windows Azure,SQL Azure,Silverlight,Custom Navigation Control Clustering with the Bing Maps Silverlight Control – Part 1Introduction There may be very good reasons why you don’t want to cluster your points of interest on a map e.g. if you want to show the density of points in a certain area. An example for this is the Bing Maps World Tour which has been developed by our partner Earthware and which visualizes the highlights of the latest Bing Maps data updates. The downside of this is though that the map looks cluttered and you can’t access the points at the bottom of the pile anymore. In addition the number of points that you render on a map also affects the performance. The performance aspect is certainly much more relevant for the AJAX control since the Silverlight performance in general is much better but after a few thousand points you might reach a level where the user experience suffers. The Bing Maps AJAX control has client-side clustering build into the API and in a previous post I have compared the performance of client- and server-side clustering for the AJAX control. The Bing Maps Silverlight control does not provide build-in clustering and hence we will have a look mainly at the clustering but we will also:
In this example we will build a photomap. On low zoom-levels, i.e. when we look at the whole world, all the photos for let’s say Sardinia are represented by a single pushpin… …but we still have access to all the photos that are represented by this pin: On higher zoom-levels we break up the cluster and show accurate positions for the photos. In the screenshot below you also see, that we extended the build-in navigation control with some custom elements to show and hide the photo-layer, toggle the mini-map and toggle full-screen mode. You can see the application here and download the sample code here Note: You will have to enter your own Bing Maps Key in the MainPage.xaml and modify the connection string in the web.config
What we need
The Concept Before we actually start coding let’s hold on for a sec and think about the concept. The Bing Maps Silverlight control supports a variety of events. Since we don’t want to load all the photos but only those that are in the current map view we use these events to determine the bounding box and a couple of other parameters for our database query whenever we finish zooming or panning the map. At a first glance it might appear that the event TargetViewChanged might be appropriate but that would be a mistake since the target view changes with the zoom-level – so far so good – but also with every frame when you pan the map. That would create quite a lot of database queries and we certainly want to avoid that. More appropriate is the ViewChangeEnd event. We will add a handler for this event to the map and call a web service asynchronously. The web service will query our database, create a cluster of points and return a List-object that we can then process in our Silverlight application. In order to cluster the photos (or points of interest) we will create in the web service a grid – let’s say with a width of 40 pixel – and determine the photos that are within each grid-cell. For each grid-cell that has one or more photo in it we will return a pin and tag it with some ID’s that identify the individual photos. Once the Silverlight application receives the response we will process the data by adding pins to the map and dynamically creating child-elements for our photo-viewer. In this example we will do it by adding thumbnail images to a StackPanel in the ChildWindow. OK, let’s do it.
The Local Database The database will be quite simple. We just have one table where me maintain the meta-data for our photos. The script for the table is listed below. CREATE TABLE [Photos]( [id] [int] IDENTITY(1,1) NOT NULL, [Lat] [float] NULL, [Lon] [float] NULL, [Title] [varchar](250) NULL, [Name] [varchar](50) NULL, [Date] [date] NULL, [Loc1] [varchar](250) NULL, [Loc2] [varchar](250) NULL, [Loc3] [varchar](250) NULL, CONSTRAINT [PK_Photos] PRIMARY KEY CLUSTERED ( [id] ASC ) ON [PRIMARY] ) ON [PRIMARY] We need columns for the latitudes and longitudes of the locations where the photo was taken, the name of the file (the part before the extension .jpg) and optionally some more information that describe the location. The photos themselves are accessible through a web server and for starters we’re going to use our local Internet Information Service to create a virtual directory that points to the location of the photos.
The Web Service Let’s first create the web service that accesses the database. In our Visual Studio we create a new Silverlight application: And choose to host the application in a new website. In the web-project we create a new Silverlight-enabled WCF Service. Let’s call it svcPhotos. If you consider using Windows Azure you must be aware of a bug that really puzzled me for a while. Everything worked well when I had my stand-alone application but once I wanted to use it within a Windows Azure project – no matter if it as in the development fabric or in the live environment – I received a weird error message: “cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree.”. Since I was actually re-writing the endpoint in my code I was pretty sure that the address was correct and finally I found out that the error can be resolved by adding the following ServiceBehaviour: In our service we create a DataContract that describes the list-items in the list-object we want to return as well as an OperationsContract that queries the database, clusters the points and returns the list-object. The OperationsContract will take as input-parameters
For the clustering we will also nee some helper functions that allow us to convert latitudes and longitudes into pixel coordinates. These functions are explained in more detail here. The full code of the web service is listed below: Imports System.ServiceModel Imports System.ServiceModel.Activation Imports System.Data.SqlClient Imports System.Runtime.Serialization Imports System.Globalization <ServiceContract(Namespace:="svcPhotos")> <ServiceBehavior(AddressFilterMode:=AddressFilterMode.Any)> <AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)> Public Class svcPhotos 'Constants for the Clustering '(addressable area in Bing Maps) Private Const MinLatitude As Double = -85.05112878 Private Const MaxLatitude As Double = 85.05112878 Private Const MinLongitude As Double = -180 Private Const MaxLongitude As Double = 180 'Grid-Size Private Const GridSize As Integer = 40 'Clips a number to the specified minimum and maximum values Private Shared Function Clip(ByVal n As Double, ByVal minValue As Double, _
Technorati Tags: Bing Maps,Virtual Earth,Clustering,Windows Azure,SQL Azure,Silverlight,Custom Navigation Control November 21 Bing Maps – Embedded MapsDeveloping with Bing Maps is great fun but not everybody wants to fire up his Visual Studio to get a map on his website. With the latest launch – Chris Pendleton blogged about it here, here, here and here – we also introduced embedded maps. Embedded maps in it’s most simple form can just be generated from our consumer facing site http://bing.com/maps. Just navigate the map to the place that you want to show and then click on the “Share” button. This will bring up a dialog where you can copy a link that will get you back to http://bing.com/maps and recreate the current map-view. That is not really new, it has been there before but there is now also another area where you can copy a piece of HTML-code that you can paste into your website in order to embed a static or interactive map. The link “Customize and preview” brings up another dialog that allows you to further customize this piece of HTML-code: As you can see this gives you plain maps with the roadmap or aerial images but in order to see the nice Bird’s Eye view you have to use the link underneath the map that get’s you back to http://bing.com/maps. In our Bing Maps AJAX SDK we have however now also a couple of changes and one of these allows you to create more comprehensive embedded maps by using additional URL-parameters.
So this iFrame for example… <iframe height="400" …gives as a nice Birds Eye view of the Microsoft office in Reading facing south: Since we also launched a Bing Maps Silverlight control we have the same approach for embedded maps available for Silverlight too. Here is the iFrame: <iframe height="400" November 20 Bing Maps Silverlight Control & PhotosynthLast week we launched a new wave of Bing Maps. My esteemed colleague Chris Pendleton has blogged about some of the changes here, here, here and here. One of the main announcements has been the launch of the Bing Maps Silverlight Control v1. You will find the interactive SDK here, the full reference on MSDN here and the download here. This control has been available as a Community Technology Preview (CTP) for quite a while but those of you who have been waiting for a fully supported version before getting involved may not be too familiar with it yet. If you did work with the CTP please be aware that it is time-bombed and will stop working by the end of the year; so please consider updating your application soon. If you have been working with the Bing Maps AJAX Control before you may actually be missing a few things that came in handy if you wanted to display additional information like for a example a Photosynth collection. This was quite simple in the AJAX control since you could simply generate an iFrame in Photosynth and just add it to a VEShape-object using the VEShape.SetDescription-method. You can look at a sample here and download the source here). Since pushpins in the Silverlight control don’t have an info-box like the ones in the AJAX-control the approach here is quite different but it still works very well. The major obstacle appear to be that we cannot directly integrate HTML-code into our Silverlight application. The solution is actually to use the HTML Bridge in order to lay a HTML DIV-element on top of the Silverlight control and arrange it appropriately. Of course you can write everything from the scratch but the guys from divelements have created a Silverlight-Control HtmlHost for us that you can download for free and use to add and control HTML content directly from your Silverlight application. Let’s have a crack at it. For this walkthrough we will need
First we create a new Silverlight application and add references to our Bing Maps Silverlight Control In the MainPage.xaml we add a reference to our Bing Maps Silverlight control… xmlns:m="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl"
…and the the map itself with a pushpin at the location where we our Photosynth collection is. We also attach an event to the pushpin that fires when we click on it. <m:Map CredentialsProvider="YOUR BING MAPS KEY" Mode="AerialWithLabels" Center="32.362980181127874,-64.71483707427978" ZoomLevel="17"> <m:Pushpin Name="pinMartelloTower" Location="32.362980181127874,-64.71483707427978" MouseLeftButtonDown="pinMartelloTower_MouseLeftButtonDown"/> </m:Map>
If you had done something like this with the CTP before you will notice a few differences:
In my sample here I chose to bring up the Photosynth collection as part of a ChildWindow. A ChildWindow is a Silverlight control that comes with the Silverlight Toolkit. So let’s add a ChildWindow as new object to our Silverlight-project. I call it Photosynth. The trouble with a ChildWindow and HTML-DIV-elements on top is that the ChildWindow has an animation and explodes when you open it. If you would just add the HTML-DIV-element when the ChildWindow opens it would appear in the bottom-right quadrant of the screen. In order to avoid this we can simply remove the animation by changing the template in Expression Blend. In Visual Studio just right-click on the ChildWindow and select “Open in Expression Blend” from the context menu. In Expression Blend right-click on the ChildWindow-object and select “Edit Template” => “Edit a Copy”. Now we switch to code-view and remove the whole VisualStateManager that handles the StoryBoards for opening and closing the window. By default this would start around line 119: While we’re at it we can optionally make a few more changes to adjust the design: Now we can leave Expression Blend and go back to Visual Studio. In order to add the HtmlHost from divelements right-click on the Toolbox, select “Choose Items” from the context menu and add the Divelements.SilverlightTools.dll from the location where you extracted the download. Now drag&drop the control on your ChildWindow. This will automatically add the required namespace you only need to add a Name-property to the HtmlHost. Your XAML-should now look like this <controls:ChildWindow x:Class="SilverlightApplication2.Photosynth" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" xmlns:my="clr-namespace:Divelements.SilverlightTools;assembly=Divelements.SilverlightTools" Width="400" Height="300" Title="Photosynth"> <controls:ChildWindow.Resources> … Finally we can start coding. The only code we need is actually in the MainPage.xaml.vb. When we initialize the page we also add a handler which resizes the ChildWindow whenever the size of the browser window changes. When we click on the pushpin we set the title for the ChildWindow as well as the source for the HtmlHost. In this case we just add the iFrame which we can copy directly from Photosynth… …and make to minor changes:
Imports System.Windows.Browser Partial Public Class MainPage Inherits UserControl Public myHeight As Integer Public myWidth As Integer Private WithEvents cwPhotosynth As New Photosynth Public Sub New() InitializeComponent() AddHandler LayoutRoot.SizeChanged, AddressOf Page_SizeChanged End Sub Private Sub Page_SizeChanged(ByVal sender As Object, ByVal e As SizeChangedEventArgs) myWidth = CInt(e.NewSize.Width) myHeight = CInt(e.NewSize.Height) cwPhotosynth.Width = e.NewSize.Width * 0.8 cwPhotosynth.Height = e.NewSize.Height * 0.8 End Sub Private Sub pinMartelloTower_MouseLeftButtonDown _ Well that’s already it: You can have a look at the sample here and download the source code here. Note: if you download the sample code you need to create a Bing Maps Key and enter it into the XAML in order to load the Bing Maps. Also note that the solution was build with Visual Studio 2010 Beta 2, however all methods work as well in Visual Studio 2008 SP1 |
No folders have been shared yet.
|
||||||||||||||||||
|
|