File manager - Edit - /home/webapp69.cm.in.th/u69319090041/portfolio/script.js
Back
/* ───────────────────────────────────────────────────────────── PETCH PORTFOLIO — SCRIPT.JS Entry Effects, Particle Canvas, Matrix, Animations ───────────────────────────────────────────────────────────── */ /* ══ Matrix Rain (Entry Screen) ════════════════════════════ */ (function initMatrix() { const canvas = document.getElementById('matrix-canvas'); if (!canvas) return; const ctx = canvas.getContext('2d'); function resize() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } resize(); window.addEventListener('resize', resize); const chars = 'アイウエオカキクケコサシスセソABCDEFGHIJKLMN0123456789<>{}[]();=+-*/'; const fontSize = 13; let cols = Math.floor(canvas.width / fontSize); let drops = Array(cols).fill(1); function drawMatrix() { ctx.fillStyle = 'rgba(5,5,16,0.05)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#00d4ff'; ctx.font = `${fontSize}px monospace`; drops.forEach((y, i) => { const char = chars[Math.floor(Math.random() * chars.length)]; ctx.fillStyle = y < 5 ? 'rgba(255,255,255,0.9)' : `rgba(0,212,255,${Math.random() * 0.5 + 0.1})`; ctx.fillText(char, i * fontSize, y * fontSize); if (y * fontSize > canvas.height && Math.random() > 0.975) drops[i] = 0; drops[i]++; }); } let matrixInterval = setInterval(drawMatrix, 40); // Resize fix window.addEventListener('resize', () => { cols = Math.floor(canvas.width / fontSize); drops = Array(cols).fill(1); }); window._stopMatrix = () => clearInterval(matrixInterval); })(); /* ══ Entry → Portfolio Transition ══════════════════════════ */ function enterPortfolio() { const entry = document.getElementById('entry-screen'); const overlay = document.getElementById('transition-overlay'); const portfolio = document.getElementById('portfolio'); const btn = document.getElementById('enter-btn'); btn.disabled = true; btn.querySelector('.btn-text').innerHTML = `<span style="font-size:0.8rem;letter-spacing:2px">LOADING...</span>`; // Phase 1: Show overlay overlay.classList.add('active'); setTimeout(() => { // Phase 2: Fade out entry entry.style.transition = 'opacity 0.5s ease, transform 0.5s ease'; entry.style.opacity = '0'; entry.style.transform = 'scale(1.05)'; }, 400); setTimeout(() => { // Phase 3: Show portfolio entry.style.display = 'none'; portfolio.classList.remove('hidden'); portfolio.style.display = 'block'; // Stop matrix to save resources if (window._stopMatrix) window._stopMatrix(); requestAnimationFrame(() => { setTimeout(() => { overlay.classList.remove('active'); portfolio.classList.add('show'); initParticles(); initTyped(); initScrollReveal(); initNavbar(); initSkillBars(); }, 100); }); }, 900); } /* ══ Particles Background (Hero) ═══════════════════════════ */ function initParticles() { const canvas = document.getElementById('particles-canvas'); if (!canvas) return; const ctx = canvas.getContext('2d'); function resize() { canvas.width = canvas.offsetWidth; canvas.height = canvas.offsetHeight; } resize(); const count = window.innerWidth < 768 ? 40 : 80; const particles = Array.from({ length: count }, () => ({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, vx: (Math.random() - 0.5) * 0.4, vy: (Math.random() - 0.5) * 0.4, r: Math.random() * 1.5 + 0.5, alpha: Math.random() * 0.5 + 0.2, })); function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); // Connections particles.forEach((p, i) => { particles.slice(i + 1).forEach(q => { const dist = Math.hypot(p.x - q.x, p.y - q.y); if (dist < 120) { ctx.strokeStyle = `rgba(0,212,255,${0.15 * (1 - dist / 120)})`; ctx.lineWidth = 0.5; ctx.beginPath(); ctx.moveTo(p.x, p.y); ctx.lineTo(q.x, q.y); ctx.stroke(); } }); }); // Dots particles.forEach(p => { ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2); ctx.fillStyle = `rgba(0,212,255,${p.alpha})`; ctx.fill(); p.x += p.vx; p.y += p.vy; if (p.x < 0 || p.x > canvas.width) p.vx *= -1; if (p.y < 0 || p.y > canvas.height) p.vy *= -1; }); requestAnimationFrame(draw); } draw(); window.addEventListener('resize', () => { resize(); }); } /* ══ Typed Text Effect ══════════════════════════════════════ */ function initTyped() { const el = document.getElementById('typed-role'); if (!el) return; const roles = [ 'Digital Creative', 'Tech Enthusiast', 'Content Creator', 'Future Developer', 'Gamer & Designer', ]; let rIdx = 0, cIdx = 0, deleting = false; function type() { const current = roles[rIdx]; el.textContent = deleting ? current.substring(0, cIdx - 1) : current.substring(0, cIdx + 1); deleting ? cIdx-- : cIdx++; let delay = deleting ? 60 : 100; if (!deleting && cIdx === current.length) { delay = 1800; deleting = true; } else if (deleting && cIdx === 0) { deleting = false; rIdx = (rIdx + 1) % roles.length; delay = 400; } setTimeout(type, delay); } type(); } /* ══ Scroll Reveal ══════════════════════════════════════════ */ function initScrollReveal() { const obs = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('visible'); obs.unobserve(e.target); } }); }, { threshold: 0.12 }); document.querySelectorAll('.reveal').forEach(el => obs.observe(el)); } /* ══ Skill Bar Animations ═══════════════════════════════════ */ function initSkillBars() { const obs = new IntersectionObserver((entries) => { entries.forEach(e => { if (e.isIntersecting) { e.target.querySelectorAll('.skill-bar-fill').forEach(bar => { const w = bar.dataset.width; setTimeout(() => { bar.style.width = w + '%'; }, 300); }); obs.unobserve(e.target); } }); }, { threshold: 0.3 }); document.querySelectorAll('.skill-category').forEach(el => obs.observe(el)); } /* ══ Navbar ═════════════════════════════════════════════════ */ function initNavbar() { const navbar = document.getElementById('navbar'); const links = document.querySelectorAll('.nav-link'); window.addEventListener('scroll', () => { navbar.classList.toggle('scrolled', window.scrollY > 50); updateActiveNav(); }); // Smooth scroll for anchor links links.forEach(link => { link.addEventListener('click', (e) => { const href = link.getAttribute('href'); if (href && href.startsWith('#')) { e.preventDefault(); const target = document.querySelector(href); if (target) { target.scrollIntoView({ behavior: 'smooth' }); // close mobile menu document.getElementById('nav-links').classList.remove('open'); } } }); }); } function updateActiveNav() { const sections = document.querySelectorAll('section[id]'); const navLinks = document.querySelectorAll('.nav-link'); let current = ''; sections.forEach(sec => { if (window.scrollY >= sec.offsetTop - 100) current = sec.id; }); navLinks.forEach(link => { link.classList.remove('active'); if (link.dataset.section === current) link.classList.add('active'); }); } function toggleMenu() { const nav = document.getElementById('nav-links'); const btn = document.getElementById('hamburger'); nav.classList.toggle('open'); const spans = btn.querySelectorAll('span'); if (nav.classList.contains('open')) { spans[0].style.transform = 'rotate(45deg) translate(5px,5px)'; spans[1].style.opacity = '0'; spans[2].style.transform = 'rotate(-45deg) translate(5px,-5px)'; } else { spans[0].style.transform = ''; spans[1].style.opacity = ''; spans[2].style.transform = ''; } } /* ══ Contact Form ═══════════════════════════════════════════ */ function handleFormSubmit(e) { e.preventDefault(); const btn = document.getElementById('btn-submit'); const success = document.getElementById('form-success'); const text = btn.querySelector('.submit-text'); text.textContent = 'กำลังส่ง...'; btn.disabled = true; setTimeout(() => { text.textContent = 'ส่งข้อความ 🚀'; btn.disabled = false; success.classList.remove('hidden'); document.getElementById('contact-form').reset(); setTimeout(() => success.classList.add('hidden'), 5000); }, 1500); } /* ══ Keyboard shortcut: Enter key on entry screen ══════════ */ document.addEventListener('keydown', (e) => { if (e.key === 'Enter') { const entryScreen = document.getElementById('entry-screen'); if (entryScreen && entryScreen.style.display !== 'none' && !document.getElementById('entry-screen').classList.contains('hidden')) { enterPortfolio(); } } }); /* ══ Cursor glow effect on hero ════════════════════════════ */ (function initCursorGlow() { document.addEventListener('mousemove', (e) => { const hero = document.getElementById('hero'); if (!hero) return; const rect = hero.getBoundingClientRect(); if (e.clientY < rect.top || e.clientY > rect.bottom) return; hero.style.setProperty('--cursor-x', e.clientX + 'px'); hero.style.setProperty('--cursor-y', (e.clientY - rect.top) + 'px'); }); })();
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0.35 |
proxy
|
phpinfo
|
Settings