Jump to content
Search Community

Perdixo

Members
  • Posts

    10
  • Joined

  • Last visited

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

Perdixo's Achievements

1

Reputation

  1. Hi folks. I'm still looking for an answer, tried different things but this is still not working ?
  2. Wow thanks @ZachSaucier, that's exactly what i was looking for!
  3. Hello guys, So i'm learning svg path manipulation. At first, i wanted to create a line that becomes "elastic" on hover. I've used the `<animate>` attribute. You can see a simple demo here : https://jsfiddle.net/7tL5osr0/2/ But i've seen it's poorly supported, and i prefer to have more control. So i've tried to convert this into some css animation. The main issue was that the animation stopped when when you stop hovering. So i've added a little bit of javascript to add / remove and `.animated` class on the line path element to allow the animation to finish even when the mouse isn't hovering it anymore. Here is a demo : https://jsfiddle.net/o64aymt8/1/ Now my issue and questions are multiples : - The animation isn't really reactive, for example if you hover too quickly over the line the animation doesn't work - I wonder how i could animate the same thing using GSAP? Animate "path d" etc. Is it possible? - If using GSAP, how can i improve the "reactivity" on the animation? Can i launch it again if for example the user hover 3 times in a row? Or make it directional? I know that's a lot of questions, but i'm still learning / reading the docs and for now i have no clue how to start.. Thanks a lot!
  4. @ZachSaucier I feel my error comes from my timeline, particularly this part : .fromTo( '.js-titles', { yPercent: 0, }, { yPercent: -(100 - 100 / titles.length), }, 0, ) Isn't it?
  5. Hey @ZachSaucier thanks for the quick reply! So i've looked at your demo, but it stills delay the titles, "Project 01" is coming too fast then, as the rest of the titles.. I've changed the images so it's more obvious : https://jsfiddle.net/opdh3vj0/
  6. Hey @ZachSaucier you were right, that was kind of an HTML / JS issue, now fixed! Thanks a lot. By the way, here is a fixed version for those interested : https://jsfiddle.net/t3ye7ga9/7/ Still im having some trouble (GSAP this time) with the slider : there is a delay with the titles when you drag the slider. So if you drag it to do a full round, you can see that the "Project 01" Re-appear right after the "Project 04", and so when you continue dragging it delays the titles (meaning the good titles don't match the images => "Project 01" should be on top of the first image, "Project 02" on the second image and so on). And the first image that appear before you drag is the fourth one.. I don't understand what i'm missing here as i'm using my items.length to translate titles..
  7. The issue is the following : It works when i don't have any other sections than the slider. You can take a look at it here : https://jsfiddle.net/j5huqxpd/15/ What i need is to add sections before and after, but as soon as i add sections with a defined height, the images don't show up anymore.
  8. Well what i want is to make my THREE.JS scene only appear in the canvas-projects div. Right now, the images from my three.js scene don't appear.. The only thing that appear is my text animation on drag. In the background, there should be the image slides but right now the background stays black and don't show them.
  9. Hey, Thanks for the welcome! So i've posted on the three.js forums and they told me that my issue was a GSAP specific question.. That's why i'm posting it here! I'm a little bit losted since i originally thought my issue was THREE related, it seems that it is not..
  10. Hi everybody! I'm trying to display a three.js scene inside a div in my html, but i can't figure out how. I've posted in the three.js forums, but it seems it's an UI issue and not a three.js one so.. here i am! Here is a jsfiddle trying to replicate the issue : JSFIDDLE So i want my three.js animation to appear in my <div id="canvas-projects"></div>, but my images don't appear. If i put my section containing the <div id="canvas-projects"></div>as my first html element, it works fine and the images appears. But it's supposed to be in the middle of my page. So my guess i that my positioning isn't good somehow. But i can't figure out how to make it work! If anybody could take a look at this and help me, i'd be super greatful! Here is my current javascript code : const store = { ww: window.innerWidth, wh: window.innerHeight, isDevice: navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i) }; class Slider { constructor(el, opts = {}) { this.bindAll(); this.el = el; this.opts = Object.assign( { speed: 2, threshold: 50, ease: 0.075 }, opts ); this.ui = { items: this.el.querySelectorAll('.p-js-slide'), titles: document.querySelectorAll('.p-js-title'), lines: document.querySelectorAll('.p-js-progress-line') }; this.state = { target: 0, current: 0, currentRounded: 0, y: 0, on: { x: 0, y: 0 }, off: 0, progress: 0, diff: 0, max: 0, min: 0, snap: { points: [] }, flags: { dragging: false } }; this.items = []; this.events = { move: store.isDevice ? 'touchmove' : 'mousemove', up: store.isDevice ? 'touchend' : 'mouseup', down: store.isDevice ? 'touchstart' : 'mousedown' }; this.init(); } bindAll() { ['onDown', 'onMove', 'onUp'].forEach(fn => (this[fn] = this[fn].bind(this))); } init() { return gsap.utils.pipe(this.setup(), this.on()); } destroy() { this.off(); this.state = null; this.items = null; this.opts = null; this.ui = null; } on() { const { move, up, down } = this.events; window.addEventListener(down, this.onDown); window.addEventListener(move, this.onMove); window.addEventListener(up, this.onUp); } off() { const { move, up, down } = this.events; window.removeEventListener(down, this.onDown); window.removeEventListener(move, this.onMove); window.removeEventListener(up, this.onUp); } setup() { const { ww } = store; const state = this.state; const { items, titles } = this.ui; const { width: wrapWidth, left: wrapDiff } = this.el.getBoundingClientRect(); // Set bounding state.max = -(items[items.length - 1].getBoundingClientRect().right - wrapWidth - wrapDiff); state.min = 0; // Global timeline this.tl = gsap .timeline({ paused: true, defaults: { duration: 1, ease: 'linear' } }) .fromTo( '.p-js-progress-line-2', { scaleX: 1 }, { scaleX: 0, duration: 0.5, ease: 'power3' }, 0 ) .fromTo( '.p-js-titles', { yPercent: 0 }, { yPercent: -(100 - 100 / titles.length) }, 0 ) .fromTo( '.p-js-progress-line', { scaleX: 0 }, { scaleX: 1 }, 0 ); // Cache stuff for (let i = 0; i < items.length; i++) { const el = items[i]; const { left, right, width } = el.getBoundingClientRect(); // Create webgl plane const plane = new Plane(); plane.init(el); // Timeline that plays when visible const tl = gsap.timeline({ paused: true }).fromTo( plane.mat.uniforms.uScale, { value: 0.65 }, { value: 1, duration: 1, ease: 'linear' } ); // Push to cache this.items.push({ el, plane, left, right, width, min: left < ww ? ww * 0.775 : -(ww * 0.225 - wrapWidth * 0.2), max: left > ww ? state.max - ww * 0.775 : state.max + (ww * 0.225 - wrapWidth * 0.2), tl, out: false }); } } calc() { const state = this.state; state.current += (state.target - state.current) * this.opts.ease; state.currentRounded = Math.round(state.current * 100) / 100; state.diff = (state.target - state.current) * 0.0005; state.progress = gsap.utils.wrap(0, 1, state.currentRounded / state.max); this.tl && this.tl.progress(state.progress); } render() { this.calc(); this.transformItems(); } transformItems() { const { flags } = this.state; for (let i = 0; i < this.items.length; i++) { const item = this.items[i]; const { translate, isVisible, progress } = this.isVisible(item); item.plane.updateX(translate); item.plane.mat.uniforms.uVelo.value = this.state.diff; if (!item.out && item.tl) { item.tl.progress(progress); } if (isVisible || flags.resize) { item.out = false; } else if (!item.out) { item.out = true; } } } isVisible({ left, right, width, min, max }) { const { ww } = store; const { currentRounded } = this.state; const translate = gsap.utils.wrap(min, max, currentRounded); // console.log(translate); const threshold = this.opts.threshold; const start = left + translate; const end = right + translate; const isVisible = start < threshold + ww && end > -threshold; const progress = gsap.utils.clamp(0, 1, 1 - (translate + left + width) / (ww + width)); return { translate, isVisible, progress }; } clampTarget() { const state = this.state; state.target = gsap.utils.clamp(state.max, 0, state.target); } getPos({ changedTouches, clientX, clientY, target }) { const x = changedTouches ? changedTouches[0].clientX : clientX; const y = changedTouches ? changedTouches[0].clientY : clientY; return { x, y, target }; } onDown(e) { const { x, y } = this.getPos(e); const { flags, on } = this.state; flags.dragging = true; on.x = x; on.y = y; } onUp() { const state = this.state; state.flags.dragging = false; state.off = state.target; } onMove(e) { const { x, y } = this.getPos(e); const state = this.state; if (!state.flags.dragging) return; const { off, on } = state; const moveX = x - on.x; const moveY = y - on.y; if (Math.abs(moveX) > Math.abs(moveY) && e.cancelable) { e.preventDefault(); e.stopPropagation(); } state.target = off + moveX * this.opts.speed; } } /** */ /** * GL STUFF *** */ /** */ const backgroundCoverUv = ` (...) `; const vertexShader = ` (...) `; const fragmentShader = ` (...) `; const loader = new THREE.TextureLoader(); loader.crossOrigin = 'anonymous'; class Gl { constructor() { this.scene = new THREE.Scene(); this.camera = new THREE.OrthographicCamera( store.ww / -2, store.ww / 2, store.wh / 2, store.wh / -2, 1, 10 ); this.camera.lookAt(this.scene.position); this.camera.position.z = 1; this.renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true }); this.renderer.setPixelRatio(1.5); this.renderer.setSize(store.ww, store.wh); this.renderer.setClearColor(0xffffff, 0); this.init(); } render() { this.renderer.render(this.scene, this.camera); } init() { const container = document.getElementById('canvas-projects'); const domEl = this.renderer.domElement; domEl.classList.add('dom-gl'); // document.body.appendChild(domEl); container.appendChild(domEl); } } class GlObject extends THREE.Object3D { init(el) { this.el = el; this.resize(); } resize() { this.rect = this.el.getBoundingClientRect(); const { left, top, width, height } = this.rect; this.pos = { x: left + width / 2 - store.ww / 2, y: top + height / 2 - store.wh / 2 }; this.position.y = this.pos.y; this.position.x = this.pos.x; this.updateX(); } updateX(current) { current && (this.position.x = current + this.pos.x); } } const planeGeo = new THREE.PlaneBufferGeometry(1, 1, 32, 32); const planeMat = new THREE.ShaderMaterial({ transparent: true, fragmentShader, vertexShader }); class Plane extends GlObject { init(el) { super.init(el); this.geo = planeGeo; this.mat = planeMat.clone(); this.mat.uniforms = { uTime: { value: 0 }, uTexture: { value: 0 }, uMeshSize: { value: new THREE.Vector2(this.rect.width, this.rect.height) }, uImageSize: { value: new THREE.Vector2(0, 0) }, uScale: { value: 0.75 }, uVelo: { value: 0 } }; this.img = this.el.querySelector('img'); this.texture = loader.load(this.img.src, texture => { texture.minFilter = THREE.LinearFilter; texture.generateMipmaps = false; this.mat.uniforms.uTexture.value = texture; this.mat.uniforms.uImageSize.value = [this.img.naturalWidth, this.img.naturalHeight]; }); this.mesh = new THREE.Mesh(this.geo, this.mat); this.mesh.scale.set(this.rect.width, this.rect.height, 1); this.add(this.mesh); gl.scene.add(this); } } /** */ /** * INIT STUFF *** */ /** */ const gl = new Gl(); const slider = new Slider(document.querySelector('.p-js-slider')); const tick = () => { gl.render(); slider.render(); }; gsap.ticker.add(tick); Here is my html (... bunch of other html sections) <section class="section section-larger section-more-projects" data-scroll-section> <div id="canvas-projects"></div> <div class="p-slider | p-js-drag-area"> (...) </div> <div class="p-titles"> (...) </div> <div class="p-progress"> (...) </div> </section> (... bunch of other html sections) And here is my css $easeOutExpo: cubic-bezier(0.2, 1, 0.2, 1); .dom-gl { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; } .p-slider { position: relative; padding: 0 22.5vw; display: flex; align-items: center; height: 100%; user-select: none; cursor: grab; z-index: 2; &__inner { display: flex; position: relative; } } .p-slide { overflow: hidden; &:first-child { position: relative; } &:not(:first-child) { position: absolute; top: 0; height: 100%; } &__inner { position: relative; overflow: hidden; width: 55vw; padding-top: 56.5%; } img { display: none; } } .p-titles { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); overflow: hidden; pointer-events: auto; z-index: 9999999999; &__list { position: absolute; top: 0; left: 0; } &__title { display: flex; align-items: center; justify-content: center; font-size: 6vw; font-weight: bold; letter-spacing: -0.1vw; color: #fff; &--proxy { visibility: hidden; } } } .p-progress { position: absolute; bottom: 0; left: 0; width: 100%; height: 0.25rem; overflow: hidden; pointer-events: none; &__line { position: absolute; top: 0; left: 0; width: 100%; height: 100%; transform: scaleX(0); transform-origin: left; background-color: #fff; &:nth-child(2) { transform-origin: right; } } } By the way, i'm also using Locomotive Scroll on my page for creating smooth inertia scrolling.
×
×
  • Create New...