Норм
This commit is contained in:
parent
4af0560f96
commit
363a6f5ecb
2 changed files with 105 additions and 36 deletions
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue