This is a migrated thread and some comments may be shown as answers.

Creating a compass

7 Answers 170 Views
Gauge
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Eric
Top achievements
Rank 1
Eric asked on 24 Mar 2009, 04:56 PM
I'd like to create a 360-degree gauge representing a compass, and I'd like the needle to be animated. When the needle goes from, say, North-West (315) to North-East (45), I'd like it to go the shortest way, through North (0). Similarly, when it goes from SW to SE, it should go through South (180).

Can I achieve this with your gauge?

Eric.

7 Answers, 1 is accepted

Sort by
0
Accepted
Andrey
Telerik team
answered on 25 Mar 2009, 04:58 PM
Hi Eric,

The compass-like radial gauge can be created using following XAML:
<UserControl x:Class="TestGaugeApplication.Page" 
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"   
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   
             xmlns:telerik="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls" 
             xmlns:control="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Gauge"   
             xmlns:gauge="clr-namespace:Telerik.Windows.Controls.Gauges;assembly=Telerik.Windows.Controls.Gauge"   
             Width="500" Height="400">  
    <UserControl.Resources> 
        <ResourceDictionary> 
            <DataTemplate x:Key="TickLabelEmpty">  
                <Grid /> 
            </DataTemplate> 
 
            <Style x:Key="MajorCustomTicks" TargetType="TextBlock">  
                <Setter Property="FontFamily" Value="Arial" /> 
                <Setter Property="FontSize" Value="14" /> 
                <Setter Property="FontWeight" Value="Bold" /> 
            </Style> 
 
            <ControlTemplate x:Key="CompasNeedleTemplate" TargetType="gauge:Needle">  
                <Grid x:Name="PART_Grid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">  
                    <Grid.ColumnDefinitions> 
                        <ColumnDefinition Width="*" /> 
                        <!-- Column 0 - tail --> 
                        <ColumnDefinition Width="*" /> 
                        <!-- Column 1 - pin point --> 
                        <ColumnDefinition Width="*" /> 
                        <!-- Column 2 - arrow --> 
                    </Grid.ColumnDefinitions> 
                    <Grid.RowDefinitions> 
                        <RowDefinition Height="*" /> 
                    </Grid.RowDefinitions> 
 
                    <Grid x:Name="PART_Shape" Grid.ColumnSpan="3" Margin="0">  
                        <Grid.ColumnDefinitions> 
                            <ColumnDefinition Width="50*" /> 
                            <ColumnDefinition Width="50*" /> 
                        </Grid.ColumnDefinitions> 
                        <Grid.RowDefinitions> 
                            <RowDefinition Height="0.3*" /> 
                            <RowDefinition Height="0.4*" /> 
                            <RowDefinition Height="0.3*" /> 
                        </Grid.RowDefinitions> 
 
                        <Path Grid.Row="1"   
                              Grid.Column="1"   
                              Stretch="Fill" 
                              Fill="Blue"   
                              StrokeThickness="1">  
                            <Path.Data> 
                                <PathGeometry> 
                                    <PathFigure StartPoint="1,0.5">  
                                        <LineSegment Point="0,1" /> 
                                        <LineSegment Point="0,0" /> 
                                    </PathFigure> 
                                </PathGeometry> 
                            </Path.Data> 
                        </Path> 
 
                        <Path Grid.Row="1"   
                              Grid.Column="0"   
                              Stretch="Fill" 
                              Fill="Red"   
                              StrokeThickness="1">  
                            <Path.Data> 
                                <PathGeometry> 
                                    <PathFigure StartPoint="1,0">  
                                        <LineSegment Point="1,1" /> 
                                        <LineSegment Point="0,0.5" /> 
                                    </PathFigure> 
                                </PathGeometry> 
                            </Path.Data> 
                        </Path> 
                    </Grid> 
 
                    <Grid Grid.Column="1">  
                        <Grid.RowDefinitions> 
                            <RowDefinition Height="0.125*" /> 
                            <RowDefinition Height="0.75*" /> 
                            <RowDefinition Height="0.125*" /> 
                        </Grid.RowDefinitions> 
                        <Grid.ColumnDefinitions> 
                            <ColumnDefinition Width="0.125*" /> 
                            <ColumnDefinition Width="0.75*" /> 
                            <ColumnDefinition Width="0.125*" /> 
                        </Grid.ColumnDefinitions> 
                        <Ellipse Grid.Column="1" Grid.Row="1" Stretch="Uniform" 
                                 Fill="White">  
                        </Ellipse> 
                    </Grid> 
 
                    <Grid Grid.Column="1">  
                        <Grid.RowDefinitions> 
                            <RowDefinition Height="0.25*" /> 
                            <RowDefinition Height="0.5*" /> 
                            <RowDefinition Height="0.25*" /> 
                        </Grid.RowDefinitions> 
                        <Grid.ColumnDefinitions> 
                            <ColumnDefinition Width="0.25*" /> 
                            <ColumnDefinition Width="0.5*" /> 
                            <ColumnDefinition Width="0.25*" /> 
                        </Grid.ColumnDefinitions> 
                        <Ellipse Grid.Column="1" Grid.Row="1" Stretch="Uniform" 
                                 Fill="White">  
                        </Ellipse> 
                    </Grid> 
                </Grid> 
            </ControlTemplate> 
              
            <Style x:Key="CompasNeedleStyle" TargetType="gauge:Needle">  
                <Setter Property="Location" Value="OverCenter" /> 
                <Setter Property="RelativeHeight" Value="0.4" /> 
                <Setter Property="RelativeShift" Value="1.4" /> 
                <Setter Property="Template" Value="{StaticResource CompasNeedleTemplate}" /> 
            </Style> 
        </ResourceDictionary> 
    </UserControl.Resources> 
    <Grid x:Name="LayoutRoot" Background="White">  
        <control:RadGauge x:Name="radGauge" Width="350" Height="350">  
            <gauge:RadialGauge> 
                <gauge:RadialScale StartAngle="270" 
                                   SweepAngle="360" 
                                   Radius="0.83" 
                                   Min="0" 
                                   Max="360" 
                                   MajorTickStep="90" 
                                   ShowLastLabel="False" 
                                   LabelRotationMode="None">  
                    <gauge:RadialScale.Label> 
                        <gauge:LabelProperties ItemTemplate="{StaticResource TickLabelEmpty}">  
                        </gauge:LabelProperties> 
                    </gauge:RadialScale.Label> 
                    <gauge:TickList> 
                        <gauge:CustomTickMark Value="0">  
                            <gauge:CustomTickMark.ItemTemplate> 
                                <DataTemplate> 
                                    <Grid> 
                                        <TextBlock Foreground="Blue" 
                                                   Style="{StaticResource MajorCustomTicks}" 
                                                   Text="N" /> 
                                    </Grid> 
                                </DataTemplate> 
                            </gauge:CustomTickMark.ItemTemplate> 
                        </gauge:CustomTickMark> 
                        <gauge:CustomTickMark Value="90">  
                            <gauge:CustomTickMark.ItemTemplate> 
                                <DataTemplate> 
                                    <Grid> 
                                        <TextBlock Foreground="Blue" 
                                                   Style="{StaticResource MajorCustomTicks}" 
                                                   Text="E" /> 
                                    </Grid> 
                                </DataTemplate> 
                            </gauge:CustomTickMark.ItemTemplate> 
                        </gauge:CustomTickMark> 
                        <gauge:CustomTickMark Value="180">  
                            <gauge:CustomTickMark.ItemTemplate> 
                                <DataTemplate> 
                                    <Grid> 
                                        <TextBlock Foreground="Blue" 
                                                   Style="{StaticResource MajorCustomTicks}" 
                                                   Text="S" /> 
                                    </Grid> 
                                </DataTemplate> 
                            </gauge:CustomTickMark.ItemTemplate> 
                        </gauge:CustomTickMark> 
                        <gauge:CustomTickMark Value="270">  
                            <gauge:CustomTickMark.ItemTemplate> 
                                <DataTemplate> 
                                    <Grid> 
                                        <TextBlock Foreground="Blue" 
                                                   Style="{StaticResource MajorCustomTicks}" 
                                                   Text="W" /> 
                                    </Grid> 
                                </DataTemplate> 
                            </gauge:CustomTickMark.ItemTemplate> 
                        </gauge:CustomTickMark> 
                    </gauge:TickList> 
                    <gauge:IndicatorList> 
                        <gauge:Needle x:Name="needle" Style="{StaticResource CompasNeedleStyle}" /> 
                    </gauge:IndicatorList> 
                </gauge:RadialScale> 
            </gauge:RadialGauge> 
        </control:RadGauge> 
    </Grid> 
