Skip to content

Commit

Permalink
add: place plot window by order and on-top
Browse files Browse the repository at this point in the history
  • Loading branch information
randolfly committed Oct 31, 2024
1 parent de6831c commit b223c7c
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 37 deletions.
5 changes: 3 additions & 2 deletions src/TwincatToolbox/Controls/LogPlotWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sctp="clr-namespace:ScottPlot.Avalonia;assembly=ScottPlot.Avalonia"
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="300"
Width="600" Height="300"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="200"
Width="400" Height="200"
Topmost="True"
x:Class="TwincatToolbox.LogPlotWindow">
<sctp:AvaPlot Name="LogPlot"/>
</Window>
71 changes: 42 additions & 29 deletions src/TwincatToolbox/Controls/LogPlotWindow.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
using System;
using System.Linq;
using System.Timers;

using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;

using MathNet.Numerics.Integration;

using ScottPlot;
using ScottPlot.Plottables;

Expand All @@ -22,30 +19,32 @@ public partial class LogPlotWindow : Window, IDisposable
private SignalXY FullDataSignal;
private Crosshair FullDataCrosshair;

public LogPlotWindow(string title, int logNum) {
public LogPlotWindow(string title, int logNum)
{
InitializeComponent();

LogName = title;
Title = LogName;
// will cause const data flow not render!
//LogPlot.Plot.Axes.ContinuouslyAutoscale = true;
LogPlot.Plot.ScaleFactor = 1.5;
LogPlot.Plot.ScaleFactor = 1.0;

DataStreamer = LogPlot.Plot.Add.DataStreamer(logNum);
DataStreamer.ViewScrollLeft();

// setup a timer to request a render periodically
UpdatePlotTimer.Elapsed += (s, e) =>
{
if (DataStreamer.HasNewData)
{
if (DataStreamer.HasNewData)
{
LogPlot.Refresh();
}
LogPlot.Plot.Axes.AutoScale();
};
LogPlot.Refresh();
}

LogPlot.Plot.Axes.AutoScale();
};
}

