NoteMAUI/GraphPage.xaml.cs
2024-11-06 14:39:48 +03:00

315 lines
12 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 DateTime tapStartTime;
private const int longPressDuration = 3000; // 3 ñåêóíäû â ìèëëèñåêóíäàõ
private readonly List<GraphNode> _nodes = new();
private readonly List<GraphConnection> _connections = new();
private GraphNode _selectedNode;
private bool _isResizing = false;
public GraphPage()
{
InitializeComponent();
// Íàñòðàèâàåì Drawable äëÿ îòðèñîâêè óçëîâ è ñâÿçåé
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);
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += OnTapped;
canvasView.GestureRecognizers.Add(tapGestureRecognizer);
}
private void OnTapped(object sender, EventArgs e)
{
tapStartTime = DateTime.Now;
Device.StartTimer(TimeSpan.FromMilliseconds(longPressDuration), () =>
{
if ((DateTime.Now - tapStartTime).TotalMilliseconds >= longPressDuration)
{
// Çäåñü âûïîëíÿåòñÿ äåéñòâèå ïðè äëèòåëüíîì íàæàòèè
OnNodeLongPressed();
}
return false; // Îñòàíàâëèâàåì òàéìåð
});
}
private void OnNodeLongPressed()
{
if (_selectedNode != null)
{
// Äîáàâëÿåì äî÷åðíþþ íîäó ðÿäîì ñ àêòèâíîé
var childNode = new GraphNode
{
Text = "Äî÷åðíÿÿ íîäà",
Position = new Point(_selectedNode.Position.X + 50, _selectedNode.Position.Y + 50),
Size = new Size(150, 100)
};
_nodes.Add(childNode);
_connections.Add(new GraphConnection { FromNode = _selectedNode, ToNode = childNode });
canvasView.Invalidate(); // Ïåðåðèñîâûâàåì
}
// Çäåñü ðåàëèçóéòå äåéñòâèå ïðè äëèòåëüíîì íàæàòèè
// DisplayAlert("Äëèòåëüíîå íàæàòèå", "Âû íàæàëè è óäåðæèâàëè ýëåìåíò", "ÎÊ");
}
private void OnNodeTapped(object sender, TappedEventArgs e)
{
var node = _selectedNode;
Debug.WriteLine("Íàæàòà íîäà - {node}");
}
private void OnChildClicked(object sender, EventArgs e)
{
if (_selectedNode != null)
{
var child = new GraphNode
{
Text = "Child Node",
Position = new Point(_selectedNode.Position.X + 5, _selectedNode.Position.Y + 5),
Size = _selectedNode.Size,
BackgroundColor = Colors.Gray,
};
_nodes.Add(child);
_connections.Add(new GraphConnection { FromNode = _selectedNode, ToNode = child });
canvasView.Invalidate();
}
else { Debug.WriteLine("Ñíà÷àëà âûáèðèòå íîäó"); }
}
private async void OnAddNodeClicked(object sender, EventArgs e)
{
var newNode = new GraphNode
{
Text = "Íîâàÿ íîäà",
Position = new Point(300, 200),
Size = new Size(200, 200),
};
_nodes.Add(newNode);
canvasView.Invalidate();
}
// Îáðàáîò÷èê äëÿ âûáîðà óçëà
// Îáðàáîò÷èê äëÿ âûáîðà óçëà
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 = IsOnRightResizeHandle(_selectedNode, _initialTouchPosition) ||
IsOnLeftResizeHandle(_selectedNode, _initialTouchPosition) ||
IsOnTopResizeHandle(_selectedNode, _initialTouchPosition) ||
IsOnBottomResizeHandle(_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 float minSize = 50f; // Óáèðàåì "f" äëÿ double
// Óâåëè÷èâàåì èëè óìåíüøàåì ðàçìåð â çàâèñèìîñòè îò íàïðàâëåíèÿ
if (_isResizing)
{
// Åñëè ìû òÿíåì ïðàâóþ "ðó÷êó", óâåëè÷èâàåì øèðèíó
if (IsOnRightResizeHandle(node, _initialTouchPosition))
{
_selectedNode.Size = new Size(
Math.Max(minSize, node.Size.Width + deltaX), // double
_selectedNode.Size.Height // double
);
}
// Åñëè ìû òÿíåì ëåâóþ "ðó÷êó", óìåíüøàåì øèðèíó
else if (IsOnLeftResizeHandle(node, _initialTouchPosition))
{
_selectedNode.Size = new Size(
Math.Max(minSize, _selectedNode.Size.Width - deltaX), // double
_selectedNode.Size.Height // double
);
// Ïåðåìåùàåì íîäó âëåâî, ÷òîáû ñîõðàíèòü åå ïîçèöèþ
_selectedNode.Position = new Point(_selectedNode.Position.X + deltaX, _selectedNode.Position.Y); // double
}
// Åñëè ìû òÿíåì âåðõíþþ "ðó÷êó", óìåíüøàåì âûñîòó
else if (IsOnTopResizeHandle(node, _initialTouchPosition))
{
_selectedNode.Size = new Size(
_selectedNode.Size.Width, // double
Math.Max(minSize, _selectedNode.Size.Height - deltaY) // double
);
// Ïåðåìåùàåì íîäó ââåðõ, ÷òîáû ñîõðàíèòü åå ïîçèöèþ
_selectedNode.Position = new Point(_selectedNode.Position.X, _selectedNode.Position.Y + deltaY); // double
}
// Åñëè ìû òÿíåì íèæíþþ "ðó÷êó", óâåëè÷èâàåì âûñîòó
else if (IsOnBottomResizeHandle(node, _initialTouchPosition))
{
_selectedNode.Size = new Size(
_selectedNode.Size.Width, // double
Math.Max(minSize, _selectedNode.Size.Height + deltaY) // double
);
}
}
}
private bool IsOnRightResizeHandle(GraphNode node, PointF point)
{
const float handleSize = 400;
return Math.Abs(point.X - (node.Position.X + node.Size.Width)) <= handleSize;
}
private bool IsOnLeftResizeHandle(GraphNode node, PointF point)
{
const float handleSize = 400;
return Math.Abs(point.X - node.Position.X) <= handleSize;
}
private bool IsOnTopResizeHandle(GraphNode node, PointF point)
{
const float handleSize = 400;
return Math.Abs(point.Y - node.Position.Y) <= handleSize;
}
private bool IsOnBottomResizeHandle(GraphNode node, PointF point)
{
const float handleSize = 400;
return Math.Abs(point.Y - (node.Position.Y + node.Size.Height)) <= handleSize;
}
// Ìåòîä äëÿ ïðîâåðêè, íàõîäèòñÿ ëè òî÷êà âíóòðè óçëà
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;
}
// Ïðîâåðêà, íàõîäèòñÿ ëè òî÷êà íà "ðó÷êå" èçìåíåíèÿ ðàçìåðà
private bool IsOnResizeHandle(GraphNode node, PointF point)
{
const float handleSize = 200f; // Ðàçìåð ðó÷êè èçìåíåíèÿ ðàçìåðà
// Îïðåäåëÿåì ïðÿìîóãîëüíèêè äëÿ êàæäîé ðó÷êè
var rightHandleRect = new RectF(
(float)(node.Position.X + node.Size.Width - handleSize),
(float)(node.Position.Y + node.Size.Height - handleSize),
handleSize, handleSize);
var leftHandleRect = new RectF(
(float)(node.Position.X),
(float)(node.Position.Y + node.Size.Height - handleSize),
handleSize, handleSize);
var topHandleRect = new RectF(
(float)(node.Position.X + (node.Size.Width / 2) - (handleSize / 2)),
(float)(node.Position.Y),
handleSize, handleSize);
var bottomHandleRect = new RectF(
(float)(node.Position.X + (node.Size.Width / 2) - (handleSize / 2)),
(float)(node.Position.Y + node.Size.Height - handleSize),
handleSize, handleSize);
// Ïðîâåðÿåì, íàõîäèòñÿ ëè êóðñîð íà îäíîé èç ðó÷åê
return rightHandleRect.Contains(point) ||
leftHandleRect.Contains(point) ||
topHandleRect.Contains(point) ||
bottomHandleRect.Contains(point);
}
}
}