This commit is contained in:
ARCHI86 2024-11-11 15:24:11 +03:00
parent 4af0560f96
commit 363a6f5ecb
2 changed files with 105 additions and 36 deletions

View file

@ -7,14 +7,15 @@
<ContentPage.Content> <ContentPage.Content>
<Grid RowDefinitions="*,Auto" Padding="10"> <Grid RowDefinitions="*,Auto" Padding="10">
<!-- Канва для рисования занимает верхнюю часть экрана --> <!-- Канва для рисования занимает верхнюю часть экрана -->
<ScrollView x:Name="scrollView" Grid.Row="0" Orientation="Both">
<AbsoluteLayout Grid.Row="0"> <AbsoluteLayout Grid.Row="0">
<GraphicsView x:Name="canvasView" <GraphicsView x:Name="canvasView"
HeightRequest="8000" HeightRequest="8000"
WidthRequest="8000" WidthRequest="8000"
/> />
</AbsoluteLayout> </AbsoluteLayout>
</ScrollView>
<!-- Панель с кнопками внизу --> <!-- Панель с кнопками внизу -->
<ScrollView Grid.Row="1" Orientation="Horizontal" HorizontalScrollBarVisibility="Always" VerticalScrollBarVisibility="Never"> <ScrollView Grid.Row="1" Orientation="Horizontal" HorizontalScrollBarVisibility="Always" VerticalScrollBarVisibility="Never">
<StackLayout Orientation="Horizontal" Spacing="1" Padding="20"> <StackLayout Orientation="Horizontal" Spacing="1" Padding="20">

View file

