|
const getLocalUser = localStorage.getItem("username"); |
|
if (getLocalUser) { |
|
document.getElementById("userProfile").innerHTML = `${getLocalUser}`; |
|
} else { |
|
document.getElementById("userProfile").innerHTML = "User"; |
|
} |
|
|
|
function populateYearDropdown(startYear, endYear) { |
|
const dropdown = document.getElementById('year-filter'); |
|
|
|
|
|
while (dropdown.options.length > 1) { |
|
dropdown.remove(1); |
|
} |
|
|
|
|
|
for (let year = endYear; year >= startYear; year--) { |
|
const option = document.createElement('option'); |
|
option.value = year; |
|
option.textContent = year; |
|
dropdown.appendChild(option); |
|
} |
|
} |
|
|
|
|
|
populateYearDropdown(1900, 2025); |
|
|
|
const profileContainer = document.getElementById("profileContainer"); |
|
const signInBtn = document.getElementById("signInBtn"); |
|
const storedUsername = localStorage.getItem("username"); |
|
const storedUserId = localStorage.getItem("userId") |
|
|
|
if (storedUsername) { |
|
profileContainer.style.display = "flex"; |
|
signInBtn.style.display = "none"; |
|
} else { |
|
profileContainer.style.display = "none"; |
|
signInBtn.style.display = "block"; |
|
} |
|
|
|
|
|
const userProfile = document.getElementById("userProfile"); |
|
const profileDropdown = document.getElementById("profileDropdown"); |
|
const profileOverlay = document.getElementById("profileOverlay"); |
|
const logoutBtn = document.getElementById("logoutBtn"); |
|
|
|
|
|
userProfile.addEventListener("click", () => { |
|
profileDropdown.classList.add("active"); |
|
profileOverlay.classList.add("active"); |
|
}); |
|
|
|
|
|
profileOverlay.addEventListener("click", () => { |
|
profileDropdown.classList.remove("active"); |
|
profileOverlay.classList.remove("active"); |
|
}); |
|
|
|
async function saveSearchToFirebase(query, year, feature) { |
|
const auth = firebase.auth(); |
|
const db = firebase.firestore(); |
|
const user = auth.currentUser; |
|
if (!user) { |
|
console.log("User not logged in, cannot save search history"); |
|
return; |
|
} |
|
|
|
try { |
|
|
|
const searchData = { |
|
type: "search", |
|
query: query, |
|
year: year || "All Years", |
|
feature: feature, |
|
timestamp: firebase.firestore.FieldValue.serverTimestamp() |
|
}; |
|
|
|
|
|
await db.collection("users") |
|
.doc(user.uid) |
|
.collection("activities") |
|
.add(searchData); |
|
|
|
console.log("Search activity saved successfully"); |
|
} catch (error) { |
|
console.error("Error saving search activity:", error); |
|
} |
|
} |
|
|
|
|
|
document.addEventListener("DOMContentLoaded", async () => { |
|
|
|
const profileName = document.getElementById("profileName"); |
|
const profileEmail = document.getElementById("profileEmail"); |
|
const profilePhone = document.getElementById("profilePhone"); |
|
const profileAddress = document.getElementById("profileAddress"); |
|
const profileProfession = document.getElementById("profileProfession"); |
|
const profileHeaderName = document.getElementById("profileHeaderName"); |
|
|
|
|
|
const auth = firebase.auth(); |
|
const db = firebase.firestore(); |
|
|
|
auth.onAuthStateChanged(async (user) => { |
|
if (user) { |
|
const userId = user.uid; |
|
|
|
|
|
profileName.value = localStorage.getItem("username") || ""; |
|
profilePhone.value = localStorage.getItem("phone") || ""; |
|
profileAddress.value = localStorage.getItem("address") || ""; |
|
profileProfession.value = localStorage.getItem("profession") || ""; |
|
profileHeaderName.innerHTML = `Welcome, ${storedUsername}`; |
|
|
|
|
|
|
|
try { |
|
|
|
const userDoc = await db.collection("users").doc(userId).get(); |
|
if (userDoc.exists) { |
|
const userData = userDoc.data(); |
|
if (!profileName.value) profileName.value = userData.name || ""; |
|
if (!profilePhone.value) profilePhone.value = userData.phone || ""; |
|
if (!profileAddress.value) profileAddress.value = userData.address || ""; |
|
if (!profileProfession.value) profileProfession.value = userData.profession || ""; |
|
} |
|
} catch (error) { |
|
console.error("Error fetching user data:", error); |
|
} |
|
} |
|
}); |
|
|
|
|
|
window.enableEdit = (fieldId) => { |
|
const inputField = document.getElementById(fieldId); |
|
inputField.removeAttribute("disabled"); |
|
inputField.focus(); |
|
inputField.addEventListener("blur", () => { |
|
|
|
inputField.setAttribute("disabled", true); |
|
}); |
|
}; |
|
|
|
|
|
const tabButtons = document.querySelectorAll(".tab-btn"); |
|
const tabContents = document.querySelectorAll(".tab-content"); |
|
|
|
tabButtons.forEach((btn) => { |
|
btn.addEventListener("click", () => { |
|
const tab = btn.getAttribute("data-tab"); |
|
tabButtons.forEach((b) => b.classList.remove("active")); |
|
tabContents.forEach((c) => c.classList.remove("active")); |
|
btn.classList.add("active"); |
|
document.getElementById(`${tab}-tab`).classList.add("active"); |
|
}); |
|
}); |
|
|
|
|
|
const avatarUpload = document.getElementById("avatarUpload"); |
|
const profileAvatar = document.getElementById("profileAvatar"); |
|
|
|
if (avatarUpload) { |
|
avatarUpload.addEventListener("change", (e) => { |
|
const file = e.target.files[0]; |
|
if (file) { |
|
const reader = new FileReader(); |
|
reader.onload = (event) => { |
|
profileAvatar.src = event.target.result; |
|
|
|
}; |
|
reader.readAsDataURL(file); |
|
} |
|
}); |
|
} |
|
|
|
|
|
const saveBtn = document.getElementById("saveBtn"); |
|
saveBtn.addEventListener("click", async () => { |
|
const user = auth.currentUser; |
|
if (!user) { |
|
alert("No user logged in!"); |
|
return; |
|
} |
|
const userId = user.uid; |
|
|
|
|
|
const updatedName = profileName.value.trim(); |
|
const updatedPhone = profilePhone.value.trim(); |
|
const updatedAddress = profileAddress.value.trim(); |
|
const updatedProfession = profileProfession.value.trim(); |
|
|
|
|
|
localStorage.setItem("username", updatedName); |
|
localStorage.setItem("phone", updatedPhone); |
|
localStorage.setItem("address", updatedAddress); |
|
localStorage.setItem("profession", updatedProfession); |
|
|
|
|
|
try { |
|
await db.collection("users").doc(userId).set( |
|
{ |
|
name: updatedName, |
|
phone: updatedPhone, |
|
address: updatedAddress, |
|
profession: updatedProfession, |
|
|
|
}, |
|
{ merge: true } |
|
); |
|
userProfile.textContent = updatedName; |
|
showPaperAlert( |
|
"Successfully Updated!", |
|
"Profile Updation Status", |
|
"fa-exclamation-circle", |
|
4000 |
|
); |
|
} catch (error) { |
|
console.error("Error updating profile:", error); |
|
showPaperAlert( |
|
"Error in Updation", |
|
"Profile Updation Status", |
|
"fa-exclamation-circle", |
|
4000 |
|
); |
|
} |
|
}); |
|
|
|
|
|
logoutBtn.addEventListener("click", async () => { |
|
try { |
|
await auth.signOut(); |
|
localStorage.clear(); |
|
window.location.href = "/home"; |
|
} catch (error) { |
|
console.error("Logout error:", error); |
|
} |
|
}); |
|
}); |
|
|
|
class Paper { |
|
constructor(x, y) { |
|
this.x = x; |
|
this.y = y; |
|
this.size = Math.random() * 15 + 5; |
|
this.rotation = Math.random() * 360; |
|
this.speedX = Math.random() * 3 - 1.5; |
|
this.speedY = Math.random() * 3 - 1.5; |
|
this.rotationSpeed = Math.random() * 2 - 1; |
|
this.opacity = 1; |
|
this.life = 100; |
|
this.element = document.createElement('div'); |
|
this.element.className = 'paper'; |
|
this.element.style.width = `${this.size}px`; |
|
this.element.style.height = `${this.size}px`; |
|
this.element.style.left = `${this.x}px`; |
|
this.element.style.top = `${this.y}px`; |
|
this.element.style.transform = `rotate(${this.rotation}deg)`; |
|
this.element.style.opacity = this.opacity; |
|
document.body.appendChild(this.element); |
|
} |
|
|
|
update() { |
|
this.life--; |
|
this.x += this.speedX; |
|
this.y += this.speedY; |
|
this.rotation += this.rotationSpeed; |
|
this.opacity = this.life / 100; |
|
|
|
this.element.style.left = `${this.x}px`; |
|
this.element.style.top = `${this.y}px`; |
|
this.element.style.transform = `rotate(${this.rotation}deg)`; |
|
this.element.style.opacity = this.opacity; |
|
|
|
if (this.life <= 0) { |
|
this.element.remove(); |
|
return false; |
|
} |
|
return true; |
|
} |
|
} |
|
|
|
|
|
let papers = []; |
|
let frameCount = 0; |
|
|
|
document.addEventListener('mousemove', (e) => { |
|
if (frameCount % 2 === 0) { |
|
papers.push(new Paper(e.clientX, e.clientY)); |
|
} |
|
}); |
|
|
|
function animate() { |
|
frameCount++; |
|
papers = papers.filter(paper => paper.update()); |
|
requestAnimationFrame(animate); |
|
} |
|
|
|
animate(); |
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
|
const container = document.getElementById('beam-container'); |
|
const circle1 = document.getElementById('circle1'); |
|
const circle2 = document.getElementById('circle2'); |
|
const circle3 = document.getElementById('circle3'); |
|
const circle4 = document.getElementById('circle4'); |
|
const circle5 = document.getElementById('circle5'); |
|
const circle6 = document.getElementById('circle6'); |
|
const circle7 = document.getElementById('circle7'); |
|
|
|
|
|
const svgContainer = document.getElementById('beams-svg'); |
|
|
|
|
|
createBeam(circle1, circle6); |
|
createBeam(circle2, circle6); |
|
createBeam(circle3, circle6); |
|
createBeam(circle4, circle6); |
|
createBeam(circle5, circle6); |
|
createBeam(circle6, circle7); |
|
|
|
|
|
window.addEventListener('resize', () => { |
|
|
|
svgContainer.innerHTML = ''; |
|
|
|
|
|
createBeam(circle1, circle6); |
|
createBeam(circle2, circle6); |
|
createBeam(circle3, circle6); |
|
createBeam(circle4, circle6); |
|
createBeam(circle5, circle6); |
|
createBeam(circle6, circle7); |
|
}); |
|
|
|
|
|
function createBeam(fromElement, toElement) { |
|
|
|
const fromRect = fromElement.getBoundingClientRect(); |
|
const toRect = toElement.getBoundingClientRect(); |
|
const containerRect = container.getBoundingClientRect(); |
|
|
|
|
|
const fromX = fromRect.left + fromRect.width / 2 - containerRect.left; |
|
const fromY = fromRect.top + fromRect.height / 2 - containerRect.top; |
|
const toX = toRect.left + toRect.width / 2 - containerRect.left; |
|
const toY = toRect.top + toRect.height / 2 - containerRect.top; |
|
|
|
|
|
const beam = document.createElementNS('http://www.w3.org/2000/svg', 'line'); |
|
beam.setAttribute('x1', fromX); |
|
beam.setAttribute('y1', fromY); |
|
beam.setAttribute('x2', toX); |
|
beam.setAttribute('y2', toY); |
|
beam.classList.add('beam'); |
|
svgContainer.appendChild(beam); |
|
|
|
|
|
const beamGlow = document.createElementNS('http://www.w3.org/2000/svg', 'line'); |
|
beamGlow.setAttribute('x1', fromX); |
|
beamGlow.setAttribute('y1', fromY); |
|
beamGlow.setAttribute('x2', toX); |
|
beamGlow.setAttribute('y2', toY); |
|
beamGlow.classList.add('beam-glow'); |
|
svgContainer.appendChild(beamGlow); |
|
} |
|
}); |
|
|
|
|
|
const inputFiles = [ |
|
{ y: 120, ext: 'ieee' }, |
|
{ y: 160, ext: 'arxiv' }, |
|
{ y: 200, ext: 'PMC' }, |
|
{ y: 240, ext: 'jstor' }, |
|
{ y: 280, ext: 'plos' } |
|
]; |
|
|
|
const outputFiles = [ |
|
{ label: 'Trend Analysis', y: 100, logoSrc: '/assets/c1.png' }, |
|
{ label: 'Citation Network', y: 180, logoSrc: '/assets/c2.png' }, |
|
{ label: 'Venue & Publisher', y: 260, logoSrc: '/assets/c3.png' }, |
|
]; |
|
|
|
const svgContainer = document.querySelector('.paths-container'); |
|
const centerBox = document.querySelector('.center-box'); |
|
|
|
|
|
let isAnimating = false; |
|
|
|
function createInputPath(startY) { |
|
const startX = 100; |
|
const endX = 400; |
|
const endY = 200; |
|
const controlX = (startX + endX) / 2; |
|
return `M ${startX} ${startY} C ${controlX} ${startY}, ${controlX} ${endY}, ${endX} ${endY}`; |
|
} |
|
|
|
function createOutputPath(endY) { |
|
const startX = 400; |
|
const startY = 200; |
|
const endX = 680; |
|
const controlX = (startX + endX) / 2; |
|
return `M ${startX} ${startY} C ${controlX} ${startY}, ${controlX} ${endY}, ${endX} ${endY}`; |
|
} |
|
|
|
function createInputPaper(data) { |
|
const container = document.createElement('div'); |
|
container.className = 'paper-container'; |
|
|
|
const paperIcon = document.createElement('div'); |
|
paperIcon.className = 'paper-icon'; |
|
paperIcon.textContent = data.ext; |
|
|
|
const label = document.createElement('span'); |
|
label.textContent = data.label || data.ext; |
|
|
|
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); |
|
path.setAttribute('class', 'path'); |
|
path.setAttribute('d', createInputPath(data.y)); |
|
svgContainer.appendChild(path); |
|
|
|
container.appendChild(paperIcon); |
|
container.appendChild(label); |
|
document.querySelector('.container').appendChild(container); |
|
|
|
container.style.left = '70px'; |
|
container.style.top = `${data.y}px`; |
|
|
|
return { container, paperIcon, path, ext: data.ext }; |
|
} |
|
|
|
function createOutputBox(data) { |
|
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); |
|
path.setAttribute('class', 'path'); |
|
path.setAttribute('d', createOutputPath(data.y)); |
|
svgContainer.appendChild(path); |
|
|
|
|
|
const outputBox = document.createElement('div'); |
|
outputBox.className = 'output-box'; |
|
document.querySelector('.container').appendChild(outputBox); |
|
outputBox.style.top = `${data.y}px`; |
|
|
|
|
|
const logo = document.createElement('img'); |
|
logo.className = 'output-logo'; |
|
logo.src = data.logoSrc; |
|
logo.alt = data.label + ' logo'; |
|
outputBox.appendChild(logo); |
|
|
|
|
|
const title = document.createElement('div'); |
|
title.className = 'box-title'; |
|
title.textContent = data.label; |
|
outputBox.appendChild(title); |
|
|
|
return { path, outputBox }; |
|
} |
|
|
|
function animatePaperAlongPath(path, ext, onComplete) { |
|
const movingPaper = document.createElement('div'); |
|
movingPaper.className = 'moving-paper'; |
|
movingPaper.textContent = ext; |
|
document.querySelector('.container').appendChild(movingPaper); |
|
|
|
const length = path.getTotalLength(); |
|
let start = null; |
|
const duration = 1200; |
|
|
|
path.style.strokeOpacity = "1"; |
|
path.style.strokeDasharray = `${length}, ${length}`; |
|
path.style.strokeDashoffset = length; |
|
|
|
function animate(timestamp) { |
|
if (!start) start = timestamp; |
|
const progress = (timestamp - start) / duration; |
|
|
|
if (progress <= 1) { |
|
const point = path.getPointAtLength(length * progress); |
|
movingPaper.style.left = `${point.x}px`; |
|
movingPaper.style.top = `${point.y}px`; |
|
|
|
|
|
path.style.strokeDashoffset = length * (1 - progress); |
|
|
|
requestAnimationFrame(animate); |
|
} else { |
|
movingPaper.remove(); |
|
path.style.strokeOpacity = "0"; |
|
if (onComplete) onComplete(); |
|
} |
|
} |
|
|
|
requestAnimationFrame(animate); |
|
} |
|
|
|
|
|
function animateDotAlongPath(path, outputBox, onComplete) { |
|
const movingDot = document.createElement('div'); |
|
movingDot.className = 'moving-dot'; |
|
document.querySelector('.container').appendChild(movingDot); |
|
|
|
const length = path.getTotalLength(); |
|
let start = null; |
|
const duration = 1000; |
|
|
|
path.style.strokeOpacity = "1"; |
|
path.style.strokeDasharray = `${length}, ${length}`; |
|
path.style.strokeDashoffset = length; |
|
|
|
function animate(timestamp) { |
|
if (!start) start = timestamp; |
|
const progress = (timestamp - start) / duration; |
|
|
|
if (progress <= 1) { |
|
const point = path.getPointAtLength(length * progress); |
|
movingDot.style.left = `${point.x}px`; |
|
movingDot.style.top = `${point.y}px`; |
|
|
|
|
|
path.style.strokeDashoffset = length * (1 - progress); |
|
|
|
requestAnimationFrame(animate); |
|
} else { |
|
movingDot.remove(); |
|
path.style.strokeOpacity = "0"; |
|
|
|
outputBox.style.display = 'flex'; |
|
outputBox.classList.add('highlight'); |
|
setTimeout(() => outputBox.classList.remove('highlight'), 500); |
|
|
|
if (onComplete) onComplete(); |
|
} |
|
} |
|
|
|
requestAnimationFrame(animate); |
|
} |
|
|
|
const inputs = inputFiles.map(createInputPaper); |
|
const outputs = outputFiles.map(createOutputBox); |
|
|
|
function pulseBox() { |
|
centerBox.classList.add('pulse'); |
|
setTimeout(() => centerBox.classList.remove('pulse'), 300); |
|
} |
|
|
|
async function animateInputs() { |
|
|
|
outputs.forEach(output => { |
|
output.outputBox.style.opacity = '0'; |
|
}); |
|
|
|
|
|
for (let i = 0; i < inputs.length; i++) { |
|
await new Promise(resolve => { |
|
animatePaperAlongPath(inputs[i].path, inputs[i].ext, () => { |
|
pulseBox(); |
|
resolve(); |
|
}); |
|
}); |
|
|
|
await new Promise(resolve => setTimeout(resolve, 200)); |
|
} |
|
|
|
pulseBox(); |
|
return true; |
|
} |
|
|
|
async function animateOutputs() { |
|
|
|
for (let i = 0; i < outputs.length; i++) { |
|
await new Promise(resolve => { |
|
animateDotAlongPath(outputs[i].path, outputs[i].outputBox, () => { |
|
outputs[i].outputBox.style.opacity = '1'; |
|
resolve(); |
|
}); |
|
}); |
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 300)); |
|
} |
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1500)); |
|
|
|
|
|
outputs.forEach(output => { |
|
output.outputBox.style.opacity = '0'; |
|
}); |
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 500)); |
|
return true; |
|
} |
|
|
|
async function completeAnimationCycle() { |
|
if (isAnimating) return; |
|
isAnimating = true; |
|
|
|
try { |
|
await animateInputs(); |
|
await new Promise(resolve => setTimeout(resolve, 800)); |
|
await animateOutputs(); |
|
isAnimating = false; |
|
setTimeout(completeAnimationCycle, 500); |
|
} catch (error) { |
|
console.error("Animation error:", error); |
|
isAnimating = false; |
|
} |
|
} |
|
|
|
setTimeout(completeAnimationCycle, 1000); |
|
|
|
function showPaperAlert(message, title = "Alert", icon = "fa-exclamation-circle", duration = 7000) { |
|
const paperAlert = document.getElementById('paperAlert'); |
|
const alertMessage = document.getElementById('alertMessage'); |
|
const alertTitle = document.getElementById('alertTitle'); |
|
const alertIcon = document.getElementById('alertIcon'); |
|
|
|
|
|
alertMessage.textContent = message; |
|
alertTitle.textContent = title; |
|
|
|
|
|
alertIcon.className = ''; |
|
alertIcon.classList.add('fas', icon); |
|
|
|
|
|
paperAlert.classList.remove("hide"); |
|
paperAlert.classList.add("show", "showAlert"); |
|
|
|
|
|
setTimeout(() => { |
|
hideAlert(); |
|
}, duration); |
|
} |
|
|
|
|
|
function hideAlert() { |
|
const paperAlert = document.getElementById('paperAlert'); |
|
paperAlert.classList.remove("show"); |
|
paperAlert.classList.add("hide"); |
|
setTimeout(() => { |
|
paperAlert.classList.remove("showAlert"); |
|
}, 500); |
|
} |
|
|
|
|
|
document.querySelector('#paperAlert .close-btn').addEventListener('click', function() { |
|
hideAlert(); |
|
}); |
|
|
|
const featureCards = document.querySelectorAll('.feature-selection .glass'); |
|
const selectionMessage = document.getElementById('selectionMessage'); |
|
const selectedFeatureText = document.getElementById('selectedFeature'); |
|
const selectedFeature = {"feature":null} |
|
|
|
let isLoggedIn = localStorage.getItem("username"); |
|
let selectedCard = null; |
|
|
|
featureCards.forEach(card => { |
|
card.addEventListener('click', () => { |
|
if (!isLoggedIn) { |
|
|
|
showPaperAlert( |
|
"You must be Logged In to continue!", |
|
"Authentication Required", |
|
"fa-exclamation-circle", |
|
7000 |
|
); |
|
return; |
|
} |
|
const isAlreadySelected = card === selectedCard; |
|
|
|
if (isAlreadySelected) { |
|
card.classList.remove('selected'); |
|
selectedCard = null; |
|
selectionMessage.classList.remove('visible'); |
|
} else { |
|
if (selectedCard) { |
|
selectedCard.classList.remove('selected'); |
|
} |
|
|
|
card.classList.add('selected'); |
|
selectedCard = card; |
|
|
|
selectedFeature.feature = card.getAttribute('data-feature'); |
|
|
|
selectedFeatureText.textContent = card.getAttribute('data-text'); |
|
selectionMessage.classList.add('visible'); |
|
} |
|
}); |
|
}); |
|
|
|
|
|
|
|
const searchBtn = document.getElementById("searchbtn"); |
|
searchBtn.addEventListener("click", function () { |
|
console.log("Search button clicked"); |
|
|
|
|
|
|
|
const isLoggedIn = localStorage.getItem("username"); |
|
if (!isLoggedIn) { |
|
alert("You must be signed in to perform a search."); |
|
return; |
|
} |
|
|
|
const searchInput = document.querySelector('#searchy'); |
|
console.log("searchInput" , searchInput) |
|
if (!searchInput) { |
|
console.error("Search input element not found"); |
|
alert("Search input not found. Please check the page structure."); |
|
return; |
|
} |
|
|
|
const searchTopic = searchInput.value.trim(); |
|
const yearFilter = document.getElementById('year-filter'); |
|
const searchYear = yearFilter ? yearFilter.value : ""; |
|
const userId = localStorage.getItem("userId"); |
|
|
|
saveSearchToFirebase(searchTopic, searchYear, selectedFeature ) |
|
|
|
|
|
|
|
if (!searchTopic) { |
|
alert("Please enter a search topic"); |
|
return; |
|
} |
|
|
|
console.log(`Searching for: ${searchTopic}, Year: ${searchYear}, Feature: ${selectedFeature}`); |
|
|
|
|
|
let currentPage = 0; |
|
const nextBtn = document.getElementById("nextBtn"); |
|
|
|
nextBtn.addEventListener("click", function () { |
|
currentPage+=1 |
|
alert("just checking bro " +currentPage ); |
|
trendanalysis(currentPage); |
|
}); |
|
|
|
|
|
|
|
function trendanalysis(pageNo){ |
|
const originalText = searchBtn.textContent; |
|
searchBtn.textContent = "Processing..."; |
|
searchBtn.disabled = true; |
|
nextBtn.style.display = "inline-block"; |
|
|
|
|
|
fetch('/check-data-exists/', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ |
|
userId: userId, |
|
topic: searchTopic, |
|
year: searchYear |
|
}) |
|
}) |
|
.then(response => { |
|
if (!response.ok) { |
|
throw new Error(`Network response was not ok: ${response.status}`); |
|
} |
|
return response.json(); |
|
}) |
|
.then(data => { |
|
if (data.exists) { |
|
console.log('Data exists, skipping analysis step'); |
|
showPaperAlert( |
|
"Data exists", |
|
"Trend Analysis.......", |
|
"fa-exclamation-circle", |
|
7000 |
|
); |
|
return fetch('/analyze-trends/', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ |
|
userId: userId, |
|
topic: searchTopic, |
|
year: searchYear, |
|
page: pageNo |
|
}) |
|
}); |
|
} else { |
|
console.log('Data does not exist, starting full analysis'); |
|
showPaperAlert( |
|
"Starting full analysis", |
|
"ATrend Analysis.......", |
|
"fa-exclamation-circle", |
|
7000 |
|
); |
|
return fetch('/analyze/', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ |
|
userId: userId, |
|
topic: searchTopic, |
|
year: searchYear |
|
}) |
|
}) |
|
.then(response => { |
|
if (!response.ok) { |
|
throw new Error(`Analysis failed: ${response.status}`); |
|
} |
|
return response.json(); |
|
}) |
|
.then(analysisData => { |
|
console.log('Analysis complete:', analysisData); |
|
|
|
showPaperAlert( |
|
"Analysis complete", |
|
"Trend Analysis.......", |
|
"fa-exclamation-circle", |
|
7000 |
|
); |
|
return fetch('/analyze-trends/', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ |
|
userId: userId, |
|
topic: searchTopic, |
|
year: searchYear, |
|
page: pageNo |
|
}) |
|
}); |
|
}); |
|
} |
|
}) |
|
.then(response => { |
|
if (!response.ok) { |
|
throw new Error(`Trend analysis failed: ${response.status}`); |
|
} |
|
return response.json(); |
|
}) |
|
.then(trendData => { |
|
console.log('Trend analysis complete:', trendData); |
|
showPaperAlert( |
|
"Analysis complete", |
|
"Trend Analysis.......", |
|
"fa-exclamation-circle", |
|
7000 |
|
); |
|
loadingOverlay.hide() |
|
|
|
}) |
|
.catch(error => { |
|
console.error('Error:', error); |
|
alert("There was an error processing your request. Please try again: " + error.message); |
|
showPaperAlert( |
|
`There was an error processing your request. Please try again:` + error.message, |
|
"Trend Analysis.......", |
|
"fa-exclamation-circle", |
|
7000 |
|
); |
|
loadingOverlay.hide() |
|
}) |
|
.finally(() => { |
|
|
|
searchBtn.textContent = originalText; |
|
searchBtn.disabled = false; |
|
}); |
|
} |
|
|
|
|
|
|
|
if (selectedFeature.feature === 'trends') { |
|
console.log("here here") |
|
loadingOverlay.show("Loading Trend Analysis") |
|
trendanalysis(0); |
|
} |
|
else if (selectedFeature.feature === 'citations') { |
|
loadingOverlay.show("Loading Citation Network Analysis") |
|
nextBtn.style.display = "none"; |
|
currentPage = 0; |
|
showPaperAlert( |
|
"Analysis Started", |
|
"Citation Network Analysis.......", |
|
"fa-exclamation-circle", |
|
7000 |
|
); |
|
|
|
const originalText = this.textContent; |
|
this.textContent = "Processing..."; |
|
this.disabled = true; |
|
|
|
|
|
fetch('/check-data-exists-citation/', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ |
|
userId: userId, |
|
topic: searchTopic, |
|
year: searchYear |
|
}) |
|
}) |
|
.then(response => { |
|
if (!response.ok) { |
|
throw new Error(`Network response was not ok: ${response.status}`); |
|
} |
|
return response.json(); |
|
}) |
|
.then(data => { |
|
if (data.exists) { |
|
console.log('Data exists, fetching citation data...'); |
|
loadingOverlay.hide() |
|
window.open(`/citation-data?userId=${encodeURIComponent(userId)}&topic=${encodeURIComponent(searchTopic)}&year=${encodeURIComponent(searchYear)}`, '_blank'); |
|
} else { |
|
console.log('Data does not exist, starting full analysis...'); |
|
showPaperAlert( |
|
"Data Collecting....", |
|
"Citation Network Analysis.......", |
|
"fa-exclamation-circle", |
|
7000 |
|
); |
|
return fetch('/save', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ |
|
userId: userId, |
|
topic: searchTopic, |
|
year: searchYear |
|
}) |
|
}) |
|
.then(response => { |
|
if (!response.ok) { |
|
throw new Error(`Save failed: ${response.status}`); |
|
} |
|
return response.json(); |
|
}) |
|
.then(saveData => { |
|
console.log('Data saved successfully:', saveData); |
|
loadingOverlay.hide() |
|
window.open(`/citation-data?userId=${encodeURIComponent(userId)}&topic=${encodeURIComponent(searchTopic)}&year=${encodeURIComponent(searchYear)}`, '_blank'); |
|
}); |
|
} |
|
}) |
|
.catch(error => { |
|
console.error('Error:', error); |
|
showPaperAlert( |
|
"There was an error processing your request. Please try again: " + error.message, |
|
"Citation Network Analysis.......", |
|
"fa-exclamation-circle", |
|
7000 |
|
); |
|
loadingOverlay.hide() |
|
}) |
|
.finally(() => { |
|
|
|
this.textContent = originalText; |
|
this.disabled = false; |
|
}); |
|
} |
|
|
|
else if (selectedFeature.feature === 'venues') { |
|
nextBtn.style.display = "none"; |
|
currentPage = 0; |
|
const originalText = this.textContent; |
|
this.textContent = "Processing..."; |
|
this.disabled = true; |
|
console.log(" here here venue") |
|
showPaperAlert( |
|
"Analysis Started", |
|
"Venue/Publisher Analysis.......", |
|
"fa-exclamation-circle", |
|
7000 |
|
); |
|
loadingOverlay.show("Started Loading.....") |
|
fetch('/check-data-exists-venue/', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ |
|
userId: userId, |
|
topic: searchTopic, |
|
year: searchYear |
|
}) |
|
}) |
|
.then(response => { |
|
if (!response.ok) { |
|
|
|
throw new Error(`Network response was not ok: ${response.status}`); |
|
|
|
} |
|
return response.json(); |
|
}) |
|
.then(data => { |
|
if (data.exists) { |
|
console.log('Data exists, loading dashboard directly'); |
|
|
|
fetch('/load_and_display_dashboard/', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ |
|
userId: userId, |
|
topic: searchTopic, |
|
year: searchYear |
|
}) |
|
}).then(response =>{ |
|
if(response.ok){ |
|
return response.json(); |
|
} |
|
} ).then(data1 =>{ |
|
let secureUrl = data1.open_url.replace(/^https?:/, window.location.protocol); |
|
window.location.href = secureUrl.redirect; |
|
console.log(secureUrl); |
|
|
|
|
|
|
|
} ) |
|
|
|
} else { |
|
console.log('Data does not exist, starting search process'); |
|
showPaperAlert( |
|
"Data Collectiong....", |
|
"Venue/Publisher Analysis.......", |
|
"fa-exclamation-circle", |
|
7000 |
|
); |
|
return fetch('/search/', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ |
|
userId: userId, |
|
topic: searchTopic, |
|
year: searchYear |
|
}) |
|
}) |
|
.then(response => { |
|
if (!response.ok) { |
|
throw new Error(`Search failed: ${response.status}`); |
|
} |
|
return response.json(); |
|
}) |
|
.then(searchData => { |
|
console.log('Search complete:', searchData); |
|
|
|
fetch('/load_and_display_dashboard/', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ |
|
userId: userId, |
|
topic: searchTopic, |
|
year: searchYear |
|
}) |
|
}).then(response =>{ |
|
if(response.ok){ |
|
return response.json(); |
|
} |
|
} ).then(data1 =>{ |
|
let secureUrl = data1.open_url.replace(/^https?:/, window.location.protocol); |
|
window.location.href = secureUrl.redirect; |
|
console.log(secureUrl); |
|
} ) |
|
}); |
|
} |
|
}) |
|
.catch(error => { |
|
console.error('Error:', error); |
|
showPaperAlert( |
|
"There was an error processing your request. Please try again: " + error.message, |
|
"Venue/Publisher Analysis.......", |
|
"fa-exclamation-circle", |
|
7000 |
|
); |
|
}) |
|
.finally(() => { |
|
this.textContent = originalText; |
|
this.disabled = false; |
|
loadingOverlay.hide(); |
|
}); |
|
|
|
} else { |
|
alert("Invalid feature selected. Please choose a valid feature."); |
|
} |
|
}); |
|
|
|
|
|
const loadingOverlay = { |
|
overlay: document.getElementById('loading-overlay'), |
|
cyclone: null, |
|
loadingText: null, |
|
animationInterval: null, |
|
paperInterval: null, |
|
|
|
initialize() { |
|
this.cyclone = document.getElementById('cyclone'); |
|
this.loadingText = document.getElementById('loading-text'); |
|
this.setupAnimation(); |
|
|
|
|
|
this.overlay.style.backgroundColor = 'rgba(137, 138, 183, 0.9)'; |
|
}, |
|
|
|
setupAnimation() { |
|
|
|
for (let i = 0; i < 10; i++) { |
|
this.createPaper(i); |
|
} |
|
}, |
|
|
|
show(message = 'Processing...') { |
|
this.loadingText.textContent = message; |
|
this.overlay.classList.add('active'); |
|
|
|
|
|
this.paperInterval = setInterval(() => { |
|
this.createPaper(); |
|
}, 120); |
|
|
|
|
|
let dots = 0; |
|
this.animationInterval = setInterval(() => { |
|
dots = (dots + 1) % 4; |
|
this.loadingText.textContent = message + '.'.repeat(dots); |
|
}, 500); |
|
}, |
|
|
|
hide() { |
|
this.overlay.classList.remove('active'); |
|
|
|
|
|
clearInterval(this.paperInterval); |
|
clearInterval(this.animationInterval); |
|
|
|
|
|
setTimeout(() => { |
|
while (this.cyclone.firstChild) { |
|
this.cyclone.removeChild(this.cyclone.firstChild); |
|
} |
|
}, 300); |
|
}, |
|
|
|
createPaper(index) { |
|
const paper = document.createElement('div'); |
|
paper.className = 'paper'; |
|
|
|
|
|
const size = 8 + Math.random() * 12; |
|
paper.style.width = `${size}px`; |
|
paper.style.height = `${size * 1.3}px`; |
|
|
|
|
|
const grayness = 65 + Math.random() * 20; |
|
paper.style.backgroundColor = `hsl(0, 0%, ${grayness}%)`; |
|
|
|
|
|
const skewX = Math.random() * 10 - 5; |
|
const skewY = Math.random() * 10 - 5; |
|
paper.style.transform = `skew(${skewX}deg, ${skewY}deg)`; |
|
|
|
|
|
const startAngle = Math.random() * Math.PI * 2; |
|
const startRadius = 60 + Math.random() * 20; |
|
const startX = 100 + startRadius * Math.cos(startAngle); |
|
const startY = -20; |
|
|
|
paper.style.left = `${startX}px`; |
|
paper.style.top = `${startY}px`; |
|
|
|
this.cyclone.appendChild(paper); |
|
|
|
|
|
this.animatePaperInCyclone(paper, startAngle); |
|
}, |
|
|
|
animatePaperInCyclone(paper, initialAngle) { |
|
|
|
const duration = 6000 + Math.random() * 2000; |
|
const startTime = Date.now(); |
|
|
|
|
|
let angle = initialAngle || 0; |
|
let height = -20; |
|
const maxHeight = 350; |
|
const rotationSpeed = 1.0 + Math.random() * 0.5; |
|
|
|
const animateFrame = () => { |
|
if (!this.overlay.classList.contains('active')) { |
|
if (paper.parentNode === this.cyclone) { |
|
this.cyclone.removeChild(paper); |
|
} |
|
return; |
|
} |
|
|
|
const now = Date.now(); |
|
const elapsed = now - startTime; |
|
const progress = elapsed / duration; |
|
|
|
if (progress < 1) { |
|
|
|
|
|
height = -20 + (maxHeight + 20) * Math.min(1, progress * 1.2); |
|
|
|
|
|
|
|
const heightProgress = height / maxHeight; |
|
const currentRadius = Math.max(10, 80 - 60 * heightProgress); |
|
|
|
|
|
const adjustedRotation = rotationSpeed * (1 + heightProgress * 0.5); |
|
angle += adjustedRotation * 0.03; |
|
|
|
|
|
const x = 100 + currentRadius * Math.cos(angle); |
|
const y = height; |
|
|
|
|
|
paper.style.left = `${x}px`; |
|
paper.style.top = `${y}px`; |
|
|
|
|
|
const rotation = angle * (180 / Math.PI); |
|
|
|
const flutter = Math.sin(elapsed * 0.01) * (5 + heightProgress * 10); |
|
paper.style.transform = `rotate(${rotation + flutter}deg) scale(${0.8 + Math.sin(progress * Math.PI * 4) * 0.1})`; |
|
|
|
|
|
if (progress > 0.8) { |
|
paper.style.opacity = (1 - progress) * 5; |
|
} |
|
|
|
requestAnimationFrame(animateFrame); |
|
} else { |
|
|
|
if (paper.parentNode === this.cyclone) { |
|
this.cyclone.removeChild(paper); |
|
} |
|
} |
|
}; |
|
|
|
requestAnimationFrame(animateFrame); |
|
} |
|
}; |
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
loadingOverlay.initialize(); |
|
}); |
|
const words = document.querySelectorAll('.liquid-word'); |
|
const splashContainer = document.getElementById('splashContainer'); |
|
let currentIndex = 0; |
|
|
|
|
|
words.forEach(word => { |
|
const letters = word.textContent.split(''); |
|
word.innerHTML = ''; |
|
|
|
letters.forEach(letter => { |
|
const charSpan = document.createElement('span'); |
|
charSpan.className = 'liquid-char'; |
|
charSpan.textContent = letter; |
|
word.appendChild(charSpan); |
|
|
|
|
|
const paperDrop = document.createElement('div'); |
|
paperDrop.className = 'paper-drop'; |
|
charSpan.appendChild(paperDrop); |
|
|
|
|
|
for (let i = 0; i < 3; i++) { |
|
const paperBg = document.createElement('div'); |
|
paperBg.className = 'paper-piece'; |
|
paperBg.style.width = `${Math.random() * 20 + 20}px`; |
|
paperBg.style.height = `${Math.random() * 15 + 15}px`; |
|
paperBg.style.transform = `rotate(${Math.random() * 40 - 20}deg)`; |
|
|
|
|
|
const offsetX = (Math.random() - 0.5) * 30; |
|
const offsetY = (Math.random() - 0.5) * 30; |
|
paperBg.style.left = `calc(50% + ${offsetX}px)`; |
|
paperBg.style.top = `calc(50% + ${offsetY}px)`; |
|
|
|
|
|
const colors = ['#ffffff', '#f8f8f8', '#f0f0f0', '#fffafa', '#f5f5f5']; |
|
paperBg.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; |
|
|
|
charSpan.appendChild(paperBg); |
|
} |
|
}); |
|
}); |
|
|
|
|
|
function createPaperSplashes(centerX, centerY) { |
|
for (let i = 0; i < 15; i++) { |
|
setTimeout(() => { |
|
const paper = document.createElement('div'); |
|
paper.className = 'paper-piece'; |
|
|
|
|
|
const size = Math.random() * 20 + 10; |
|
paper.style.width = `${size}px`; |
|
paper.style.height = `${size * (Math.random() * 0.5 + 0.5)}px`; |
|
|
|
|
|
const rotation = Math.random() * 360; |
|
paper.style.setProperty('--rotation', `${rotation}deg`); |
|
|
|
|
|
const angle = Math.random() * Math.PI * 2; |
|
const distance = Math.random() * 100 + 20; |
|
const x = centerX + Math.cos(angle) * distance; |
|
const y = centerY + Math.sin(angle) * distance; |
|
|
|
paper.style.left = `${x}px`; |
|
paper.style.top = `${y}px`; |
|
|
|
|
|
const colors = ['#ffffff', '#f8f8f8', '#f0f0f0', '#fffafa', '#f5f5f5']; |
|
paper.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; |
|
|
|
|
|
if (Math.random() > 0.7) { |
|
paper.style.border = '1px solid rgba(0,0,0,0.05)'; |
|
} |
|
|
|
|
|
paper.style.animation = `paperSplash ${Math.random() * 0.8 + 0.6}s forwards`; |
|
|
|
splashContainer.appendChild(paper); |
|
|
|
|
|
setTimeout(() => paper.remove(), 1500); |
|
}, i * 40); |
|
} |
|
} |
|
|
|
|
|
function animateLettersIn(word) { |
|
const chars = word.querySelectorAll('.liquid-char'); |
|
|
|
chars.forEach((char, i) => { |
|
setTimeout(() => { |
|
|
|
char.style.animation = 'paperIn 0.7s forwards'; |
|
char.style.opacity = '1'; |
|
|
|
|
|
const paperDrop = char.querySelector('.paper-drop'); |
|
setTimeout(() => { |
|
paperDrop.style.animation = 'paperDrop 0.5s forwards'; |
|
}, 350); |
|
|
|
|
|
const paperPieces = char.querySelectorAll('.paper-piece'); |
|
paperPieces.forEach((piece, j) => { |
|
setTimeout(() => { |
|
piece.style.opacity = '1'; |
|
piece.style.transform += ' scale(1)'; |
|
}, j * 100 + 300); |
|
}); |
|
|
|
}, i * 100); |
|
}); |
|
} |
|
|
|
|
|
function animateLettersOut(word) { |
|
const chars = word.querySelectorAll('.liquid-char'); |
|
|
|
chars.forEach((char, i) => { |
|
setTimeout(() => { |
|
char.style.animation = 'paperOut 0.5s forwards'; |
|
|
|
|
|
const paperPieces = char.querySelectorAll('.paper-piece'); |
|
paperPieces.forEach(piece => { |
|
piece.style.opacity = '0'; |
|
}); |
|
}, i * 60); |
|
}); |
|
} |
|
|
|
|
|
function transitionWords() { |
|
|
|
const currentWord = words[currentIndex]; |
|
const rect = currentWord.getBoundingClientRect(); |
|
const centerX = rect.width / 2; |
|
const centerY = rect.height / 2; |
|
|
|
|
|
animateLettersOut(currentWord); |
|
|
|
setTimeout(() => { |
|
|
|
currentWord.classList.remove('active'); |
|
|
|
|
|
currentIndex = (currentIndex + 1) % words.length; |
|
const nextWord = words[currentIndex]; |
|
|
|
|
|
nextWord.classList.add('active'); |
|
|
|
|
|
createPaperSplashes(centerX, centerY); |
|
|
|
|
|
setTimeout(() => { |
|
animateLettersIn(nextWord); |
|
}, 200); |
|
|
|
}, 500); |
|
} |
|
|
|
|
|
setTimeout(() => { |
|
animateLettersIn(words[0]); |
|
}, 500); |
|
|
|
|
|
setInterval(transitionWords, 3500); |
|
|
|
|
|
const carousel = document.getElementById('carousel'); |
|
const pages = document.querySelectorAll('.page'); |
|
const nextBtn2 = document.getElementById('nextBtn2'); |
|
const prevBtn = document.getElementById('prevBtn'); |
|
const dots = document.querySelectorAll('.dot'); |
|
const pageShadows = document.querySelectorAll('.page-shadow'); |
|
|
|
let currentPage = 0; |
|
let totalSlides = 6; |
|
|
|
|
|
pages.forEach((page, index) => { |
|
page.style.transform = 'rotateY(0deg)'; |
|
page.style.zIndex = 6 - index; |
|
}); |
|
|
|
|
|
function nextPage() { |
|
if (currentPage < pages.length) { |
|
|
|
if (currentPage > 0) { |
|
pageShadows[currentPage-1].style.opacity = '0'; |
|
} |
|
|
|
pages[currentPage].style.transform = 'rotateY(-180deg)'; |
|
pages[currentPage].style.zIndex = 10 + currentPage; |
|
|
|
if (currentPage < pages.length - 1) { |
|
pageShadows[currentPage].style.opacity = '1'; |
|
} |
|
|
|
currentPage++; |
|
|
|
|
|
const newRotationDegree = (currentPage % totalSlides) * (360 / totalSlides); |
|
carousel.style.transform = `rotateY(${-newRotationDegree}deg)`; |
|
|
|
|
|
updatePagination(currentPage % totalSlides); |
|
} |
|
} |
|
|
|
|
|
function prevPage() { |
|
if (currentPage > 0) { |
|
currentPage--; |
|
|
|
|
|
if (currentPage > 0) { |
|
pageShadows[currentPage-1].style.opacity = '1'; |
|
} |
|
|
|
pages[currentPage].style.transform = 'rotateY(0deg)'; |
|
setTimeout(() => { |
|
pages[currentPage].style.zIndex = 10 - currentPage; |
|
}, 300); |
|
|
|
pageShadows[currentPage].style.opacity = '0'; |
|
|
|
|
|
const newRotationDegree = (currentPage % totalSlides) * (360 / totalSlides); |
|
carousel.style.transform = `rotateY(${-newRotationDegree}deg)`; |
|
|
|
|
|
updatePagination(currentPage % totalSlides); |
|
} |
|
} |
|
|
|
|
|
function resetBook() { |
|
pages.forEach((page, index) => { |
|
page.style.transition = 'none'; |
|
page.style.transform = 'rotateY(0deg)'; |
|
setTimeout(() => { |
|
page.style.zIndex = 5 - index; |
|
page.style.transition = 'transform 0.6s ease, z-index 0s 0.3s'; |
|
}, 50); |
|
}); |
|
|
|
pageShadows.forEach(shadow => { |
|
shadow.style.opacity = '0'; |
|
}); |
|
|
|
currentPage = 0; |
|
|
|
|
|
carousel.style.transform = 'rotateY(0deg)'; |
|
updatePagination(0); |
|
} |
|
|
|
|
|
function updatePagination(index) { |
|
dots.forEach((dot, i) => { |
|
if (i === index) { |
|
dot.classList.add('active'); |
|
} else { |
|
dot.classList.remove('active'); |
|
} |
|
}); |
|
} |
|
|
|
|
|
nextBtn2.addEventListener('click', nextPage); |
|
prevBtn.addEventListener('click', prevPage); |
|
|
|
|
|
dots.forEach((dot, index) => { |
|
dot.addEventListener('click', () => { |
|
|
|
const currentInCycle = currentPage % totalSlides; |
|
|
|
|
|
let pagesToMove; |
|
|
|
if (index > currentInCycle) { |
|
pagesToMove = index - currentInCycle; |
|
} else if (index < currentInCycle) { |
|
pagesToMove = totalSlides - currentInCycle + index; |
|
} else { |
|
return; |
|
} |
|
|
|
|
|
for (let i = 0; i < pagesToMove; i++) { |
|
setTimeout(() => nextPage(), i * 400); |
|
} |
|
}); |
|
}); |
|
|
|
|
|
pages.forEach((page, index) => { |
|
page.addEventListener('click', () => { |
|
if (index === currentPage - 1) { |
|
prevPage(); |
|
} else if (index === currentPage) { |
|
nextPage(); |
|
} |
|
}); |
|
}); |
|
|
|
const canvas = document.getElementById('bgParticles'); |
|
if (canvas) { |
|
const ctx = canvas.getContext('2d'); |
|
let particles = []; |
|
const colors = ['#ff6ec4', '#7873f5', '#1fd1f9', '#43e97b']; |
|
let width = window.innerWidth; |
|
let height = window.innerHeight; |
|
canvas.width = width; |
|
canvas.height = height; |
|
|
|
function randomBetween(a, b) { return a + Math.random() * (b - a); } |
|
|
|
function createParticles(num) { |
|
particles = []; |
|
for (let i = 0; i < num; i++) { |
|
particles.push({ |
|
x: randomBetween(0, width), |
|
y: randomBetween(0, height), |
|
r: randomBetween(2, 5), |
|
color: colors[Math.floor(Math.random() * colors.length)], |
|
dx: randomBetween(-0.7, 0.7), |
|
dy: randomBetween(-0.7, 0.7), |
|
alpha: randomBetween(0.3, 0.8) |
|
}); |
|
} |
|
} |
|
|
|
function drawParticles() { |
|
ctx.clearRect(0, 0, width, height); |
|
for (let p of particles) { |
|
ctx.save(); |
|
ctx.globalAlpha = p.alpha; |
|
ctx.beginPath(); |
|
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2); |
|
ctx.fillStyle = p.color; |
|
ctx.shadowColor = p.color; |
|
ctx.shadowBlur = 16; |
|
ctx.fill(); |
|
ctx.restore(); |
|
|
|
p.x += p.dx; |
|
p.y += p.dy; |
|
if (p.x < 0 || p.x > width) p.dx *= -1; |
|
if (p.y < 0 || p.y > height) p.dy *= -1; |
|
} |
|
requestAnimationFrame(drawParticles); |
|
} |
|
|
|
createParticles(48); |
|
drawParticles(); |
|
|
|
window.addEventListener('resize', () => { |
|
width = window.innerWidth; |
|
height = window.innerHeight; |
|
canvas.width = width; |
|
canvas.height = height; |
|
createParticles(48); |
|
}); |
|
} |
|
|