Contact Windows Support

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Saturday, 29 June 2013

Windows Phone 8 - Map and Clusters

Posted on 06:00 by Unknown
This code example demonstrates how to dynamically group pushpins in the map control.
There is a lot of code for Windows Phone 7, then I merged all what I need to create a project for WP8.


First of all you need some namespace declaration: for map control and for pushpins from WP Toolkit.

xmlns:map="clr-namespace:Microsoft.Phone.Maps.Controls;assembly=Microsoft.Phone.Maps"
xmlns:maptk="clr-namespace:Microsoft.Phone.Maps.Toolkit;assembly=Microsoft.Phone.Controls.Toolkit"

You need also two templates: one for a standard pushpin and the other for the cluster.
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="PushpinTemplate">
<maptk:Pushpin GeoCoordinate="{Binding GeoCoordinate}" Content="{Binding}" />
</DataTemplate>
<DataTemplate x:Key="ClusterTemplate">
<maptk:Pushpin GeoCoordinate="{Binding GeoCoordinate}" Content="{Binding Count}"/>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>

ClustersGenerator is the core of the project. It's a static class that accepts in input
  • Map control
  • Pushpins collection
  • Cluster DataTemplate.
public ClustersGenerator(Map map, List<Pushpin> pushpins, DataTemplate clusterTemplate)
{
_map = map;
_pushpins = pushpins;
this.ClusterTemplate = clusterTemplate;

// maps event
_map.ViewChanged += (s, e) => GeneratePushpins();
_map.ZoomLevelChanged += (s, e) => GeneratePushpins();
_map.CenterChanged += (s, e) => GeneratePushpins();

// first generate
GeneratePushpins();
}

Every map event launches the pushpins elaboration, but first to explain GeneratePushpins method, let's introduce another class: PushpinGroup.
PushpinGroup represents a standard pushpin or a cluster, and exposes a GetElement method to return them. If the group is a cluster, it needs to get only the first pushpin GeoCoordinate and the content is a group of all pushpins.
public class PushpinsGroup
{
private List<Pushpin> _pushpins = new List<Pushpin>();
public Point MapLocation { get; set; }

public PushpinsGroup(Pushpin pushpin, Point location)
{
_pushpins.Add(pushpin);
MapLocation = location;
}

public FrameworkElement GetElement(DataTemplate clusterTemplate)
{
if (_pushpins.Count == 1)
return _pushpins[0];

// more pushpins
return new Pushpin()
{
// just need the first coordinate
GeoCoordinate = _pushpins.First().GeoCoordinate,
Content = _pushpins.Select(p => p.DataContext).ToList(),
ContentTemplate = clusterTemplate,
};
}

public void IncludeGroup(PushpinsGroup group)
{
foreach (var pin in group._pushpins)
_pushpins.Add(pin);
}
}

The GeneratePushipins function creates clusters based on map ViewPort and a constant named MAXDISTANCE. An extension method convert pushpin GeoCoordinate to a ViewPort Point. That is used to get the distance from other points. If this distance is less then the MAXDISTANCE, the pushpin become a part of cluster.
private void GeneratePushpins()
{
List<PushpinsGroup> pushpinsToAdd = new List<PushpinsGroup>();
foreach (var pushpin in _pushpins)
{
bool addGroup = true;
var newGroup = new PushpinsGroup(pushpin, _map.ConvertGeoCoordinateToViewportPoint(pushpin.GeoCoordinate));

foreach (var pushpinToAdd in pushpinsToAdd)
{
double distance = pushpinToAdd.MapLocation.GetDistanceTo(newGroup.MapLocation);

if (distance < MAXDISTANCE)
{
pushpinToAdd.IncludeGroup(newGroup);
addGroup = false;
break;
}
}

if (addGroup)
pushpinsToAdd.Add(newGroup);
}

_map.Dispatcher.BeginInvoke(() =>
{
_map.Layers.Clear();
MapLayer layer = new MapLayer();
foreach (var visibleGroup in pushpinsToAdd.Where(p => _map.IsVisiblePoint(p.MapLocation)))
{
var cluster = visibleGroup.GetElement(this.ClusterTemplate) as Pushpin;
if (cluster != null)
{
layer.Add(new MapOverlay() { GeoCoordinate = cluster.GeoCoordinate, Content = cluster.Content, ContentTemplate = cluster.ContentTemplate});
}
}
if (layer.Count > 0)
_map.Layers.Add(layer);
});
}

The extension method GetDistanceTo is the algorithm to calculate the distance between two points:
public static double GetDistanceTo(this Point p1, Point p2)
{
return Math.Sqrt((p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y));
}

Instead IsPointVisible returns true if the point is visible in the map, otherwise false:
public static bool IsVisiblePoint(this Map map, Point point)
{
return point.X > 0 && point.X < map.ActualWidth && point.Y > 0 && point.Y < map.ActualHeight;
}

