Jump to content
Search Community

teejay_hh

Members
  • Posts

    18
  • Joined

  • Last visited

Posts posted by teejay_hh

  1. Hello I have a question performance. I wrote small horizontal slider which also moves 2 background images.  The following code shows my slider

    implementation. I wrote this for my team so there are few more comments which dont assume gsap knowledge. 

     

    define(function (require) {
      const gsap = require('gsap/gsap.min').gsap
      const Draggable = require('gsap/Draggable.min').Draggable
      const InertiaPlugin = require('gsap/InertiaPlugin.min').InertiaPlugin
      gsap.registerPlugin(Draggable, InertiaPlugin)
    
      /**
       * The slider class creates a draggable slider which uses gsap's draggable plugin
       * The slider requires a certain dom structure to function and therefore is not reusable
       * The class requires `gsap` as wells as the 2 plugins `Draggable, InertiaPlugin` to be registered
       *
       * The draggable will start an auto rotation by default, which can be interrupted via interacting with it.
       *
       * @class Slider
       *
       *
       *
       */
      return class Slider {
        constructor(delay = 8, endCallback = () => {}) {
          this.slideDelay = delay
          this.slideDuration = 1
          this.slider = document.getElementById('slider')
          this.slides = document.querySelectorAll('.slide')
          this.slidesInner = document.querySelectorAll('.slides-inner')
          this.grass = document.getElementById('bg-three')
          this.hills = document.getElementById('bg-two')
          this.clouds = document.getElementById('bg-one')
          this.numSlides = this.slides.length
          this.snapX = 0
          this.animationCounter = 1
          this.slideWidth = this.slides[0].offsetWidth
          this.endCallback = endCallback
          this.hillsXSetter = gsap.quickSetter(this.hills, 'css')
          this.cloudsXSetter = gsap.quickSetter(this.clouds, 'css')
    
          this.createResizeListener()
          this.createDraggable()
          this.initiateSliderAnimation()
        }
    
        /**
         * Creates the draggable component with a few defaults. Please check out the
         * documentation if you would like to know more about what this plugin can do
         *
         * @see https://greensock.com/docs/v3/Plugins/Draggable
         */
        createDraggable() {
          this.draggable = new Draggable(this.slidesInner, {
            type: 'x', // only horizontal scrolling
            bounds: this.slider, // bounds the draggable to the container so it cant be dragged out of it
            inertia: true, // momentum - throwing behaviour (magic)
            edgeResistance: 0.8,
            dragResistance: 0.3,
            throwProps: true,
            onDragStart: this.killAnimation, // callback which gets executed on every tick of dragging
            onDrag: this.onDrag, // callback which gets executed on every tick of dragging
            onThrowUpdate: this.onDrag, // callback which gets executed when the draggable is thrown
            snap: this.snapX, // is set to a function which calculates a snapping position
            callbackScope: this, // sets the callback scope to be the class instead of the draggable instance
            // implement some cool live snapping
          })
        }
    
        /**
         * We start a delayed call which initiated the animation cycle to run through all slides until the end
         * This will set a timer variable which can be used to either kill the call or to restart it.
         */
        initiateSliderAnimation() {
          this.timer = gsap.delayedCall(this.slideDelay, this.autoPlay, null, this)
        }
    
        /**
         * Stop the animation loop
         */
        killAnimation() {
          if (this.timer) this.timer.kill()
        }
    
        /**
         * The method get called by the delayed call `initiateSliderAnimation` which starts the slide animation
         * When the draggable is pressed, dragged or thrown at the time of execution then we will kill the next call.
         * We also stop at the end of the last slide which executes a callback which is used to redirect to a different page.
         */
        autoPlay() {
          if (this.animationCounter >= this.numSlides) {
            this.killAnimation()
            this.endCallback()
            return
          }
    
          if (this.draggable.isPressed || this.draggable.isDragging || this.draggable.isThrowing) {
            this.killAnimation()
          } else {
            this.animateSlides()
          }
        }
    
        /**
         * The animateSlides method runs an animation which slides the draggable one screen further
         * If the function is called multiple times it will progress through all slides sequentially
         * We use the timer variable to create a loop which calls the delayed call from `initiateSliderAnimation`  method
         * again.
         */
        animateSlides() {
          const _this = this // callback functions require us to use a scope var
    
          _this.animationCounter++
          _this.timer.restart(true) // create a loop
    
          // slides the draggable one screen further
          gsap.to(_this.slidesInner, {
            x: '-=' + _this.slideWidth,
            duration: _this.slideDuration,
            ease: 'quad.inOut',
            onUpdate: function (s) {
              const drag = _this.draggable.update()
              _this.onDrag(null, drag.x)
            },
          })
        }
    
        /**
         * This method is called when the we animate or drag the draggable. Its used to create the paralax effect
         * on the different backgrounds.
         *
         * @param pointer
         * @param s
         */
        onDrag(pointer = null, s = null) {
          if (s === null) s = this.draggable.x
          // quicksetter (defined in the constructor) have a massive performance boost
          // to the normal set method at least 50% - https://greensock.com/docs/v3/GSAP/gsap.quickSetter()
          this.hillsXSetter({ x: s / 5 })
          this.cloudsXSetter({ x: s / 8 })
        }
    
        /**
         * The resizeListener listens to the window resize event and sets the Draggable width programmatically
         */
        createResizeListener() {
          window.addEventListener('resize', this.setDraggableWidth.bind(this))
          this.setDraggableWidth()
        }
    
        /**
         * We use the window width set the slide width to stretch the whole screen
         * The slides are setup as flex colums of 1, which means they will adjust to the size of its parent container.
         * To make these slides fullscreen we need to set the container the size of x times the screen width.
         * We also adjust the snaping based on the current screen width.
         */
        setDraggableWidth() {
          this.slideWidth = document.documentElement.clientWidth || document.body.clientWidth
          gsap.set(this.slidesInner, { width: this.numSlides * this.slideWidth + 'px' })
          gsap.set(this.slides, { width: 100 / this.numSlides + '%' })
    
          // make sure we show the inner container after the slides are repositioned.
          gsap.to(this.slidesInner, { delay: 0.5, duration: 0.5, autoAlpha: 1 })
    
          this.snapX = function (endValue) {
            const slideWidth = document.body.offsetWidth
            return Math.round(endValue / slideWidth) * slideWidth
          }
    
          if (this.draggable) this.draggable.update(true)
        }
      }
    })

    Its fairly straight forward and pretty pretty fast on my mbpro but thats not the measure.  (I am not sure I can create a pen with the business plugins and I would have to change all assets (I guess placeholder would work))

     

    Unfortunately this is not running smooth (like 60fps smooth) on an ipad of the 7th gen which I consider pretty fast (A10 Fusion chip). 

    When I take out the dragging x setter (no paralax effect) everything is really nice, but moving the images is the problem.  What steps can I take to optimize it? 

     

    Perhaps:

    - dont resize images, keep them in their original size (no with 100% stretch)?

    - try different way of setting the x pos on those images ?

    - reduce size of images (remove transparent portion)

    - I have implemented the paralax effect wrong ?

     

    Please let me know if you have any tips.

     

    Cheers Thomas

     

  2. Hello, 

     

    I am wondering if there is a nice and simple way to set all tweens duration of a timeline  to 0 so it does not animate anything but instead applies the props instantly and other timelines.

     

    Essentially go to the end without animation anything.

     

    I created a codepen which uses seek to do this sort of thing, would this be the right approach or is there something more elegant?

    See the Pen yQRrYO by teejayhh (@teejayhh) on CodePen

  3. Thx, mikel but I really prefer my solution as it does exactly what I expect scrollto to do in first place. Adding additional space to the bottom of a scrollable area is not great, imagine this on a website with a fixed header its simply not working like that. 

     

    I really appreciate your input, but you suggested exactly the one thing, I mentioned in my first post , that didn’t want to do. 

     

    Have a great weekend 

    Thomas

  4. Hello mikel, your suggested solution is simply not working in a dynamic context, which I didn’t make quite clear, the search input field could have given it away though.  This is why this can’t be a pure css solution. So I had to find a difference solution.  

    And the more I think about it the more I think that the offsetY behaviour is buggy in that regard, but it might not be trivial to fix. Anyway the solution above is workable and easy enough to implement. 

     

    Cheers everyone. Have great weekend... soon. 

  5. 10 hours ago, mikel said:

    Hi @teejay_hh,


    Why 'margin-bottom'? Set a height that offers enough room to scroll.

    Happy tweening ...

    Mikel

     

     

     

    For that I would have to measure the ul for its height. Adding a margin-bottom to the ul of the 'offsetY' value would do the trick, but its uggly :)

  6. thx for the suggestions, I dont really want to set height or margin on any element. For this case it really only affects the last entry. I might be able to get away the `max` solution for the last entry

     

    { y: 'max', offsetY: 0 }

     

    I kind of still think scrollTo should have the smarts to do this by itself. The same happens for fixed elements and window scroll btw. Try scrolling to the last item

     

    See the Pen EdQyNb by teejayhh (@teejayhh) on CodePen

     

     

  7. Hi, I have build a really small component (see codepen) which is a list of entries with the first being sticky element. I would like to scroll to an entry which seem slightly buggy due to the sticky element, or I am doing something wrong. If you click on the the last element you will see what the problem is. It works well for entries where scrolling is required, but if en entry sits at the end (entry 9 for instance), where we can't scroll to, then the scroller does not scroll to very end but leaves the gap at the bottom (offset of 30px). Is there a way around this (without adding a margin-bottom to the ul list). 

     

    I hope I could explain it well, if not, please let me know and will try to elaborate. 

     

    Best regards Thomas

     

    PS: the markup can't be changed

    See the Pen OBQNWE by teejayhh (@teejayhh) on CodePen

  8. Ok I got something. 

    I created a shim which created the wiggle namespace. 

     

    /* global define, self */
    
    (function() {
      var plugins = {
        'CustomEase': CustomEase,
        'CustomWiggle': CustomWiggle,
      };
    
      define('wiggle', [], function() {
        'use strict';
        return plugins;
      });
    
    })();

     

    Then you can add the the imports to the ember-cli-build.js file
     

    app.import('vendor/CustomEase.min.js')
    app.import('vendor/CustomWiggle.min.js')
    app.import('vendor/gsapShim.js', { exports: { 'wiggle': ['CustomWiggle', 'CustomEase'] } })


    And then you can use it like this in your components.

     

    import { CustomWiggle } from 'wiggle'

     

    • Like 2
  9. That package is a community addon which makes it pretty easy to add just TimelineMax or specific easting to the ember build.  I have not tried it without the addon, which would still leave me with what would I need to import to actually use Tweenmax for instance.

    I tried this 
    https://guides.emberjs.com/v2.13.0/addons-and-dependencies/managing-dependencies/#toc_amd-javascript-modules

     

    app.import('vendor/CustomWiggle.min.js', { exports: { wiggle: ['CustomWiggle'] } })

     

    and then 

     

    import { CustomWiggle } from 'wiggle'


    But no luck.

  10. Hello, I am an ember developer and convinced my company to have a closer look at gsap and they did. So we are gsap member and I am now kinda struggling to figure out how I can use the shiny plugins which are not free to use. 
    I use an ember package -> https://github.com/willviles/ember-gsap  to load gsap into an ember application. 

    You can import gsap via an es6 import
     

    import { TimelineMax } from 'gsap'


    The ember gsap addon doesnt support any of the business green plugins so I am looking for workarounds. In ember you can add files to the vendor folder which then can be loaded on startup. 

    I know this is very framework specific and I probably dont find anyone here with ember knowledge. 

    so in the ember-cli-build.js you can add something like this. 

     

      app.import('vendor/CustomEase.min.js')
      app.import('vendor/CustomBounce.min.js')
      app.import('vendor/CustomWiggle.min.js')

     

    Which now makes the plugins available. The only thing left todo is to import them where you need them. Which is my problem.

     

    I dont really know how to import  `import CustomWiggle from  ?????` it. Any tips ??

  11. Hello, I have a problem with an animation I am trying to do. I am trying to build a button which can be fed different states like error, load and done, which in return should play a specific animation seamlessly. That means the loading state goes seamlessly into the error or done state. The error state should also be able to transition into the loading state. I have created a pen to show you the structure of this mess. I probably have a problem with structuring the different timelines, but I am not sure.  I would be super happy if someone could have a look at this and point me into the right direction. 

     

    Cheers Thomas
     

    See the Pen KZRjRv by teejayhh (@teejayhh) on CodePen

×
×
  • Create New...