@ -5,6 +5,7 @@ namespace NotesDataAnalyst
{ {
public partial class GraphPage : ContentPage public partial class GraphPage : ContentPage
{ {
private Point _initialPanPosition;
private PointF _initialNodePosition; private PointF _initialNodePosition;
private PointF _initialTouchPosition; private PointF _initialTouchPosition;
private SizeF _initialNodeSize; private SizeF _initialNodeSize;
@ -13,6 +14,11 @@ namespace NotesDataAnalyst
private GraphNode _selectedNode; private GraphNode _selectedNode;
private bool _isScrollingBlocked = false; private bool _isScrollingBlocked = false;
private double _scale = 1.0;
private double _initialScale = 1.0;
private bool _isNodeBeingMoved = false;
private const double SmoothFactor = 0.2; // Коэффициент сглаживания
private Point _lastTranslation;
public GraphPage() public GraphPage()
{ {
@ -29,9 +35,100 @@ namespace NotesDataAnalyst
tapGesture.Tapped += OnCanvasTapped; tapGesture.Tapped += OnCanvasTapped;
canvasView.GestureRecognizers.Add(tapGesture); canvasView.GestureRecognizers.Add(tapGesture);
// Добавляем Pinch только один раз
if (!canvasView.GestureRecognizers.OfType<PinchGestureRecognizer>().Any())
{
var pinchGesture = new PinchGestureRecognizer();
pinchGesture.PinchUpdated += OnPinchUpdated;
canvasView.GestureRecognizers.Add(pinchGesture);
}
} }
// Обработчик жеста перемещения (Pan) для перемещения канвы или ноды
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
if (_selectedNode != null)
{
// Начало перетаскивания
if (e.StatusType == GestureStatus.Started)
{
// Запоминаем начальную позицию касания и ноды
_initialTouchPosition = new Point(e.TotalX, e.TotalY);
_initialNodePosition = _selectedNode.Position;
}
// Перемещение
else if (e.StatusType == GestureStatus.Running)
{
var deltaX = e.TotalX - _initialTouchPosition.X; // Разница с начальной точкой
var deltaY = e.TotalY - _initialTouchPosition.Y;
// Перемещаем ноду относительно её начальной позиции
_selectedNode.Position = new Point(
_initialNodePosition.X + deltaX,
_initialNodePosition.Y + deltaY
);
canvasView.Invalidate(); // Перерисовываем канву
}
// Завершение перетаскивания
else if (e.StatusType == GestureStatus.Completed)
{
// Можно добавить логику на завершение перетаскивания, например, включить прокрутку
//scrollView.IsEnabled = true;
}
}
else // Перемещение канвы при снятии выделения с ноды
{
if (e.StatusType == GestureStatus.Started)
{
_initialPanPosition = new Point(canvasView.TranslationX, canvasView.TranslationY);
_lastTranslation = _initialPanPosition;
}
else if (e.StatusType == GestureStatus.Running)
{
var deltaX = e.TotalX;
var deltaY = e.TotalY;
// Применяем сглаживание к движению
double smoothedX = _lastTranslation.X + SmoothFactor * (deltaX - _lastTranslation.X);
double smoothedY = _lastTranslation.Y + SmoothFactor * (deltaY - _lastTranslation.Y);
// Обновляем положение канвы
canvasView.TranslationX = _initialPanPosition.X + smoothedX;
canvasView.TranslationY = _initialPanPosition.Y + smoothedY;
// Сохраняем последнюю смягченную позицию для следующего цикла
_lastTranslation = new Point(smoothedX, smoothedY);
}
else if (e.StatusType == GestureStatus.Completed)
{
_initialPanPosition = new Point(canvasView.TranslationX, canvasView.TranslationY);
canvasView.Invalidate();
}
}
}
private void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
{
if (e.Status == GestureStatus.Started)
{
// Сохраняем начальный масштаб
_initialScale = _scale;
}
else if (e.Status == GestureStatus.Running)
{
// Вычисляем новый масштаб
_scale = Math.Max(0.5, Math.Min(_initialScale * e.Scale, 3.0));
// Применяем масштаб к канве
canvasView.Scale = _scale;
}
}
private async void OnEditTextClicked(object sender, EventArgs e) private async void OnEditTextClicked(object sender, EventArgs e)
{ {
// Проверяем, выбрана ли нода // Проверяем, выбрана ли нода
@ -124,6 +221,7 @@ namespace NotesDataAnalyst
_nodes.Add(childNode); _nodes.Add(childNode);
_connections.Add(new GraphConnection { FromNode = _selectedNode, ToNode = childNode }); _connections.Add(new GraphConnection { FromNode = _selectedNode, ToNode = childNode });
canvasView.Invalidate(); canvasView.Invalidate();
_selectedNode = childNode;
} }
else else
{ {
@ -145,41 +243,11 @@ namespace NotesDataAnalyst
node.IsActive = node == _selectedNode; node.IsActive = node == _selectedNode;
canvasView.Invalidate(); canvasView.Invalidate();
} }
} }
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
if (_selectedNode == null) return;
// Начало перетаскивания
if (e.StatusType == GestureStatus.Started)
{
// Запоминаем начальную позицию касания и ноды
_initialTouchPosition = new Point(e.TotalX, e.TotalY);
_initialNodePosition = _selectedNode.Position;
}
// Перемещение
else if (e.StatusType == GestureStatus.Running)
{
var deltaX = e.TotalX - _initialTouchPosition.X; // Разница с начальной точкой
var deltaY = e.TotalY - _initialTouchPosition.Y;
// Перемещаем ноду относительно её начальной позиции
_selectedNode.Position = new Point(
_initialNodePosition.X + deltaX,
_initialNodePosition.Y + deltaY
);
canvasView.Invalidate(); // Перерисовываем канву
}
// Завершение перетаскивания
else if (e.StatusType == GestureStatus.Completed)
{
// Можно добавить логику на завершение перетаскивания, например, включить прокрутку
scrollView.IsEnabled = true;
}
}
private bool IsPointInsideNode(PointF point, GraphNode node) private bool IsPointInsideNode(PointF point, GraphNode node)
{ {