May 5

Written by: Soul Solutions
Tuesday, 5 May 2009 

johnWeeGo[1] 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.

pinstreet

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.

pinworld

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.01

Adding a Pushpin

Since the control has no built in Pushpin lets make our own, it will simply be a Silverlight control called pin.xaml.

addcontrol

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.

Tags:

2 comment(s) so far...

Re: Powerlaw scaling Pushpin in the Virtual Earth Silverlight control

Good Job. Waiting for your post in-depth.

By LionGG on   Wednesday, 6 May 2009

Re: Powerlaw scaling Pushpin in the Virtual Earth Silverlight control

I am interested in the implementation of IDisposable. I have images within a usercontrol that require a fair amount of memory. I remove the usercontrol, set the image.source to null, set the image to null, remove all the event handlers... you name it...but I can never get the garabage collection to reclaim the object. At least in C++, I could blame it on me! I can spend equal amount of time in C# attempting to get memory reclaimed as one would chase pointer bugs in c++.

Thanks in advance

Bruce

By Bruce Chase on   Monday, 3 August 2009

Your name:
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
Enter the code shown above in the box below
Add Comment   Cancel 
Copyright © 2002-2009 Soul Solutions Pty Ltd. | Login