fix:校准画布编辑与图片导出文字水平垂直位置偏移问题,修改屏幕尺寸为960x1361像素

This commit is contained in:
Zhukj
2026-04-20 10:16:25 +08:00
parent 2afee798f8
commit c93dd4c304
3 changed files with 74 additions and 50 deletions

View File

@@ -864,8 +864,10 @@
startX = clientX;
startY = clientY;
startLeft = element.offsetLeft;
startTop = element.offsetTop;
const containerRect = imageContainer.getBoundingClientRect();
const elemRect = element.getBoundingClientRect();
startLeft = elemRect.left - containerRect.left;
startTop = elemRect.top - containerRect.top;
// 延迟判断是否为拖拽
dragTimer = setTimeout(() => {
@@ -1782,31 +1784,27 @@
}
}
// 生成画布(预览与保存样式一致)
// 生成画布(所见即所得 - 使用显示尺寸)
async function generateCanvas() {
const canvas = exportCanvas;
const ctx = canvas.getContext('2d');
const container = imageContainer;
const containerWidth = container.clientWidth;
const containerHeight = container.clientHeight;
const width = container.clientWidth;
const height = container.clientHeight;
canvas.width = containerWidth;
canvas.height = containerHeight;
canvas.width = width;
canvas.height = height;
// 绘制白色背景
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(0, 0, width, height);
// 绘制背景图(考虑滑动偏移)
if (currentImage) {
drawImageWithOffset(ctx, currentImage, containerWidth, containerHeight);
drawBgImageOnCanvas(ctx, currentImage, width, height);
}
// 绘制层叠图(等待图片加载完成)
await drawOverlayImages(ctx);
// 绘制文字(动态获取所有文本输入框)
const textInputs = container.querySelectorAll('.preview-input-layer .text-input');
textInputs.forEach(textInput => {
drawTextOnCanvas(ctx, textInput);
@@ -1815,6 +1813,38 @@
return canvas;
}
// 绘制背景图
function drawBgImageOnCanvas(ctx, img, width, height) {
// 使用与编辑时完全相同的计算逻辑
const containerWidth = width;
const containerHeight = height;
const imgRatio = img.naturalWidth / img.naturalHeight;
const containerRatio = containerWidth / containerHeight;
let imgWidth, imgHeight;
if (imgRatio > containerRatio) {
imgHeight = containerHeight;
imgWidth = imgHeight * imgRatio;
} else {
imgWidth = containerWidth;
imgHeight = imgWidth / imgRatio;
}
// 应用缩放
const scaledWidth = imgWidth * bgImageScale;
const scaledHeight = imgHeight * bgImageScale;
// 计算位置(与 updateBgImage 函数完全一致)
const baseLeft = (containerWidth - scaledWidth) / 2;
const drawX = baseLeft + imageOffsetX;
const drawY = (containerHeight - scaledHeight) / 2;
ctx.globalAlpha = bgImageOpacity;
ctx.drawImage(img, drawX, drawY, scaledWidth, scaledHeight);
ctx.globalAlpha = 1;
}
// 绘制层叠图
function drawOverlayImages(ctx) {
return new Promise((resolve) => {
@@ -1832,20 +1862,25 @@
return;
}
// 使用 offsetLeft/offsetTop 获取相对于 overlayLayer 的位置
const left = overlayEl.offsetLeft;
const top = overlayEl.offsetTop;
const width = overlayEl.offsetWidth;
const height = overlayEl.offsetHeight;
ctx.globalAlpha = overlayEl.style.opacity || 1;
const img = new Image();
img.onload = () => {
ctx.drawImage(img, left, top, width, height);
ctx.globalAlpha = 1;
loadedCount++;
if (loadedCount >= overlayImages.length) {
resolve();
}
};
img.onerror = () => {
ctx.globalAlpha = 1;
loadedCount++;
if (loadedCount >= overlayImages.length) {
resolve();
@@ -1856,42 +1891,33 @@
});
}
// 绘制图片(考虑滑动偏移)
function drawImageWithOffset(ctx, img, containerWidth, containerHeight) {
const imgRatio = img.naturalWidth / img.naturalHeight;
const containerRatio = containerWidth / containerHeight;
let imgWidth, imgHeight;
if (imgRatio > containerRatio) {
imgHeight = containerHeight;
imgWidth = imgHeight * imgRatio;
} else {
imgWidth = containerWidth;
imgHeight = imgWidth / imgRatio;
}
const baseLeft = (containerWidth - imgWidth) / 2;
const drawX = baseLeft + imageOffsetX;
ctx.drawImage(img, drawX, 0, imgWidth, imgHeight);
}
// 在画布上绘制文字
function drawTextOnCanvas(ctx, inputElement) {
const text = inputElement.textContent;
if (!text) return;
const deleteBtn = inputElement.querySelector('.text-delete-btn');
let text = inputElement.textContent;
if (deleteBtn) {
text = text.replace(deleteBtn.textContent, '');
}
if (!text.trim()) return;
const style = window.getComputedStyle(inputElement);
// 使用 offsetLeft/offsetTop 获取相对于 preview-input-layer 的位置
const inputLeft = inputElement.offsetLeft;
const inputTop = inputElement.offsetTop;
const style = window.getComputedStyle(inputElement);
const fontSize = parseInt(style.fontSize);
const lineHeight = parseFloat(style.lineHeight);
ctx.font = `${style.fontWeight} ${fontSize}px ${style.fontFamily}`;
ctx.fillStyle = style.color;
ctx.textBaseline = 'top';
ctx.textBaseline = 'alphabetic';
ctx.fillText(text, inputLeft, inputTop);
// 计算文本垂直偏移量,使其与 DOM 渲染一致
// DOM 中 line-height 会影响文本位置,需要计算实际文本基线位置
const actualLineHeight = lineHeight || fontSize * 1.4;
const textOffsetY = (actualLineHeight - fontSize) / 2 + fontSize * 0.85;
ctx.fillText(text, inputLeft, inputTop + textOffsetY);
}
// 保存图片