Jump to content


  • Posts

  • Joined

  • Last visited

awagner's Achievements



  1. @OSUblake - wow. Don't know what to say, other than you'll be getting a hefty comment block in the canvas implementation of this transition. THANK YOU. Let me know if there are any links you'd like to plug, other than your GH. Speaking of that ... here it is: http://adamwagner.io/ Should work in Chrome, FF, and Safari on OSX now. Haven't checked Windows yet. Please let me know if you experience jank, stutter, flashing. Even with the canvas implementation, I had some issues with the previous route flashing when the animation ended. I ended up reducing the impact of this by registering a callback on the Timeline that changes the route 95% of the way through the animation. It's a pretty good compromise, but does add some stutter to the animation depending on CPU throttling. When throttling is set to 20x slower in Chrome perf tools, the animation actually proceeds non-linearly (progressing, regressing, then progressing again). I experimented with using "useFrames", but it was not an improvement. I did update to React 16, which uses Fiber, and should theoretically be more performant alongside animations. Didn't see an improvement though. At this point, I think the performance issues are caused by changing the route at the end, or near the end of the animation. It's a SPA running on react, so it's not a full page load, but it does spike the JS load. Thanks a million for all of your help.
  2. @OSUblake - thank you so much for the canvas example. Funny thing - I was just experimenting with using Canvas for these animations yesterday morning. I had trouble integrating it with GSAP, and abandoned that route. So, thank you very much! I updated the live site (remember, *chrome only* for now) with the canvas version of the ripple, and am happy to report a performance improvement! Now, I'm wondering if I should do the same thing with the image, since its movement is still a bit uneven. The challenge I see there is getting a canvas image element to act like a div with "background-size: cover". However, I've seen a couple of examples of it, and will give it a shot. @OSUblake - do you have a "buy me coffee" link, or anything to which I could send a thank you? Your help was pivotal in moving this forward for me.
  3. Update: Just fixed the really bad flicker during the route transition. Turns out I wasn't pre-caching the assets for that route. So that's gone. But the animation itself (especially from the detail page back to the index page) is still choppy until run a few times. Will continue exploring @OSUblake's suggestions.
  4. Thanks so much, Blake! Based on your username, I assume you're from Ohio So am I. Didn't attend OSU though (boo). I'll check out your resources and report back. Thanks again for the tips and error-finding!
  5. Hi everyone! Would love to get your opinion on what might be causing performance bottlenecks in a page transition animation I'm working on. Live WIP site is here: http://adamwagner.io/ Click on the first image below the Lorem Ipsum "about me" section. The image is of a band playing. Notice the low frame rate as the image animates to the hero position, a circular splash element hides the page, and then the route changes to the project detail page. Click the "back" text at bottom left below the hero image. This will take you back to the home page with a reverse animation. NOTE: only works in Chrome because I'm using webm for the image I refer to above. Will fix for prod of course. Performance increases after multiple runs, but typically first run performance is very janky. I would love some tips - even if they involve a totally different approach. Thank you so much in advance! I've attempted to use best practices. For instance, I clone the image before animating, making it fixed position to avoid reflow. GSAP delightfully takes care of optimizing position tweens, but I also need to animate height and width. I also need to set autoRound: false, because I need perfect overlap with the real hero image once the transitory clone is removed. Here's the code: import React from 'react' import { injectGlobal, styled } from "styled-components"; import {TweenMax, Bezier, TimelineMax, Power3, Sine} from "gsap"; import store from 'store' // import ripple from '../utils/splash' let globalSpeed = 1; export default class ProjectImage extends React.Component { getDuration(start, end) { let pixelsPerSecond = 700; let duration = Math.abs((end - start) / pixelsPerSecond); // set min value of .2 duration = duration < .25 ? .25 : duration // set max value of .5 duration = duration > .5 ? .5 : duration return duration * globalSpeed; } onImageClick = (e) => { // get the first element - the <body> let body = document.body // get window width minus scrollbar let w = body.clientWidth let h = body.clientHeight // get clicked project element and position data let el_original = this.refs.project_image let {top, left, width, height} = el_original.getBoundingClientRect(); // clone it let el = el_original.cloneNode() // place element on top of original // find a cleaner way to copy these over let elStyles = ` cursor: pointer; width: 100%; height: 40vw; will-change: width, transform; background-image: url(${this.props.image}); background-position: center center; background-size: cover; pointer-events: none; ` el.style.cssText = elStyles + `z-index:200; position: fixed; top:${top}px; left:${left}px; width:${width}px; height:${height}px;` body.append(el) // get mouse click coordinates let {clientY, clientX} = e; // save original image coords for "going back" transition store.set('lastClickedProject', {top, left, width, height}) // create and append splash circle let splash = document.createElement('div') splash.style = ` border-radius:100%; width: 50px; height: 50px; background: ${this.props.pageColor}; position: fixed; top:${clientY}px; left:${clientX}px; z-index:100; opacity: 0.75; will-change: transform; ` body.append(splash) // animate splash TweenMax.to(splash, (0.6 * globalSpeed), {scale:80, opacity:1, transformOrigin: "50% 15%"}, Sine.easeIn); // animate image to the hero position TweenMax.to(el, this.getDuration(0, top), {bezier: {curviness:0.25, values:[ {x:0, y:0, width:width, height: height}, {x:-left, y:-(top/2.5), width: w, height: height+25}, {x:-left, y:-top, width: w, height: height+100}, ]}, ease:Power3.easeOut, autoRound:false}); // redirect to detail page setTimeout(() => { el.remove() splash.remove() window.___navigateTo(this.props.path) }, (this.getDuration(0,top)*1000)) } render() { let style = { cursor:'pointer', width:'100%', height:'40vw', willChange:'width, transform', backgroundImage:`url(${this.props.image})`, backgroundPosition:'center', backgroundSize:'cover', } return ( <div onClick={this.onImageClick} style={style} ref="project_image"> </div> ) } }