NoteMAUI/GraphPage.xaml.cs
2024-11-10 23:19:41 +03:00

190 lines
6.7 KiB
C#

using System.Diagnostics;
using System.Linq;
namespace NotesDataAnalyst
{
public partial class GraphPage : ContentPage
{
private PointF _initialNodePosition;
private PointF _initialTouchPosition;
private SizeF _initialNodeSize;
private readonly List<GraphNode> _nodes = new();
private readonly List<GraphConnection> _connections = new();
private GraphNode _selectedNode;
private bool _isResizing = false;
public GraphPage()
{
InitializeComponent();
var graphDrawable = new GraphDrawable(_nodes, _connections);
canvasView.Drawable = graphDrawable;
var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += OnPanUpdated;
canvasView.GestureRecognizers.Add(panGesture);
var tapGesture = new TapGestureRecognizer();
tapGesture.Tapped += OnCanvasTapped;
canvasView.GestureRecognizers.Add(tapGesture);
}
private async void OnResizeNodeClicked(object sender, EventArgs e)
{
// Проверяем, выбрана ли нода
if (_selectedNode == null)
{
await DisplayAlert("Ошибка", "Сначала выберите ноду", "OK");
return;
}
// Открываем диалог для ввода новых размеров
var result = await DisplayPromptAsync("Изменить размер", "Введите ширину и высоту",
initialValue: $"{_selectedNode.Size.Width} x {_selectedNode.Size.Height}",
keyboard: Keyboard.Numeric);
if (string.IsNullOrEmpty(result)) return;
// Разбиваем введенное значение на ширину и высоту
var dimensions = result.Split('x');
if (dimensions.Length == 2 &&
double.TryParse(dimensions[0].Trim(), out double width) &&
double.TryParse(dimensions[1].Trim(), out double height))
{
// Обновляем размеры ноды
_selectedNode.Size = new Size(width, height);
canvasView.Invalidate(); // Перерисовываем канву
}
else
{
await DisplayAlert("Ошибка", "Неверный формат. Введите значения в формате ширина x высота.", "OK");
}
}
private async void OnAddNodeClicked(object sender, EventArgs e)
{
var newNode = new GraphNode
{
Text = "Новая нода",
Position = new Point(100, 200),
Size = new Size(100, 50),
};
_nodes.Add(newNode);
canvasView.Invalidate();
}
private void OnChildClicked(object sender, EventArgs e)
{
if (_selectedNode != null)
{
var childNode = new GraphNode
{
Text = "Child Node",
Position = new Point(_selectedNode.Position.X + 100, _selectedNode.Position.Y + 70),
Size = _selectedNode.Size,
BackgroundColor = Colors.Gray,
};
_nodes.Add(childNode);
_connections.Add(new GraphConnection { FromNode = _selectedNode, ToNode = childNode });
canvasView.Invalidate();
}
else
{
Debug.WriteLine("Сначала выберите ноду");
}
}
private void OnCanvasTapped(object sender, TappedEventArgs e)
{
var tapPosition = e.GetPosition((View)sender);
_selectedNode = null;
if (tapPosition.HasValue)
{
var touchPoint = new PointF((float)tapPosition.Value.X, (float)tapPosition.Value.Y);
_selectedNode = _nodes.FirstOrDefault(node => IsPointInsideNode(touchPoint, node));
foreach (var node in _nodes)
node.IsActive = node == _selectedNode;
canvasView.Invalidate();
}
}
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
if (_selectedNode == null) return;
if (e.StatusType == GestureStatus.Started)
{
_initialNodePosition = _selectedNode.Position;
_initialTouchPosition = new PointF((float)e.TotalX, (float)e.TotalY);
_initialNodeSize = _selectedNode.Size;
_isResizing = IsOnResizeHandle(_selectedNode, _initialTouchPosition);
}
else if (e.StatusType == GestureStatus.Running)
{
var deltaX = (float)e.TotalX - _initialTouchPosition.X;
var deltaY = (float)e.TotalY - _initialTouchPosition.Y;
if (_isResizing)
{
ResizeNode(_selectedNode, deltaX, deltaY);
}
else
{
_selectedNode.Position = new PointF(
_initialNodePosition.X + deltaX,
_initialNodePosition.Y + deltaY
);
}
canvasView.Invalidate();
}
else if (e.StatusType == GestureStatus.Completed)
{
_isResizing = false;
}
}
private void ResizeNode(GraphNode node, double deltaX, double deltaY)
{
const double minSize = 50.0;
if (_isResizing)
{
_selectedNode.Size = new Size(
Math.Max(minSize, _initialNodeSize.Width + deltaX),
Math.Max(minSize, _initialNodeSize.Height + deltaY)
);
}
}
private bool IsOnResizeHandle(GraphNode node, PointF point)
{
const float handleSize = 20f;
var resizeHandleRect = new RectF(
(float)(node.Position.X + node.Size.Width - handleSize),
(float)(node.Position.Y + node.Size.Height - handleSize),
handleSize, handleSize
);
return resizeHandleRect.Contains(point);
}
private bool IsPointInsideNode(PointF point, GraphNode node)
{
return point.X >= node.Position.X &&
point.X <= node.Position.X + node.Size.Width &&
point.Y >= node.Position.Y &&
point.Y <= node.Position.Y + node.Size.Height;
}
}
}