Wheel_of_Fortune_Plugin/admin/js/wheel.js

157 lines
6.1 KiB
JavaScript

/**
* Wheel of Fortune - JavaScript for wheel functionality
* Robust, smooth animation using requestAnimationFrame and easing functions.
*/
jQuery(document).ready(function($) {
// Check if wheelSettings are available
if (typeof wheelSettings === 'undefined') {
console.error('Wheel of Fortune: Settings (wheelSettings) are not defined. Please check the plugin setup.');
return;
}
// Elements
const wheel = $('.wheel');
const button = $('.wheel-button');
const resultDiv = $('.wheel-result');
const spinsCounter = $('.wheel-spins-counter span');
// Animation state
let isSpinning = false;
let animationFrameId = null;
let accumulatedRotation = 0; // Total rotation is maintained between spins
// Animation settings
const spinDuration = 8000; // 8 seconds for a more dramatic effect
const spinRotations = 5; // Number of full rotations before stopping
/**
* Easing function (cubic-bezier out) for natural deceleration
* @param {number} t - Current time (0 to 1)
* @returns {number} - Animation progress (0 to 1)
*/
function easeOutCubic(t) {
return 1 - Math.pow(1 - t, 3);
}
/**
* Main animation loop
* @param {number} startTime - Animation start time
* @param {number} startRotation - Starting rotation angle
* @param {number} rotationAmount - Total rotation to perform for this spin
*/
function animateWheel(startTime, startRotation, rotationAmount) {
const currentTime = Date.now();
const elapsedTime = currentTime - startTime;
if (elapsedTime >= spinDuration) {
wheel.css('transform', `rotate(${startRotation + rotationAmount}deg)`);
accumulatedRotation = startRotation + rotationAmount; // Update the final position
finishSpin();
return;
}
// Calculate progress within the animation duration
const timeProgress = elapsedTime / spinDuration;
// Apply the easing function to determine the rotation progress
const rotationProgress = easeOutCubic(timeProgress);
// Calculate the current rotation
const newRotation = startRotation + (rotationAmount * rotationProgress);
wheel.css('transform', `rotate(${newRotation}deg)`);
// Continue to the next frame
animationFrameId = requestAnimationFrame(() => animateWheel(startTime, startRotation, rotationAmount));
}
/**
* Function to execute after the spin animation is complete
*/
function finishSpin() {
// Display the result with a slight delay for better effect
setTimeout(() => {
const prize = window.spinResult.prize;
resultDiv.html(`<h3>Congratulations!</h3><p>You've won: <strong>${prize.name}</strong></p>`);
resultDiv.addClass('win').fadeIn(300);
isSpinning = false;
// Re-enable the button if there are remaining spins
if (window.spinResult.remaining_spins > 0) {
button.prop('disabled', false);
} else {
button.prop('disabled', true);
}
}, 500); // 500ms pause before showing the result
}
// Spin button click handler
button.on('click', function() {
if (isSpinning) return;
isSpinning = true;
button.prop('disabled', true);
resultDiv.hide().removeClass('win error');
$.ajax({
url: wheelSettings.ajaxUrl,
method: 'POST',
data: {
action: 'wheel_spin',
nonce: wheelSettings.nonce
},
beforeSend: function(xhr) {
xhr.setRequestHeader('X-WP-Nonce', wheelSettings.nonce);
},
success: function(response) {
if (response.success) {
window.spinResult = response;
// The target angle (0-360) for the wheel to stop at, sent by the server.
const targetAngle = response.degree;
// Add several full rotations for a nice visual effect.
const fullSpins = spinRotations * 360;
// Get the current angle of the wheel, normalized to 0-360 degrees.
const currentAngle = accumulatedRotation % 360;
// Calculate the rotation needed to get from the current angle to the target angle.
// We must always rotate forward (clockwise, positive rotation).
let rotationToTarget = targetAngle - currentAngle;
if (rotationToTarget < 0) {
rotationToTarget += 360;
}
// The total amount of rotation for this spin.
const rotationAmount = fullSpins + rotationToTarget;
const startRotation = accumulatedRotation;
// Start the animation. The function will rotate the wheel by 'rotationAmount' degrees.
animateWheel(Date.now(), startRotation, rotationAmount);
// Update the remaining spins counter on the screen.
spinsCounter.text(response.remaining_spins);
} else {
// Display error from server
resultDiv.html(`<p>${response.data.message || 'An error occurred.'}</p>`);
resultDiv.addClass('error').fadeIn(300);
isSpinning = false;
button.prop('disabled', false);
}
},
error: function(xhr) {
const errorMsg = xhr.responseJSON ? xhr.responseJSON.message : 'A communication error occurred.';
resultDiv.html(`<p>${errorMsg}</p>`);
resultDiv.addClass('error').fadeIn(300);
isSpinning = false;
button.prop('disabled', false);
}
});
});
// Initialization
if (wheelSettings.remainingSpins <= 0) {
button.prop('disabled', true);
}
});