hi ,
i am newer to xamdatachart so i want sample code for developing for crosshair for interpolated data in xamdatachart ,
if anybodies having idea about xamdatachart plz give me some sample
whether crosshair is possible to do in xamdatachart if possible means give me some example ,if not means how can i achieve crosshair
in chart ,plz anybodies give me reply it's very urgent for me
thanks in advance
Hi, do you just mean turning on the crosshairs? Or do you mean displaying the axis values at the exact point of the crosshair?
Turning on the crosshairs is done through the CrosshairVisibility property on the XamDataChart.
If you want access to the closest item to the crosshair then you should look at the SeriesCursorMouseMove event on the chart.
If you want to get the exact axis values at each move of the crosshair, then you should look at these samples: http://community.infragistics.com/forums/p/41666/237218.aspx#237218
The chart does not natively expose that information to you yet.
Hope this helps!
-Graham
hi Graham ,
i don't want display the axis values at the exact point of the crosshair but i need all the values of axis where ever touches the crosshair in chart
plz help me it's very urgent
Madhusudan
hi Graham,
The horizontal crosshair intersect the chart at multiple points so i want see the values for all intersection ( and now i am getting vertical crosshair values samething i want horizontal crosshair values)
totally what i am expecting in chart , the vertical and horizontal crosshairs intersect the chart , so i want to show the values for all intersection this is my problem
hope you understood now
Hi,
If you were to display a graphic at every point that the crosshair intersected the lines then things would get very messy. The chart does not natively support this behavior, but I've tried to emulate it and it ends up looking like this:
How would you like to deal with the rendering of the information when the crosshair intersects with the line so many times? Your best bet might be to use this sample: http://community.infragistics.com/forums/p/39579/235496.aspx#235496 to get the axis values of the crosshair, and then you can do your own analysis of the data to present where the crosshair intersects to the side of the chart. Or make a feature request, but try to define how the rendering should look for the above case where the line makes many crossings of the crosshair line.
Or would you just like to diplay a list or grid with the information?
i added the sample code through which one you gave me the link , but i didn't get the all intersect values of Horizontal crosshair like which one you attached one screenshot in my thread
here i attached my code and xaml code plz see this , i think i did some mistake ,where i did i unable to findout plz help me this
4705.xaml.txt
6378.Code.txt
thanks a lot Graham, it's working once again thank you so much...
--Madhusudan
Make sure you didn't miss merging any changes into your project, there were a lot of updates. I've attached my working project so that you can compare it to your project.
your code is Running without any error but i didn't get any values of intersect vertical and horizontal crosshair for your reference i attached my screenshot
Hi, I didn't share with you the code that does all the intersections because it isn't useful graphically. But in case you want to use the list of intersections in a listbox or something, here it is:
Tooltip template:
<DataTemplate x:Key="tooltipTemplate"> <Border BorderBrush="Gray" BorderThickness="1" CornerRadius="5" Background="White" IsHitTestVisible="False" Padding="5"> <!--<ItemsControl ItemsSource="{Binding}"> <ItemsControl.ItemTemplate> <DataTemplate>--> <StackPanel Orientation="Horizontal"> <ContentPresenter Content="{Binding}" ContentTemplate="{Binding Series.LegendItemBadgeTemplate}" /> <TextBlock Text="Series: " /> <TextBlock Text="{Binding Series.Title}" /> <TextBlock Text=" " /> <TextBlock Text="Value: " /> <TextBlock Text="{Binding Value}" /> </StackPanel> <!--</DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>--> </Border> </DataTemplate>
Control:
<UserControl x:Class="SilverlightApplication86.XamDataChartHostControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:igChart="clr-namespace:Infragistics.Controls.Charts;assembly=InfragisticsSL4.Controls.Charts.XamDataChart.v10.2" xmlns:igCtrl="clr-namespace:Infragistics.Controls;assembly=InfragisticsSL4.DataVisualization.v10.2" xmlns:local="clr-namespace:SilverlightApplication86" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <UserControl.Resources> <LinearGradientBrush x:Key="rscGradientBackground" StartPoint="0.0, 0.0" EndPoint="1.0, 1.0"> <GradientStop Color="#FFFFFFFF" Offset="0" /> <GradientStop Color="#c0c2c8" Offset="0.4" /> <GradientStop Color="#e0e2e8" Offset="1" /> </LinearGradientBrush> <Style x:Key="rscXamDataChartStyle" TargetType="igChart:XamDataChart"> <Setter Property="PlotAreaBackground" Value="Transparent" /> </Style> <!--<Style x:Key="LegendStyle" TargetType="{x:Type igChart:Legend}"> <Setter Property="Background"> <Setter.Value> <LinearGradientBrush EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="White" Offset="0" /> <GradientStop Color="White" Offset="0.5" /> <GradientStop Color="White" Offset="0.5" /> <GradientStop Color="#FFE8E8EF" Offset="1" /> </LinearGradientBrush> </Setter.Value> </Setter> <Setter Property="BorderBrush" Value="{StaticResource rscGradientBorder}"/> <Setter Property="BorderThickness" Value="0.75" /> <Setter Property="Orientation" Value="Vertical" /> <Setter Property="Padding" Value="4" /> <Setter Property="Margin" Value="2" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type igChart:Legend}"> <Grid Margin="{TemplateBinding Margin}"> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="3" Background="Transparent" CornerRadius="4"> <Grid Margin="{TemplateBinding Padding}"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <ContentPresenter Content="{TemplateBinding Content}" Margin="0" Grid.Row="1" /> <ScrollViewer BorderThickness="0" HorizontalScrollBarVisibility="Auto" Grid.Row="2" VerticalScrollBarVisibility="Auto" Margin="3,0,0,0"> <ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Grid.Row="1" /> </ScrollViewer> </Grid> </Border> <Border BorderBrush="Transparent" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="4" IsHitTestVisible="False"> <Border.Background> <LinearGradientBrush EndPoint="0,1" Opacity="0" StartPoint="0,0"> <GradientStop Color="Transparent" Offset="0" /> <GradientStop Color="#10FFFFFF" Offset="0.499" /> <GradientStop Color="Transparent" Offset="0.501" /> </LinearGradientBrush> </Border.Background> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>--> <LinearGradientBrush x:Key="rscGradientBorder" StartPoint="0.0, 0.0" EndPoint="0.0, 1.0"> <GradientStop Color="#FFFFFFFF" Offset="0" /> <GradientStop Color="#c0c2c8" Offset="0.75" /> <GradientStop Color="#e0e2e8" Offset="1" /> </LinearGradientBrush> </UserControl.Resources> <Border CornerRadius="5" Margin="5" Background="{StaticResource rscGradientBackground}"> <igChart:XamDataChart Grid.Row="1" Name="wpfWebDataChart1" Style="{StaticResource rscXamDataChartStyle}" Legend="{Binding ElementName=Legend}" CrosshairVisibility="Visible" > <!--<igChart:Legend igCtrl:XamDock.Edge="OutsideRight" x:Name="Legend" Style="{DynamicResource LegendStyle}" igCtrl:XamDock.VerticalAlignment="Center" Content="Prices" />--> <local:ChartBehaviors.CursorTooltip> <local:CursorTooltipBehavior TooltipTemplate="{StaticResource tooltipTemplate}" > <local:CursorTooltipBehavior.IntersectionFinder> <local:IntersectionFinder /> </local:CursorTooltipBehavior.IntersectionFinder> </local:CursorTooltipBehavior> </local:ChartBehaviors.CursorTooltip> <igChart:XamDataChart.Axes> <igChart:CategoryXAxis x:Name="XAxis" VerticalAlignment="Top" ItemsSource="{Binding}" /> <igChart:NumericYAxis x:Name="YAxis" /> </igChart:XamDataChart.Axes> <igChart:XamDataChart.Series> <igChart:LineSeries Title="High" Legend="{Binding ElementName=Legend}" XAxis="{Binding ElementName=XAxis}" YAxis="{Binding ElementName=YAxis}" MarkerType="None" ItemsSource="{Binding}" ValueMemberPath="Column2" ToolTip="{}{Series.Title} {Item.Column0:D}: {Item.Column2:C}" /> <igChart:LineSeries Title="Low" XAxis="{Binding ElementName=XAxis}" YAxis="{Binding ElementName=YAxis}" Legend="{Binding ElementName=Legend}" ItemsSource="{Binding}" ValueMemberPath="Column3" ToolTip="{}{Series.Title} {Item.Column0:D}: {Item.Column3:C}" /> <igChart:LineSeries Title="Close" Legend="{Binding ElementName=Legend}" XAxis="{Binding ElementName=XAxis}" YAxis="{Binding ElementName=YAxis}" ItemsSource="{Binding}" ValueMemberPath="Column4" ToolTip="{}{Series.Title} {Item.Column0:D}: {Item.Column4:C}" /> </igChart:XamDataChart.Series> </igChart:XamDataChart> </Border> </UserControl>
Control code behind:
public partial class XamDataChartHostControl : UserControl { private CursorTooltipBehavior curt; public XamDataChartHostControl() { InitializeComponent(); } public XamDataChart XamDataChart { get { return wpfWebDataChart1; } } private void wpfWebDataChart1_SeriesCursorMouseMove(object sender, ChartCursorEventArgs e) { //CursorTooltipBehavior temp = new CursorTooltipBehavior(); //temp.Chart_SeriesCursorMouseMove(sender, e); //if (e.Series != null && e.Item != null) //{ // curt.Chart_SeriesCursorMouseMove(sender , e ); //} } } public class ChartBehaviors : DependencyObject { public static readonly DependencyProperty CursorTooltipProperty = DependencyProperty.RegisterAttached("CursorTooltip", typeof(CursorTooltipBehavior), typeof(ChartBehaviors), new PropertyMetadata(null, (o, e) => CursorTooltipChanged(o as XamDataChart, e.OldValue as CursorTooltipBehavior, e.NewValue as CursorTooltipBehavior))); public static CursorTooltipBehavior GetCursorTooltip(DependencyObject target) { return target.GetValue(CursorTooltipProperty) as CursorTooltipBehavior; } public static void SetCursorTooltip(DependencyObject target, CursorTooltipBehavior behavior) { target.SetValue(CursorTooltipProperty, behavior); } private static void CursorTooltipChanged(XamDataChart chart, CursorTooltipBehavior oldValue, CursorTooltipBehavior newValue) { if (chart == null) { return; } if (oldValue != null) { oldValue.OnDetach(chart); } if (newValue != null) { newValue.OnAttach(chart); } } } public class SeriesItemInfo : INotifyPropertyChanged { private Series _series; public Series Series { get { return _series; } set { _series = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Series")); PropertyChanged(this, new PropertyChangedEventArgs("Value")); } } } private object _item; public object Item { get { return _item; } set { _item = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Item")); PropertyChanged(this, new PropertyChangedEventArgs("Value")); } } } private Point _position; public Point Position { get { return _position; } set { _position = value; if (PropertyChanged != null) { PropertyChanged( this, new PropertyChangedEventArgs("Position")); } } } private double _value; private FastReflectionHelper _helper = new FastReflectionHelper(); public double Value { get { if (Series == null || Item == null) { return 0.0; } if (Series is AnchoredCategorySeries) { _helper.PropertyName = ((AnchoredCategorySeries)Series) .ValueMemberPath; return Convert.ToDouble(_helper.GetPropertyValue(Item)); } return 0.0; } } public event PropertyChangedEventHandler PropertyChanged; } public class SeriesItemInfoCollection : ObservableCollection<SeriesItemInfo> { internal void UpdateSeriesItems(Series series, IList<Tuple<object, Point>> intersectedAxisItems) { bool found = false; var old = (from curr in this where curr.Series == series select curr).ToList(); foreach (var item in old) { Remove(item); } foreach (var item in intersectedAxisItems) { Add(new SeriesItemInfo() { Series = series, Item = item.Item1, Position = item.Item2 }); } } } public class PopupCollection { private XamDataChart _owner = null; private List<Popup> _popups = new List<Popup>(); public PopupCollection(XamDataChart owner) { _owner = owner; } public void RefreshPopups( IList<SeriesItemInfo> infos, DataTemplate tooltipTemplate, Rect viewportRect) { int index = 0; foreach (var popup in _popups) { if (index >= infos.Count) { break; } ContentControl control = popup.Child as ContentControl; control.ContentTemplate = tooltipTemplate; control.Content = infos[index]; UpdatePopupPosition(popup, infos[index], viewportRect); popup.IsOpen = true; index++; } for (int i = index; i < infos.Count; i++) { Popup popup = new Popup(); popup.Child = new ContentControl(); ContentControl control = popup.Child as ContentControl; control.ContentTemplate = tooltipTemplate; control.Content = infos[i]; UpdatePopupPosition(popup, infos[i], viewportRect); popup.IsOpen = true; Panel container; if (_owner.Parent != null && _owner.Parent is Panel) { container = _owner.Parent as Panel; container.Children.Add(popup); } _popups.Add(popup); index++; } for (int i = index; i < _popups.Count; i++) { _popups[i].IsOpen = false; } } private void UpdatePopupPosition( Popup popup, SeriesItemInfo info, Rect viewportRect) { double xPosition = ((AnchoredCategorySeries)info.Series).XAxis .GetScaledValue( info.Position.X, info.Series.Chart.WindowRect, viewportRect); double yPosition = ((AnchoredCategorySeries)info.Series).YAxis .GetScaledValue( info.Position.Y, info.Series.Chart.WindowRect, viewportRect); popup.HorizontalOffset = xPosition; popup.VerticalOffset = yPosition; } } public class CursorTooltipBehavior { private bool _isOverChart = false; private PopupCollection _popups = null; private ContentControl _content = new ContentControl(); private Panel _container; private XamDataChart _owner = null; private DataTemplate _tooltipTemplate; private SeriesItemInfoCollection _items = new SeriesItemInfoCollection(); public DataTemplate TooltipTemplate { get { return _tooltipTemplate; } set { _tooltipTemplate = value; _content.ContentTemplate = _tooltipTemplate; } } //protected bool IsOverChart //{ // get { return _isOverChart; } // set // { // bool last = _isOverChart; // _isOverChart = value; // if (_isOverChart && !last) // { // ShowPopup(); // } // if (!_isOverChart && last) // { // HidePopup(); // } // } //} public void OnAttach(XamDataChart chart) { if (_owner != null) { OnDetach(_owner); } _owner = chart; chart.MouseLeave += Chart_MouseLeave; chart.MouseMove += Chart_MouseMove; //chart.SeriesCursorMouseMove += Chart_SeriesCursorMouseMove; chart.PropertyUpdated += Chart_PropertyUpdated; _popups = new PopupCollection(_owner); } void Chart_PropertyUpdated(object sender, PropertyUpdatedEventArgs e) { if (e.PropertyName == "CrosshairPoint") { if (e.NewValue != null && e.NewValue is Point && _owner != null) { //get the relevant axes. CategoryXAxis x = _owner.Axes.First((a) => a is CategoryXAxis) as CategoryXAxis; NumericYAxis y = _owner.Axes.First((a) => a is NumericYAxis) as NumericYAxis; //determine the series viewport. Rect viewportRect = GetViewportRect( _owner.Series[0], x, y); Point p = (Point)e.NewValue; double left; double right; double top; double bottom; GetInViewAxisBounds(x, y, viewportRect, out left, out right, out top, out bottom); //get crosshair window values. double windowX = (p.X - _owner.WindowRect.Left) / _owner.WindowRect.Width; double windowY = (p.Y - _owner.WindowRect.Top) / _owner.WindowRect.Height; //interpolate axis values. double xAxisValue = left + (windowX * (right - left)); double yAxisValue = top + (windowY * (bottom - top)); if (!double.IsNaN(xAxisValue) && !double.IsNaN(yAxisValue) && IntersectionFinder != null) { foreach (var series in _owner.Series) { IList<Tuple<object, Point>> intersectedAxisItems = IntersectionFinder.GetIntersectedItemAxisItems( series, new Point(xAxisValue, yAxisValue)); _items.UpdateSeriesItems(series, intersectedAxisItems); } } } } } public IIntersectionFinder IntersectionFinder { get; set; } private void GetInViewAxisBounds( CategoryXAxis x, NumericYAxis y, Rect viewportRect, out double left, out double right, out double top, out double bottom) { left = x.GetUnscaledValue( viewportRect.Left, _owner.WindowRect, viewportRect); right = x.GetUnscaledValue( viewportRect.Right, _owner.WindowRect, viewportRect); top = y.GetUnscaledValue( viewportRect.Top, _owner.WindowRect, viewportRect); bottom = y.GetUnscaledValue( viewportRect.Bottom, _owner.WindowRect, viewportRect); } private Rect GetViewportRect( Series target, CategoryXAxis x, NumericYAxis y) { double top = 0; double left = 0; double bottom = y.ActualHeight; double right = x.ActualWidth; double width = right - left; double height = bottom - top; if (width > 0.0 && height > 0.0) { return new Rect(left, top, width, height); } return Rect.Empty; } public void OnDetach(XamDataChart chart) { if (_owner != chart) { return; } chart.MouseLeave -= Chart_MouseLeave; chart.MouseMove -= Chart_MouseMove; //chart.SeriesCursorMouseMove -= Chart_SeriesCursorMouseMove; chart.PropertyUpdated -= Chart_PropertyUpdated; //IsOverChart = false; _items.Clear(); _owner = null; } void Chart_MouseMove(object sender, MouseEventArgs e) { CategoryXAxis x = _owner.Axes.First((a) => a is CategoryXAxis) as CategoryXAxis; NumericYAxis y = _owner.Axes.First((a) => a is NumericYAxis) as NumericYAxis; //determine the series viewport. Rect viewportRect = GetViewportRect( _owner.Series[0], x, y); _popups.RefreshPopups(_items, _tooltipTemplate, viewportRect); //IsOverChart = true; } //public void Chart_SeriesCursorMouseMove(object sender, ChartCursorEventArgs e) //{ // if (e.Series != null && e.Item != null) // { // _items.UpdateSeriesItem(e.Series, e.Item); // } //} public void Chart_MouseLeave(object sender, MouseEventArgs e) { //IsOverChart = false; } } public interface IIntersectionFinder { IList<Tuple<object, Point>> GetIntersectedItemAxisItems( Series series, Point crosshairAxisPosition); }
Test Data:
public class TestData : ObservableCollection<TestDataItem> { private static Random _rand = new Random(); public TestData() { double curr = 10.0; for (int i = 0; i < 100; i++) { if (_rand.NextDouble() < .5) { curr += _rand.NextDouble() * 3.0; } else { curr -= _rand.NextDouble() * 3.0; } Add(new TestDataItem() { Column0 = i, Column1 = curr + _rand.NextDouble() * 3.0, Column2 = curr + _rand.NextDouble() * 3.0, Column3 = curr - _rand.NextDouble() * 3.0, Column4 = curr - _rand.NextDouble() * 3.0 }); } } } public class TestDataItem { public double Column0 { get; set; } public double Column1 { get; set; } public double Column2 { get; set; } public double Column3 { get; set; } public double Column4 { get; set; } } public class IntersectionFinder : IIntersectionFinder { FastReflectionHelper _helper = new FastReflectionHelper(); public IList<Tuple<object, System.Windows.Point>> GetIntersectedItemAxisItems( Series series, System.Windows.Point crosshairAxisPosition ) { var intersections = new List<Tuple<object, Point>>(); int index = 0; _helper.PropertyName = ((AnchoredCategorySeries)series).ValueMemberPath; double prevX = double.NaN; double prevY = double.NaN; foreach (var item in series.ItemsSource.OfType<TestDataItem>()) { double xVal = index; double yVal = Convert.ToDouble(_helper.GetPropertyValue(item)); if (!double.IsNaN(xVal) && !double.IsNaN(yVal)) { if ((prevY < crosshairAxisPosition.Y && yVal >= crosshairAxisPosition.Y) || (prevY > crosshairAxisPosition.Y && yVal <= crosshairAxisPosition.Y)) { intersections.Add(new Tuple<object,Point>( item, new Point(xVal,yVal))); } } index++; prevX = xVal; prevY = yVal; } return intersections; } }
Hope that helps.