Now in your MainPage.xaml, you only need to pass all pushpins to the ClusterGenerator and it will do all work for you.

var clusterer = new ClustersGenerator(map, pushpins, this.Resources["ClusterTemplate"] as DataTemplate);

You can download all code here.

With this article I won TechNet Guru Contribution June 2013 - Windows Phone.
Email ThisBlogThis!Share to XShare to FacebookShare to Pinterest
Posted in Clusters, Maps, windows phone | No comments
Newer Post Older Post Home

0 comments:

Post a Comment

Subscribe to: Post Comments (Atom)

Popular Posts

  • Happy New Year!
    Posted by Lawrence Chang, Product Marketing Manager, Google mobile team When I first asked the mobile team to send me pictures of how they r...
  • XMAS TIME - Get a Lumia 925 for free
    Do you want a Lumia 925 for Christmas? Thanks to DVLUP you can get it easy :) Check the new xmas challenge ! You just need to create 3 new ...
  • Our 5 favourite new Windows Phone apps of the week
    Today myMoneyBook is featured in Nokia's blog:  Our 5 favourite new Windows Phone apps of the week . Thank you so much  Nokia !
  • Mobile Web Calendar for iPhone and Android, now with event management
    It's probably no news to all you parents out there, but as a new dad I only recently found out just how busy life gets with kids. So I w...
  • Windows Phone 8 - Map and Clusters
    This code example demonstrates how to dynamically group pushpins in the map control. There is a lot of code for Windows Phone 7, then I merg...
  • Places Directory app for Android
    As an engineer based in Taipei, I frequently travel to Google headquarters in Mountain View. When I'm there, I'm always looking for...
  • The Iterative Web App - Faster Address Auto-complete and Keyboard Shortcuts
    On April 7th, we announced a new version of Gmail for mobile for iPhone and Android-powered devices. Among the improvements was a complete...
  • Our newest Mobile Search feature: Where am I?
    Many of our improvements to search quality come from analyzing actual search queries. We’re constantly trying to surface more relevant sea...
  • [ITA] Dal 920 al Lumia 1020
    Che dire... Il Lumia 1020 subentra di prepotenza con il suo colore giallo. La prima impressione รจ sicuramente molto positiva, non solo per l...
  • Impressions of CES
    Posted by Lawrence Chang, Product Marketing Manager, Google mobile team As the 2008 Consumer Electronics Show winds to a close, some of you...

