Start Counting on Visibility
January 16, 2025 ยท AI Conversations
jQuery(document).ready(function($) {
$('.elementor-counter-number').css('opacity', 0); // Hide numbers initially
$('.elementor-counter').each(function(index) {
var counter = $(this);
var countTo = parseFloat(counter.find('.elementor-counter-number').data('to-value')); // Get the target value as a float
var hasDecimals = countTo % 1 !== 0; // Check if the number has decimals
counter.find('.elementor-counter-number').text(0); // Set the initial count to zero
// Start counting with a delay
setTimeout(function() {
counter.find('.elementor-counter-number').css('opacity', 1); // Make the number visible
$({ countNum: 0 }).animate({ countNum: countTo }, {
duration: 2000, // Duration for counting
easing: 'linear',
step: function() {
// Display the number with or without decimals
counter.find('.elementor-counter-number').text(
hasDecimals ? this.countNum.toFixed(2) : Math.floor(this.countNum)
);
},
complete: function() {
// Ensure it shows the final value with or without decimals
counter.find('.elementor-counter-number').text(
hasDecimals ? this.countNum.toFixed(2) : Math.floor(this.countNum)
);
}
});
}, index * 1000); // Delay between each counter
});
});
### Updated Code:
jQuery(document).ready(function($) {
$('.elementor-counter-number').css('opacity', 0); // Hide numbers initially
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
var counter = $(entry.target);
var countTo = parseFloat(counter.find('.elementor-counter-number').data('to-value')); // Get the target value as a float
var hasDecimals = countTo % 1 !== 0; // Check if the number has decimals
counter.find('.elementor-counter-number').text(0); // Set the initial count to zero
// Start counting
counter.find('.elementor-counter-number').css('opacity', 1); // Make the number visible
$({ countNum: 0 }).animate({ countNum: countTo }, {
duration: 2000, // Duration for counting
easing: 'linear',
step: function() {
// Display the number with or without decimals
counter.find('.elementor-counter-number').text(
hasDecimals ? this.countNum.toFixed(2) : Math.floor(this.countNum)
);
},
complete: function() {
// Ensure it shows the final value with or without decimals
counter.find('.elementor-counter-number').text(
hasDecimals ? this.countNum.toFixed(2) : Math.floor(this.countNum)
);
}
});
observer.unobserve(entry.target); // Stop observing once counting starts
}
});
}, {
threshold: 0.1 // Trigger when at least 10% of the element is visible
});
// Attach the observer to each counter
$('.elementor-counter').each(function() {
observer.observe(this);
});
});
### Explanation:
1. **Intersection Observer**:
– Monitors when an element becomes visible in the viewport.
– `entry.isIntersecting` checks if the observed element is in the viewport.
2. **Unobserve After Start**:
– Once the counting starts for an element, `observer.unobserve(entry.target)` stops further observation, improving performance.
3. **Threshold**:
– The `threshold: 0.1` triggers the callback when at least 10% of the element is visible. Adjust this value as needed.
This approach ensures the counting animation only starts when the `.elementor-counter` becomes visible, enhancing performance and user experience.
jQuery(document).ready(function($) {
$('.elementor-counter-number').css('opacity', 0); // Hide numbers initially
// Initialize Intersection Observer
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
var counter = $(entry.target);
var countTo = parseFloat(counter.find('.elementor-counter-number').data('to-value')); // Get the target value as a float
var hasDecimals = countTo % 1 !== 0; // Check if the number has decimals
counter.find('.elementor-counter-number').text(0); // Set the initial count to zero
// Start counting
counter.find('.elementor-counter-number').css('opacity', 1); // Make the number visible
$({ countNum: 0 }).animate({ countNum: countTo }, {
duration: 2000, // Duration for counting
easing: 'linear',
step: function() {
// Display the number with or without decimals
counter.find('.elementor-counter-number').text(
hasDecimals ? this.countNum.toFixed(2) : Math.floor(this.countNum)
);
},
complete: function() {
// Ensure it shows the final value with or without decimals
counter.find('.elementor-counter-number').text(
hasDecimals ? this.countNum.toFixed(2) : Math.floor(this.countNum)
);
}
});
observer.unobserve(entry.target); // Stop observing once counting starts
}
});
}, {
threshold: 0.1 // Trigger when at least 10% of the element is visible
});
// Attach the observer to each counter
$('.elementor-counter').each(function() {
observer.observe(this);
});
});
### Key Adjustments:
1. **Hiding Initially**:
– Ensures the counter numbers are hidden (`opacity: 0`) until they start counting.
2. **Observer Initialization**:
– The `IntersectionObserver` monitors visibility of `.elementor-counter` elements.
3. **Counting Logic**:
– Triggers counting logic only when the `.elementor-counter` becomes visible (`entry.isIntersecting`).
4. **Performance Optimization**:
– `observer.unobserve(entry.target)` ensures that each element is observed only once, avoiding redundant triggers.
### Usage:
Ensure the `.elementor-counter` elements have the necessary structure and the `data-to-value` attribute to specify the target number. This script starts the animation when at least 10% of the element is visible in the viewport. Adjust the `threshold` value as needed for your specific requirements.
Here's the updated code:
### Updated Code: Sequential Counter Start
jQuery(document).ready(function($) {
$('.elementor-counter-number').css('opacity', 0); // Hide numbers initially
// Initialize Intersection Observer
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
var counter = $(entry.target);
// Sequential delay based on index
var index = $('.elementor-counter').index(entry.target);
var delay = index * 1000; // 1 second delay between each counter
setTimeout(function() {
var countTo = parseFloat(counter.find('.elementor-counter-number').data('to-value')); // Target value
var hasDecimals = countTo % 1 !== 0; // Check for decimals
counter.find('.elementor-counter-number').text(0); // Initialize counter
// Start counting
counter.find('.elementor-counter-number').css('opacity', 1); // Make visible
$({ countNum: 0 }).animate({ countNum: countTo }, {
duration: 2000, // Counting duration
easing: 'linear',
step: function() {
// Update the number during animation
counter.find('.elementor-counter-number').text(
hasDecimals ? this.countNum.toFixed(2) : Math.floor(this.countNum)
);
},
complete: function() {
// Ensure final value is accurate
counter.find('.elementor-counter-number').text(
hasDecimals ? this.countNum.toFixed(2) : Math.floor(this.countNum)
);
}
});
}, delay);
observer.unobserve(entry.target); // Stop observing once triggered
}
});
}, {
threshold: 0.1 // Trigger when at least 10% of the element is visible
});
// Attach observer to each counter
$('.elementor-counter').each(function() {
observer.observe(this);
});
});
### Key Adjustments:
1. **Sequential Delay**:
– The `index` of each counter determines the delay: `index * 1000` (1-second intervals).
– This creates a staggered, left-to-right counting effect.
2. **Visibility Trigger**:
– Each counter starts counting only after becoming visible in the viewport, respecting the `IntersectionObserver`.
3. **Performance**:
– After the counting starts, the element is unobserved to avoid redundant triggers.
### How It Works:
– The observer detects when a `.elementor-counter` becomes visible.
– Based on the counter's position (`index`), a delay is applied before starting its animation.
– Counters animate sequentially from left to right.
### Adjustments:
– To change the delay between counters, modify `index * 1000` (e.g., `index * 500` for 0.5-second intervals).
– Adjust the `threshold` in `IntersectionObserver` for when counters should begin (e.g., `0.5` for 50% visibility).
This ensures that counters are triggered sequentially and create a visually pleasing effect.