Your Privacy Matters: We use our own and third-party cookies to improve your experience on our website. By continuing to use the website we understand that you accept their use. Cookie Policy
170
Track corresponding chart value according to mouse postion in chart.
posted

In the XamDataChart We want to be able to only display the marker to which the mouse's x-coordinate is closest to.  In other words, we want to visually track the current x-location along the chart. 

This idea is similar to Google Finance.  It displays a circle on the chart.

In the attached picture, obviously three circles are displayed - one for each stock.

 

 Hope this makes sense.  Thanks in advance.

Adam

  • 30692
    Offline posted

    Adam,

     

    Here's one way of approaching this. Hope it helps you out!

    The xaml:

    <UserControl.Resources>
            <local:TestData x:Key="data1" />
            <local:TestData x:Key="data2" />
            <DataTemplate x:Key="customTemplate">
                <Grid>
                    <Grid.Resources>
                        <local:EqualChecker x:Key="checker" 
                                            Value1="{Binding Path=Series.(local:SeriesExtensions.CrosshairItem)}"
                                            Value2="{Binding Path=Item}"/>
                        <local:VisibilityConverter x:Key="converter" />
                        <local:VisibleItemsRegisterer x:Key="registerer" Item="{Binding Path=Item}" />
                    </Grid.Resources>
    
                    <Ellipse Stretch="Fill" 
                             HorizontalAlignment="Stretch" 
                             VerticalAlignment="Stretch" 
                             Fill="Transparent" 
                             Stroke="Transparent" 
                             StrokeThickness="0.5" MinWidth="10" MinHeight="10"
                             >
                    </Ellipse>
    
                    <Ellipse Stretch="Fill" 
                             HorizontalAlignment="Stretch" 
                             VerticalAlignment="Stretch" 
                             Fill="{Binding ActualItemBrush}" 
                             Stroke="{Binding Series.ActualMarkerOutline}" 
                             StrokeThickness="0.5" MinWidth="10" MinHeight="10"
                             Visibility="{Binding Path=Result, Source={StaticResource checker}, Converter={StaticResource converter}}" 
                             >
                    </Ellipse>
                </Grid>
            </DataTemplate>
            
            <Style x:Key="crosshairStyle" TargetType="Line">
                <Style.Setters>
                    <Setter Property="Visibility" Value="Collapsed" />
                </Style.Setters>
            </Style>
        </UserControl.Resources>
    
    
            <Grid x:Name="LayoutRoot" Background="White">
            <ig:XamDataChart Name="xamDataChart1" 
                             CrosshairVisibility="Visible"
                             CrosshairLineStyle="{StaticResource crosshairStyle}"
                             SeriesCursorMouseMove="xamDataChart1_SeriesCursorMouseMove">
                <ig:XamDataChart.Axes>
                    <ig:CategoryXAxis x:Name="xAxis" ItemsSource="{StaticResource data1}" />
                    <ig:NumericYAxis x:Name="yAxis" />
                </ig:XamDataChart.Axes>
                <ig:XamDataChart.Series>
                    <ig:LineSeries x:Name="testLine" 
                                   ItemsSource="{StaticResource data1}" 
                                   XAxis="{Binding ElementName=xAxis}"
                                   YAxis="{Binding ElementName=yAxis}"
                                   ValueMemberPath="Value"
                                   MarkerTemplate="{StaticResource customTemplate}"/>
    
                    <ig:LineSeries x:Name="testLine2" 
                                   ItemsSource="{StaticResource data2}" 
                                   XAxis="{Binding ElementName=xAxis}"
                                   YAxis="{Binding ElementName=yAxis}"
                                   ValueMemberPath="Value"
                                   MarkerTemplate="{StaticResource customTemplate}"/>
                </ig:XamDataChart.Series>
            </ig:XamDataChart>
        </Grid>
    

    And the code behind:

    public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
            }
    
            private void xamDataChart1_SeriesCursorMouseMove(
                object sender,
                Infragistics.Controls.Charts.ChartCursorEventArgs e)
            {
                if (e.Item != null &&
                    e.Series != null &&
                    VisibleItemsRegisterer.ItemVisible(e.Item))
                {
                    SeriesExtensions.SetCrosshairItem(
                        e.Series,
                        e.Item);
                }
            }
        }
    
        public class SeriesExtensions
        {
            public static readonly DependencyProperty CrosshairItemProperty =
                DependencyProperty.RegisterAttached(
                "CrosshairItem",
                typeof(object),
                typeof(SeriesExtensions),
                new PropertyMetadata(null));
    
            public static object GetCrosshairItem(
                DependencyObject target)
            {
                return target.GetValue(CrosshairItemProperty);
            }
    
            public static void SetCrosshairItem(
                DependencyObject target,
                object value)
            {
                target.SetValue(CrosshairItemProperty, value);
            }
        }
    
        public class VisibilityConverter
            : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                if (targetType == typeof(Visibility) &&
                    value is bool)
                {
                    if ((bool)value)
                    {
                        return Visibility.Visible;
                    }
                }
    
                return Visibility.Collapsed;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    
        public class VisibleItemsRegisterer
            : DependencyObject
        {
            private static Dictionary<object, object> _items
                = new Dictionary<object, object>();
    
            public static bool ItemVisible(object item)
            {
                return _items.ContainsKey(item);
            }
    
            public static readonly DependencyProperty ItemProperty =
               DependencyProperty.Register(
               "Item",
               typeof(object),
               typeof(VisibleItemsRegisterer),
               new PropertyMetadata(null,
                   (o, e) =>
                       (o as VisibleItemsRegisterer).OnItemChanged(e)));
    
            public object Item
            {
                get { return GetValue(ItemProperty); }
                set { SetValue(ItemProperty, value); }
            }
    
            private void OnItemChanged(
                DependencyPropertyChangedEventArgs e)
            {
                if (e.OldValue != null &&
                    _items.ContainsKey(e.OldValue))
                {
                    _items.Remove(e.OldValue);
                }
                if (e.NewValue != null &&
                    !_items.ContainsKey(e.NewValue))
                {
                    _items.Add(e.NewValue, e.NewValue);
                }
            }
        }
    
        public class EqualChecker
            : DependencyObject
        {
            public static readonly DependencyProperty Value1Property =
                DependencyProperty.Register(
                "Value1",
                typeof(object),
                typeof(EqualChecker),
                new PropertyMetadata(null,
                    (o, e) =>
                        (o as EqualChecker).OnValue1Changed(e)));
    
            public object Value1
            {
                get { return GetValue(Value1Property); }
                set { SetValue(Value1Property, value); }
            }
    
            private void OnValue1Changed(
                DependencyPropertyChangedEventArgs e)
            {
                Result = Value1 == Value2;
            }
    
            public static readonly DependencyProperty Value2Property =
                DependencyProperty.Register(
                "Value2",
                typeof(object),
                typeof(EqualChecker),
                new PropertyMetadata(null,
                    (o, e) =>
                        (o as EqualChecker).OnValue2Changed(e)));
    
            public object Value2
            {
                get { return GetValue(Value2Property); }
                set { SetValue(Value2Property, value); }
            }
    
            private void OnValue2Changed(
                DependencyPropertyChangedEventArgs e)
            {
                Result = Value1 == Value2;
            }
    
            public static readonly DependencyProperty ResultProperty =
                DependencyProperty.Register(
                "Result",
                typeof(object),
                typeof(EqualChecker),
                new PropertyMetadata(null,
                    (o, e) => { }));
    
            public object Result
            {
                get { return GetValue(ResultProperty); }
                set { SetValue(ResultProperty, value); }
            }
    
        }
    
        public class TestDataItem
        {
            public string Label { get; set; }
            public double Value { get; set; }
        }
    
        public class TestData
            : ObservableCollection<TestDataItem>
        {
            private static Random rand = new Random();
    
            public TestData()
            {
                double curr = 0;
                for (int i = 0; i < 1000; i++)
                {
                    if (rand.NextDouble() > .5)
                    {
                        curr += rand.NextDouble();
                    }
                    else
                    {
                        curr -= rand.NextDouble();
                    }
    
                    Add(
                        new TestDataItem()
                        {
                            Label = i.ToString(),
                            Value = curr
                        });
                }
            }
        }
    

    Let me know if you have any questions.

    -Graham