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?
Graham,
Perhaps this is a stupid question but I just can't figure out why you multiply the ticks by 170000?
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
Mike,
You might be able to do that. I'll try it out in the sample I sent you and let you know.
-Graham
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?
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).