If there are multiple players on a chart is it possible to have a unified tooltip that displays the current Y value of each layer currently in contact with the vertical crosshair without having to have the cursor touching each layer individually?
You can adapt the code from this post: https://ko.infragistics.com/community/forums/f/retired-products-and-controls/39579/xamwebdatachart---crosshairs-position
to display the crosshair value for each series in the chart. The key would be to use the assigned x and y axis for each series to map from the world coordinate points to the axis values for each set of axes. Once you have resolved the values for each series, just store them somewhere that you can bind to from the tooltip. Would you like more info, or does this put you on the right path?
-Graham
With the release bits is there a more elegant solution to this or shold I still use the code from your previous post? In the post you linked to you indicated that the initial release did not have the bits to make this elegant.
Actually any example you have would be helpful. Since I am adding all series, axes, etc. dynamically from code I have difficulties getting the standard functionality to work much less something a bit more advanced like this.
Thanks!Mike
Mike,Here's how you might use the NumericXAxis to have greater control over the time labels that are displayed.This sample pushes the minimum and maximum so that an even number of minutes is represented in the range.Then it sets the interval equal to 20 seconds. So a tickmark will be displayed every 20 seconds. Is this more what you are after?Hopefully the CategoryDateTimeXAxis will soon also support your scenario, but it doesnt currently allow for you to have this degree of configuration.The Xaml:
<UserControl.Resources> <local:TicksToDateTime x:Key="converter" /> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <ig:XamDataChart Name="xamDataChart1" HorizontalZoomable="True" VerticalZoomable="True"> <ig:XamDataChart.Axes> <ig:NumericXAxis x:Name="xAxis" > <ig:NumericXAxis.Label> <DataTemplate> <TextBlock Text="{Binding Path=Item, Converter={StaticResource converter}, ConverterParameter='hh:mm:ss'}" /> </DataTemplate> </ig:NumericXAxis.Label> </ig:NumericXAxis> <ig:NumericYAxis x:Name="yAxis" MinimumValue="0" MaximumValue="8" /> </ig:XamDataChart.Axes> <ig:XamDataChart.Series> <ig:ScatterLineSeries x:Name="scatter" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" XMemberPath="XValue" YMemberPath="YValue" /> </ig:XamDataChart.Series> </ig:XamDataChart> </Grid>
And the code behind:
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); DateTimeData data = new DateTimeData(); NumericXAxis a = xamDataChart1.Axes.OfType<NumericXAxis>().First(); DateTime s = data[0].XValue; DateTime e = data[data.Count - 1].XValue; //push the min and max to be on even minute values. s = new DateTime(s.Year, s.Month, s.Day, s.Hour, s.Minute, 0 , 0); e = new DateTime(e.Year, e.Month, e.Day, e.Hour, e.Minute + 1, 0, 0); a.MinimumValue = s.Ticks; a.MaximumValue = e.Ticks; //set the gridline/label interval to 20 seconds. a.Interval = TimeSpan.FromSeconds(20).Ticks; xamDataChart1.Series[0].ItemsSource = data; } } public class TicksToDateTime : IValueConverter { public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value is double && targetType == typeof(string)) { string param = parameter as string; double val = (double)value; if (!string.IsNullOrEmpty(param)) { return new DateTime((long)val) .ToString(param, culture.DateTimeFormat); } else { return new DateTime((long)val) .ToString(culture.DateTimeFormat); } } return ""; } public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } public class DateTimeData : ObservableCollection<DateTimeDataItem> { public DateTimeData() { for (int i = 0; i < 100; i++) { Add(new DateTimeDataItem() { XValue = DateTime.Now.AddSeconds(i), YValue = i % 6 }); } } } public class DateTimeDataItem { public DateTime XValue { get; set; } public double YValue { get; set; } }
Hope this helps! Please note the scatter line chart's performance is currently not as good as line series, so make sure it is still a good fit for your scenario.Let me know if you have any questions.-Graham
Graham,
Will I have to use the ScatterLineSeries? Can I not use a StepLineSeries with the NumericXAxis? I haven't looked thorugh the example yet but there will be occations when I will have several hundred thousand points to plot (possibly into the millions).
I see now why I cannot use the StepLineSeries...this could be a problem.
How difficult (or even if possible) do you think it would be to use a CategoryDateTimeXAxis for my series hiding the xaxis gridlines and then add in a ScatterLineSeries with the same number of points with nulls for the y and all the same dates in tick simply for the xaxis labels?
Mike,
You might be able to do that. I'll try it out in the sample I sent you and let you know.
Mike,Here's how you could experiment with showing one axis but using the other.I've added the work around for short timespans on the CategoryDateTimeXAxis also.
<UserControl.Resources> <local:TicksToDateTime x:Key="converter" /> <local:TimeTranslator x:Key="translator" /> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <ig:XamDataChart Name="xamDataChart1" HorizontalZoomable="True" VerticalZoomable="True"> <ig:XamDataChart.Axes> <ig:CategoryDateTimeXAxis x:Name="dateAxis" DateTimeMemberPath="XValue" MajorStroke="Transparent" MinorStroke="Transparent" > <ig:CategoryDateTimeXAxis.LabelSettings> <ig:AxisLabelSettings Visibility="Collapsed"/> </ig:CategoryDateTimeXAxis.LabelSettings> </ig:CategoryDateTimeXAxis> <ig:NumericXAxis x:Name="xAxis" > <ig:NumericXAxis.Label> <DataTemplate> <TextBlock Text="{Binding Path=Item, Converter={StaticResource converter}, ConverterParameter='hh:mm:ss'}" /> </DataTemplate> </ig:NumericXAxis.Label> </ig:NumericXAxis> <ig:NumericYAxis x:Name="yAxis" MinimumValue="0" MaximumValue="20" /> </ig:XamDataChart.Axes> <ig:XamDataChart.Series> <ig:StepLineSeries x:Name="stepLine" XAxis="{Binding ElementName=dateAxis}" YAxis="{Binding ElementName=yAxis}" ValueMemberPath="YValue" > </ig:StepLineSeries> <ig:ScatterLineSeries x:Name="scatter" XAxis="{Binding ElementName=xAxis}" YAxis="{Binding ElementName=yAxis}" XMemberPath="XValue" YMemberPath="YValue" /> </ig:XamDataChart.Series> </ig:XamDataChart> </Grid>
with the code behind:
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); DateTimeData data = new DateTimeData(); DateTime s = TimeTranslator.UnTranslate(data[0].XValue); DateTime e = TimeTranslator.UnTranslate(data[data.Count - 1].XValue); //push the min and max to be on even minute values. s = TimeTranslator.Translate( new DateTime(s.Year, s.Month, s.Day, s.Hour, s.Minute, 0 , 0)); e = TimeTranslator.Translate( new DateTime(e.Year, e.Month, e.Day, e.Hour, e.Minute + 1, 0, 0)); data.Insert( 0, new DateTimeDataItem() { XValue = s, YValue = double.NaN }); data.Add( new DateTimeDataItem() { XValue = e, YValue = double.NaN }); NumericXAxis a = xamDataChart1.Axes.OfType<NumericXAxis>().First(); ScatterLineSeries scatterLine = xamDataChart1.Series.OfType<ScatterLineSeries>().First(); CategoryDateTimeXAxis dateAxis = xamDataChart1.Axes.OfType<CategoryDateTimeXAxis>().First(); StepLineSeries stepLine = xamDataChart1.Series.OfType<StepLineSeries>().First(); dateAxis.ItemsSource = data; stepLine.ItemsSource = data; a.MinimumValue = s.Ticks; a.MaximumValue = e.Ticks; //set the gridline/label interval to 20 seconds. a.Interval = TimeSpan.FromSeconds(30).Ticks * 170000; } } public class TicksToDateTime : IValueConverter { public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value is double && targetType == typeof(string)) { string param = parameter as string; double val = (double)value; if (!string.IsNullOrEmpty(param)) { return TimeTranslator .UnTranslate(new DateTime((long)val)) .ToString(param, culture.DateTimeFormat); } else { return TimeTranslator .UnTranslate(new DateTime((long)val)) .ToString(culture.DateTimeFormat); } } return ""; } public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } public class TimeTranslator : IValueConverter { private static DateTime _progStartTime = DateTime.Now; public static DateTime Translate(DateTime from) { return new DateTime(((from - _progStartTime).Ticks * 170000) + _progStartTime.Ticks); } public static DateTime UnTranslate(DateTime from) { return new DateTime(((from - _progStartTime).Ticks / 170000) + _progStartTime.Ticks); } public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if ((targetType == typeof(DateTime) || (targetType == typeof(string))) && value is DateTime) { return UnTranslate((DateTime)value); } return DateTime.MinValue; } public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } public class DateTimeData : ObservableCollection<DateTimeDataItem> { public DateTimeData() { for (int i = 0; i < 400; i++) { Add(new DateTimeDataItem() { XValue = TimeTranslator.Translate( DateTime.Now.AddSeconds(i)), YValue = i % 10 }); } } } public class DateTimeDataItem { public DateTime XValue { get; set; } public double YValue { get; set; } }
Hope this helps!-Graham
There are situations where you should not share a CategoryDateTimeXAxis in the same way that you should not really share a CategoryXAxis unless the series have the same labels and number of items. If you have the same number of items with the same dates assigned then you should be able to share the CategoryDateTimeXAxis. Sharing the NumericXAxis or NumericYAxis should not be a problem in those other scenarios as their range will just expand to accomodate all the series that they are assigned to.
Oh, I read that and then completely forgot about that issue. I am usging the new service release now so I removed that code. This works so far. Hopefully I won't run into any new issues.
If I am dynamically adding multiple series that all will have the same time period should I have them all use the same axes or should they all use independent x axes?
along with the multiplication your were curious about.
Thats applying the workaround I posted here: http://community.infragistics.com/forums/p/42507/242634.aspx#242634
Because I didn't know if you were running the RTM or the Service release (which I think has the fix for the CategoryDateTimeXAxis problem in question). You can rip out all the TimeTranslator stuff if you aren't having that problem.
Perhaps this is a stupid question but I just can't figure out why you multiply the ticks by 170000?