Spaces:
Paused
Paused
| // راهاندازی اولیه و هندلرهای رویداد اصلی | |
| window.onload = function() { | |
| startAnim('#animPreviewStatic'); | |
| initDB().then(() => { | |
| loadHome(); | |
| }); | |
| syncModeButtons(); | |
| const timeline = document.getElementById('timelineScroll'); | |
| timeline.addEventListener('touchstart', () => { v.pause(); togglePlayIcon(false); }, {passive: true}); | |
| timeline.addEventListener('mousedown', () => { v.pause(); togglePlayIcon(false); }); | |
| // هماهنگسازی حرکت انیمیشن ویژوالایزرها با وضعیت پخش و توقف ویدیو | |
| v.addEventListener('play', () => { | |
| const vBars = tEl.querySelectorAll('.v-bar'); | |
| vBars.forEach(b => b.style.animationPlayState = 'running'); | |
| }); | |
| v.addEventListener('pause', () => { | |
| const vBars = tEl.querySelectorAll('.v-bar'); | |
| vBars.forEach(b => b.style.animationPlayState = 'paused'); | |
| }); | |
| }; | |
| window.onresize = fit; | |
| // --- موتور زمانسنج هوشمند (High-Precision Sync) جایگزین v.ontimeupdate --- | |
| function runFastSync() { | |
| // فقط وقتی ویدیو در حال پخش است یا دستی جابجا میشود اجرا شود | |
| if (!v.paused || manualOverride) { | |
| const cur = v.currentTime; | |
| const timeDisplay = document.getElementById('globalTimeDisplay'); | |
| if (timeDisplay) { | |
| timeDisplay.innerText = `${formatTimeSimple(cur)} / ${formatTimeSimple(v.duration || 0)}`; | |
| } | |
| if (!v.paused) manualOverride = false; | |
| let foundWord = false; | |
| // اضافه کردن 0.1 ثانیه تلورانس برای دیده شدن کلمات آخر جمله | |
| for (let s = 0; s < state.segs.length; s++) { | |
| const seg = state.segs[s]; | |
| if (cur >= seg.start && cur < (seg.end + 0.1)) { | |
| if (seg.words) { | |
| for (let w = 0; w < seg.words.length; w++) { | |
| const word = seg.words[w]; | |
| // بررسی فعال بودن کلمه با دقت بالا و تلورانس شروع و پایان | |
| if (cur >= (word.start - 0.02) && cur < (word.end + 0.05)) { | |
| const uid = `${s}-${w}`; | |
| if (activeWordId !== uid) { | |
| activeWordId = uid; | |
| document.querySelectorAll('.word-chip').forEach(c => c.classList.remove('active')); | |
| const el = document.getElementById(`w-${uid}`); | |
| if(el) { | |
| el.classList.add('active'); | |
| if(!manualOverride) el.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); | |
| } | |
| updateSplitButton(); | |
| } | |
| foundWord = true; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| if (foundWord) break; | |
| } | |
| if (!foundWord && !manualOverride) { | |
| document.querySelectorAll('.word-chip').forEach(c => c.classList.remove('active')); | |
| activeWordId = null; | |
| const toolbar = document.getElementById('toolbar'); | |
| if (toolbar) toolbar.classList.remove('show'); | |
| } | |
| updateOverlayContent(cur); | |
| } | |
| // تکرار مداوم برای دقت ۶۰ فریم در ثانیه | |
| requestAnimationFrame(runFastSync); | |
| } | |
| // شروع به کار موتور همزمان با لود شدن صفحه | |
| requestAnimationFrame(runFastSync); | |
| // --- سیستم لمسی --- | |
| tEl.addEventListener('touchstart', (e) => { | |
| if(e.touches.length === 1) { | |
| // Drag | |
| touchMode = 'drag'; | |
| initialY = e.touches[0].clientY; | |
| initialX = e.touches[0].clientX; | |
| initialBottom = state.st.y; | |
| initialXState = state.st.x || 0; | |
| } else if (e.touches.length === 2) { | |
| // Pinch (Zoom) | |
| touchMode = 'pinch'; | |
| initialDist = Math.hypot(e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY); | |
| initialFontSize = state.st.fz; | |
| } | |
| }, {passive: false}); | |
| tEl.addEventListener('touchmove', (e) => { | |
| if (!touchMode) return; | |
| e.preventDefault(); | |
| if (touchMode === 'drag' && e.touches.length === 1) { | |
| let diffY = (initialY - e.touches[0].clientY) * 1.8; | |
| let newBottom = initialBottom + diffY; | |
| state.st.y = Math.round(newBottom); | |
| let diffX = (e.touches[0].clientX - initialX) * 1.5; | |
| let newX = initialXState + diffX; | |
| state.st.x = Math.round(newX); | |
| syncUIWithState(); | |
| upd(); | |
| } else if (touchMode === 'pinch' && e.touches.length === 2) { | |
| let dist = Math.hypot(e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY); | |
| let newSize = initialFontSize * (dist / initialDist); | |
| state.st.fz = Math.round(Math.max(10, Math.min(150, newSize))); | |
| syncUIWithState(); | |
| upd(); | |
| } | |
| }, {passive: false}); | |
| tEl.addEventListener('touchend', () => { | |
| touchMode = null; | |
| saveProjectToDB(); | |
| }); |