diff --git a/AppShell.xaml b/AppShell.xaml
index ec82c4e..96d0e53 100644
--- a/AppShell.xaml
+++ b/AppShell.xaml
@@ -10,7 +10,7 @@
-
+
diff --git a/GraphPage.xaml.cs b/GraphPage.xaml.cs
index e6c5873..7345952 100644
--- a/GraphPage.xaml.cs
+++ b/GraphPage.xaml.cs
@@ -1,18 +1,13 @@
-using System.Diagnostics;
+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 PointF _initialNodePosition;
+ private PointF _initialTouchPosition;
+ private SizeF _initialNodeSize;
private readonly List _nodes = new();
private readonly List _connections = new();
private GraphNode _selectedNode;
@@ -22,13 +17,9 @@ namespace NotesDataAnalyst
{
InitializeComponent();
-
-
- // Íàñòðàèâàåì Drawable äëÿ îòðèñîâêè óçëîâ è ñâÿçåé
var graphDrawable = new GraphDrawable(_nodes, _connections);
canvasView.Drawable = graphDrawable;
- // Äîáàâëÿåì æåñòû
var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += OnPanUpdated;
canvasView.GestureRecognizers.Add(panGesture);
@@ -36,73 +27,6 @@ namespace NotesDataAnalyst
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)
@@ -110,18 +34,38 @@ namespace NotesDataAnalyst
var newNode = new GraphNode
{
- Text = "Íîâàÿ íîäà",
+ Text = "Ã�îâà ÿ Ãîäà ",
Position = new Point(300, 200),
Size = new Size(200, 200),
-
+
};
_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);
@@ -132,37 +76,27 @@ namespace NotesDataAnalyst
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);
+ _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;
@@ -172,7 +106,6 @@ namespace NotesDataAnalyst
}
else
{
- // Ïåðåìåùåíèå
_selectedNode.Position = new PointF(
_initialNodePosition.X + deltaX,
_initialNodePosition.Y + deltaY
@@ -187,86 +120,32 @@ namespace NotesDataAnalyst
}
}
- // Èçìåíåíèå ðàçìåðà óçëà
private void ResizeNode(GraphNode node, double deltaX, double deltaY)
{
- const float minSize = 50f; // Óáèðàåì "f" äëÿ double
+ const double minSize = 50.0;
- // Óâåëè÷èâàåì èëè óìåíüøàåì ðàçìåð â çàâèñèìîñòè îò íàïðàâëåíèÿ
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
- );
- }
+ _selectedNode.Size = new Size(
+ Math.Max(minSize, _initialNodeSize.Width + deltaX),
+ Math.Max(minSize, _initialNodeSize.Height + deltaY)
+ );
}
-
-
-
-
}
-
- private bool IsOnRightResizeHandle(GraphNode node, PointF point)
+ private bool IsOnResizeHandle(GraphNode node, PointF point)
{
- const float handleSize = 10;
- return Math.Abs(point.X - (node.Position.X + node.Size.Width - 1)) <= handleSize;
+ 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 IsOnLeftResizeHandle(GraphNode node, PointF point)
- {
- const float handleSize = 10;
- return Math.Abs(point.X - node.Position.X) <= handleSize;
- }
-
- private bool IsOnTopResizeHandle(GraphNode node, PointF point)
- {
- const float handleSize = 10;
- return Math.Abs(point.Y - node.Position.Y) <= handleSize;
- }
-
- private bool IsOnBottomResizeHandle(GraphNode node, PointF point)
- {
- const float handleSize = 10;
- 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 &&
@@ -274,42 +153,5 @@ namespace NotesDataAnalyst
point.Y >= node.Position.Y &&
point.Y <= node.Position.Y + node.Size.Height;
}
-
-
- // Ïðîâåðêà, íàõîäèòñÿ ëè òî÷êà íà "ðó÷êå" èçìåíåíèÿ ðàçìåðà
- private bool IsOnResizeHandle(GraphNode node, PointF point)
- {
- const float handleSize = 20f; // Ðàçìåð ðó÷êè èçìåíåíèÿ ðàçìåðà
-
- // Îïðåäåëÿåì ïðÿìîóãîëüíèêè äëÿ êàæäîé ðó÷êè
- 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);
- }
-
-
}
}
-
diff --git a/ResizableCanvasPage.xaml.cs b/ResizableCanvasPage.xaml.cs
index 427b8d2..f206d16 100644
--- a/ResizableCanvasPage.xaml.cs
+++ b/ResizableCanvasPage.xaml.cs
@@ -1,5 +1,6 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;
+using Microsoft.Maui.Layouts;
using System;
namespace NotesDataAnalyst
@@ -9,98 +10,120 @@ namespace NotesDataAnalyst
private const double InitialWidth = 150;
private const double InitialHeight = 100;
private double startX, startY;
+ private bool isResizing;
public ResizableCanvasPage()
{
InitializeComponent();
}
- // Ìåòîä äëÿ äîáàâëåíèÿ îáúåêòà íà õîëñò
private void AddResizableObject(double x, double y)
{
- // Ñîçäàíèå Frame äëÿ ãðàôè÷åñêîãî îáúåêòà
+ // Ñîçäàåì îñíîâíîé êîíòåéíåð (Frame) äëÿ îáúåêòà è ðó÷êè
var resizableFrame = new Frame
{
BackgroundColor = Colors.LightBlue,
BorderColor = Colors.DarkBlue,
CornerRadius = 8,
WidthRequest = InitialWidth,
- HeightRequest = InitialHeight
+ HeightRequest = InitialHeight,
+ Padding = 0,
+ HasShadow = true
};
- // Îáðàáîòêà ïåðåìåùåíèÿ îáúåêòà
- var panGesture = new PanGestureRecognizer();
- panGesture.PanUpdated += (s, e) => OnDragPanUpdated(s, e, resizableFrame);
- resizableFrame.GestureRecognizers.Add(panGesture);
+ var content = new Label
+ {
+ Text = "Resizable Object",
+ HorizontalOptions = LayoutOptions.Center,
+ VerticalOptions = LayoutOptions.Center
+ };
- // Ñîçäàíèå ðó÷êè äëÿ èçìåíåíèÿ ðàçìåðà
+ resizableFrame.Content = content;
+
+ // Ñîçäàåì ðó÷êó äëÿ èçìåíåíèÿ ðàçìåðà
var resizeHandle = new BoxView
{
BackgroundColor = Colors.Gray,
WidthRequest = 20,
- HeightRequest = 20
+ HeightRequest = 20,
+ HorizontalOptions = LayoutOptions.End,
+ VerticalOptions = LayoutOptions.End
};
- // Îáðàáîòêà èçìåíåíèÿ ðàçìåðà îáúåêòà
+ // Ñîçäàåì ñëîé AbsoluteLayout äëÿ ðó÷êè è ôðåéìà
+ var layout = new AbsoluteLayout();
+ AbsoluteLayout.SetLayoutBounds(resizableFrame, new Rect(0, 0, InitialWidth, InitialHeight));
+ layout.Children.Add(resizableFrame);
+
+ // Ïîçèöèîíèðóåì ðó÷êó
+ AbsoluteLayout.SetLayoutFlags(resizeHandle, AbsoluteLayoutFlags.PositionProportional);
+ AbsoluteLayout.SetLayoutBounds(resizeHandle, new Rect(1, 1, 20, 20));
+ layout.Children.Add(resizeHandle);
+
+ // Äîáàâëÿåì îáðàáîò÷èê ïåðåìåùåíèÿ
+ var panGesture = new PanGestureRecognizer();
+ panGesture.PanUpdated += (s, e) => OnDragPanUpdated(s, e, layout);
+ resizableFrame.GestureRecognizers.Add(panGesture);
+
+ // Äîáàâëÿåì îáðàáîò÷èê äëÿ èçìåíåíèÿ ðàçìåðà
var resizePanGesture = new PanGestureRecognizer();
- resizePanGesture.PanUpdated += (s, e) => OnResizePanUpdated(s, e, resizableFrame, resizeHandle);
+ resizePanGesture.PanUpdated += (s, e) => OnResizePanUpdated(s, e, layout);
resizeHandle.GestureRecognizers.Add(resizePanGesture);
- // Ïîçèöèîíèðîâàíèå îáúåêòà è ðó÷êè
- AbsoluteLayout.SetLayoutBounds(resizableFrame, new Rect(x, y, InitialWidth, InitialHeight));
- CanvasLayout.Children.Add(resizableFrame);
- CanvasLayout.Children.Add(resizeHandle);
-
- UpdateResizeHandlePosition(resizableFrame, resizeHandle);
+ // Óñòàíàâëèâàåì íà÷àëüíóþ ïîçèöèþ
+ AbsoluteLayout.SetLayoutBounds(layout, new Rect(x, y, InitialWidth, InitialHeight));
+ CanvasLayout.Children.Add(layout);
}
- // Îáðàáîòêà ïåðåìåùåíèÿ îáúåêòà
- private void OnDragPanUpdated(object sender, PanUpdatedEventArgs e, Frame frame)
+ // Ëîãèêà ïåðåìåùåíèÿ
+ private void OnDragPanUpdated(object sender, PanUpdatedEventArgs e, AbsoluteLayout layout)
{
+ if (isResizing) return;
+
if (e.StatusType == GestureStatus.Started)
{
- startX = AbsoluteLayout.GetLayoutBounds(frame).X;
- startY = AbsoluteLayout.GetLayoutBounds(frame).Y;
+ startX = AbsoluteLayout.GetLayoutBounds(layout).X;
+ startY = AbsoluteLayout.GetLayoutBounds(layout).Y;
}
else if (e.StatusType == GestureStatus.Running)
{
double x = startX + e.TotalX;
double y = startY + e.TotalY;
- AbsoluteLayout.SetLayoutBounds(frame, new Rect(x, y, frame.WidthRequest, frame.HeightRequest));
- UpdateResizeHandlePosition(frame, CanvasLayout.Children[CanvasLayout.Children.IndexOf(frame) + 1] as BoxView);
+
+ // Îáíîâëåíèå UI ÷åðåç Dispatcher
+ Dispatcher.Dispatch(() =>
+ {
+ AbsoluteLayout.SetLayoutBounds(layout, new Rect(x, y, layout.WidthRequest, layout.HeightRequest));
+ });
}
}
- // Îáðàáîòêà èçìåíåíèÿ ðàçìåðà îáúåêòà
- private void OnResizePanUpdated(object sender, PanUpdatedEventArgs e, Frame frame, BoxView resizeHandle)
+ // Ëîãèêà èçìåíåíèÿ ðàçìåðà
+ private void OnResizePanUpdated(object sender, PanUpdatedEventArgs e, AbsoluteLayout layout)
{
+ isResizing = true;
if (e.StatusType == GestureStatus.Started)
{
- startX = frame.WidthRequest;
- startY = frame.HeightRequest;
+ startX = layout.WidthRequest;
+ startY = layout.HeightRequest;
}
else if (e.StatusType == GestureStatus.Running)
{
double newWidth = Math.Max(50, startX + e.TotalX);
double newHeight = Math.Max(50, startY + e.TotalY);
- frame.WidthRequest = newWidth;
- frame.HeightRequest = newHeight;
- UpdateResizeHandlePosition(frame, resizeHandle);
+ Dispatcher.Dispatch(() =>
+ {
+ layout.WidthRequest = newWidth;
+ layout.HeightRequest = newHeight;
+ });
+ }
+ else if (e.StatusType == GestureStatus.Completed || e.StatusType == GestureStatus.Canceled)
+ {
+ isResizing = false;
}
}
- // Ìåòîä äëÿ ôèêñàöèè ïîçèöèè ðó÷êè â óãëó îáúåêòà
- private void UpdateResizeHandlePosition(Frame frame, BoxView resizeHandle)
- {
- var frameBounds = AbsoluteLayout.GetLayoutBounds(frame);
- double x = frameBounds.X + frame.WidthRequest - resizeHandle.WidthRequest / 2;
- double y = frameBounds.Y + frame.HeightRequest - resizeHandle.HeightRequest / 2;
-
- AbsoluteLayout.SetLayoutBounds(resizeHandle, new Rect(x, y, resizeHandle.WidthRequest, resizeHandle.HeightRequest));
- }
-
- // Äîáàâëåíèå îáúåêòîâ íà õîëñò ïðè çàïóñêå
protected override void OnAppearing()
{
base.OnAppearing();