feat: Add real-time node drag preview and improve pan accuracy
- Add ghost rendering at original position during node drag - Implement real-time drag preview with Update() for immediate rendering - Add visual feedback: shadow effects, cyan borders, pulse animations - Improve pan movement accuracy with zoom level compensation (PointF precision) - Add mouse capture for stable drag operations - Fix coordinate precision loss by changing _panOffset from Point to PointF 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -14,8 +14,17 @@ namespace AGVNavigationCore.Controls
|
|||||||
{
|
{
|
||||||
#region Paint Events
|
#region Paint Events
|
||||||
|
|
||||||
|
private static int _paintCounter = 0;
|
||||||
|
|
||||||
private void UnifiedAGVCanvas_Paint(object sender, PaintEventArgs e)
|
private void UnifiedAGVCanvas_Paint(object sender, PaintEventArgs e)
|
||||||
{
|
{
|
||||||
|
// 디버그: Paint 이벤트 실행 확인
|
||||||
|
if (_isDragging)
|
||||||
|
{
|
||||||
|
_paintCounter++;
|
||||||
|
//System.Diagnostics.Debug.WriteLine($"Paint #{_paintCounter} 실행! 현재 노드 위치: ({_selectedNode?.Position.X}, {_selectedNode?.Position.Y})");
|
||||||
|
}
|
||||||
|
|
||||||
var g = e.Graphics;
|
var g = e.Graphics;
|
||||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||||
g.InterpolationMode = InterpolationMode.High;
|
g.InterpolationMode = InterpolationMode.High;
|
||||||
@@ -50,6 +59,12 @@ namespace AGVNavigationCore.Controls
|
|||||||
// 노드 그리기 (라벨 제외)
|
// 노드 그리기 (라벨 제외)
|
||||||
DrawNodesOnly(g);
|
DrawNodesOnly(g);
|
||||||
|
|
||||||
|
// 드래그 고스트 그리기 (노드 위에 표시되도록 나중에 그리기)
|
||||||
|
if (_isDragging && _selectedNode != null)
|
||||||
|
{
|
||||||
|
DrawDragGhost(g);
|
||||||
|
}
|
||||||
|
|
||||||
// AGV 그리기
|
// AGV 그리기
|
||||||
DrawAGVs(g);
|
DrawAGVs(g);
|
||||||
|
|
||||||
@@ -382,7 +397,203 @@ namespace AGVNavigationCore.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 드래그 고스트 그리기 - 원래 위치에 반투명 노드 표시
|
||||||
|
/// </summary>
|
||||||
|
private void DrawDragGhost(Graphics g)
|
||||||
|
{
|
||||||
|
if (_selectedNode == null || !_isDragging) return;
|
||||||
|
|
||||||
|
// 반투명 효과를 위한 브러시 생성
|
||||||
|
Brush ghostBrush = null;
|
||||||
|
switch (_selectedNode.Type)
|
||||||
|
{
|
||||||
|
case NodeType.Normal:
|
||||||
|
ghostBrush = new SolidBrush(Color.FromArgb(120, 100, 149, 237)); // 반투명 파란색
|
||||||
|
break;
|
||||||
|
case NodeType.Rotation:
|
||||||
|
ghostBrush = new SolidBrush(Color.FromArgb(120, 255, 165, 0)); // 반투명 주황색
|
||||||
|
break;
|
||||||
|
case NodeType.Docking:
|
||||||
|
ghostBrush = new SolidBrush(Color.FromArgb(120, 50, 205, 50)); // 반투명 초록색
|
||||||
|
break;
|
||||||
|
case NodeType.Charging:
|
||||||
|
ghostBrush = new SolidBrush(Color.FromArgb(120, 255, 215, 0)); // 반투명 금색
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ghostBrush = new SolidBrush(Color.FromArgb(120, 200, 200, 200)); // 반투명 회색
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 고스트 노드 그리기
|
||||||
|
switch (_selectedNode.Type)
|
||||||
|
{
|
||||||
|
case NodeType.Label:
|
||||||
|
DrawLabelGhost(g);
|
||||||
|
break;
|
||||||
|
case NodeType.Image:
|
||||||
|
DrawImageGhost(g);
|
||||||
|
break;
|
||||||
|
case NodeType.Docking:
|
||||||
|
DrawPentagonGhost(g, ghostBrush);
|
||||||
|
break;
|
||||||
|
case NodeType.Charging:
|
||||||
|
DrawTriangleGhost(g, ghostBrush);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DrawCircleGhost(g, ghostBrush);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ghostBrush?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawCircleGhost(Graphics g, Brush ghostBrush)
|
||||||
|
{
|
||||||
|
var rect = new Rectangle(
|
||||||
|
_dragStartPosition.X - NODE_RADIUS,
|
||||||
|
_dragStartPosition.Y - NODE_RADIUS,
|
||||||
|
NODE_SIZE,
|
||||||
|
NODE_SIZE
|
||||||
|
);
|
||||||
|
g.FillEllipse(ghostBrush, rect);
|
||||||
|
// 회색 점선 테두리
|
||||||
|
g.DrawEllipse(new Pen(Color.FromArgb(180, 128, 128, 128), 2) { DashStyle = DashStyle.Dash }, rect);
|
||||||
|
// 빨간색 외곽 테두리 (디버깅용 - 고스트가 확실히 보이도록)
|
||||||
|
var outerRect = new Rectangle(rect.X - 2, rect.Y - 2, rect.Width + 4, rect.Height + 4);
|
||||||
|
g.DrawEllipse(new Pen(Color.FromArgb(200, 255, 0, 0), 1), outerRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawPentagonGhost(Graphics g, Brush ghostBrush)
|
||||||
|
{
|
||||||
|
var points = new Point[5];
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
var angle = (Math.PI * 2 * i / 5) - Math.PI / 2;
|
||||||
|
points[i] = new Point(
|
||||||
|
(int)(_dragStartPosition.X + NODE_RADIUS * Math.Cos(angle)),
|
||||||
|
(int)(_dragStartPosition.Y + NODE_RADIUS * Math.Sin(angle))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
g.FillPolygon(ghostBrush, points);
|
||||||
|
// 회색 점선 테두리
|
||||||
|
g.DrawPolygon(new Pen(Color.FromArgb(180, 128, 128, 128), 2) { DashStyle = DashStyle.Dash }, points);
|
||||||
|
// 빨간색 외곽 테두리 (디버깅용)
|
||||||
|
var outerPoints = new Point[5];
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
var angle = (Math.PI * 2 * i / 5) - Math.PI / 2;
|
||||||
|
outerPoints[i] = new Point(
|
||||||
|
(int)(_dragStartPosition.X + (NODE_RADIUS + 3) * Math.Cos(angle)),
|
||||||
|
(int)(_dragStartPosition.Y + (NODE_RADIUS + 3) * Math.Sin(angle))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
g.DrawPolygon(new Pen(Color.FromArgb(200, 255, 0, 0), 1), outerPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawTriangleGhost(Graphics g, Brush ghostBrush)
|
||||||
|
{
|
||||||
|
var points = new Point[3];
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
var angle = (Math.PI * 2 * i / 3) - Math.PI / 2;
|
||||||
|
points[i] = new Point(
|
||||||
|
(int)(_dragStartPosition.X + NODE_RADIUS * Math.Cos(angle)),
|
||||||
|
(int)(_dragStartPosition.Y + NODE_RADIUS * Math.Sin(angle))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
g.FillPolygon(ghostBrush, points);
|
||||||
|
// 회색 점선 테두리
|
||||||
|
g.DrawPolygon(new Pen(Color.FromArgb(180, 128, 128, 128), 2) { DashStyle = DashStyle.Dash }, points);
|
||||||
|
// 빨간색 외곽 테두리 (디버깅용)
|
||||||
|
var outerPoints = new Point[3];
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
var angle = (Math.PI * 2 * i / 3) - Math.PI / 2;
|
||||||
|
outerPoints[i] = new Point(
|
||||||
|
(int)(_dragStartPosition.X + (NODE_RADIUS + 3) * Math.Cos(angle)),
|
||||||
|
(int)(_dragStartPosition.Y + (NODE_RADIUS + 3) * Math.Sin(angle))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
g.DrawPolygon(new Pen(Color.FromArgb(200, 255, 0, 0), 1), outerPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawLabelGhost(Graphics g)
|
||||||
|
{
|
||||||
|
var text = string.IsNullOrEmpty(_selectedNode.LabelText) ? _selectedNode.NodeId : _selectedNode.LabelText;
|
||||||
|
var font = new Font(_selectedNode.FontFamily, _selectedNode.FontSize, _selectedNode.FontStyle);
|
||||||
|
var textBrush = new SolidBrush(Color.FromArgb(120, _selectedNode.ForeColor));
|
||||||
|
var textSize = g.MeasureString(text, font);
|
||||||
|
var textPoint = new Point(
|
||||||
|
(int)(_dragStartPosition.X - textSize.Width / 2),
|
||||||
|
(int)(_dragStartPosition.Y - textSize.Height / 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (_selectedNode.ShowBackground)
|
||||||
|
{
|
||||||
|
var backgroundBrush = new SolidBrush(Color.FromArgb(120, _selectedNode.BackColor));
|
||||||
|
var backgroundRect = new Rectangle(
|
||||||
|
textPoint.X - _selectedNode.Padding,
|
||||||
|
textPoint.Y - _selectedNode.Padding,
|
||||||
|
(int)textSize.Width + (_selectedNode.Padding * 2),
|
||||||
|
(int)textSize.Height + (_selectedNode.Padding * 2)
|
||||||
|
);
|
||||||
|
g.FillRectangle(backgroundBrush, backgroundRect);
|
||||||
|
g.DrawRectangle(new Pen(Color.FromArgb(180, 128, 128, 128), 2) { DashStyle = DashStyle.Dash }, backgroundRect);
|
||||||
|
backgroundBrush.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
g.DrawString(text, font, textBrush, textPoint);
|
||||||
|
|
||||||
|
// 배경이 없어도 테두리 표시
|
||||||
|
if (!_selectedNode.ShowBackground)
|
||||||
|
{
|
||||||
|
var borderRect = new Rectangle(
|
||||||
|
textPoint.X - 2,
|
||||||
|
textPoint.Y - 2,
|
||||||
|
(int)textSize.Width + 4,
|
||||||
|
(int)textSize.Height + 4
|
||||||
|
);
|
||||||
|
g.DrawRectangle(new Pen(Color.FromArgb(180, 128, 128, 128), 2) { DashStyle = DashStyle.Dash }, borderRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 빨간색 외곽 테두리 (디버깅용)
|
||||||
|
var outerRect = new Rectangle(
|
||||||
|
textPoint.X - 4,
|
||||||
|
textPoint.Y - 4,
|
||||||
|
(int)textSize.Width + 8,
|
||||||
|
(int)textSize.Height + 8
|
||||||
|
);
|
||||||
|
g.DrawRectangle(new Pen(Color.FromArgb(200, 255, 0, 0), 1), outerRect);
|
||||||
|
|
||||||
|
font.Dispose();
|
||||||
|
textBrush.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawImageGhost(Graphics g)
|
||||||
|
{
|
||||||
|
var displaySize = _selectedNode.GetDisplaySize();
|
||||||
|
if (displaySize.IsEmpty)
|
||||||
|
displaySize = new Size(50, 50);
|
||||||
|
|
||||||
|
var imageRect = new Rectangle(
|
||||||
|
_dragStartPosition.X - displaySize.Width / 2,
|
||||||
|
_dragStartPosition.Y - displaySize.Height / 2,
|
||||||
|
displaySize.Width,
|
||||||
|
displaySize.Height
|
||||||
|
);
|
||||||
|
|
||||||
|
// 반투명 회색 사각형
|
||||||
|
using (var ghostBrush = new SolidBrush(Color.FromArgb(120, 200, 200, 200)))
|
||||||
|
{
|
||||||
|
g.FillRectangle(ghostBrush, imageRect);
|
||||||
|
g.DrawRectangle(new Pen(Color.FromArgb(180, 128, 128, 128), 2) { DashStyle = DashStyle.Dash }, imageRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 빨간색 외곽 테두리 (디버깅용)
|
||||||
|
var outerRect = new Rectangle(imageRect.X - 2, imageRect.Y - 2, imageRect.Width + 4, imageRect.Height + 4);
|
||||||
|
g.DrawRectangle(new Pen(Color.FromArgb(200, 255, 0, 0), 1), outerRect);
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawNodesOnly(Graphics g)
|
private void DrawNodesOnly(Graphics g)
|
||||||
{
|
{
|
||||||
@@ -444,19 +655,42 @@ namespace AGVNavigationCore.Controls
|
|||||||
|
|
||||||
private void DrawCircleNodeShape(Graphics g, MapNode node, Brush brush)
|
private void DrawCircleNodeShape(Graphics g, MapNode node, Brush brush)
|
||||||
{
|
{
|
||||||
|
// 드래그 중인 노드는 약간 크게 그리기
|
||||||
|
bool isDraggingThisNode = _isDragging && node == _selectedNode;
|
||||||
|
int sizeAdjustment = isDraggingThisNode ? 4 : 0;
|
||||||
|
|
||||||
var rect = new Rectangle(
|
var rect = new Rectangle(
|
||||||
node.Position.X - NODE_RADIUS,
|
node.Position.X - NODE_RADIUS - sizeAdjustment,
|
||||||
node.Position.Y - NODE_RADIUS,
|
node.Position.Y - NODE_RADIUS - sizeAdjustment,
|
||||||
NODE_SIZE,
|
NODE_SIZE + sizeAdjustment * 2,
|
||||||
NODE_SIZE
|
NODE_SIZE + sizeAdjustment * 2
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 드래그 중인 노드의 그림자 효과
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
var shadowRect = new Rectangle(rect.X + 3, rect.Y + 3, rect.Width, rect.Height);
|
||||||
|
using (var shadowBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
|
||||||
|
{
|
||||||
|
g.FillEllipse(shadowBrush, shadowRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 노드 그리기
|
// 노드 그리기
|
||||||
g.FillEllipse(brush, rect);
|
g.FillEllipse(brush, rect);
|
||||||
g.DrawEllipse(Pens.Black, rect);
|
g.DrawEllipse(Pens.Black, rect);
|
||||||
|
|
||||||
|
// 드래그 중인 노드 강조 (가장 강력한 효과)
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
// 청록색 두꺼운 테두리
|
||||||
|
g.DrawEllipse(new Pen(Color.Cyan, 3), rect);
|
||||||
|
// 펄스 효과
|
||||||
|
var pulseRect = new Rectangle(rect.X - 4, rect.Y - 4, rect.Width + 8, rect.Height + 8);
|
||||||
|
g.DrawEllipse(new Pen(Color.FromArgb(150, 0, 255, 255), 2) { DashStyle = DashStyle.Dash }, pulseRect);
|
||||||
|
}
|
||||||
// 선택된 노드 강조
|
// 선택된 노드 강조
|
||||||
if (node == _selectedNode)
|
else if (node == _selectedNode)
|
||||||
{
|
{
|
||||||
g.DrawEllipse(_selectedNodePen, rect);
|
g.DrawEllipse(_selectedNodePen, rect);
|
||||||
}
|
}
|
||||||
@@ -472,8 +706,8 @@ namespace AGVNavigationCore.Controls
|
|||||||
g.DrawEllipse(new Pen(Color.Gold, 2) { DashStyle = DashStyle.Dash }, pulseRect);
|
g.DrawEllipse(new Pen(Color.Gold, 2) { DashStyle = DashStyle.Dash }, pulseRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 호버된 노드 강조
|
// 호버된 노드 강조 (드래그 중이 아닐 때만)
|
||||||
if (node == _hoveredNode)
|
if (node == _hoveredNode && !isDraggingThisNode)
|
||||||
{
|
{
|
||||||
var hoverRect = new Rectangle(rect.X - 2, rect.Y - 2, rect.Width + 4, rect.Height + 4);
|
var hoverRect = new Rectangle(rect.X - 2, rect.Y - 2, rect.Width + 4, rect.Height + 4);
|
||||||
g.DrawEllipse(new Pen(Color.Orange, 2), hoverRect);
|
g.DrawEllipse(new Pen(Color.Orange, 2), hoverRect);
|
||||||
@@ -488,7 +722,11 @@ namespace AGVNavigationCore.Controls
|
|||||||
|
|
||||||
private void DrawPentagonNodeShape(Graphics g, MapNode node, Brush brush)
|
private void DrawPentagonNodeShape(Graphics g, MapNode node, Brush brush)
|
||||||
{
|
{
|
||||||
var radius = NODE_RADIUS;
|
// 드래그 중인 노드는 약간 크게 그리기
|
||||||
|
bool isDraggingThisNode = _isDragging && node == _selectedNode;
|
||||||
|
int radiusAdjustment = isDraggingThisNode ? 4 : 0;
|
||||||
|
|
||||||
|
var radius = NODE_RADIUS + radiusAdjustment;
|
||||||
var center = node.Position;
|
var center = node.Position;
|
||||||
|
|
||||||
// 5각형 꼭짓점 계산 (위쪽부터 시계방향)
|
// 5각형 꼭짓점 계산 (위쪽부터 시계방향)
|
||||||
@@ -502,12 +740,43 @@ namespace AGVNavigationCore.Controls
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 드래그 중인 노드의 그림자 효과
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
var shadowPoints = new Point[5];
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
shadowPoints[i] = new Point(points[i].X + 3, points[i].Y + 3);
|
||||||
|
}
|
||||||
|
using (var shadowBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
|
||||||
|
{
|
||||||
|
g.FillPolygon(shadowBrush, shadowPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 5각형 그리기
|
// 5각형 그리기
|
||||||
g.FillPolygon(brush, points);
|
g.FillPolygon(brush, points);
|
||||||
g.DrawPolygon(Pens.Black, points);
|
g.DrawPolygon(Pens.Black, points);
|
||||||
|
|
||||||
|
// 드래그 중인 노드 강조 (가장 강력한 효과)
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
// 청록색 두꺼운 테두리
|
||||||
|
g.DrawPolygon(new Pen(Color.Cyan, 3), points);
|
||||||
|
// 펄스 효과
|
||||||
|
var pulsePoints = new Point[5];
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
var angle = (Math.PI * 2 * i / 5) - Math.PI / 2;
|
||||||
|
pulsePoints[i] = new Point(
|
||||||
|
(int)(center.X + (radius + 5) * Math.Cos(angle)),
|
||||||
|
(int)(center.Y + (radius + 5) * Math.Sin(angle))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
g.DrawPolygon(new Pen(Color.FromArgb(150, 0, 255, 255), 2) { DashStyle = DashStyle.Dash }, pulsePoints);
|
||||||
|
}
|
||||||
// 선택된 노드 강조
|
// 선택된 노드 강조
|
||||||
if (node == _selectedNode)
|
else if (node == _selectedNode)
|
||||||
{
|
{
|
||||||
g.DrawPolygon(_selectedNodePen, points);
|
g.DrawPolygon(_selectedNodePen, points);
|
||||||
}
|
}
|
||||||
@@ -531,8 +800,8 @@ namespace AGVNavigationCore.Controls
|
|||||||
g.DrawPolygon(new Pen(Color.Gold, 2) { DashStyle = DashStyle.Dash }, pulsePoints);
|
g.DrawPolygon(new Pen(Color.Gold, 2) { DashStyle = DashStyle.Dash }, pulsePoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 호버된 노드 강조
|
// 호버된 노드 강조 (드래그 중이 아닐 때만)
|
||||||
if (node == _hoveredNode)
|
if (node == _hoveredNode && !isDraggingThisNode)
|
||||||
{
|
{
|
||||||
// 확장된 5각형 계산
|
// 확장된 5각형 계산
|
||||||
var hoverPoints = new Point[5];
|
var hoverPoints = new Point[5];
|
||||||
@@ -556,7 +825,11 @@ namespace AGVNavigationCore.Controls
|
|||||||
|
|
||||||
private void DrawTriangleNodeShape(Graphics g, MapNode node, Brush brush)
|
private void DrawTriangleNodeShape(Graphics g, MapNode node, Brush brush)
|
||||||
{
|
{
|
||||||
var radius = NODE_RADIUS;
|
// 드래그 중인 노드는 약간 크게 그리기
|
||||||
|
bool isDraggingThisNode = _isDragging && node == _selectedNode;
|
||||||
|
int radiusAdjustment = isDraggingThisNode ? 4 : 0;
|
||||||
|
|
||||||
|
var radius = NODE_RADIUS + radiusAdjustment;
|
||||||
var center = node.Position;
|
var center = node.Position;
|
||||||
|
|
||||||
// 삼각형 꼭짓점 계산 (위쪽 꼭짓점부터 시계방향)
|
// 삼각형 꼭짓점 계산 (위쪽 꼭짓점부터 시계방향)
|
||||||
@@ -570,12 +843,43 @@ namespace AGVNavigationCore.Controls
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 드래그 중인 노드의 그림자 효과
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
var shadowPoints = new Point[3];
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
shadowPoints[i] = new Point(points[i].X + 3, points[i].Y + 3);
|
||||||
|
}
|
||||||
|
using (var shadowBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
|
||||||
|
{
|
||||||
|
g.FillPolygon(shadowBrush, shadowPoints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 삼각형 그리기
|
// 삼각형 그리기
|
||||||
g.FillPolygon(brush, points);
|
g.FillPolygon(brush, points);
|
||||||
g.DrawPolygon(Pens.Black, points);
|
g.DrawPolygon(Pens.Black, points);
|
||||||
|
|
||||||
|
// 드래그 중인 노드 강조 (가장 강력한 효과)
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
// 청록색 두꺼운 테두리
|
||||||
|
g.DrawPolygon(new Pen(Color.Cyan, 3), points);
|
||||||
|
// 펄스 효과
|
||||||
|
var pulsePoints = new Point[3];
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
var angle = (Math.PI * 2 * i / 3) - Math.PI / 2;
|
||||||
|
pulsePoints[i] = new Point(
|
||||||
|
(int)(center.X + (radius + 5) * Math.Cos(angle)),
|
||||||
|
(int)(center.Y + (radius + 5) * Math.Sin(angle))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
g.DrawPolygon(new Pen(Color.FromArgb(150, 0, 255, 255), 2) { DashStyle = DashStyle.Dash }, pulsePoints);
|
||||||
|
}
|
||||||
// 선택된 노드 강조
|
// 선택된 노드 강조
|
||||||
if (node == _selectedNode)
|
else if (node == _selectedNode)
|
||||||
{
|
{
|
||||||
g.DrawPolygon(_selectedNodePen, points);
|
g.DrawPolygon(_selectedNodePen, points);
|
||||||
}
|
}
|
||||||
@@ -599,8 +903,8 @@ namespace AGVNavigationCore.Controls
|
|||||||
g.DrawPolygon(new Pen(Color.Gold, 2) { DashStyle = DashStyle.Dash }, pulsePoints);
|
g.DrawPolygon(new Pen(Color.Gold, 2) { DashStyle = DashStyle.Dash }, pulsePoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 호버된 노드 강조
|
// 호버된 노드 강조 (드래그 중이 아닐 때만)
|
||||||
if (node == _hoveredNode)
|
if (node == _hoveredNode && !isDraggingThisNode)
|
||||||
{
|
{
|
||||||
// 확장된 삼각형 계산
|
// 확장된 삼각형 계산
|
||||||
var hoverPoints = new Point[3];
|
var hoverPoints = new Point[3];
|
||||||
@@ -725,6 +1029,9 @@ namespace AGVNavigationCore.Controls
|
|||||||
|
|
||||||
private void DrawLabelNode(Graphics g, MapNode node)
|
private void DrawLabelNode(Graphics g, MapNode node)
|
||||||
{
|
{
|
||||||
|
// 드래그 중인 노드 확인
|
||||||
|
bool isDraggingThisNode = _isDragging && node == _selectedNode;
|
||||||
|
|
||||||
var text = string.IsNullOrEmpty(node.LabelText) ? node.NodeId : node.LabelText;
|
var text = string.IsNullOrEmpty(node.LabelText) ? node.NodeId : node.LabelText;
|
||||||
|
|
||||||
// 폰트 설정
|
// 폰트 설정
|
||||||
@@ -738,6 +1045,16 @@ namespace AGVNavigationCore.Controls
|
|||||||
(int)(node.Position.Y - textSize.Height / 2)
|
(int)(node.Position.Y - textSize.Height / 2)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 드래그 중일 때 그림자 효과
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
var shadowPoint = new Point(textPoint.X + 3, textPoint.Y + 3);
|
||||||
|
using (var shadowBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
|
||||||
|
{
|
||||||
|
g.DrawString(text, font, shadowBrush, shadowPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 배경 그리기 (설정된 경우)
|
// 배경 그리기 (설정된 경우)
|
||||||
if (node.ShowBackground)
|
if (node.ShowBackground)
|
||||||
{
|
{
|
||||||
@@ -756,8 +1073,24 @@ namespace AGVNavigationCore.Controls
|
|||||||
// 텍스트 그리기
|
// 텍스트 그리기
|
||||||
g.DrawString(text, font, textBrush, textPoint);
|
g.DrawString(text, font, textBrush, textPoint);
|
||||||
|
|
||||||
|
// 드래그 중인 노드 강조 (가장 강력한 효과)
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
var dragPadding = node.Padding + 4;
|
||||||
|
var dragRect = new Rectangle(
|
||||||
|
textPoint.X - dragPadding,
|
||||||
|
textPoint.Y - dragPadding,
|
||||||
|
(int)textSize.Width + (dragPadding * 2),
|
||||||
|
(int)textSize.Height + (dragPadding * 2)
|
||||||
|
);
|
||||||
|
g.DrawRectangle(new Pen(Color.Cyan, 3), dragRect);
|
||||||
|
|
||||||
|
// 펄스 효과
|
||||||
|
var pulseRect = new Rectangle(dragRect.X - 2, dragRect.Y - 2, dragRect.Width + 4, dragRect.Height + 4);
|
||||||
|
g.DrawRectangle(new Pen(Color.FromArgb(150, 0, 255, 255), 2) { DashStyle = DashStyle.Dash }, pulseRect);
|
||||||
|
}
|
||||||
// 선택된 노드 강조
|
// 선택된 노드 강조
|
||||||
if (node == _selectedNode)
|
else if (node == _selectedNode)
|
||||||
{
|
{
|
||||||
var selectionPadding = node.Padding + 2;
|
var selectionPadding = node.Padding + 2;
|
||||||
var selectionRect = new Rectangle(
|
var selectionRect = new Rectangle(
|
||||||
@@ -769,8 +1102,8 @@ namespace AGVNavigationCore.Controls
|
|||||||
g.DrawRectangle(_selectedNodePen, selectionRect);
|
g.DrawRectangle(_selectedNodePen, selectionRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 호버된 노드 강조
|
// 호버된 노드 강조 (드래그 중이 아닐 때만)
|
||||||
if (node == _hoveredNode)
|
if (node == _hoveredNode && !isDraggingThisNode)
|
||||||
{
|
{
|
||||||
var hoverPadding = node.Padding + 4;
|
var hoverPadding = node.Padding + 4;
|
||||||
var hoverRect = new Rectangle(
|
var hoverRect = new Rectangle(
|
||||||
@@ -788,6 +1121,9 @@ namespace AGVNavigationCore.Controls
|
|||||||
|
|
||||||
private void DrawImageNode(Graphics g, MapNode node)
|
private void DrawImageNode(Graphics g, MapNode node)
|
||||||
{
|
{
|
||||||
|
// 드래그 중인 노드 확인
|
||||||
|
bool isDraggingThisNode = _isDragging && node == _selectedNode;
|
||||||
|
|
||||||
// 이미지 로드 (필요시)
|
// 이미지 로드 (필요시)
|
||||||
if (node.LoadedImage == null && !string.IsNullOrEmpty(node.ImagePath))
|
if (node.LoadedImage == null && !string.IsNullOrEmpty(node.ImagePath))
|
||||||
{
|
{
|
||||||
@@ -801,6 +1137,12 @@ namespace AGVNavigationCore.Controls
|
|||||||
if (displaySize.IsEmpty)
|
if (displaySize.IsEmpty)
|
||||||
displaySize = new Size(50, 50); // 기본 크기
|
displaySize = new Size(50, 50); // 기본 크기
|
||||||
|
|
||||||
|
// 드래그 중일 때 약간 크게 표시
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
displaySize = new Size((int)(displaySize.Width * 1.1), (int)(displaySize.Height * 1.1));
|
||||||
|
}
|
||||||
|
|
||||||
var imageRect = new Rectangle(
|
var imageRect = new Rectangle(
|
||||||
node.Position.X - displaySize.Width / 2,
|
node.Position.X - displaySize.Width / 2,
|
||||||
node.Position.Y - displaySize.Height / 2,
|
node.Position.Y - displaySize.Height / 2,
|
||||||
@@ -808,6 +1150,16 @@ namespace AGVNavigationCore.Controls
|
|||||||
displaySize.Height
|
displaySize.Height
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 드래그 중일 때 그림자 효과
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
var shadowRect = new Rectangle(imageRect.X + 3, imageRect.Y + 3, imageRect.Width, imageRect.Height);
|
||||||
|
using (var shadowBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
|
||||||
|
{
|
||||||
|
g.FillRectangle(shadowBrush, shadowRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 회전이 있는 경우
|
// 회전이 있는 경우
|
||||||
if (node.Rotation != 0)
|
if (node.Rotation != 0)
|
||||||
{
|
{
|
||||||
@@ -855,14 +1207,21 @@ namespace AGVNavigationCore.Controls
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 드래그 중인 노드 강조 (가장 강력한 효과)
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
g.DrawRectangle(new Pen(Color.Cyan, 3), imageRect);
|
||||||
|
var pulseRect = new Rectangle(imageRect.X - 3, imageRect.Y - 3, imageRect.Width + 6, imageRect.Height + 6);
|
||||||
|
g.DrawRectangle(new Pen(Color.FromArgb(150, 0, 255, 255), 2) { DashStyle = DashStyle.Dash }, pulseRect);
|
||||||
|
}
|
||||||
// 선택된 노드 강조
|
// 선택된 노드 강조
|
||||||
if (node == _selectedNode)
|
else if (node == _selectedNode)
|
||||||
{
|
{
|
||||||
g.DrawRectangle(_selectedNodePen, imageRect);
|
g.DrawRectangle(_selectedNodePen, imageRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 호버된 노드 강조
|
// 호버된 노드 강조 (드래그 중이 아닐 때만)
|
||||||
if (node == _hoveredNode)
|
if (node == _hoveredNode && !isDraggingThisNode)
|
||||||
{
|
{
|
||||||
var hoverRect = new Rectangle(imageRect.X - 2, imageRect.Y - 2, imageRect.Width + 4, imageRect.Height + 4);
|
var hoverRect = new Rectangle(imageRect.X - 2, imageRect.Y - 2, imageRect.Width + 4, imageRect.Height + 4);
|
||||||
g.DrawRectangle(new Pen(Color.Orange, 2), hoverRect);
|
g.DrawRectangle(new Pen(Color.Orange, 2), hoverRect);
|
||||||
@@ -872,13 +1231,24 @@ namespace AGVNavigationCore.Controls
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 이미지가 없는 경우 기본 사각형으로 표시
|
// 이미지가 없는 경우 기본 사각형으로 표시
|
||||||
|
int sizeAdjustment = isDraggingThisNode ? 5 : 0;
|
||||||
var rect = new Rectangle(
|
var rect = new Rectangle(
|
||||||
node.Position.X - 25,
|
node.Position.X - 25 - sizeAdjustment,
|
||||||
node.Position.Y - 25,
|
node.Position.Y - 25 - sizeAdjustment,
|
||||||
50,
|
50 + sizeAdjustment * 2,
|
||||||
50
|
50 + sizeAdjustment * 2
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 드래그 중일 때 그림자 효과
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
var shadowRect = new Rectangle(rect.X + 3, rect.Y + 3, rect.Width, rect.Height);
|
||||||
|
using (var shadowBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
|
||||||
|
{
|
||||||
|
g.FillRectangle(shadowBrush, shadowRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g.FillRectangle(Brushes.LightGray, rect);
|
g.FillRectangle(Brushes.LightGray, rect);
|
||||||
g.DrawRectangle(Pens.Black, rect);
|
g.DrawRectangle(Pens.Black, rect);
|
||||||
|
|
||||||
@@ -893,14 +1263,21 @@ namespace AGVNavigationCore.Controls
|
|||||||
g.DrawString(text, font, Brushes.Black, textPoint);
|
g.DrawString(text, font, Brushes.Black, textPoint);
|
||||||
font.Dispose();
|
font.Dispose();
|
||||||
|
|
||||||
|
// 드래그 중인 노드 강조 (가장 강력한 효과)
|
||||||
|
if (isDraggingThisNode)
|
||||||
|
{
|
||||||
|
g.DrawRectangle(new Pen(Color.Cyan, 3), rect);
|
||||||
|
var pulseRect = new Rectangle(rect.X - 3, rect.Y - 3, rect.Width + 6, rect.Height + 6);
|
||||||
|
g.DrawRectangle(new Pen(Color.FromArgb(150, 0, 255, 255), 2) { DashStyle = DashStyle.Dash }, pulseRect);
|
||||||
|
}
|
||||||
// 선택된 노드 강조
|
// 선택된 노드 강조
|
||||||
if (node == _selectedNode)
|
else if (node == _selectedNode)
|
||||||
{
|
{
|
||||||
g.DrawRectangle(_selectedNodePen, rect);
|
g.DrawRectangle(_selectedNodePen, rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 호버된 노드 강조
|
// 호버된 노드 강조 (드래그 중이 아닐 때만)
|
||||||
if (node == _hoveredNode)
|
if (node == _hoveredNode && !isDraggingThisNode)
|
||||||
{
|
{
|
||||||
var hoverRect = new Rectangle(rect.X - 2, rect.Y - 2, rect.Width + 4, rect.Height + 4);
|
var hoverRect = new Rectangle(rect.X - 2, rect.Y - 2, rect.Width + 4, rect.Height + 4);
|
||||||
g.DrawRectangle(new Pen(Color.Orange, 2), hoverRect);
|
g.DrawRectangle(new Pen(Color.Orange, 2), hoverRect);
|
||||||
@@ -1600,6 +1977,7 @@ namespace AGVNavigationCore.Controls
|
|||||||
g.DrawString(scaleText, font, Brushes.Black, scaleRect.X + 5, scaleRect.Y + 2);
|
g.DrawString(scaleText, font, Brushes.Black, scaleRect.X + 5, scaleRect.Y + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 측정 정보 (우하단 - 사용자 정의 정보가 있을 경우)
|
// 측정 정보 (우하단 - 사용자 정의 정보가 있을 경우)
|
||||||
if (!string.IsNullOrEmpty(_measurementInfo))
|
if (!string.IsNullOrEmpty(_measurementInfo))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -143,12 +143,17 @@ namespace AGVNavigationCore.Controls
|
|||||||
if (hitNode != null)
|
if (hitNode != null)
|
||||||
{
|
{
|
||||||
_isDragging = true;
|
_isDragging = true;
|
||||||
|
_isPanning = false; // 🔥 팬 모드 비활성화 - 중요!
|
||||||
_selectedNode = hitNode;
|
_selectedNode = hitNode;
|
||||||
|
_dragStartPosition = hitNode.Position; // 원래 위치 저장 (고스트용)
|
||||||
_dragOffset = new Point(
|
_dragOffset = new Point(
|
||||||
worldPoint.X - hitNode.Position.X,
|
worldPoint.X - hitNode.Position.X,
|
||||||
worldPoint.Y - hitNode.Position.Y
|
worldPoint.Y - hitNode.Position.Y
|
||||||
);
|
);
|
||||||
|
_mouseMoveCounter = 0; // 디버그: 카운터 리셋
|
||||||
Cursor = Cursors.SizeAll;
|
Cursor = Cursors.SizeAll;
|
||||||
|
Capture = true; // 🔥 마우스 캡처 활성화 - 이게 핵심!
|
||||||
|
//System.Diagnostics.Debug.WriteLine($"MouseDown: 드래그 시작! Capture={Capture}, isDragging={_isDragging}, isPanning={_isPanning}, Node={hitNode.NodeId}");
|
||||||
Invalidate();
|
Invalidate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -158,6 +163,7 @@ namespace AGVNavigationCore.Controls
|
|||||||
_isPanning = true;
|
_isPanning = true;
|
||||||
_lastMousePosition = e.Location;
|
_lastMousePosition = e.Location;
|
||||||
Cursor = Cursors.SizeAll;
|
Cursor = Cursors.SizeAll;
|
||||||
|
Capture = true; // 🔥 마우스 캡처 활성화
|
||||||
}
|
}
|
||||||
else if (e.Button == MouseButtons.Middle)
|
else if (e.Button == MouseButtons.Middle)
|
||||||
{
|
{
|
||||||
@@ -165,6 +171,7 @@ namespace AGVNavigationCore.Controls
|
|||||||
_isPanning = true;
|
_isPanning = true;
|
||||||
_lastMousePosition = e.Location;
|
_lastMousePosition = e.Location;
|
||||||
Cursor = Cursors.Hand;
|
Cursor = Cursors.Hand;
|
||||||
|
Capture = true; // 🔥 마우스 캡처 활성화
|
||||||
}
|
}
|
||||||
else if (e.Button == MouseButtons.Right)
|
else if (e.Button == MouseButtons.Right)
|
||||||
{
|
{
|
||||||
@@ -181,6 +188,12 @@ namespace AGVNavigationCore.Controls
|
|||||||
{
|
{
|
||||||
var worldPoint = ScreenToWorld(e.Location);
|
var worldPoint = ScreenToWorld(e.Location);
|
||||||
|
|
||||||
|
// 디버그: MouseMove 카운터 증가
|
||||||
|
if (_isDragging)
|
||||||
|
{
|
||||||
|
_mouseMoveCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
// 호버 노드 업데이트
|
// 호버 노드 업데이트
|
||||||
var newHoveredNode = GetNodeAt(worldPoint);
|
var newHoveredNode = GetNodeAt(worldPoint);
|
||||||
if (newHoveredNode != _hoveredNode)
|
if (newHoveredNode != _hoveredNode)
|
||||||
@@ -191,21 +204,25 @@ namespace AGVNavigationCore.Controls
|
|||||||
|
|
||||||
if (_isPanning)
|
if (_isPanning)
|
||||||
{
|
{
|
||||||
// 팬 처리
|
// 팬 처리 - 줌 레벨 보정 적용
|
||||||
var deltaX = e.X - _lastMousePosition.X;
|
var deltaX = e.X - _lastMousePosition.X;
|
||||||
var deltaY = e.Y - _lastMousePosition.Y;
|
var deltaY = e.Y - _lastMousePosition.Y;
|
||||||
|
|
||||||
_panOffset.X += deltaX;
|
// 🔥 스크린 좌표 델타를 월드 좌표 델타로 변환 (줌 레벨 보정)
|
||||||
_panOffset.Y += deltaY;
|
// PointF로 float 정밀도 유지 (소수점 손실 방지)
|
||||||
|
_panOffset.X += deltaX / _zoomFactor;
|
||||||
|
_panOffset.Y += deltaY / _zoomFactor;
|
||||||
|
|
||||||
_lastMousePosition = e.Location;
|
_lastMousePosition = e.Location;
|
||||||
Invalidate();
|
Invalidate();
|
||||||
|
Update(); // 팬도 실시간 업데이트
|
||||||
}
|
}
|
||||||
else if (_isDragging && _canvasMode == CanvasMode.Edit)
|
else if (_isDragging && _canvasMode == CanvasMode.Edit)
|
||||||
{
|
{
|
||||||
// 노드 드래그
|
// 노드 드래그
|
||||||
if (_selectedNode != null)
|
if (_selectedNode != null)
|
||||||
{
|
{
|
||||||
|
var oldPosition = _selectedNode.Position;
|
||||||
var newPosition = new Point(
|
var newPosition = new Point(
|
||||||
worldPoint.X - _dragOffset.X,
|
worldPoint.X - _dragOffset.X,
|
||||||
worldPoint.Y - _dragOffset.Y
|
worldPoint.Y - _dragOffset.Y
|
||||||
@@ -222,6 +239,7 @@ namespace AGVNavigationCore.Controls
|
|||||||
NodeMoved?.Invoke(this, _selectedNode);
|
NodeMoved?.Invoke(this, _selectedNode);
|
||||||
MapChanged?.Invoke(this, EventArgs.Empty);
|
MapChanged?.Invoke(this, EventArgs.Empty);
|
||||||
Invalidate();
|
Invalidate();
|
||||||
|
Update(); // 🔥 즉시 Paint 이벤트 처리하여 화면 업데이트
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_isConnectionMode && _canvasMode == CanvasMode.Edit)
|
else if (_isConnectionMode && _canvasMode == CanvasMode.Edit)
|
||||||
@@ -242,12 +260,14 @@ namespace AGVNavigationCore.Controls
|
|||||||
if (_isDragging && _canvasMode == CanvasMode.Edit)
|
if (_isDragging && _canvasMode == CanvasMode.Edit)
|
||||||
{
|
{
|
||||||
_isDragging = false;
|
_isDragging = false;
|
||||||
|
Capture = false; // 🔥 마우스 캡처 해제
|
||||||
Cursor = GetCursorForMode(_editMode);
|
Cursor = GetCursorForMode(_editMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isPanning)
|
if (_isPanning)
|
||||||
{
|
{
|
||||||
_isPanning = false;
|
_isPanning = false;
|
||||||
|
Capture = false; // 🔥 마우스 캡처 해제
|
||||||
Cursor = Cursors.Default;
|
Cursor = Cursors.Default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,6 +277,7 @@ namespace AGVNavigationCore.Controls
|
|||||||
if (_isPanning)
|
if (_isPanning)
|
||||||
{
|
{
|
||||||
_isPanning = false;
|
_isPanning = false;
|
||||||
|
Capture = false; // 🔥 마우스 캡처 해제
|
||||||
Cursor = Cursors.Default;
|
Cursor = Cursors.Default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -896,7 +917,7 @@ namespace AGVNavigationCore.Controls
|
|||||||
public void ResetZoom()
|
public void ResetZoom()
|
||||||
{
|
{
|
||||||
_zoomFactor = 1.0f;
|
_zoomFactor = 1.0f;
|
||||||
_panOffset = Point.Empty;
|
_panOffset = PointF.Empty;
|
||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,15 +88,17 @@ namespace AGVNavigationCore.Controls
|
|||||||
// 편집 관련 (EditMode에서만 사용)
|
// 편집 관련 (EditMode에서만 사용)
|
||||||
private bool _isDragging;
|
private bool _isDragging;
|
||||||
private Point _dragOffset;
|
private Point _dragOffset;
|
||||||
|
private Point _dragStartPosition; // 드래그 시작 위치 (고스트 표시용)
|
||||||
private Point _lastMousePosition;
|
private Point _lastMousePosition;
|
||||||
private bool _isConnectionMode;
|
private bool _isConnectionMode;
|
||||||
private MapNode _connectionStartNode;
|
private MapNode _connectionStartNode;
|
||||||
private Point _connectionEndPoint;
|
private Point _connectionEndPoint;
|
||||||
|
private int _mouseMoveCounter = 0; // 디버그용: MouseMove 실행 횟수
|
||||||
|
|
||||||
// 그리드 및 줌 관련
|
// 그리드 및 줌 관련
|
||||||
private bool _showGrid = true;
|
private bool _showGrid = true;
|
||||||
private float _zoomFactor = 1.0f;
|
private float _zoomFactor = 1.0f;
|
||||||
private Point _panOffset = Point.Empty;
|
private PointF _panOffset = PointF.Empty; // float 정밀도로 변경 (팬 이동 정확도 개선)
|
||||||
private bool _isPanning;
|
private bool _isPanning;
|
||||||
|
|
||||||
// 자동 증가 카운터
|
// 자동 증가 카운터
|
||||||
|
|||||||
Reference in New Issue
Block a user