Clustering pushpins in Silverlight Map Control
- Is there a way to cluster pushpins that are close to each other in the Silverlight Map Control?
Answers
- Oh really?
Well lets see how it looks in here....
I was asked on the MSDN VE forum if the new Silverlight control had pushpins and indeed clustered pushpins. The answer is that it doesn’t have the concept of a pushpin but rather a much more flexible method of attaching any UIElement to the map.
In terms of clustering this is very possible but today I’d like to start by showing Powerlaw scaling from Lutz applied to the VE control.
Powerlaw scaling applies a scale transform to the object based on the zoomlevel. It makes the object full size at street level and tiny at world level. It produces a more realistic effect as you zoom in and out where a static sized object appears to grow as you zoom out.

The interesting part of this is it allows you to show much more information on the map without pins overlapping. It will reduce the situations where you need to cluster your data.
The formula I use is:
Math.Pow(0.05*(currentZoomLevel + 1), 2) + 0.01Adding a Pushpin
Since the control has no built in Pushpin lets make our own, it will simply be a Silverlight control called pin.xaml.

For the XAML we will have Grid with the scale transform and an Image control:
<UserControl x:Class="SoulSolutions.VESL.CustomPushPin.Pin" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Grid HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5"> <Grid.RenderTransform> <ScaleTransform x:Name="PinScaleTransform" ScaleX="1" ScaleY="1" /> </Grid.RenderTransform> <Image Width="250" Stretch="Uniform" x:Name="PinImage"></Image> </Grid> </UserControl>
Note we gave the scale transform and the image a name so we can access these in the code behind:
using System; using System.Windows.Media; using Microsoft.VirtualEarth.MapControl; namespace SoulSolutions.VESL.CustomPushPin { public partial class Pin { public Pin() { InitializeComponent(); } private Map _map; public Map MapInstance { get { return _map; } set { _map = value; _map.ViewChangeOnFrame += MapViewChangeOnFrame; ApplyPowerLawScaling(_map.ZoomLevel); } } public ImageSource ImageSource { get { return PinImage.Source; } set { PinImage.Source = value; } } void MapViewChangeOnFrame(object sender, MapEventArgs e) { ApplyPowerLawScaling(MapInstance.ZoomLevel); } private void ApplyPowerLawScaling(double currentZoomLevel) { double scale = Math.Pow(0.05*(currentZoomLevel + 1), 2) + 0.01; if (scale > 1) scale = 1; if (scale < 0.125) scale = 0.125; PinScaleTransform.ScaleX = scale; PinScaleTransform.ScaleY = scale; } } }
Our class has two public properties, the MapInstance, set so we can access the map itself to get the zoomlevel and listen to the ViewChangeOnFrame event, and the ImageSource property to easily set the actual image for the pin.
When the MapInstance is set we apply the initial scaling, same on every frame of ViewChange. The ApplyPowerLawScaling simply applies the formula with some min/max thresholds.
To add the pin to the map we create a new layer and use the AddChild() methods like so:
var layer = new MapLayer(); map.AddChild(layer); //Sydney layer.AddChild(new Pin { ImageSource = new BitmapImage(new Uri("pin.png", UriKind.Relative)), MapInstance = map }, new Location(-33.86643, 151.2062), PositionMethod.Center);
Pretty cool hey? See it in action here. Download the full source here (162KB).
Next steps
If you’re interested I can show you how to implement IDisposable to clean up events and stop an animation you may want to be running on your pins as well as extend the control to have a label and a infobox balloon. Leave me a comment if you’re interested.
Windows Live Developer MVP - www.soulsolutions.com.au - follow http://twitter.com/virtualearth for latest VE news.- Marked As Answer byRichard_BrundrittMVP, ModeratorFriday, November 20, 2009 5:57 AM
All Replies
- as with the other thread, there are no specific "pushpin" controls or functionality to support them currently in the Silverlight control
Brian @ Earthware - UK interactive mapping web developers http://www.earthware.co.uk/blog | http://www.twitter.com/earthware - Yes it is very early days but Silverlight is so much more powerful then javascript I don't think it will take long for something to be published to help you out.
Are you looking to simple provide a better experience for overlapping pins or looking for performance increases?
Windows Live Developer MVP - www.soulsolutions.com.au - follow http://twitter.com/virtualearth for latest VE news. Are you looking to simple provide a better experience for overlapping pins or looking for performance increases?
Mainly to provide a better experience for overlapping pins.- My short term solution is to use Lutz powerlaw scaling to make the icons appear smaller as you zoomout, I can post a working sample of this in the VE control if this is useful to you?
http://blogs.msdn.com/lutzg/archive/2008/11/03/powerlaw-scaling-of-synchronized-content-with-deep-zoom.aspx
John.
Windows Live Developer MVP - www.soulsolutions.com.au - follow http://twitter.com/virtualearth for latest VE news. That seems useful, yes. I suppose the scaling of the pins would work. An example would be great, thanks :)
- I'll do a blog post a little later with a clean sample, my pushpin has labels and an infobox and stuff that will confuse everyone.
In the constructor to my custom control that xaml look something like this:
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5"> <Grid.RenderTransform> <ScaleTransform x:Name="PinScaleTransform" ScaleX="1" ScaleY="1" /> </Grid.RenderTransform> <Image Width="100" x:Name="PinImage"></Image> </Grid>
I pass in the map object so I can attach to the "ViewChangeOnFrame" event.
In this event if the ZoomLevel has actually changed I call my method to scale the control, I also call this in the constructor to start it off correctly:
private void ApplyPowerLawScaling(currentZoomLevel) { double scale = Math.Pow(0.05*(currentZoomLevel + 1), 2) + 0.01; if (scale > 1) scale = 1; if (scale < 0.125) scale = 0.125; PinScaleTransform.ScaleX = scale; PinScaleTransform.ScaleY = scale; }You may need to tweak the values to suit, I'll clean this up to have a configurable scale factor over the weekend.
I hope this gets you off to good start.
john.
Windows Live Developer MVP - www.soulsolutions.com.au - follow http://twitter.com/virtualearth for latest VE news. - Hi John
Interesting approach, Im playing with exactly this concept today but for over 1,000 pushpins. Any idea how well you idea would work then? I am looking at adding a pushpin with a bounding rectange which then makes it a fixed size so as you zoom out it gets smaller and larger as you zoom in, Ive set my pushpin content to have a max width so it doesnt get massive when you are really zoomed in and it seems to work ok without having to hook up any events. I almost have it working with a few issues when pins are located at the edge of the map.
I'll hopefully get a blog article on it asap once I have this project out the way in a few weeks, would be good to see an article on your approach and its scalability.
Brian @ Earthware - UK interactive mapping web developers http://www.earthware.co.uk/blog | http://www.twitter.com/earthware - Ok, a little late I know but I have posted up a working sample and full source:
http://www.soulsolutions.com.au/Blog/tabid/73/EntryId/599/Powerlaw-scaling-Pushpin-in-the-Virtual-Earth-Silverlight-control.aspx
I was very close with my example here but always easier to see a full solution. The trick is you have to use a centred image, so in my example I resized the pin image so the tip is in the centre.
John.
Windows Live Developer MVP - www.soulsolutions.com.au - follow http://twitter.com/virtualearth for latest VE news. - Hi John,
Thanks for the example. However, I get a runtime error when trying to view http://www.soulsolutions.com.au/Blog/tabid/73/EntryId/599/Powerlaw-scaling-Pushpin-in-the-Virtual-Earth-Silverlight-control.aspx
Morten - Oh really?
Well lets see how it looks in here....
I was asked on the MSDN VE forum if the new Silverlight control had pushpins and indeed clustered pushpins. The answer is that it doesn’t have the concept of a pushpin but rather a much more flexible method of attaching any UIElement to the map.
In terms of clustering this is very possible but today I’d like to start by showing Powerlaw scaling from Lutz applied to the VE control.
Powerlaw scaling applies a scale transform to the object based on the zoomlevel. It makes the object full size at street level and tiny at world level. It produces a more realistic effect as you zoom in and out where a static sized object appears to grow as you zoom out.

