Compare commits

..

3 Commits

Author SHA1 Message Date
Zhukj
13a282d93a feat(工具栏): 添加水平镜像功能并调整工具栏样式
- 在工具栏添加水平镜像按钮
- 调整工具栏间距和分割线样式
- 实现图片水平镜像功能及状态同步
2026-04-21 18:28:43 +08:00
Zhukj
0665987a03 feat(旋转控制): 为旋转滑块添加吸附功能并固定数值显示宽度
在旋转滑块附近0°、-90°、90°时添加5度的吸附阈值,使操作更精准
为旋转度数和百分比数值显示元素设置固定宽度,保持布局稳定
2026-04-21 16:30:51 +08:00
Zhukj
da2f3cfbff feat: 添加图片旋转功能
- 在工具栏中添加旋转滑块控件
- 实现图片旋转功能及角度显示
- 支持读取和更新当前选中图片的旋转角度
2026-04-21 16:17:14 +08:00
3 changed files with 102 additions and 3 deletions

View File

@@ -158,7 +158,7 @@ html, body {
display: none;
justify-content: center;
align-items: center;
gap: 4px;
gap: 2px;
width: 100%;
}
@@ -193,17 +193,22 @@ html, body {
font-style: italic;
}
/* 镜像按钮样式 */
.toolbar-btn.mirror-btn {
font-size: 18px;
}
.toolbar-divider {
width: 1px;
height: 24px;
background: #ddd;
margin: 0 2px;
margin: 0 1px;
}
.toolbar-label {
display: flex;
align-items: center;
gap: 4px;
gap: 2px;
font-size: 12px;
color: #666;
}
@@ -233,6 +238,28 @@ html, body {
margin: 0;
}
.rotate-slider {
width: 100px;
height: 32px;
cursor: pointer;
accent-color: #4a90e2;
margin: 0;
}
/* 旋转度数显示固定宽度 */
#rotateValue {
display: inline-block;
min-width: 40px;
text-align: center;
}
/* 百分比显示固定宽度 */
#opacityValue, #bgScaleValue, #bgOpacityValue {
display: inline-block;
min-width: 40px;
text-align: center;
}
/* 字号滚轮选择器 */
.roller-picker {
display: flex;

View File

@@ -57,6 +57,14 @@
<input type="range" id="opacitySlider" min="0" max="100" value="100" class="opacity-slider">
<span id="opacityValue">100%</span>
</label>
<div class="toolbar-divider"></div>
<label class="toolbar-label">
<span>旋转</span>
<input type="range" id="rotateSlider" min="-180" max="180" value="0" class="rotate-slider">
<span id="rotateValue">0°</span>
</label>
<div class="toolbar-divider"></div>
<button class="toolbar-btn mirror-btn" id="mirrorHBtn" title="水平镜像">↔</button>
</div>
<!-- 背景图编辑工具 -->
<div class="toolbar-group bg-tools" id="bgTools">

View File

@@ -21,6 +21,9 @@
const bgTools = document.getElementById('bgTools');
const opacitySlider = document.getElementById('opacitySlider');
const opacityValue = document.getElementById('opacityValue');
const rotateSlider = document.getElementById('rotateSlider');
const rotateValue = document.getElementById('rotateValue');
const mirrorHBtn = document.getElementById('mirrorHBtn');
const bgScaleSlider = document.getElementById('bgScaleSlider');
const bgScaleValue = document.getElementById('bgScaleValue');
const bgOpacitySlider = document.getElementById('bgOpacitySlider');
@@ -125,6 +128,53 @@
}
});
// 旋转滑块
rotateSlider.addEventListener('input', (e) => {
if (selectedOverlay) {
let rotateDeg = parseInt(e.target.value);
// 吸附功能:在 0°、-90°、90° 附近吸附
const snapAngles = [0, -90, 90];
const snapThreshold = 5; // 吸附阈值 5 度
for (const snapAngle of snapAngles) {
if (Math.abs(rotateDeg - snapAngle) < snapThreshold) {
rotateDeg = snapAngle;
// 更新滑动条位置
rotateSlider.value = rotateDeg;
break;
}
}
selectedOverlay.style.transform = `rotate(${rotateDeg}deg)`;
rotateValue.textContent = rotateDeg + '°';
}
});
// 水平镜像按钮
mirrorHBtn.addEventListener('click', () => {
if (selectedOverlay) {
const img = selectedOverlay.querySelector('img');
if (img) {
const currentTransform = img.style.transform || '';
const isMirroredH = currentTransform.includes('scaleX(-1)');
// 移除之前的 scaleX 变换
let newTransform = currentTransform.replace(/scaleX\(-?1\)/g, '').trim();
// 如果之前没有水平镜像,则添加
if (!isMirroredH) {
newTransform = newTransform ? newTransform + ' scaleX(-1)' : 'scaleX(-1)';
mirrorHBtn.classList.add('active');
} else {
mirrorHBtn.classList.remove('active');
}
img.style.transform = newTransform;
}
}
});
// 背景图缩放滑块
bgScaleSlider.addEventListener('input', (e) => {
bgImageScale = e.target.value / 100;
@@ -622,6 +672,20 @@
const currentOpacity = overlayEl.style.opacity || '1';
opacitySlider.value = parseFloat(currentOpacity) * 100;
opacityValue.textContent = opacitySlider.value + '%';
// 更新旋转滑块为当前层叠图的旋转角度
const currentTransform = overlayEl.style.transform || '';
const rotateMatch = currentTransform.match(/rotate\(([-\d.]+)deg\)/);
const currentRotate = rotateMatch ? parseFloat(rotateMatch[1]) : 0;
rotateSlider.value = currentRotate;
rotateValue.textContent = currentRotate + '°';
// 更新镜像按钮状态
const img = overlayEl.querySelector('img');
if (img) {
const imgTransform = img.style.transform || '';
mirrorHBtn.classList.toggle('active', imgTransform.includes('scaleX(-1)'));
}
}
// 计算图片滑动边界