Categories

  • 100th post
  • 3D
  • 6210 navigator
  • 6220 classic
  • adsense
  • adsense for mobile
  • alexandra's mobile [ad]itude
  • Amber
  • android
  • android market
  • android widget
  • app
  • appdeals
  • apphub
  • apple
  • apps
  • att
  • autocomplete
  • best buy mobile
  • better know your mobile
  • biking directions
  • BlackBerry
  • BlackBerry Storm
  • blackjack
  • blogger
  • brightpoint
  • bug
  • buxfer
  • Buzz
  • buzz for mobile
  • c#
  • cab4me
  • Calendar
  • Caliburn
  • canada
  • CES
  • check-in
  • chi-2008
  • clearwire
  • cloud print
  • Clusters
  • Coding4fun
  • Contacts
  • convenience key
  • countdown to 2009
  • coupons
  • csharp
  • culture
  • dennis woodside
  • developers
  • Docs
  • Doodle
  • doodles
  • dotorg
  • doubleclick mobile
  • droid
  • DVLUP
  • e-series
  • ebook
  • election
  • enterprise
  • feature phones
  • france
  • free
  • g1
  • geo
  • geolocation api
  • germany
  • Gesture search
  • gmail
  • gmail for android
  • gmail for mobile
  • GOOG-411
  • googe search
  • Google
  • Google Africa
  • google analytics
  • Google Apps
  • Google Apps Blog
  • google apps device policy
  • google apps for mobile
  • google book search
  • google buzz
  • google buzz for mobile
  • Google Custom Search
  • google docs
  • google earth
  • google finance
  • google gears for mobile
  • google goggles
  • Google I/O
  • google instant
  • google latitude
  • google local search
  • Google Location Alerts
  • google location history
  • Google Locaton History
  • google maps
  • google maps for mobile
  • google maps navigation
  • google mobile
  • google mobile ads
  • google mobile help
  • google mobile help forum
  • Google Mobile Search
  • google mobile tips
  • google mobile tricks
  • google moderator
  • Google News
  • google offers
  • google product search
  • Google profile
  • Google public location badge
  • google search
  • google search app
  • google search by voice
  • google search for mobile
  • google shopper
  • google sites
  • google sky map
  • Google SMS
  • google suggest
  • google sync
  • google talk
  • google toolbar
  • google translate
  • google translate for animals
  • google voice
  • google wallet
  • google+
  • googlenew
  • gps
  • hangouts
  • history
  • honeycomb
  • hot
  • hotpot
  • html 5
  • i-mode
  • igoogle
  • image ads
  • image search
  • inside search
  • Interative web app
  • iOS
  • ipad
  • iphone
  • ipod touch
  • italy
  • iterative web app
  • Iterative Webapp
  • J2ME
  • jason spero
  • lambda
  • latitude api
  • layers
  • Listen
  • Local Business Center
  • local inventory
  • local search
  • locale
  • location based search
  • location tag
  • Lumia 1020
  • Lumia 925
  • mac
  • macworld
  • Mail
  • Maps
  • marketplace
  • mary meeker
  • meow me now
  • microsoft
  • mobile
  • mobile [ad]itude
  • mobile advertising
  • mobile calendar
  • mobile tricks
  • mobile world congress
  • mobile.google.com
  • moneybook
  • motorola
  • movies
  • music
  • MVVM
  • my location
  • my tracks
  • myBattery
  • mymoneybook
  • n-series
  • n78
  • n95
  • n96
  • navigation
  • new york city
  • nexus
  • nfc
  • nokia
  • Nokia Pro Camera
  • NowPlaying
  • ntt docomo
  • NuGet; Visual Studio
  • nyc
  • open handset alliance
  • opera
  • opera mini
  • opera mobile
  • orkut
  • outbox
  • palm
  • palm webos
  • Panoramio
  • personalized suggest
  • Picasa web albums
  • Place Pages for mobile
  • Places
  • Places Directory
  • pre
  • product ideas
  • product search
  • produt search for mobile
  • quick search box
  • Reader
  • registration
  • research
  • s60
  • samsung
  • santa
  • search
  • search by voice
  • Search Options
  • sharing
  • shortcut
  • sidekey
  • silverlight
  • sky lab
  • smart navigation
  • social
  • Sony
  • sony ericsson
  • spain
  • Spreadsheeets
  • sprint
  • sql ce
  • sqlite
  • starring
  • stars
  • street view
  • Summer Games
  • symbian
  • Sync
  • Syncfusion
  • t-mobile
  • tablet
  • tasks
  • TechNet
  • TechNet wiki
  • telerik
  • Thomson
  • TileView
  • tips
  • transit
  • uiq
  • uk
  • universal search
  • verizon
  • visual search
  • voice actions
  • voice search
  • vote
  • walking directions
  • walking navigation
  • web app
  • wep app
  • wikininjas
  • windows 8
  • windows mobile
  • windows phone
  • Windows Phone 7.8
  • Windows phone 8
  • windows RT
  • Windows Store
  • wireless week
  • xaml
  • xna
  • youtube
  • youtube channel
  • YouTube for mobile
  • zoho

Blog Archive

  • ▼  2013 (21)
    • ►  November (3)
    • ►  October (1)
    • ►  September (3)
    • ►  August (3)
    • ►  July (2)
    • ▼  June (4)
      • Windows Phone 8 - Map and Clusters
      • Windows Phone - Caliburn Micro and App.xaml error
      • Windows Phone - Caliburn Micro and Telerik
      • Coding4Fun - ThemedImageConverter
    • ►  April (1)
    • ►  March (1)
    • ►  February (2)
    • ►  January (1)
  • ►  2012 (32)
    • ►  December (2)
    • ►  November (3)
    • ►  October (3)
    • ►  September (6)
    • ►  August (1)
    • ►  June (1)
    • ►  May (2)
    • ►  April (3)
    • ►  March (5)
    • ►  February (5)
    • ►  January (1)
  • ►  2011 (98)
    • ►  December (8)
    • ►  November (9)
    • ►  October (6)
    • ►  September (7)
    • ►  August (2)
    • ►  July (12)
    • ►  June (7)
    • ►  May (11)
    • ►  April (8)
    • ►  March (12)
    • ►  February (9)
    • ►  January (7)
  • ►  2010 (122)
    • ►  December (18)
    • ►  November (10)
    • ►  October (8)
    • ►  September (10)
    • ►  August (10)
    • ►  July (4)
    • ►  June (11)
    • ►  May (7)
    • ►  April (14)
    • ►  March (13)
    • ►  February (10)
    • ►  January (7)
  • ►  2009 (109)
    • ►  December (7)
    • ►  November (14)
    • ►  October (14)
    • ►  September (6)
    • ►  August (7)
    • ►  July (9)
    • ►  June (13)
    • ►  May (10)
    • ►  April (7)
    • ►  March (7)
    • ►  February (11)
    • ►  January (4)
  • ►  2008 (92)
    • ►  December (11)
    • ►  November (7)
    • ►  October (9)
    • ►  September (6)
    • ►  August (6)
    • ►  July (11)
    • ►  June (12)
    • ►  May (4)
    • ►  April (8)
    • ►  March (5)
    • ►  February (5)
    • ►  January (8)
  • ►  2007 (9)
    • ►  December (6)
    • ►  November (3)
Powered by Blogger.

About Me

Unknown
View my complete profile