feat: 新增文字移动实时显示网格辅助线

This commit is contained in:
Zhukj
2026-04-21 09:03:01 +08:00
parent 16de547957
commit d34bed9200
3 changed files with 100 additions and 24 deletions

View File

@@ -513,3 +513,23 @@ html, body {
.guide-line.visible {
display: block;
}
/* 1px 网格线 */
.grid-lines {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
z-index: 5;
display: none;
background-image:
linear-gradient(to right, rgba(0, 0, 0, 0.05) 1px, transparent 1px),
linear-gradient(to bottom, rgba(0, 0, 0, 0.05) 1px, transparent 1px);
background-size: 10px 10px;
}
.grid-lines.visible {
display: block;
}

View File

@@ -80,6 +80,8 @@
</div>
<!-- 层叠图图层 -->
<div class="overlay-layer" id="overlayLayer"></div>
<!-- 1px 网格线 -->
<div class="grid-lines" id="gridLines"></div>
<!-- 拖拽辅助线 -->
<div class="guide-line guide-horizontal" id="guideH"></div>
<div class="guide-line guide-vertical" id="guideV"></div>

View File

@@ -38,6 +38,7 @@
document.body.appendChild(overlayInput);
const guideH = document.getElementById('guideH');
const guideV = document.getElementById('guideV');
const gridLines = document.getElementById('gridLines');
let currentImage = null;
let bgImageScale = 1;
@@ -207,6 +208,9 @@
// 初始化文本编辑器工具栏
initTextEditorToolbar();
// 初始化键盘微调功能
initKeyboardNudge();
// 加载默认背景图
loadDefaultBackground();
@@ -450,27 +454,23 @@
const dx = clientX - startX;
const dy = clientY - startY;
const moveDistance = Math.sqrt(dx * dx + dy * dy);
if (moveDistance > 5) {
let newLeft = startLeft + dx;
let newTop = startTop + dy;
// 移除移动距离限制,实现 1px 精确移动
let newLeft = startLeft + dx;
let newTop = startTop + dy;
// 使用吸附功能
const snapped = getSnapPosition(overlayEl, newLeft, newTop);
newLeft = snapped.left;
newTop = snapped.top;
// 使用吸附功能
const snapped = getSnapPosition(overlayEl, newLeft, newTop);
newLeft = snapped.left;
newTop = snapped.top;
// 显示对齐辅助线
if (snapped.showGuide) {
showAlignmentGuides(overlayEl);
} else {
hideGuides();
}
overlayEl.style.left = newLeft + 'px';
overlayEl.style.top = newTop + 'px';
// 显示对齐辅助线(网格线已在 getSnapPosition 中显示)
if (snapped.showGuide) {
showAlignmentGuides(overlayEl);
}
overlayEl.style.left = newLeft + 'px';
overlayEl.style.top = newTop + 'px';
e.preventDefault();
}
@@ -974,7 +974,8 @@
Math.pow(clientY - clickStartY, 2)
);
if (moveDistance > 5) {
// 只要有移动就开始拖拽,实现 1px 精确移动
if (moveDistance > 0) {
hasMoved = true;
if (dragTimer) {
clearTimeout(dragTimer);
@@ -997,11 +998,9 @@
element.style.left = snapped.left + 'px';
element.style.top = snapped.top + 'px';
// 显示对齐辅助线
// 显示对齐辅助线(网格线已在 getSnapPosition 中显示)
if (snapped.showGuide) {
showAlignmentGuides(element);
} else {
hideGuides();
}
}
@@ -1217,11 +1216,16 @@
const cCenterX = cWidth / 2;
const cCenterY = cHeight / 2;
const threshold = 5;
const threshold = 1;
let snapLeft = newLeft;
let snapTop = newTop;
let showGuide = false;
// 显示网格线
if (gridLines) {
gridLines.classList.add('visible');
}
// 水平垂直分别检测
let snapX = false;
let snapY = false;
@@ -1257,7 +1261,7 @@
}
// 检测其他元素对齐(输入框和层叠图)
const otherInputs = [input1, input2].filter(el => el && el !== draggedEl);
const otherInputs = [input1, input2, input3].filter(el => el && el !== draggedEl);
const otherOverlays = Array.from(overlayLayer.querySelectorAll('.overlay-image'))
.filter(el => el !== draggedEl);
@@ -1420,7 +1424,7 @@
const elCenterX = elLeft + elWidth / 2;
const elCenterY = elTop + elHeight / 2;
const threshold = 5;
const threshold = 1;
let guideHPos = null;
let guideVPos = null;
@@ -1571,6 +1575,9 @@
function hideGuides() {
guideH.classList.remove('visible');
guideV.classList.remove('visible');
if (gridLines) {
gridLines.classList.remove('visible');
}
}
// 取消所有选中
@@ -1738,6 +1745,53 @@
}, { passive: false });
}
// 初始化键盘微调功能(方向键 1px 移动)
function initKeyboardNudge() {
document.addEventListener('keydown', (e) => {
// 如果正在编辑文本,不处理方向键
if (editingInput) return;
// 获取当前选中的元素
const targetEl = selectedInput || selectedOverlay;
if (!targetEl) return;
// 防止默认行为(页面滚动)
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)) {
e.preventDefault();
}
let currentLeft = parseInt(targetEl.style.left) || targetEl.offsetLeft;
let currentTop = parseInt(targetEl.style.top) || targetEl.offsetTop;
switch(e.key) {
case 'ArrowUp':
currentTop -= 1;
break;
case 'ArrowDown':
currentTop += 1;
break;
case 'ArrowLeft':
currentLeft -= 1;
break;
case 'ArrowRight':
currentLeft += 1;
break;
default:
return;
}
// 应用新位置
targetEl.style.left = currentLeft + 'px';
targetEl.style.top = currentTop + 'px';
// 显示对齐辅助线(网格线已在 getSnapPosition 中显示)
const snapped = getSnapPosition(targetEl, currentLeft, currentTop);
if (snapped.showGuide) {
showAlignmentGuides(targetEl);
}
});
}
// 显示右键菜单
function showContextMenu(x, y) {
hideContextMenu();