157 lines
6.1 KiB
JavaScript
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);
|
|
}
|
|
}); |