</UserControl> 

Unfortunately you can’t switch build-in indicator’s animation to go the shortest way. It always walk from current to the next value through the values in the [current, next] interval. But you can create your own animation routines which will work as you’d like. You need check if the sweep angle between current and next value is more than 180 degree and then operate depends on the test result:

  1. If distance is less than 180 degree – create 1 double animation which will change value of the needle from current to next value.
  2. If distance is more than 180 degree – create 2 double animations. One from current value to 0 or 360 depends on direction of change. And second from 0 or 260 to the next value.

Following code represents how it can be done:

/// <summary>  
/// Indicates whether the 2 animations should be used  
/// </summary>  
private bool doubleAnimation = false;  
 
/// <summary>  
/// From value for second animation  
/// </summary>  
private double secondFromValue;  
 
/// <summary>  
/// To value for second animation  
/// </summary>  
private double secondToValue;  
 
private void SetNewValueToIndicator(double newValue)  
{  
    CreateAndRunAnimation(needle.Value, newValue);  
}  
 
private Storyboard CreateAnimation(double fromValue, double toValue, Duration duration)  
{  
    // Create DoubleAnimations and set their properties.  
    DoubleAnimation needleValueAnimation = new DoubleAnimation();  
 
    needleValueAnimation.Duration = duration;  
 
    Storyboard storyboard = new Storyboard();  
    storyboard.Children.Add(needleValueAnimation);  
    Storyboard.SetTarget(needleValueAnimation, needle);  
    Storyboard.SetTargetProperty(needleValueAnimation, new PropertyPath("(Needle.Value)"));  
 
    needleValueAnimation.From = (double.IsNaN(fromValue) ? 0 : fromValue);  
    needleValueAnimation.To = toValue;  
 
    return storyboard;  
}  
 
