345 lines
12 KiB
JavaScript
345 lines
12 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function() {
|
|
const card = document.getElementById('current-card');
|
|
const lastActionText = document.getElementById('last-action');
|
|
const leftHint = document.querySelector('.left-hint');
|
|
const rightHint = document.querySelector('.right-hint');
|
|
const upHint = document.querySelector('.up-hint');
|
|
const downHint = document.querySelector('.down-hint');
|
|
|
|
// Modal elements
|
|
const modal = document.getElementById('fullscreen-modal');
|
|
const fullscreenImage = document.getElementById('fullscreen-image');
|
|
const closeModal = document.querySelector('.close-modal');
|
|
const modalResolution = document.getElementById('modal-resolution');
|
|
const modalFilename = document.getElementById('modal-filename');
|
|
const modalCreationDate = document.getElementById('modal-creation-date');
|
|
|
|
// Current image information
|
|
let currentImageInfo = null;
|
|
|
|
// Button event listeners
|
|
document.getElementById('btn-left').addEventListener('click', () => performSwipe('left'));
|
|
document.getElementById('btn-right').addEventListener('click', () => performSwipe('right'));
|
|
document.getElementById('btn-up').addEventListener('click', () => performSwipe('up'));
|
|
document.getElementById('btn-down').addEventListener('click', () => performSwipe('down'));
|
|
|
|
// Touch start time for distinguishing between swipe and tap
|
|
let touchStartTime = 0;
|
|
|
|
// Touch variables
|
|
let startX, startY, moveX, moveY;
|
|
let isDragging = false;
|
|
const swipeThreshold = 100; // Minimum distance for a swipe to be registered
|
|
|
|
// Touch event handlers
|
|
card.addEventListener('touchstart', handleTouchStart, false);
|
|
card.addEventListener('touchmove', handleTouchMove, false);
|
|
card.addEventListener('touchend', handleTouchEnd, false);
|
|
|
|
// Mouse event handlers (for desktop testing)
|
|
card.addEventListener('mousedown', handleMouseDown, false);
|
|
document.addEventListener('mousemove', handleMouseMove, false);
|
|
document.addEventListener('mouseup', handleMouseUp, false);
|
|
|
|
// Click handler for viewing full-resolution image
|
|
card.addEventListener('click', handleCardClick);
|
|
|
|
// Close modal when clicking the close button
|
|
closeModal.addEventListener('click', () => {
|
|
modal.style.display = 'none';
|
|
});
|
|
|
|
// Close modal when clicking outside the image
|
|
window.addEventListener('click', (e) => {
|
|
if (e.target === modal) {
|
|
modal.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
// Close modal with escape key
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape' && modal.style.display === 'block') {
|
|
modal.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
function handleTouchStart(e) {
|
|
startX = e.touches[0].clientX;
|
|
startY = e.touches[0].clientY;
|
|
isDragging = true;
|
|
card.classList.add('swiping');
|
|
|
|
// Store touch start time to differentiate between swipe and tap
|
|
touchStartTime = new Date().getTime();
|
|
}
|
|
|
|
function handleTouchMove(e) {
|
|
if (!isDragging) return;
|
|
|
|
moveX = e.touches[0].clientX - startX;
|
|
moveY = e.touches[0].clientY - startY;
|
|
|
|
// Apply transform to the card
|
|
card.style.transform = `translate(${moveX}px, ${moveY}px) rotate(${moveX * 0.1}deg)`;
|
|
|
|
// Show appropriate hint based on direction
|
|
updateHints(moveX, moveY);
|
|
}
|
|
|
|
function handleTouchEnd(e) {
|
|
if (!isDragging) return;
|
|
|
|
// Calculate touch duration
|
|
const touchEndTime = new Date().getTime();
|
|
const touchDuration = touchEndTime - touchStartTime;
|
|
|
|
// Determine if this was a tap (short touch with minimal movement)
|
|
const absX = Math.abs(moveX || 0);
|
|
const absY = Math.abs(moveY || 0);
|
|
const isTap = touchDuration < 300 && Math.max(absX, absY) < 10;
|
|
|
|
isDragging = false;
|
|
|
|
if (isTap) {
|
|
// This was a tap, not a swipe
|
|
resetCardPosition();
|
|
handleCardClick(e);
|
|
} else if (Math.max(absX, absY) > swipeThreshold) {
|
|
// This was a swipe
|
|
if (absX > absY) {
|
|
// Horizontal swipe
|
|
if (moveX > 0) {
|
|
performSwipe('right');
|
|
} else {
|
|
performSwipe('left');
|
|
}
|
|
} else {
|
|
// Vertical swipe
|
|
if (moveY > 0) {
|
|
performSwipe('down');
|
|
} else {
|
|
performSwipe('up');
|
|
}
|
|
}
|
|
} else {
|
|
// Reset card position if swipe wasn't strong enough
|
|
resetCardPosition();
|
|
}
|
|
|
|
// Hide all hints
|
|
hideAllHints();
|
|
}
|
|
|
|
function handleMouseDown(e) {
|
|
// Store the initial position and set the dragging flag
|
|
startX = e.clientX;
|
|
startY = e.clientY;
|
|
isDragging = true;
|
|
card.classList.add('swiping');
|
|
|
|
// Prevent default to avoid text selection during drag
|
|
e.preventDefault();
|
|
}
|
|
|
|
function handleMouseMove(e) {
|
|
if (!isDragging) return;
|
|
|
|
moveX = e.clientX - startX;
|
|
moveY = e.clientY - startY;
|
|
|
|
// Apply transform to the card
|
|
card.style.transform = `translate(${moveX}px, ${moveY}px) rotate(${moveX * 0.1}deg)`;
|
|
|
|
// Show appropriate hint based on direction
|
|
updateHints(moveX, moveY);
|
|
}
|
|
|
|
function handleMouseUp(e) {
|
|
if (!isDragging) return;
|
|
|
|
// Determine if this was a click (minimal movement) or a swipe
|
|
const absX = Math.abs(moveX || 0);
|
|
const absY = Math.abs(moveY || 0);
|
|
|
|
isDragging = false;
|
|
|
|
if (Math.max(absX, absY) > swipeThreshold) {
|
|
if (absX > absY) {
|
|
// Horizontal swipe
|
|
if (moveX > 0) {
|
|
performSwipe('right');
|
|
} else {
|
|
performSwipe('left');
|
|
}
|
|
} else {
|
|
// Vertical swipe
|
|
if (moveY > 0) {
|
|
performSwipe('down');
|
|
} else {
|
|
performSwipe('up');
|
|
}
|
|
}
|
|
} else {
|
|
// Reset card position if swipe wasn't strong enough
|
|
resetCardPosition();
|
|
// We don't trigger click here because the card already has a click event listener
|
|
}
|
|
|
|
// Hide all hints
|
|
hideAllHints();
|
|
}
|
|
|
|
function updateHints(moveX, moveY) {
|
|
hideAllHints();
|
|
|
|
const absX = Math.abs(moveX);
|
|
const absY = Math.abs(moveY);
|
|
|
|
if (absX > absY) {
|
|
// Horizontal movement is dominant
|
|
if (moveX > 0) {
|
|
rightHint.style.opacity = '1';
|
|
} else {
|
|
leftHint.style.opacity = '1';
|
|
}
|
|
} else {
|
|
// Vertical movement is dominant
|
|
if (moveY > 0) {
|
|
downHint.style.opacity = '1';
|
|
} else {
|
|
upHint.style.opacity = '1';
|
|
}
|
|
}
|
|
}
|
|
|
|
function hideAllHints() {
|
|
leftHint.style.opacity = '0';
|
|
rightHint.style.opacity = '0';
|
|
upHint.style.opacity = '0';
|
|
downHint.style.opacity = '0';
|
|
}
|
|
|
|
function resetCardPosition() {
|
|
card.classList.remove('swiping');
|
|
card.style.transform = '';
|
|
}
|
|
|
|
function performSwipe(direction) {
|
|
// Add the appropriate swipe class
|
|
card.classList.add(`swipe-${direction}`);
|
|
|
|
// Update the last action text
|
|
lastActionText.textContent = `Last action: Swiped ${direction}`;
|
|
|
|
// Record the selection in the database if we have a current image
|
|
if (currentImageInfo) {
|
|
recordSelection(currentImageInfo, direction);
|
|
}
|
|
|
|
// After animation completes, reset and load a new image
|
|
setTimeout(() => {
|
|
card.classList.remove(`swipe-${direction}`);
|
|
card.classList.remove('swiping');
|
|
card.style.transform = '';
|
|
|
|
// Load a new random image from our server
|
|
loadNewImage();
|
|
}, 300);
|
|
}
|
|
|
|
// Function to record a selection in the database
|
|
function recordSelection(imageInfo, action) {
|
|
// Create the data to send
|
|
const data = {
|
|
path: imageInfo.path,
|
|
resolution: imageInfo.resolution,
|
|
action: action
|
|
};
|
|
|
|
// Send the data to the server
|
|
fetch('/record-selection', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(data)
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Failed to record selection');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
console.log('Selection recorded:', data);
|
|
})
|
|
.catch(error => {
|
|
console.error('Error recording selection:', error);
|
|
});
|
|
}
|
|
|
|
// Function to load a new image from our local server
|
|
function loadNewImage() {
|
|
// Show loading state
|
|
const img = card.querySelector('img');
|
|
img.style.opacity = '0.5';
|
|
|
|
// Fetch a random image from our API
|
|
fetch('/random-image')
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Failed to fetch image');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
// Store current image info
|
|
currentImageInfo = data;
|
|
|
|
// Extract filename from path
|
|
const pathParts = data.path.split('/');
|
|
const filename = pathParts[pathParts.length - 1];
|
|
currentImageInfo.filename = filename;
|
|
currentImageInfo.creation_date = data.creation_date || 'Unknown';
|
|
|
|
// Update the image source
|
|
img.onload = function() {
|
|
img.style.opacity = '1';
|
|
};
|
|
img.src = data.path;
|
|
|
|
// Update status with resolution info
|
|
const statusElement = document.querySelector('.status-area p:first-child');
|
|
statusElement.textContent = `Current resolution: ${data.resolution}`;
|
|
})
|
|
.catch(error => {
|
|
console.error('Error loading image:', error);
|
|
img.style.opacity = '1';
|
|
img.src = 'data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22400%22%20height%3D%22400%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Crect%20width%3D%22400%22%20height%3D%22400%22%20fill%3D%22%23e0e0e0%22%2F%3E%3Ctext%20x%3D%22200%22%20y%3D%22200%22%20font-size%3D%2220%22%20text-anchor%3D%22middle%22%20alignment-baseline%3D%22middle%22%20fill%3D%22%23999%22%3EImage%20not%20found%3C%2Ftext%3E%3C%2Fsvg%3E';
|
|
});
|
|
}
|
|
|
|
// Function to handle card click for viewing full-resolution image
|
|
function handleCardClick(e) {
|
|
// Only process click if we have image info and we're not in the middle of a swipe
|
|
if (!currentImageInfo || card.classList.contains('swiping')) return;
|
|
|
|
// Prevent click from propagating (important for touch devices)
|
|
if (e) e.stopPropagation();
|
|
|
|
// Set the full-resolution image source
|
|
fullscreenImage.src = currentImageInfo.path;
|
|
|
|
// Update modal info
|
|
modalResolution.textContent = `Resolution: ${currentImageInfo.resolution}`;
|
|
modalFilename.textContent = `Filename: ${currentImageInfo.filename || 'Unknown'}`;
|
|
modalCreationDate.textContent = `Creation Date: ${currentImageInfo.creation_date || 'Unknown'}`;
|
|
|
|
// Display the modal
|
|
modal.style.display = 'block';
|
|
}
|
|
|
|
// Load initial image
|
|
loadNewImage();
|
|
});
|