更新
This commit is contained in:
@@ -280,22 +280,7 @@ public sealed class RealtimeForceChart : FrameworkElement
|
|||||||
|
|
||||||
private static int ResolveXAxisDivisions(double plotWidth)
|
private static int ResolveXAxisDivisions(double plotWidth)
|
||||||
{
|
{
|
||||||
if (plotWidth >= 700)
|
return Math.Clamp((int)Math.Ceiling(plotWidth / 110), 4, 240);
|
||||||
{
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plotWidth >= 520)
|
|
||||||
{
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plotWidth >= 360)
|
|
||||||
{
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCenteredText(
|
private void DrawCenteredText(
|
||||||
|
|||||||
@@ -251,21 +251,31 @@
|
|||||||
<RowDefinition Height="300" />
|
<RowDefinition Height="300" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<controls:RealtimeForceChart x:Name="RealtimeForceChart"
|
<ScrollViewer x:Name="RealtimeChartScrollViewer"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Margin="0,0,0,8"
|
Margin="0,0,0,8"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalScrollBarVisibility="Auto"
|
||||||
VerticalAlignment="Stretch"
|
VerticalScrollBarVisibility="Disabled"
|
||||||
Samples="{Binding RealtimeForceSamples}"
|
CanContentScroll="False"
|
||||||
PeakLineSamples="{Binding RealtimePeakLineSamples}"
|
Loaded="RealtimeChartScrollViewer_Loaded"
|
||||||
AverageLineSamples="{Binding RealtimeAverageLineSamples}"
|
ScrollChanged="RealtimeChartScrollViewer_ScrollChanged">
|
||||||
CurrentPointSamples="{Binding RealtimeCurrentPointSamples}"
|
<controls:RealtimeForceChart x:Name="RealtimeForceChart"
|
||||||
XMax="{Binding RealtimeChartXMax}"
|
Width="{Binding RealtimeChartCanvasWidth}"
|
||||||
YMax="{Binding RealtimeChartYMax}"
|
MinWidth="{Binding ViewportWidth, ElementName=RealtimeChartScrollViewer}"
|
||||||
TravelMm="{Binding Recipe.TravelMm}"
|
Height="{Binding ViewportHeight, ElementName=RealtimeChartScrollViewer}"
|
||||||
SledMassGrams="{Binding Recipe.SledMassGrams}"
|
HorizontalAlignment="Left"
|
||||||
Loaded="RealtimeForceChart_Loaded"
|
VerticalAlignment="Stretch"
|
||||||
SizeChanged="RealtimeForceChart_SizeChanged" />
|
Samples="{Binding RealtimeForceSamples}"
|
||||||
|
PeakLineSamples="{Binding RealtimePeakLineSamples}"
|
||||||
|
AverageLineSamples="{Binding RealtimeAverageLineSamples}"
|
||||||
|
CurrentPointSamples="{Binding RealtimeCurrentPointSamples}"
|
||||||
|
XMax="{Binding RealtimeChartXMax}"
|
||||||
|
YMax="{Binding RealtimeChartYMax}"
|
||||||
|
TravelMm="{Binding Recipe.TravelMm}"
|
||||||
|
SledMassGrams="{Binding Recipe.SledMassGrams}"
|
||||||
|
Loaded="RealtimeForceChart_Loaded"
|
||||||
|
SizeChanged="RealtimeForceChart_SizeChanged" />
|
||||||
|
</ScrollViewer>
|
||||||
|
|
||||||
<Border Grid.Row="1" Style="{StaticResource PanelBorderStyle}" Padding="10" Margin="0,0,0,8">
|
<Border Grid.Row="1" Style="{StaticResource PanelBorderStyle}" Padding="10" Margin="0,0,0,8">
|
||||||
<Grid>
|
<Grid>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public partial class MainWindow : Window
|
|||||||
private readonly MainViewModel _viewModel = new();
|
private readonly MainViewModel _viewModel = new();
|
||||||
private readonly DispatcherTimer _realtimeChartRenderTimer;
|
private readonly DispatcherTimer _realtimeChartRenderTimer;
|
||||||
private bool _isRealtimeChartLayoutRefreshQueued;
|
private bool _isRealtimeChartLayoutRefreshQueued;
|
||||||
|
private bool _isRealtimeChartAutoScrollPinned = true;
|
||||||
private DateTime _realtimeChartRenderUntilUtc = DateTime.MinValue;
|
private DateTime _realtimeChartRenderUntilUtc = DateTime.MinValue;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
@@ -73,6 +74,30 @@ public partial class MainWindow : Window
|
|||||||
RequestRealtimeChartRender(RealtimeChartStartupRenderPulseDuration);
|
RequestRealtimeChartRender(RealtimeChartStartupRenderPulseDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RealtimeChartScrollViewer_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_isRealtimeChartAutoScrollPinned = true;
|
||||||
|
RequestRealtimeChartRender(RealtimeChartStartupRenderPulseDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RealtimeChartScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.ExtentWidthChange < -1)
|
||||||
|
{
|
||||||
|
_isRealtimeChartAutoScrollPinned = true;
|
||||||
|
ScrollRealtimeChartToEndIfPinned();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.Abs(e.ExtentWidthChange) > 0 || Math.Abs(e.ViewportWidthChange) > 0)
|
||||||
|
{
|
||||||
|
ScrollRealtimeChartToEndIfPinned();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isRealtimeChartAutoScrollPinned = IsRealtimeChartScrolledToEnd();
|
||||||
|
}
|
||||||
|
|
||||||
private void RealtimeForceChart_SizeChanged(object sender, SizeChangedEventArgs e)
|
private void RealtimeForceChart_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.NewSize.Width <= 0 || e.NewSize.Height <= 0)
|
if (e.NewSize.Width <= 0 || e.NewSize.Height <= 0)
|
||||||
@@ -196,5 +221,29 @@ public partial class MainWindow : Window
|
|||||||
RealtimeForceChart.InvalidateArrange();
|
RealtimeForceChart.InvalidateArrange();
|
||||||
RealtimeForceChart.InvalidateVisual();
|
RealtimeForceChart.InvalidateVisual();
|
||||||
RealtimeForceChart.UpdateLayout();
|
RealtimeForceChart.UpdateLayout();
|
||||||
|
RealtimeChartScrollViewer.UpdateLayout();
|
||||||
|
ScrollRealtimeChartToEndIfPinned();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsRealtimeChartScrolledToEnd()
|
||||||
|
{
|
||||||
|
const double tolerance = 8;
|
||||||
|
return RealtimeChartScrollViewer.HorizontalOffset >= RealtimeChartScrollViewer.ScrollableWidth - tolerance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ScrollRealtimeChartToEndIfPinned()
|
||||||
|
{
|
||||||
|
if (!_isRealtimeChartAutoScrollPinned)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RealtimeChartScrollViewer.ScrollableWidth <= 0)
|
||||||
|
{
|
||||||
|
RealtimeChartScrollViewer.ScrollToHorizontalOffset(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RealtimeChartScrollViewer.ScrollToHorizontalOffset(RealtimeChartScrollViewer.ScrollableWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
private static readonly TimeSpan RealtimeChartRefreshInterval = TimeSpan.FromMilliseconds(250);
|
private static readonly TimeSpan RealtimeChartRefreshInterval = TimeSpan.FromMilliseconds(250);
|
||||||
private const double RealtimeChartTimeStepSeconds = 0.05;
|
private const double RealtimeChartTimeStepSeconds = 0.05;
|
||||||
private const double RealtimeChartXAxisPaddingSeconds = 1;
|
private const double RealtimeChartXAxisPaddingSeconds = 1;
|
||||||
|
private const double RealtimeChartMinimumCanvasWidth = 900;
|
||||||
|
private const double RealtimeChartPixelsPerSecond = 18;
|
||||||
private const double MinimumEmptyChartXAxisMaxLimit = 1;
|
private const double MinimumEmptyChartXAxisMaxLimit = 1;
|
||||||
private const double EmptyChartYAxisMaxLimit = 0.5;
|
private const double EmptyChartYAxisMaxLimit = 0.5;
|
||||||
private const double EmptyChartPointForceN = 0.001;
|
private const double EmptyChartPointForceN = 0.001;
|
||||||
@@ -308,6 +310,8 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
|
|
||||||
public double RealtimeChartXMax => _lastForceXAxisMaxLimit;
|
public double RealtimeChartXMax => _lastForceXAxisMaxLimit;
|
||||||
|
|
||||||
|
public double RealtimeChartCanvasWidth => Math.Max(RealtimeChartMinimumCanvasWidth, _lastForceXAxisMaxLimit * RealtimeChartPixelsPerSecond);
|
||||||
|
|
||||||
public double RealtimeChartYMax => _lastForceYAxisMaxLimit;
|
public double RealtimeChartYMax => _lastForceYAxisMaxLimit;
|
||||||
|
|
||||||
public RelayCommand StartCommand => _startCommand;
|
public RelayCommand StartCommand => _startCommand;
|
||||||
@@ -1306,6 +1310,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
OnPropertyChanged(nameof(ForceXAxes));
|
OnPropertyChanged(nameof(ForceXAxes));
|
||||||
OnPropertyChanged(nameof(ForceYAxes));
|
OnPropertyChanged(nameof(ForceYAxes));
|
||||||
OnPropertyChanged(nameof(RealtimeChartXMax));
|
OnPropertyChanged(nameof(RealtimeChartXMax));
|
||||||
|
OnPropertyChanged(nameof(RealtimeChartCanvasWidth));
|
||||||
OnPropertyChanged(nameof(RealtimeChartYMax));
|
OnPropertyChanged(nameof(RealtimeChartYMax));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1319,6 +1324,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
OnPropertyChanged(nameof(ForceXAxes));
|
OnPropertyChanged(nameof(ForceXAxes));
|
||||||
OnPropertyChanged(nameof(ForceYAxes));
|
OnPropertyChanged(nameof(ForceYAxes));
|
||||||
OnPropertyChanged(nameof(RealtimeChartXMax));
|
OnPropertyChanged(nameof(RealtimeChartXMax));
|
||||||
|
OnPropertyChanged(nameof(RealtimeChartCanvasWidth));
|
||||||
OnPropertyChanged(nameof(RealtimeChartYMax));
|
OnPropertyChanged(nameof(RealtimeChartYMax));
|
||||||
NotifyRealtimeChartChanged();
|
NotifyRealtimeChartChanged();
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
COFTester/摩擦仪.jpg
Normal file
BIN
COFTester/摩擦仪.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 293 KiB |
Reference in New Issue
Block a user