Eugene1984 Posted June 4, 2023 Posted June 4, 2023 Hi Based on the demo codepen provided by you, how can I add the draggable plugin? Note that this must also work on mobile. Thanks See the Pen WNjaxKp by GreenSock (@GreenSock) on CodePen.
Cassie Posted June 4, 2023 Posted June 4, 2023 Hi there! Thanks for being part of club GreenSock ? Here's a thread that should help get you started - 1
Eugene1984 Posted June 6, 2023 Author Posted June 6, 2023 This works for me. Thank you for pointing me in the right direction. 1
Eugene1984 Posted June 7, 2023 Author Posted June 7, 2023 Hi again Is there a way to add scrolling to left and right? What I mean by this is that when on a Macbook and I use the trackpad, I'm unable to scroll left or right using 2 fingers. I hope this question makes sense.
Cassie Posted June 7, 2023 Posted June 7, 2023 Happy to help - Could you provide a minimal demo so we can see what code you're using, there's a lot of examples in this thread and linked content. Thanks!
Eugene1984 Posted June 26, 2023 Author Posted June 26, 2023 Hi Sorry, it's been a while. I have a new issue. The timeline takes ages to load and when scrolling, near the end, the browser almost freezes. It's very glitchy. I suspect performance issues. I can give you code to review, but unfortunately I can't send you a link as the project is still in development and not yet for public eyes. Also note that I'm using Wordpress. I've built a custom array made up of 2 custom post types that appear on the timeline. // GSAP import {gsap} from 'gsap'; import {ScrollTrigger} from 'gsap/ScrollTrigger'; import {ScrollSmoother} from 'gsap/ScrollSmoother'; import {Draggable} from 'gsap/Draggable'; import {ScrollToPlugin} from 'gsap/all'; export function storyTimeline() { gsap.registerPlugin( ScrollTrigger, Draggable, ScrollSmoother, ScrollToPlugin ); const panelsContainer = document.querySelector('.container'); if (panelsContainer) { const sections = gsap.utils.toArray('.panel'); let maxWidth = 0; const getMaxWidth = () => { maxWidth = 0; sections.forEach((section) => { maxWidth += section.offsetWidth; }); }; getMaxWidth(); ScrollTrigger.addEventListener('refreshInit', getMaxWidth); let scrollTween = gsap.to(sections, { x: () => `-${maxWidth - window.innerWidth}`, ease: 'none', }); let horizontalScroll = ScrollTrigger.create({ animation: scrollTween, trigger: panelsContainer, pin: true, scrub: true, end: () => `+=${maxWidth}`, invalidateOnRefresh: true, }); var dragRatio = maxWidth / (maxWidth - window.innerWidth); var drag = Draggable.create('.proxy', { trigger: panelsContainer, type: 'x', allowContextMenu: true, onPress() { this.startScroll = horizontalScroll.scroll(); }, onDrag() { horizontalScroll.scroll( this.startScroll - (this.x - this.startX) * dragRatio ); }, })[0]; let storyLinks = document.querySelectorAll('.story'); let years = document.querySelectorAll('.year'); years.forEach((year) => { ScrollTrigger.create({ trigger: year, containerAnimation: scrollTween, onEnter: () => year.classList.add('selected'), start: 'left 90%', ease: 'none' }); }); storyLinks.forEach((storyLink) => { ScrollTrigger.create({ trigger: storyLink, containerAnimation: scrollTween, onEnter: () => storyLink.classList.add('selected'), start: 'left 80%', ease: 'none' }); }); gsap.to('.navbar .button', { opacity: 1, pointerEvents: 'visible', duration: 1, ease: 'none', scrollTrigger: { trigger: '.panel.story-board', containerAnimation: scrollTween, start: 'left center', toggleActions: 'play none none reset', }, }); document.querySelectorAll('.button-round').forEach((anchor) => { anchor.addEventListener('click', function (e) { e.preventDefault(); let targetElem = document.querySelector( e.target.getAttribute('href') ), y = targetElem; if ( targetElem && panelsContainer.isSameNode(targetElem.parentElement) ) { let totalScroll = scrollTween.scrollTrigger.end - scrollTween.scrollTrigger.start, totalMovement = (sections.length - 1) * targetElem.offsetWidth; y = Math.round( scrollTween.scrollTrigger.start + (targetElem.offsetLeft / totalMovement) * totalScroll ); } gsap.to(window, { scrollTo: { y: y, autoKill: false, }, duration: 1, }); }); }); } }; <?php $timeline = get_timeline(); ?> <section class="panel story-board" id="storyBoard"> <ul class="years"> <?php foreach ($timeline as $item) : ?> <?php if (!empty($item['lodge_ids']) || !empty($item['story_ids'])) : ?> <li class="year"> <?= (!empty($item['year'])) ? '<h3>' . $item['year'] . '</h3>' : ''; ?> <?php $lodgeClass = (!empty($item['lodge_ids'])) ? 'has-lodge' : ''; ?> <ul class="stories <?= $lodgeClass; ?>"> <?php if (!empty($item['lodge_ids'])) : ?> <?php foreach ($item['lodge_ids'] as $lodgeId) : ?> <li class="story lodge"> <div class="inner"> <div class="story-head"> <div class="location"> <h5><?= get_the_title($lodgeId); ?></h5> <p> <?php $terms = get_the_terms($lodgeId, 'location'); if ($terms && !is_wp_error($terms)) { $single_term = reset($terms); $term_name = $single_term->name; echo str_replace(' - ', ', ', $term_name); } ?> </p> </div> <div class="dated"> <span class="opened">Opened</span> <span class="date"> <span><?= get_the_date('M', $lodgeId); ?></span> <span> <?php $year = get_the_date('Y', $lodgeId); echo substr($year, 0, 2) . '<br>' . substr($year, 2); ?> </span> </span> </div> </div> <?php if (has_post_thumbnail($lodgeId)) : ?> <div class="story-img"> <?php $thumb_url = get_the_post_thumbnail_url($lodgeId); ?> <img src="<?= $thumb_url; ?>" alt="Featured" class="lazyload visi" /> </div> <?php endif; ?> <?php $post_content = get_post($lodgeId); $content = $post_content->post_content; if ($content) : ?> <div class="excerpt"> <?= wpautop($content); ?> </div> <?php endif; ?> </div> </li> <?php endforeach; ?> <?php endif; ?> <?php if (!empty($item['story_ids'])) : foreach ($item['story_ids'] as $storyId) : $storyDate = get_post_meta($storyId, 'story-date', true); $storyTitle = get_the_title($storyId); $storyGuest = get_post_meta($storyId, 'your-name', true); $storyLodges = get_post_meta($storyId, 'lodge-visited', true); $storyWords = get_post_meta($storyId, 'story-words', true); ?> <li class="story"> <a href="#" class="story-link" data-story-id="<?= $storyId; ?>"> <span class="story-date"> <?php if ($storyDate) { $date = DateTime::createFromFormat('M Y', $storyDate); $formatted_date = $date->format('M Y'); echo $formatted_date; } ?> </span> <?php $attachments = get_attached_media('', $storyId); if (!empty($attachments)) : $single_attachment = reset($attachments); $attachment_url = wp_get_attachment_url($single_attachment->ID); $file_ext = wp_check_filetype($attachment_url); ?> <div class="story-img"> <?php if (($file_ext['ext'] === 'jpg' || $file_ext['ext'] === 'jpeg' || $file_ext['ext'] === 'png')) : ?> <img src="<?= $attachment_url; ?>" alt="<?= $single_attachment->post_title; ?>" style="display: block; width: 100%;"> <?php endif; ?> <?php if ($file_ext['ext'] === 'mp4' || $file_ext['ext'] === 'mov') : ?> <video> <source src="<?= $attachment_url; ?>" type="video/mp4"> Your browser does not support HTML video. </video> <?php endif; ?> </div> <?php endif; ?> <div class="story-auth"> <?php if ($storyGuest) { echo '<span>' . $storyGuest . '</span>'; } if ($storyLodges) { echo '<span>' . str_replace(',', ', ', $storyLodges) . '</span>'; } ?> </div> <div class="story-excerpt"> <?= ($storyWords) ? wp_trim_words($storyWords, 20, '...') : ''; ?> </div> </a> </li> <?php endforeach; ?> <?php endif; ?> </ul> </li> <?php endif; ?> <?php endforeach; ?> </ul> <div class="story-tail"> <h2>Pioneering spirit, enduring purpose</h2> <p> As we look to the next 30 years of our conservation journey, Lorem ipsum donor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p> </div> </section>
GSAP Helper Posted June 26, 2023 Posted June 26, 2023 It's pretty tough to troubleshoot without a minimal demo - the issue could be caused by CSS, markup, a third party library, your browser, an external script that's totally unrelated to GSAP, etc. Would you please provide a very simple CodePen or CodeSandbox that demonstrates the issue? Please don't include your whole project. Just some colored <div> elements and the GSAP code is best (avoid frameworks if possible). See if you can recreate the issue with as few dependancies as possible. If not, incrementally add code bit by bit until it breaks. Usually people solve their own issues during this process! If not, then at least we have a reduced test case which greatly increases your chances of getting a relevant answer. Here's a starter CodePen that loads all the plugins. Just click "fork" at the bottom right and make your minimal demo: See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen. If you're using something like React/Next/Vue/Nuxt or some other framework, you may find StackBlitz easier to use. We have a series of collections with different templates for you to get started on these different frameworks: React/Next/Vue/Nuxt. Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions.
Eugene1984 Posted June 26, 2023 Author Posted June 26, 2023 Hi I've tried to keep it as simple as possible given what my problem is. It seems to be working fine on the pen, but maybe you can let me know if the code provided is recommended for what I'm trying to do. See pen below See the Pen eYQgEKd by demeillon (@demeillon) on CodePen.
Cassie Posted June 27, 2023 Posted June 27, 2023 Hi there - Yeah, nothing looks like a red flag to me (aside from the fact that you're doing all the animation in CSS, which seems a little bit of an odd choice, using CSS and GSAP is a good way to get into a muddle and end up with conflicts between tweens and transition times) This seems to be working great though https://cdpn.io/pen/debug/eYQgEKd?authentication_hash=GnAnbWnXXZLA If it's working in codepen then maybe the issue is elsewhere? Large images, other JS running at the same time and slowing stuff down? Other animations?
Eugene1984 Posted June 27, 2023 Author Posted June 27, 2023 Thanks @Cassie Yes, I think it might be other JS or large images. I'll try a couple of things and see how it goes. 1
Eugene1984 Posted June 29, 2023 Author Posted June 29, 2023 Okay, so I've removed all other JS and images, but it's still very slow. On some devices the page crashes. I've also removed the CSS animations and rather using GSAP for this. I'm thinking of maybe using AJAX to load one item at a time on scroll. I've tried this, but it seems like the scrolltrigger needs to be reinitialised after the AJAX call. I've added the function in the success property so that the scrolltrigger gets initialised again, but this also doesn't work. Maybe someone can point me in the right direction for this?
Rodrigo Posted June 29, 2023 Posted June 29, 2023 Hi, What you could try is use ScrollTrigger.refresh() after the Ajax call and once you are completely sure that the data returned from the Ajax call is reflected in the DOM, you can call the refresh method: https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.refresh() Here is an example that uses an approach that emulates the approach of getting data from an API call: See the Pen YzOzjbL by GreenSock (@GreenSock) on CodePen. Hopefully this helps. Happy Tweening! 1
Eugene1984 Posted June 30, 2023 Author Posted June 30, 2023 Hi @Rodrigo Thanks for the reply. I've tried the refresh() method, but did not work for me. The killAll() method however did. I would really like to know why I'm adding this here for reference and so that it can help others with a similar problem. I hade to add the ScrollTrigger.killAll() method after the successful AJAX call. Then I've added a little timeout on the ScrollTrigger functions. $.ajax({ url: main_ajax_scripts.ajax_url, data: { action: 'get_more_years', yearNumber: yearNumber++, last_year: lastYear, }, success: function (data) { $('#timelineContainer').append(data); ScrollTrigger.killAll(); setTimeout(() => { storyTimeline(); }, 500); }, error: function (errorThrown) { console.log(errorThrown); }, });
Rodrigo Posted June 30, 2023 Posted June 30, 2023 Hi, The approach with the refresh method only works for the ScrollTrigger instances that were created before the ajax call, there is actually no need to re-create ScrollTrigger instances that existed before you make the API request, those have to be refreshed, that's why in the example you see this: // Create a new batch just for the new content createBatch(newContent); ScrollTrigger.refresh(); You create the ScrollTrigger instances for the new content that is added after the API response and then you just run the refresh method. Killing all existing ScrollTrigger instances and then create everything from scratch might not be the best option performance-wise. Hopefully this helps. Happy Tweening!
Solution Eugene1984 Posted July 3, 2023 Author Solution Posted July 3, 2023 Hi @Rodrigo Thanks for your help, but I've managed to find the problem for the very slow loading time. So no need for AJAX anymore. The first thing I spotted was that it only loading extremely slow in Chrome and not Safari or Firefox. I then did a couple of Lighthouse page speed analysis, and removed unused stylesheets etc... It was the damn "wp-block-library" stylesheet. I've dequeued this and problem solved! 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now