spingenius-pro / script.js
dazman72's picture
ad more customisation options, use cutting edge libraries for a rich user experience and the ability to create totally unique and custom loaders
1a52121 verified
Raw History Blame Contribute Delete
17.4 kB
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const spinner = document.getElementById('spinner');
const animationContainer = document.getElementById('animation-container');
const playBtn = document.getElementById('play-btn');
const spinnerType = document.getElementById('spinner-type');
const spinnerColor = document.getElementById('spinner-color');
const spinnerColor2 = document.getElementById('spinner-color-2');
const spinnerSize = document.getElementById('spinner-size');
const sizeValue = document.getElementById('size-value');
const spinnerSpeed = document.getElementById('spinner-speed');
const speedValue = document.getElementById('speed-value');
const animationStyle = document.getElementById('animation-style');
const customSvgUpload = document.getElementById('custom-svg-upload');
const svgUpload = document.getElementById('svg-upload');
const particleControls = document.getElementById('particle-controls');
const particleCount = document.getElementById('particle-count');
const particleSize = document.getElementById('particle-size');
// Export buttons
const exportCssBtn = document.getElementById('export-css');
const exportHtmlBtn = document.getElementById('export-html');
const exportJsBtn = document.getElementById('export-js');
const exportReactBtn = document.getElementById('export-react');
const exportVueBtn = document.getElementById('export-vue');
const exportGifBtn = document.getElementById('export-gif');
const exportSvgBtn = document.getElementById('export-svg');
const exportLottieBtn = document.getElementById('export-lottie');
const animationCards = document.querySelectorAll('.animation-card');
// Current animation state
let currentAnimation = 'circle';
let isPlaying = true;
let customSvgPath = null;
let animationTimeline = null;
// Initialize
updateSizeDisplay();
updateSpeedDisplay();
feather.replace();
// Setup Konva stage for advanced animations
const stage = new Konva.Stage({
container: animationContainer,
width: animationContainer.clientWidth,
height: animationContainer.clientHeight
});
const layer = new Konva.Layer();
stage.add(layer);
// Event Listeners
spinnerType.addEventListener('change', function() {
updateSpinnerType();
toggleAdvancedControls();
});
spinnerColor.addEventListener('input', updateSpinnerColor);
spinnerColor2.addEventListener('input', updateSpinnerColor);
spinnerSize.addEventListener('input', updateSpinnerSize);
spinnerSpeed.addEventListener('input', updateSpinnerSpeed);
animationStyle.addEventListener('change', updateAnimationStyle);
svgUpload.addEventListener('change', handleSvgUpload);
particleCount.addEventListener('input', updateParticles);
particleSize.addEventListener('input', updateParticles);
playBtn.addEventListener('click', toggleAnimation);
exportCssBtn.addEventListener('click', exportCSS);
exportHtmlBtn.addEventListener('click', exportHTML);
exportJsBtn.addEventListener('click', exportJS);
exportReactBtn.addEventListener('click', exportReact);
exportVueBtn.addEventListener('click', exportVue);
exportGifBtn.addEventListener('click', exportGIF);
exportSvgBtn.addEventListener('click', exportSVG);
exportLottieBtn.addEventListener('click', exportLottie);
// Add click events to gallery items
animationCards.forEach(card => {
card.addEventListener('click', function() {
const type = this.getAttribute('data-type');
spinnerType.value = type;
updateSpinnerType();
});
});
// Toggle advanced controls based on selected animation type
function toggleAdvancedControls() {
customSvgUpload.classList.add('hidden');
particleControls.classList.add('hidden');
if (currentAnimation === 'custom') {
customSvgUpload.classList.remove('hidden');
} else if (currentAnimation === 'particles') {
particleControls.classList.remove('hidden');
}
}
// Handle SVG upload
function handleSvgUpload(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(event) {
customSvgPath = event.target.result;
updateSpinnerType();
};
reader.readAsText(file);
}
// Update particle animation
function updateParticles() {
if (currentAnimation === 'particles') {
updateSpinnerType();
}
}
// Update animation easing style
function updateAnimationStyle() {
if (animationTimeline) {
animationTimeline.easing(animationStyle.value);
}
}
// Main function to update spinner type
function updateSpinnerType() {
currentAnimation = spinnerType.value;
animationContainer.innerHTML = '';
let newSpinner;
switch(currentAnimation) {
case 'circle':
newSpinner = document.createElement('div');
newSpinner.className = 'rounded-full border-4 border-t-transparent animate-spin';
newSpinner.style.borderColor = spinnerColor.value;
newSpinner.style.width = `${spinnerSize.value}px`;
newSpinner.style.height = `${spinnerSize.value}px`;
newSpinner.style.animationDuration = `${spinnerSpeed.value}s`;
break;
case 'dots':
newSpinner = document.createElement('div');
newSpinner.className = 'flex gap-2 items-center';
for (let i = 0; i < 3; i++) {
const dot = document.createElement('div');
dot.className = 'rounded-full animate-bounce';
dot.style.backgroundColor = spinnerColor.value;
dot.style.width = `${spinnerSize.value/5}px`;
dot.style.height = `${spinnerSize.value/5}px`;
dot.style.animationDuration = `${spinnerSpeed.value}s`;
dot.style.animationDelay = `${i * 0.2}s`;
newSpinner.appendChild(dot);
}
break;
case 'bar':
newSpinner = document.createElement('div');
newSpinner.className = 'w-3/4 h-2 bg-gray-200 rounded-full overflow-hidden';
const innerBar = document.createElement('div');
innerBar.className = 'h-full rounded-full animate-progress';
innerBar.style.backgroundColor = spinnerColor.value;
innerBar.style.animationDuration = `${spinnerSpeed.value}s`;
newSpinner.appendChild(innerBar);
break;
case 'pulse':
newSpinner = document.createElement('div');
newSpinner.className = 'rounded-full animate-pulse';
newSpinner.style.backgroundColor = spinnerColor.value;
newSpinner.style.width = `${spinnerSize.value}px`;
newSpinner.style.height = `${spinnerSize.value}px`;
newSpinner.style.animationDuration = `${spinnerSpeed.value}s`;
break;
case 'bounce':
newSpinner = document.createElement('div');
newSpinner.className = 'rounded-full animate-custom-bounce';
newSpinner.style.backgroundColor = spinnerColor.value;
newSpinner.style.width = `${spinnerSize.value}px`;
newSpinner.style.height = `${spinnerSize.value}px`;
newSpinner.style.animationDuration = `${spinnerSpeed.value}s`;
break;
}
animationContainer.appendChild(newSpinner);
spinner = newSpinner;
}
function updateSpinnerColor() {
const elements = animationContainer.querySelectorAll('div');
elements.forEach(el => {
if (el.style.borderColor) {
el.style.borderColor = spinnerColor.value;
}
if (el.style.backgroundColor) {
el.style.backgroundColor = spinnerColor.value;
}
});
}
function updateSpinnerSize() {
sizeValue.textContent = spinnerSize.value;
const elements = animationContainer.querySelectorAll('div');
elements.forEach(el => {
if (currentAnimation === 'dots') {
el.style.width = `${spinnerSize.value/5}px`;
el.style.height = `${spinnerSize.value/5}px`;
} else {
if (el.style.width) el.style.width = `${spinnerSize.value}px`;
if (el.style.height) el.style.height = `${spinnerSize.value}px`;
}
});
}
function updateSpinnerSpeed() {
speedValue.textContent = spinnerSpeed.value;
const elements = animationContainer.querySelectorAll('div');
elements.forEach(el => {
if (el.style.animationDuration) {
el.style.animationDuration = `${spinnerSpeed.value}s`;
}
});
}
function updateSizeDisplay() {
sizeValue.textContent = spinnerSize.value;
}
function updateSpeedDisplay() {
speedValue.textContent = spinnerSpeed.value;
}
function toggleAnimation() {
const elements = animationContainer.querySelectorAll('div');
if (isPlaying) {
elements.forEach(el => {
el.style.animationPlayState = 'paused';
});
playBtn.innerHTML = '<i data-feather="play"></i> Play';
isPlaying = false;
} else {
elements.forEach(el => {
el.style.animationPlayState = 'running';
});
playBtn.innerHTML = '<i data-feather="pause"></i> Pause';
isPlaying = true;
}
feather.replace();
}
function createParticleAnimation() {
layer.destroyChildren();
const count = parseInt(particleCount.value);
const size = parseInt(particleSize.value);
const centerX = stage.width() / 2;
const centerY = stage.height() / 2;
const radius = Math.min(stage.width(), stage.height()) * 0.3;
const particles = [];
for (let i = 0; i < count; i++) {
const angle = (i / count) * Math.PI * 2;
const x = centerX + Math.cos(angle) * radius;
const y = centerY + Math.sin(angle) * radius;
const particle = new Konva.Circle({
x: x,
y: y,
radius: size,
fill: spinnerColor.value,
opacity: 0.7
});
layer.add(particle);
particles.push(particle);
}
animationTimeline = anime.timeline({
duration: parseInt(spinnerSpeed.value) * 1000,
easing: animationStyle.value,
loop: true
});
particles.forEach((particle, i) => {
const angle = (i / particles.length) * Math.PI * 2;
animationTimeline.add({
targets: particle,
x: centerX + Math.cos(angle + Math.PI) * radius,
y: centerY + Math.sin(angle + Math.PI) * radius,
fill: spinnerColor2.value,
duration: parseInt(spinnerSpeed.value) * 1000,
offset: 0
});
});
layer.draw();
}
function exportCSS() {
let cssCode = '';
switch(currentAnimation) {
case 'circle':
cssCode = `/* Circle Spinner */
.spinner {
width: ${spinnerSize.value}px;
height: ${spinnerSize.value}px;
border: 4px solid ${spinnerColor.value};
border-top-color: transparent;
border-radius: 50%;
animation: spin ${spinnerSpeed.value}s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}`;
break;
case 'dots':
cssCode = `/* Bouncing Dots */
.dots-container {
display: flex;
gap: 8px;
align-items: center;
}
.dot {
width: ${spinnerSize.value/5}px;
height: ${spinnerSize.value/5}px;
background-color: ${spinnerColor.value};
border-radius: 50%;
animation: bounce ${spinnerSpeed.value}s infinite;
}
.dot:nth-child(2) {
animation-delay: 0.2s;
}
.dot:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes bounce {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-15px); }
}`;
break;
case 'bar':
cssCode = `/* Progress Bar */
.progress-container {
width: 75%;
height: 8px;
background-color: #e5e7eb;
border-radius: 4px;
overflow: hidden;
}
.progress-bar {
height: 100%;
background-color: ${spinnerColor.value};
border-radius: 4px;
animation: progress ${spinnerSpeed.value}s ease-in-out infinite;
}
@keyframes progress {
0% { width: 0%; }
100% { width: 100%; }
}`;
break;
case 'pulse':
cssCode = `/* Pulse Animation */
.pulse {
width: ${spinnerSize.value}px;
height: ${spinnerSize.value}px;
background-color: ${spinnerColor.value};
border-radius: 50%;
animation: pulse ${spinnerSpeed.value}s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(0.8); opacity: 0.5; }
}`;
break;
case 'bounce':
cssCode = `/* Bounce Animation */
.bounce {
width: ${spinnerSize.value}px;
height: ${spinnerSize.value}px;
background-color: ${spinnerColor.value};
border-radius: 50%;
animation: customBounce ${spinnerSpeed.value}s infinite;
}
@keyframes customBounce {
0%, 100% { transform: translateY(0) scale(1); }
25% { transform: translateY(-20px) scale(1.1); }
50% { transform: translateY(0) scale(1); }
75% { transform: translateY(-10px) scale(1.05); }
}`;
break;
}
// Create download link
const blob = new Blob([cssCode], { type: 'text/css' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'spinner-animation.css';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
function exportHTML() {
let htmlCode = '';
switch(currentAnimation) {
case 'circle':
htmlCode = `<div class="spinner"></div>`;
break;
case 'dots':
htmlCode = `<div class="dots-container">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>`;
break;
case 'bar':
htmlCode = `<div class="progress-container">
<div class="progress-bar"></div>
</div>`;
break;
case 'pulse':
htmlCode = `<div class="pulse"></div>`;
break;
case 'bounce':
htmlCode = `<div class="bounce"></div>`;
break;
}
// Create download link
const blob = new Blob([htmlCode], { type: 'text/html' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'spinner-animation.html';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
function exportJS() {
let jsCode = '';
// Generate JavaScript code for the animation
// This would use the animation parameters to create a vanilla JS implementation
alert('JavaScript export would generate code using the current animation parameters');
}
function exportReact() {
let reactCode = '';
// Generate React component code for the animation
alert('React export would generate a React component with the current animation');
}
function exportVue() {
let vueCode = '';
// Generate Vue component code for the animation
alert('Vue export would generate a Vue component with the current animation');
}
function exportSVG() {
// Generate SVG markup for the current animation
alert('SVG export would generate SVG markup for the current animation');
}
function exportLottie() {
// Generate Lottie JSON for the current animation
alert('Lottie export would generate JSON for use with Lottie/Bodymovin');
}
function exportGIF() {
// Use gif.js or similar library to capture frames and create GIF
alert('GIF export would capture frames and generate an animated GIF');
}
});