public void UpdatePlot(double newData) {
public void UpdatePlot(double newData)
{
DataStreamer.Add(newData);
// slide marker to the left
LogPlot.Plot.GetPlottables<Marker>()
Expand All @@ -54,27 +53,37 @@ public void UpdatePlot(double newData) {

// remove off-screen marks
LogPlot.Plot.GetPlottables<Marker>()
.Where(m => m.X < 0)
.ToList()
.ForEach(m => LogPlot.Plot.Remove(m));
.Where(m => m.X < 0)
.ToList()
.ForEach(m => LogPlot.Plot.Remove(m));
}

private (double x, double y) GetPlotViewWindowPos(int id, int windowNum, int windowWidth = 600,
int windowHeight = 300) {
const int windowRowSize = 3;
/// <summary>
/// manage plot window position by plot id
/// </summary>
/// <param name="windowId">the id of plot window in the plot dict</param>
public void SetPlotViewWindowPosById(int windowId)
{
// todo: figure out the windows place rule
// the window height is wrong, actual height:1440, return height: 1600=>about 0.19 ratio
var screen = Screens?.Primary;
var workingArea = screen?.WorkingArea ?? new Avalonia.PixelRect(0, 0, windowWidth, windowHeight);
var left = workingArea.Right - (id / windowRowSize + 1) * windowWidth;
var top = workingArea.Bottom - (id % windowRowSize + 1) * windowHeight;
return (left, top);
var widthScaling = (screen?.Scaling ?? 1.0);
var heightScaling = widthScaling + 0.2;
var workingArea = screen?.WorkingArea ?? new Avalonia.PixelRect(0, 0, (int)Width, (int)Height);
var windowRowSize = (int)((workingArea.Height) / Height / heightScaling);
var left = (workingArea.Right) - (windowId / windowRowSize + 1) * ((int)(Width * widthScaling));
var top = (workingArea.Bottom) - (windowId % windowRowSize + 1) * ((int)(Height * heightScaling));

Position = new PixelPoint(left, top);
}

/// <summary>
/// clear current plot and show new data with SignalConst Type for better performance
/// </summary>
/// <param name="ys"></param>
/// <param name="sampleTime">sample time, unit ms</param>
public void ShowAllData(double[] ys, int sampleTime = 1) {
public void ShowAllData(double[] ys, int sampleTime = 1)
{
UpdatePlotTimer.Stop();
LogPlot.Plot.Clear();
//LogPlot.Plot.Axes.ContinuouslyAutoscale = false;
Expand Down Expand Up @@ -122,7 +131,8 @@ public void ShowAllData(double[] ys, int sampleTime = 1) {
};
}

private void CustomPlotInteraction() {
private void CustomPlotInteraction()
{
LogPlot.UserInputProcessor.IsEnabled = true;

// remove all existing responses so we can create and add our own
Expand All @@ -135,7 +145,8 @@ private void CustomPlotInteraction() {

// right-click-drag zoom rectangle
var zoomRectangleButton = ScottPlot.Interactivity.StandardMouseButtons.Right;
var zoomRectangleResponse = new ScottPlot.Interactivity.UserActionResponses.MouseDragZoomRectangle(zoomRectangleButton);
var zoomRectangleResponse =
new ScottPlot.Interactivity.UserActionResponses.MouseDragZoomRectangle(zoomRectangleButton);
LogPlot.UserInputProcessor.UserActionResponses.Add(zoomRectangleResponse);

// right-click autoscale
Expand All @@ -151,7 +162,8 @@ private void CustomPlotInteraction() {
// Q key autoscale too
var autoscaleKey = new ScottPlot.Interactivity.Key("Q");
Action<ScottPlot.Plot, ScottPlot.Pixel> autoscaleAction = (plot, pixel) => plot.Axes.AutoScale();
var autoscaleKeyResponse = new ScottPlot.Interactivity.UserActionResponses.KeyPressResponse(autoscaleKey, autoscaleAction);
var autoscaleKeyResponse =
new ScottPlot.Interactivity.UserActionResponses.KeyPressResponse(autoscaleKey, autoscaleAction);
LogPlot.UserInputProcessor.UserActionResponses.Add(autoscaleKeyResponse);

// WASD keys pan
Expand All @@ -165,7 +177,8 @@ private void CustomPlotInteraction() {
LogPlot.UserInputProcessor.UserActionResponses.Add(keyPanResponse);
}

public void Dispose() {
public void Dispose()
{
UpdatePlotTimer.Dispose();
}
}
}
9 changes: 5 additions & 4 deletions src/TwincatToolbox/Services/LogPlotService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class LogPlotService : ILogPlotService

public void AddChannel(string channelName, int plotBufferCapacity) {
var logPlotWindow = new LogPlotWindow(channelName, plotBufferCapacity);
logPlotWindow.SetPlotViewWindowPosById(_plotDict.Count);
_plotDict.Add(channelName, logPlotWindow);
logPlotWindow.Show();
}
Expand All @@ -28,18 +29,18 @@ public void RemoveAllChannels() {
}

public void AddData(string channelName, double data) {
if (_plotDict.ContainsKey(channelName))
if (_plotDict.TryGetValue(channelName, value: out var value))
{
_plotDict[channelName].UpdatePlot(data);
value.UpdatePlot(data);
}
}

public void ShowAllChannelsWithNewData(Dictionary<string, List<double>> dataSrcDict, int sampleTime = 1) {
foreach (var (channelName, data) in dataSrcDict)
{
if (_plotDict.ContainsKey(channelName))
if (_plotDict.TryGetValue(channelName, out var value))
{
_plotDict[channelName].ShowAllData(data.ToArray(), sampleTime);
value.ShowAllData(data.ToArray(), sampleTime);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/TwincatToolbox/ViewModels/DashboardViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace TwincatToolbox.ViewModels;

public partial class DashboardViewModel() : ViewModelBase("Dashboard", MaterialIconKind.CircleOutline, -1000)
public partial class DashboardViewModel() : ViewModelBase("Dashboard", MaterialIconKind.CircleOutline, 0)
{

}
2 changes: 1 addition & 1 deletion src/TwincatToolbox/ViewModels/DataLogViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public List<SymbolInfo> SearchResultSymbols

public DataLogViewModel(IAdsComService adsComService,
ILogDataService logDataService, ILogPlotService logPlotService)
: base("DataLog", MaterialIconKind.Blog)
: base("DataLog", MaterialIconKind.Blog, index: -1)
{
_adsComService = adsComService;
_logDataService = logDataService;
Expand Down

0 comments on commit b223c7c

Please sign in to comment.