From cfbebfef6cda9905b0547887e5342cd9e2605eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9C=9F=E7=8B=97?= <9944191+song2770@user.noreply.gitee.com> Date: Tue, 10 Jun 2025 15:15:27 +0800 Subject: [PATCH] add reline can be moved --- js/draggable-line.js | 142 +++++++++++++++++++++++++++++++++++++++++++ js/main.js | 4 +- styles/main.css | 14 ++++- 3 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 js/draggable-line.js diff --git a/js/draggable-line.js b/js/draggable-line.js new file mode 100644 index 0000000..b53897f --- /dev/null +++ b/js/draggable-line.js @@ -0,0 +1,142 @@ +export class DraggableLine { + constructor() { + this.readingLine = document.getElementById('readingLine'); + this.isDragging = false; + this.startY = 0; + this.startTop = 0; + this.defaultPosition = 25; // 默认位置25% + + this.init(); + } + + init() { + if (!this.readingLine) return; + + // 绑定事件 + this.readingLine.addEventListener('mousedown', this.onMouseDown.bind(this)); + document.addEventListener('mousemove', this.onMouseMove.bind(this)); + document.addEventListener('mouseup', this.onMouseUp.bind(this)); + + // 触摸事件支持 + this.readingLine.addEventListener('touchstart', this.onTouchStart.bind(this)); + document.addEventListener('touchmove', this.onTouchMove.bind(this)); + document.addEventListener('touchend', this.onTouchEnd.bind(this)); + + // 双击重置位置 + this.readingLine.addEventListener('dblclick', this.resetPosition.bind(this)); + } + + onMouseDown(e) { + e.preventDefault(); + this.startDrag(e.clientY); + } + + onTouchStart(e) { + e.preventDefault(); + this.startDrag(e.touches[0].clientY); + } + + startDrag(clientY) { + this.isDragging = true; + this.startY = clientY; + + // 获取当前top值(百分比) + const computedStyle = window.getComputedStyle(this.readingLine); + const currentTop = computedStyle.top; + if (currentTop.includes('%')) { + this.startTop = parseFloat(currentTop); + } else { + // 如果是像素值,转换为百分比 + const topPx = parseFloat(currentTop); + this.startTop = (topPx / window.innerHeight) * 100; + } + + this.readingLine.classList.add('dragging'); + document.body.style.userSelect = 'none'; + } + + onMouseMove(e) { + if (!this.isDragging) return; + this.updatePosition(e.clientY); + } + + onTouchMove(e) { + if (!this.isDragging) return; + e.preventDefault(); + this.updatePosition(e.touches[0].clientY); + } + + updatePosition(clientY) { + const deltaY = clientY - this.startY; + const deltaPercent = (deltaY / window.innerHeight) * 100; + let newTop = this.startTop + deltaPercent; + + // 限制范围在5%到95%之间 + newTop = Math.max(5, Math.min(95, newTop)); + + this.readingLine.style.top = newTop + '%'; + } + + onMouseUp() { + this.endDrag(); + } + + onTouchEnd() { + this.endDrag(); + } + + endDrag() { + if (!this.isDragging) return; + + this.isDragging = false; + this.readingLine.classList.remove('dragging'); + document.body.style.userSelect = ''; + + // 保存当前位置 + this.savePosition(); + } + + resetPosition() { + this.readingLine.style.top = this.defaultPosition + '%'; + this.savePosition(); + } + + savePosition() { + // 保存位置到localStorage + const currentTop = window.getComputedStyle(this.readingLine).top; + let topPercent; + if (currentTop.includes('%')) { + topPercent = parseFloat(currentTop); + } else { + const topPx = parseFloat(currentTop); + topPercent = (topPx / window.innerHeight) * 100; + } + localStorage.setItem('readingLinePosition', topPercent.toString()); + } + + loadPosition() { + // 从localStorage加载位置 + const savedPosition = localStorage.getItem('readingLinePosition'); + if (savedPosition) { + const position = parseFloat(savedPosition); + if (position >= 5 && position <= 95) { + this.readingLine.style.top = position + '%'; + return; + } + } + // 如果没有保存的位置或位置无效,使用默认位置 + this.readingLine.style.top = this.defaultPosition + '%'; + } + + getCurrentPosition() { + const currentTop = window.getComputedStyle(this.readingLine).top; + if (currentTop.includes('%')) { + return parseFloat(currentTop); + } else { + const topPx = parseFloat(currentTop); + return (topPx / window.innerHeight) * 100; + } + } +} + +// 模块已在main.js中统一初始化 \ No newline at end of file diff --git a/js/main.js b/js/main.js index bdffccc..7ea7b75 100644 --- a/js/main.js +++ b/js/main.js @@ -6,7 +6,7 @@ import { AudioController } from './audio.js'; import { SettingsController } from './settings.js'; import { WatermarkController } from './watermark.js'; import { FlipController } from './flip.js'; -import { defaultText } from './defaultText.js'; +import { DraggableLine } from './draggable-line.js'; // 主应用程序入口 class TeleprompterApp { @@ -31,6 +31,8 @@ class TeleprompterApp { window.settingsController = new SettingsController(); window.watermarkController = new WatermarkController(); window.flipController = new FlipController(); + window.draggableLine = new DraggableLine(); + window.draggableLine.loadPosition(); this.setupEventListeners(); this.loadDefaultText(); diff --git a/styles/main.css b/styles/main.css index cead1d7..de8ba75 100644 --- a/styles/main.css +++ b/styles/main.css @@ -81,10 +81,22 @@ body { left: 0; right: 0; height: 4px; - background: linear-gradient(to right, transparent 0%, #ff4444 10%, #ff4444 95%, transparent 100%); + background: linear-gradient(to right, transparent 0%, #ff4444 15%, #ff4444 90%, transparent 100%); z-index: 500; box-shadow: 0 0 40px rgba(255, 68, 68, 0.9); transition: opacity 0.3s ease; + cursor: ns-resize; + padding: 1px 0; +} + +.reading-line:hover { + box-shadow: 0 0 60px rgba(255, 68, 68, 1); + transform: all 0.3s ease; +} + +.reading-line.dragging { + transition: none; + box-shadow: 0 0 80px rgba(255, 68, 68, 1); } /* 主内容区域 */