feat: 背景图新增缩放+透明度编辑,三图文共用统一切换工具栏
This commit is contained in:
175
js/script.js
175
js/script.js
@@ -17,8 +17,13 @@
|
||||
const editorToolbar = document.getElementById('editorToolbar');
|
||||
const textTools = document.getElementById('textTools');
|
||||
const imageTools = document.getElementById('imageTools');
|
||||
const bgTools = document.getElementById('bgTools');
|
||||
const opacitySlider = document.getElementById('opacitySlider');
|
||||
const opacityValue = document.getElementById('opacityValue');
|
||||
const bgScaleSlider = document.getElementById('bgScaleSlider');
|
||||
const bgScaleValue = document.getElementById('bgScaleValue');
|
||||
const bgOpacitySlider = document.getElementById('bgOpacitySlider');
|
||||
const bgOpacityValue = document.getElementById('bgOpacityValue');
|
||||
const boldBtn = document.getElementById('boldBtn');
|
||||
const italicBtn = document.getElementById('italicBtn');
|
||||
const colorPicker = document.getElementById('colorPicker');
|
||||
@@ -34,6 +39,8 @@
|
||||
const guideV = document.getElementById('guideV');
|
||||
|
||||
let currentImage = null;
|
||||
let bgImageScale = 1;
|
||||
let bgImageOpacity = 1;
|
||||
let selectedInput = null;
|
||||
let editingInput = null;
|
||||
let longPressTimer = null;
|
||||
@@ -45,6 +52,7 @@
|
||||
let imageStartOffsetX = 0;
|
||||
let minOffsetX = 0;
|
||||
let maxOffsetX = 0;
|
||||
let isInteractingWithBgImage = false;
|
||||
|
||||
// 初始化
|
||||
init();
|
||||
@@ -113,6 +121,20 @@
|
||||
}
|
||||
});
|
||||
|
||||
// 背景图缩放滑块
|
||||
bgScaleSlider.addEventListener('input', (e) => {
|
||||
bgImageScale = e.target.value / 100;
|
||||
bgScaleValue.textContent = e.target.value + '%';
|
||||
updateBgImage();
|
||||
});
|
||||
|
||||
// 背景图透明度滑块
|
||||
bgOpacitySlider.addEventListener('input', (e) => {
|
||||
bgImageOpacity = e.target.value / 100;
|
||||
bgOpacityValue.textContent = e.target.value + '%';
|
||||
bgImage.style.opacity = bgImageOpacity;
|
||||
});
|
||||
|
||||
// 点击空白区域取消选中
|
||||
document.addEventListener('click', (e) => {
|
||||
// 只有点击真正的空白区域(不是输入框,不是图片容器,不是工具栏)才取消选中
|
||||
@@ -128,6 +150,10 @@
|
||||
|
||||
// 点击容器空白处取消选中
|
||||
function handleContainerClick(e) {
|
||||
if (isInteractingWithBgImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isBackground = e.target === imageContainer ||
|
||||
e.target === bgLayer ||
|
||||
e.target === bgImage ||
|
||||
@@ -202,7 +228,15 @@
|
||||
calculateImageBounds();
|
||||
// 背景图选择后默认居中显示
|
||||
imageOffsetX = 0;
|
||||
updateImagePosition();
|
||||
// 重置缩放
|
||||
bgImageScale = 1;
|
||||
bgScaleSlider.value = 100;
|
||||
bgScaleValue.textContent = '100%';
|
||||
// 重置透明度
|
||||
bgImageOpacity = 1;
|
||||
bgOpacitySlider.value = 100;
|
||||
bgOpacityValue.textContent = '100%';
|
||||
updateBgImage();
|
||||
};
|
||||
img.src = e.target.result;
|
||||
};
|
||||
@@ -523,6 +557,7 @@
|
||||
editorToolbar.classList.add('active');
|
||||
textTools.classList.remove('active');
|
||||
imageTools.classList.add('active');
|
||||
bgTools.classList.remove('active');
|
||||
|
||||
// 更新透明度滑块为当前层叠图的透明度
|
||||
const currentOpacity = overlayEl.style.opacity || '1';
|
||||
@@ -569,13 +604,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 更新图片位置
|
||||
function updateImagePosition() {
|
||||
// 更新背景图(缩放和透明度)
|
||||
function updateBgImage() {
|
||||
if (!currentImage) return;
|
||||
|
||||
// 限制滑动范围,确保不露出白板
|
||||
imageOffsetX = Math.max(minOffsetX, Math.min(maxOffsetX, imageOffsetX));
|
||||
|
||||
const containerWidth = imageContainer.clientWidth;
|
||||
const containerHeight = imageContainer.clientHeight;
|
||||
const imgRatio = currentImage.naturalWidth / currentImage.naturalHeight;
|
||||
@@ -591,11 +623,71 @@
|
||||
imgHeight = imgWidth / imgRatio;
|
||||
}
|
||||
|
||||
// 应用位置
|
||||
const baseLeft = (containerWidth - imgWidth) / 2;
|
||||
bgImage.style.width = imgWidth + 'px';
|
||||
bgImage.style.height = imgHeight + 'px';
|
||||
// 应用缩放
|
||||
bgImage.style.width = (imgWidth * bgImageScale) + 'px';
|
||||
bgImage.style.height = (imgHeight * bgImageScale) + 'px';
|
||||
|
||||
// 应用透明度
|
||||
bgImage.style.opacity = bgImageOpacity;
|
||||
|
||||
// 重新计算边界
|
||||
const scaledWidth = imgWidth * bgImageScale;
|
||||
const scaledHeight = imgHeight * bgImageScale;
|
||||
if (scaledWidth > containerWidth) {
|
||||
minOffsetX = -(scaledWidth - containerWidth) / 2;
|
||||
maxOffsetX = (scaledWidth - containerWidth) / 2;
|
||||
} else {
|
||||
minOffsetX = 0;
|
||||
maxOffsetX = 0;
|
||||
}
|
||||
// 限制当前位置在新范围内
|
||||
imageOffsetX = Math.max(minOffsetX, Math.min(maxOffsetX, imageOffsetX));
|
||||
|
||||
// 重新应用位置(居中 + 偏移)
|
||||
const baseLeft = (containerWidth - scaledWidth) / 2;
|
||||
bgImage.style.left = (baseLeft + imageOffsetX) + 'px';
|
||||
bgImage.style.top = ((containerHeight - scaledHeight) / 2) + 'px';
|
||||
}
|
||||
|
||||
// 更新图片位置
|
||||
function updateImagePosition() {
|
||||
if (!currentImage) return;
|
||||
|
||||
const containerWidth = imageContainer.clientWidth;
|
||||
const containerHeight = imageContainer.clientHeight;
|
||||
const imgRatio = currentImage.naturalWidth / currentImage.naturalHeight;
|
||||
|
||||
let imgWidth, imgHeight;
|
||||
|
||||
if (imgRatio > containerWidth / containerHeight) {
|
||||
imgHeight = containerHeight;
|
||||
imgWidth = imgHeight * imgRatio;
|
||||
} else {
|
||||
imgWidth = containerWidth;
|
||||
imgHeight = imgWidth / imgRatio;
|
||||
}
|
||||
|
||||
// 应用缩放
|
||||
const scaledWidth = imgWidth * bgImageScale;
|
||||
const scaledHeight = imgHeight * bgImageScale;
|
||||
|
||||
// 限制滑动范围
|
||||
if (scaledWidth > containerWidth) {
|
||||
minOffsetX = -(scaledWidth - containerWidth) / 2;
|
||||
maxOffsetX = (scaledWidth - containerWidth) / 2;
|
||||
} else {
|
||||
minOffsetX = 0;
|
||||
maxOffsetX = 0;
|
||||
}
|
||||
imageOffsetX = Math.max(minOffsetX, Math.min(maxOffsetX, imageOffsetX));
|
||||
|
||||
// 应用位置
|
||||
const baseLeft = (containerWidth - scaledWidth) / 2;
|
||||
bgImage.style.width = scaledWidth + 'px';
|
||||
bgImage.style.height = scaledHeight + 'px';
|
||||
bgImage.style.left = (baseLeft + imageOffsetX) + 'px';
|
||||
bgImage.style.top = ((containerHeight - scaledHeight) / 2) + 'px';
|
||||
bgImage.style.opacity = bgImageOpacity;
|
||||
bgImage.style.transform = 'none';
|
||||
}
|
||||
|
||||
@@ -613,6 +705,53 @@
|
||||
document.addEventListener('mouseup', handleImageEnd);
|
||||
document.addEventListener('touchend', handleImageEnd);
|
||||
|
||||
// 点击背景图显示工具栏
|
||||
bgImage.addEventListener('click', (e) => {
|
||||
if (!currentImage) return;
|
||||
e.stopPropagation();
|
||||
|
||||
isInteractingWithBgImage = true;
|
||||
|
||||
// 显示背景图工具栏
|
||||
editorToolbar.classList.add('active');
|
||||
textTools.classList.remove('active');
|
||||
imageTools.classList.remove('active');
|
||||
bgTools.classList.add('active');
|
||||
|
||||
// 同步滑块值
|
||||
bgScaleSlider.value = bgImageScale * 100;
|
||||
bgScaleValue.textContent = Math.round(bgImageScale * 100) + '%';
|
||||
bgOpacitySlider.value = bgImageOpacity * 100;
|
||||
bgOpacityValue.textContent = Math.round(bgImageOpacity * 100) + '%';
|
||||
|
||||
setTimeout(() => {
|
||||
isInteractingWithBgImage = false;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
bgLayer.addEventListener('click', (e) => {
|
||||
if (!currentImage) return;
|
||||
e.stopPropagation();
|
||||
|
||||
isInteractingWithBgImage = true;
|
||||
|
||||
// 显示背景图工具栏
|
||||
editorToolbar.classList.add('active');
|
||||
textTools.classList.remove('active');
|
||||
imageTools.classList.remove('active');
|
||||
bgTools.classList.add('active');
|
||||
|
||||
// 同步滑块值
|
||||
bgScaleSlider.value = bgImageScale * 100;
|
||||
bgScaleValue.textContent = Math.round(bgImageScale * 100) + '%';
|
||||
bgOpacitySlider.value = bgImageOpacity * 100;
|
||||
bgOpacityValue.textContent = Math.round(bgImageOpacity * 100) + '%';
|
||||
|
||||
setTimeout(() => {
|
||||
isInteractingWithBgImage = false;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
function handleImageStart(e) {
|
||||
// 如果点击的是输入框,不处理图片滑动
|
||||
if (e.target.closest('.text-input')) {
|
||||
@@ -642,9 +781,22 @@
|
||||
}
|
||||
|
||||
isDraggingImage = true;
|
||||
isInteractingWithBgImage = true;
|
||||
imageStartX = clientX;
|
||||
imageStartOffsetX = imageOffsetX;
|
||||
|
||||
// 显示背景图工具栏
|
||||
editorToolbar.classList.add('active');
|
||||
textTools.classList.remove('active');
|
||||
imageTools.classList.remove('active');
|
||||
bgTools.classList.add('active');
|
||||
|
||||
// 同步滑块值
|
||||
bgScaleSlider.value = bgImageScale * 100;
|
||||
bgScaleValue.textContent = Math.round(bgImageScale * 100) + '%';
|
||||
bgOpacitySlider.value = bgImageOpacity * 100;
|
||||
bgOpacityValue.textContent = Math.round(bgImageOpacity * 100) + '%';
|
||||
|
||||
if (isTouch) {
|
||||
e.preventDefault();
|
||||
}
|
||||
@@ -670,6 +822,7 @@
|
||||
|
||||
function handleImageEnd() {
|
||||
isDraggingImage = false;
|
||||
isInteractingWithBgImage = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -863,6 +1016,7 @@
|
||||
editorToolbar.classList.add('active');
|
||||
textTools.classList.add('active');
|
||||
imageTools.classList.remove('active');
|
||||
bgTools.classList.remove('active');
|
||||
|
||||
// 更新工具栏状态
|
||||
updateToolbarState(element);
|
||||
@@ -885,6 +1039,7 @@
|
||||
editorToolbar.classList.add('active');
|
||||
textTools.classList.add('active');
|
||||
imageTools.classList.remove('active');
|
||||
bgTools.classList.remove('active');
|
||||
|
||||
// 更新工具栏状态
|
||||
updateToolbarState(element);
|
||||
|
||||
Reference in New Issue
Block a user