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"
<
phone:PhoneApplicationPage.Resources
>
DataTemplate
x:Key
=
"PushpinTemplate"
maptk:Pushpin
GeoCoordinate
"{Binding GeoCoordinate}"
Content
"{Binding}"
/>
</
"ClusterTemplate"
"{Binding Count}"
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.
class
PushpinsGroup
private
List<Pushpin> _pushpins =
new
List<Pushpin>();
Point MapLocation {
get
;
set
; }
PushpinsGroup(Pushpin pushpin, Point location)
_pushpins.Add(pushpin);
MapLocation = location;
FrameworkElement GetElement(DataTemplate clusterTemplate)
if
(_pushpins.Count == 1)
return
_pushpins[0];
// more pushpins
Pushpin()
// just need the first coordinate
GeoCoordinate = _pushpins.First().GeoCoordinate,
Content = _pushpins.Select(p => p.DataContext).ToList(),
ContentTemplate = clusterTemplate,
};
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.
GeneratePushpins()
List<PushpinsGroup> pushpinsToAdd =
List<PushpinsGroup>();
(var pushpin
_pushpins)
bool
addGroup =
true
var newGroup =
PushpinsGroup(pushpin, _map.ConvertGeoCoordinateToViewportPoint(pushpin.GeoCoordinate));
(var pushpinToAdd
pushpinsToAdd)
double
distance = pushpinToAdd.MapLocation.GetDistanceTo(newGroup.MapLocation);
(distance < MAXDISTANCE)
pushpinToAdd.IncludeGroup(newGroup);
false
break
(addGroup)
pushpinsToAdd.Add(newGroup);
_map.Dispatcher.BeginInvoke(() =>
_map.Layers.Clear();
MapLayer layer =
MapLayer();
(var visibleGroup
pushpinsToAdd.Where(p => _map.IsVisiblePoint(p.MapLocation)))
var cluster = visibleGroup.GetElement(
.ClusterTemplate)
as
Pushpin;
(cluster !=
null
)
layer.Add(
MapOverlay() { GeoCoordinate = cluster.GeoCoordinate, Content = cluster.Content, ContentTemplate = cluster.ContentTemplate});
(layer.Count > 0)
_map.Layers.Add(layer);
});
The extension method GetDistanceTo is the algorithm to calculate the distance between two points:
static
GetDistanceTo(
Point p1, Point p2)
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:
IsVisiblePoint(
Map map, Point point)
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 =
ClustersGenerator(map, pushpins,
.Resources[
]
DataTemplate);
You can download all code here.
Naomi N edited Revision 8. Comment: Minor edit
Ed Price - MSFT edited Revision 2. Comment: Title casing, needs tech in title, adding tags
Congratulations on winning the gold! blogs.technet.com/.../technet-guru-awards-june-2013.aspx
Your article was featured here on MSDN blogs: blogs.msdn.com/.../windows-phone-guru-windows-phone-8-development-maps-and-clusters.aspx
Thanks!
Thank you Ed!
You're welcome Tiziano! Your article was also featured on the home page of TNWiki:
social.technet.microsoft.com/wiki
Finally your article was featured on the Wiki Ninjas blog here: blogs.technet.com/.../june-windows-phone-guru-tiziano-cacioppolini-brings-us-quot-windows-phone-8-development-maps-and-clusters-quot.aspx
Thanks again!
This is great! Thanks