The interesting part of this is it allows you to show much more information on the map without pins overlapping. It will reduce the situations where you need to cluster your data.
The formula I use is:
Math.Pow(0.05*(currentZoomLevel + 1), 2) + 0.01Adding a Pushpin
Since the control has no built in Pushpin lets make our own, it will simply be a Silverlight control called pin.xaml.

For the XAML we will have Grid with the scale transform and an Image control:
<UserControl x:Class="SoulSolutions.VESL.CustomPushPin.Pin" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Grid HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5"> <Grid.RenderTransform> <ScaleTransform x:Name="PinScaleTransform" ScaleX="1" ScaleY="1" /> </Grid.RenderTransform> <Image Width="250" Stretch="Uniform" x:Name="PinImage"></Image> </Grid> </UserControl>
Note we gave the scale transform and the image a name so we can access these in the code behind:
using System; using System.Windows.Media; using Microsoft.VirtualEarth.MapControl; namespace SoulSolutions.VESL.CustomPushPin { public partial class Pin { public Pin() { InitializeComponent(); } private Map _map; public Map MapInstance { get { return _map; } set { _map = value; _map.ViewChangeOnFrame += MapViewChangeOnFrame; ApplyPowerLawScaling(_map.ZoomLevel); } } public ImageSource ImageSource { get { return PinImage.Source; } set { PinImage.Source = value; } } void MapViewChangeOnFrame(object sender, MapEventArgs e) { ApplyPowerLawScaling(MapInstance.ZoomLevel); } private void ApplyPowerLawScaling(double currentZoomLevel) { double scale = Math.Pow(0.05*(currentZoomLevel + 1), 2) + 0.01; if (scale > 1) scale = 1; if (scale < 0.125) scale = 0.125; PinScaleTransform.ScaleX = scale; PinScaleTransform.ScaleY = scale; } } }
Our class has two public properties, the MapInstance, set so we can access the map itself to get the zoomlevel and listen to the ViewChangeOnFrame event, and the ImageSource property to easily set the actual image for the pin.
When the MapInstance is set we apply the initial scaling, same on every frame of ViewChange. The ApplyPowerLawScaling simply applies the formula with some min/max thresholds.
To add the pin to the map we create a new layer and use the AddChild() methods like so:
var layer = new MapLayer(); map.AddChild(layer); //Sydney layer.AddChild(new Pin { ImageSource = new BitmapImage(new Uri("pin.png", UriKind.Relative)), MapInstance = map }, new Location(-33.86643, 151.2062), PositionMethod.Center);
Pretty cool hey? See it in action here. Download the full source here (162KB).
Next steps
If you’re interested I can show you how to implement IDisposable to clean up events and stop an animation you may want to be running on your pins as well as extend the control to have a label and a infobox balloon. Leave me a comment if you’re interested.
Windows Live Developer MVP - www.soulsolutions.com.au - follow http://twitter.com/virtualearth for latest VE news.- Marked As Answer byRichard_BrundrittMVP, ModeratorFriday, November 20, 2009 5:57 AM
- This works well. Thank you. Can you provide an example of the next steps please?
"If you’re interested I can show you how to implement IDisposable to clean up events and stop an animation you may want to be running on your pins as well as extend the control to have a label and a infobox balloon. Leave me a comment if you’re interested." - Very very nice.
How did you create the pushpin image? I need them in different colors to display different groups. - That pushpin is from Lutz (Microsoft), I'm not sure what the copyright is sorry. I had one made for my commerical projects. If you have photoshop then you do this:
Image->Adjustments->hue/saturation
Then change the hue slider to the colour you desire.
John.
Windows Live Developer MVP - www.soulsolutions.com.au - follow http://twitter.com/bingmapsdev for latest news. - hey is it a must to use VE controls if i want to ad a "UIELEMENT" to my multiscaleimage control??? or a pushpin of sth????
- There is a wrapper library of DeepZoom in silverlight.
- Supports Push Pin with graphic asset
- Custom Map
- Pan & Zoom In/Out just like Google Map
- Contains objects such as moving cloud and cars
- Supports PathAnimation class that allow user move any object by curve
Sample Page : http://hirihiri.com/project_ROH/silverlight/deepzoomcontainer/DeepZoomContainer.TestTestPage.html
http://deepzoomcontainer.codeplex.com/

