I use the XamDataChart to display bulk data in LineSeries (aprox. 1200 datapoints).For some of the datapoints comments are existing.If a comment on a datapoint exists, this is shown by a marker. This is controlled through a MarkerType definition.
Unfortunately, I had to notice that not all datapoints are displayed in the chart and some of the comment markers therefore do not appear. Is there a possibility, to force to show certain datapoints in XamDataChart?
I've adapted my sample from here: http://community.infragistics.com/forums/p/45157/246174.aspx#246174To show how you could add points and point annotations to the chart manually for interesting effects. You could use this to annotate the points that must be shown, because as Petar said, the chart will not necessarily display all points if some are too close together at a zoom level. Don't use this sample to add too many annotations to the chart or you will negate that performance advantage.The Xaml:
<UserControl.Resources> <local:TestData x:Key="vm" /> <DataTemplate x:Key="TriangleMarkerTemplate"> <!-- This is a bit bigger than the standard triangle template --> <Polygon Points="0, 0 8, 16 16, 0" Stretch="Fill" Fill="{Binding Data.Series.ActualMarkerBrush}" Stroke="{Binding Data.Series.ActualMarkerOutline}" StrokeThickness="0.5" /> </DataTemplate> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <ig:XamDataChart x:Name="chart" VerticalZoomable="True" HorizontalZoomable="True" > <local:ChartBehaviors.ChartPoints> <local:ChartPointsBehavior> <local:ChartPointsBehavior.PointTemplate> <DataTemplate> <Grid> <ContentPresenter Margin="6" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ContentTemplate="{StaticResource TriangleMarkerTemplate}" Content="{Binding}"> </ContentPresenter> </Grid> </DataTemplate> </local:ChartPointsBehavior.PointTemplate> <local:ChartPointsBehavior.Points> <local:PointInfo X="1" Y="2"> <local:PointInfo.Data> <ig:DataContext Series="{Binding ElementName=line}" Item="{Binding ElementName=line, Path=ItemsSource[1]}"/> </local:PointInfo.Data> </local:PointInfo> </local:ChartPointsBehavior.Points> </local:ChartPointsBehavior> </local:ChartBehaviors.ChartPoints> <ig:XamDataChart.Axes> <ig:CategoryXAxis x:Name="xAxis" ItemsSource="{StaticResource vm}" Label="{}{Label}" /> <ig:NumericYAxis x:Name="yAxis" /> </ig:XamDataChart.Axes> <ig:XamDataChart.Series> <ig:LineSeries x:Name="line" MarkerType="Triangle" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" ValueMemberPath="Value" ItemsSource="{StaticResource vm}"/> </ig:XamDataChart.Series> </ig:XamDataChart> </Grid>
The code behind:
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } } public class TestData : ObservableCollection<TestDataItem> { public TestData() { Add(new TestDataItem() { Label = "1", Value = 1 }); Add(new TestDataItem() { Label = "2", Value = 2 }); Add(new TestDataItem() { Label = "3", Value = 3 }); Add(new TestDataItem() { Label = "4", Value = 4 }); Add(new TestDataItem() { Label = "5", Value = 5 }); Add(new TestDataItem() { Label = "6", Value = 6 }); Add(new TestDataItem() { Label = "7", Value = 7 }); } } public class TestDataItem { public string Label { get; set; } public double Value { get; set; } } public class ChartBehaviors : DependencyObject { public static readonly DependencyProperty ChartPointsProperty = DependencyProperty.RegisterAttached("ChartPoints", typeof(ChartPointsBehavior), typeof(ChartBehaviors), new PropertyMetadata(null, (o, e) => CursorTooltipChanged( o as XamDataChart, e.OldValue as ChartPointsBehavior, e.NewValue as ChartPointsBehavior))); public static ChartPointsBehavior GetChartPoints( DependencyObject target) { return target.GetValue(ChartPointsProperty) as ChartPointsBehavior; } public static void SetChartPoints( DependencyObject target, ChartPointsBehavior behavior) { target.SetValue(ChartPointsProperty, behavior); } private static void CursorTooltipChanged( XamDataChart chart, ChartPointsBehavior oldValue, ChartPointsBehavior newValue) { if (chart == null) { return; } if (oldValue != null) { oldValue.OnDetach(chart); } if (newValue != null) { newValue.OnAttach(chart); } } } public class PointInfo : DependencyObject { public PointInfo() { _id = Guid.NewGuid(); X = double.NaN; Y = double.NaN; } private PointInfo(Guid id) { _id = id; X = double.NaN; Y = double.NaN; } private Guid _id; public Guid Id { get { return _id; } private set { _id = value; } } public double X { get; set; } public double Y { get; set; } public string Label { get; set; } public Brush Fill { get; set; } public DataTemplate PointTemplate { get; set; } public static readonly DependencyProperty DataProperty = DependencyProperty.Register( "Data", typeof(object), typeof(PointInfo), new PropertyMetadata(null)); public object Data { get { return GetValue(DataProperty); } set { SetValue(DataProperty, value); } } public PointInfo Clone() { PointInfo newPointInfo = new PointInfo(_id); newPointInfo.X = X; newPointInfo.Y = Y; newPointInfo.Label = Label; newPointInfo.PointTemplate = PointTemplate; newPointInfo.Fill = Fill; BindingOperations.SetBinding( newPointInfo, PointInfo.DataProperty, new Binding("Data") { Source = this }); return newPointInfo; } } public class PointInfoCollection : ObservableCollection<PointInfo> { } public class ChartPointsBehavior : DependencyObject { public ChartPointsBehavior() { Points = new PointInfoCollection(); } public static readonly DependencyProperty StripsProperty = DependencyProperty.Register("Points", typeof(PointInfoCollection), typeof(ChartPointsBehavior), new PropertyMetadata(null, (o, e) => (o as ChartPointsBehavior) .OnPointsChanged( e.OldValue as PointInfoCollection, e.NewValue as PointInfoCollection))); public PointInfoCollection Points { get { return (PointInfoCollection)GetValue(StripsProperty); } set { SetValue(StripsProperty, value); } } public DataTemplate PointTemplate { get; set; } private void OnPointsChanged( PointInfoCollection oldValue, PointInfoCollection newValue) { if (oldValue != null) { oldValue.CollectionChanged -= Points_CollectionChanged; } if (newValue != null) { newValue.CollectionChanged += Points_CollectionChanged; } RefreshPoints(); } void Points_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e) { RefreshPoints(); } private XamDataChart _owner = null; public void OnAttach(XamDataChart chart) { if (_owner != null) { OnDetach(_owner); } _owner = chart; _owner.WindowRectChanged += Owner_WindowRectChanged; _owner.SizeChanged += Owner_SizeChanged; _owner.Axes.CollectionChanged += Axes_CollectionChanged; _owner.Axes.CollectionResetting += Axes_CollectionResetting; RefreshPoints(); } void Owner_SizeChanged(object sender, SizeChangedEventArgs e) { RefreshPoints(); } void Axes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.OldItems != null) { foreach (Axis axis in e.OldItems) { axis.SizeChanged -= Axis_SizeChanged; } } if (e.NewItems != null) { foreach (Axis axis in e.NewItems) { axis.SizeChanged += Axis_SizeChanged; } } RefreshPoints(); } void Axis_SizeChanged(object sender, SizeChangedEventArgs e) { RefreshPoints(); } void Axes_CollectionResetting(object sender, EventArgs e) { foreach (Axis axis in _owner.Axes) { axis.SizeChanged -= Axis_SizeChanged; } RefreshPoints(); } void Owner_WindowRectChanged(object sender, Infragistics.RectChangedEventArgs e) { RefreshPoints(); } private void GetAxes( out Axis xAxis, out Axis yAxis) { if (_owner == null) { xAxis = null; yAxis = null; return; } xAxis = (from axis in _owner.Axes where axis is NumericXAxis || axis is CategoryXAxis || axis is CategoryDateTimeXAxis select axis).FirstOrDefault(); yAxis = (from axis in _owner.Axes where axis is NumericYAxis select axis).FirstOrDefault(); } private Series GetSeries() { if (_owner == null) { return null; } return _owner.Series.FirstOrDefault(); } private void ClearExisting() { var series = GetSeries(); if (series == null) { return; } if (series.RootCanvas == null) { return; } var existing = from child in series.RootCanvas.Children where child is ContentControl && (child as ContentControl).Content != null && (child as ContentControl).Content is PointInfo select child; existing.ToList().ForEach( (ele) => series.RootCanvas.Children.Remove(ele)); } private void RefreshPoints() { Axis xAxis; Axis yAxis; GetAxes(out xAxis, out yAxis); if (xAxis == null || yAxis == null || xAxis.RootCanvas == null) { return; } ClearExisting(); Rect viewport = GetViewportRect(xAxis); foreach (PointInfo info in Points) { PointInfo toAdd = info.Clone(); if (double.IsNaN(toAdd.X)) { toAdd.X = viewport.Left; } else { toAdd.X = xAxis.GetScaledValue( toAdd.X, _owner.WindowRect, viewport); } if (double.IsNaN(toAdd.Y)) { toAdd.Y = viewport.Top; } else { toAdd.Y = yAxis.GetScaledValue( toAdd.Y, _owner.WindowRect, viewport); } if (toAdd.PointTemplate == null) { toAdd.PointTemplate = this.PointTemplate; } if (toAdd.PointTemplate != null && !double.IsNaN(toAdd.Y) && !double.IsInfinity(toAdd.Y) && !double.IsNaN(toAdd.X) && !double.IsInfinity(toAdd.X)) { var series = GetSeries(); if (series == null) { continue; } var pointControl = new ContentControl(); Canvas.SetZIndex(pointControl, 2000); pointControl.ContentTemplate = toAdd.PointTemplate; pointControl.Content = toAdd; series.RootCanvas.Children.Add(pointControl); pointControl.Measure( new Size( double.PositiveInfinity, double.PositiveInfinity)); Canvas.SetLeft(pointControl, toAdd.X - (pointControl.DesiredSize.Width / 2.0)); Canvas.SetTop(pointControl, toAdd.Y - (pointControl.DesiredSize.Height / 2.0)); } } } private Rect GetViewportRect( Axis axis) { double top = 0; double bottom = axis.ActualHeight; double left = 0; double right = axis.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; } _owner.WindowRectChanged -= Owner_WindowRectChanged; _owner.SizeChanged -= Owner_SizeChanged; _owner.Axes.CollectionChanged -= Axes_CollectionChanged; _owner.Axes.CollectionResetting -= Axes_CollectionResetting; Axis xAxis; Axis yAxis; GetAxes(out xAxis, out yAxis); if (xAxis == null || yAxis == null) { return; } ClearExisting(); _owner = null; } }
Which should give you a result looking like this:
Hope this helps!-Graham
Hello,
I have been looking into your request and such functionality is not built-in. This rendering functionality is one of the XamDataChart’s main performance enhancements, which make it suitable for working with huge amounts of data.
I you want a new Feature Request can be submitted here on our website: http://devcenter.infragistics.com/Protected/RequestFeature.aspx so it could appear in one of our future releases.
Please let me know if I can assist you further on the matter.
Sincerely,
Petar Monov
Developer Support Engineer
Infragistics Bulgaria
www.infragistics.com/support