private void CreateAndRunAnimation(double fromValue, double toValue)  
{  
    Duration duration;  
    double distance = Math.Abs(toValue - fromValue);  
    if (distance > 180)  
    {  
        doubleAnimation = true;  
        if (toValue > 180)  
        {  
            secondFromValue = 360;  
            secondToValue = toValue;  
            toValue = 0;  
        }  
        else if (fromValue > 180)  
        {  
            secondFromValue = 0;  
            secondToValue = toValue;  
            toValue = 360;  
        }  
        duration = new Duration(TimeSpan.FromSeconds(0.4));  
    }  
    else 
    {  
        doubleAnimation = false;  
        duration = new Duration(TimeSpan.FromSeconds(0.8));  
    }  
 
    Storyboard storyboard = CreateAnimation(fromValue, toValue, duration);  
    storyboard.Completed += new EventHandler(Storyboard_Completed);  
    storyboard.Begin();  
}  
 
private void Storyboard_Completed(object sender, EventArgs e)  
{  
    if (doubleAnimation)  
    {  
        // Create a duration of 1 seconds.  
        Duration duration = new Duration(TimeSpan.FromSeconds(0.4));  
 
        Storyboard storyboard = CreateAnimation(secondFromValue, secondToValue, duration);  
        storyboard.Begin();  
    }  

All the best,
Andrey Murzov
the Telerik team


Check out Telerik Trainer , the state of the art learning tool for Telerik products.
0
Eric
Top achievements
Rank 1
answered on 26 Mar 2009, 05:44 PM
Many thanks.

Eric
0
Danette Cross
Top achievements
Rank 1
answered on 30 Jun 2010, 10:38 PM
What references do we use for the storyboard and doubleanimation? I have using statements for Telerik.Windows.Controls and Telerik.Windows.Controls.Guages but seems I am missing an assembly reference.
0
Andrey
Telerik team
answered on 01 Jul 2010, 09:54 AM
Hi Danette,

The Storyboard and DoubleAnimation classes are contained in the System.Windows.Media.Animation namespace.

Sincerely yours,
Andrey Murzov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Chris
Top achievements
Rank 1
answered on 01 May 2012, 12:27 PM
Sorry to Hijack the thread but we have just purchased the RadControls and we have a need to create a compas that allows the user to move the needle and subsequently the guage value with the mouse, so they can in essence select a bearing by draging the needle, could anyone provide me with some guidance with the best way to achieve this ??


Many Thanks in advance

0
Andrey
Telerik team
answered on 03 May 2012, 05:08 PM
Hello Chris,

Simply set the RadialScale.IsInteractive property to true and you will be able to drag the needle and position it by clicking on the scale.

Kind regards,
Andrey Murzov
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

0
Chris
Top achievements
Rank 1
answered on 04 May 2012, 10:14 AM
Many Thanks, it worked liked a charm :-)
Tags
Gauge
Asked by
Eric
Top achievements
Rank 1
Answers by
Andrey
Telerik team
Eric
Top achievements
Rank 1
Danette Cross
Top achievements
Rank 1
Chris
Top achievements
Rank 1
Share this question
or