skew text on scroll, how to target class instead of section - javascript

Found this scrolling effect on Codepen. Is it possible to adjust the code so that I can target lines of text by class '.hometext', rather than targeting the entire section '#work' as it currently does?
const section = document.querySelector("#work");
let currentPixel = window.pageYOffset
//looper keeps running and keeps track of where the new pixel is
const looper = function () {
const newPixel = window.pageYOffset;
const diff = newPixel - currentPixel
const speed = diff * 0.05;
section.style.transform = "skewY(" + speed + "deg)"
currentPixel = newPixel;
requestAnimationFrame(looper)
}
looper();

document.querySelectorAll => elements array
then for of elements
const section = document.querySelectorAll(".hometext");
let currentPixel = window.pageYOffset
//looper keeps running and keeps track of where the new pixel is
const looper = function () {
const newPixel = window.pageYOffset;
const diff = newPixel - currentPixel
const speed = diff * 0.35;
//for of elements
for(let el of section){
el.style.transform = "skewY(" + speed + "deg)"
}
currentPixel = newPixel;
requestAnimationFrame(looper)
}
looper();

Related

Glitch (content jumping) with parallax scrolling

I'm working on an animation for a site and I've gotten a glitch that I can not find a solution to. I update a 's translateY based on scroll connected to an eventListener on "scroll". The issue is that the is jumping and not behaving as expected. It works sometimes and almost all the time in Safari. The issue is always present in Firefox. I created a Codepen here.
I've tried exchange translateY to top, margin-top and padding-top. I've also tried exchange Grid to Flex and even Float. I've also tried to throttle the scroll event with lodash throttle.
If you can't see the issue, I can provide a video.
Basically, here is the JS:
const move_content = (leader, follower) => {
console.log(leader.getBoundingClientRect().top);
let margin_top = 0;
if (0 > leader.getBoundingClientRect().top) {
const pixels_scrolled = leader.getBoundingClientRect().top * -1;
const pixels_scrolled_with_viewport =
pixels_scrolled +
(window.innerHeight * pixels_scrolled) / leader.offsetHeight;
let percentage_scrolled =
pixels_scrolled_with_viewport / leader.offsetHeight;
if (1 <= percentage_scrolled) {
percentage_scrolled = 1;
}
const max_margin_pixels = leader.offsetHeight - follower.offsetHeight;
margin_top =
Math.round(max_margin_pixels * percentage_scrolled * 100) / 100;
}
follower.style.transform = "translateY(" + margin_top + "px)";
};
const syncronized_scroll = () => {
const content = document.querySelector(".test > div:first-child");
const reads = document.querySelector(".test > div:last-child");
if (content.offsetHeight > reads.offsetHeight) {
move_content(content, reads);
} else {
move_content(reads, content);
}
};
window.addEventListener("scroll", syncronized_scroll);

how to implement click logic

hi everyone!
i have a map with dots MAP which every 3 seconds shows a block with info
a function that is already in progress, and I want the function to stop when clicking on a point and display an infoblock for me(and i did it).
sorry in advance below is my code
// map with dots
var isActive = 0;
var isLoading = 1;
const count = document.querySelectorAll("[data-id]");//circle svg around dot
function removeClass() {
let infoCards = document.querySelectorAll("[data-info-id]");// info page name of the project
infoCards.forEach((el) => {
el.classList.remove("show");
});
}
function removeCircle() {
count.forEach((el) => {
el.style.display = "none";
});
}
function ready() {
function setAround(percent, idx) {
removeCircle();
let beforeElemIdx = idx === 0 ? count.length - 1 : idx - 1;
let beforeElem = document.querySelector(
'[data-id="' + beforeElemIdx + '"]'
);
let elem = document.querySelector('[data-id="' + idx + '"]');
elem.style.display = "block";
elem.classList.remove('active-circle');
beforeElem.style.display = "block";
const math = 2 * Math.PI * elem.r.baseVal.value;
elem.style.strokeDasharray = `${math} 1000`;
let a = math * (1 - percent / 100);
elem.style.strokeDashoffset = a;
if (percent >= 99.5) {
removeClass();
let infoShow = document.querySelector(`[data-info-id="${idx}"]`);
infoShow.classList.add("show");
isLoading++;
if (isLoading === count.length) {
isLoading = 0;
}
}
}
requestAnimationFrame(draw);
function draw(t) {
let idx = isLoading;
requestAnimationFrame(draw);
setAround((t / 30) % 100, idx);//timer 3sec
}
}
document.addEventListener("DOMContentLoaded", ready);
and i did this
var dots = document.querySelectorAll(".dota");
var infoCards = document.querySelectorAll("[data-info-id]");
let circle = document.querySelectorAll('[data-id]');
dots.forEach((el) => {
el.addEventListener('click', () => {
let idx = el.dataset.dota;
let circle = el.dataset.dota;
showInfo(idx);
addCircle(idx);
});
});
function showInfo(idx) {
removeClass();
let elem = document.querySelector(`[data-info-id='${idx}']`);
elem.classList.add('show');
}
function addCircle(idx) {
let circle = document.querySelector(`[data-id='${idx}']`);
circle.classList.add('active-circle');
}
and if u want my site pls dm me i'll send my github page
PUG CODE
TY ALL!
Have you tried making a condition into the drawing function that pauses it?
If it's paused you can call another function that will draw the info of the specific dot only once and then create a condition in which it will resume the drawing normally.
When I used drawing function I've simply added a bool variable that stored if paused or not in the recursive function.

How to shorter the code using each() method?

I have a question. I have a script :
$(document).ready(function () {
$(document).on('scroll', function () {
const windowHeight = $(window).height()
const scrollValue = $(this).scrollTop();
const $art1 = $('.art1');
const art1FromTop = $art1.offset().top
const art1Height = $art1.outerHeight()
const $art2 = $('.art2');
const art2FromTop = $art2.offset().top
const art2Height = $art2.outerHeight()
const $art3 = $('.art3');
const art3FromTop = $art3.offset().top
const art3Height = $art3.outerHeight()
const $art4 = $('.art4');
const art4FromTop = $art4.offset().top
const art4Height = $art4.outerHeight()
const $art5 = $('.art5');
const art5FromTop = $art5.offset().top
const art5Height = $art5.outerHeight()
const $art6 = $('.art6');
const art6FromTop = $art6.offset().top
const art6Height = $art6.outerHeight()
const $art7 = $('.art7');
const art7FromTop = $art7.offset().top
const art7Height = $art7.outerHeight()
if (scrollValue > art1FromTop + art1Height / 2 - windowHeight) {
$art1.addClass('active');
}
if (scrollValue > art2FromTop + art2Height / 2 - windowHeight) {
$art2.addClass('active');
}
if (scrollValue > art3FromTop + art3Height / 2 - windowHeight) {
$art3.addClass('active');
}
if (scrollValue > art4FromTop + art4Height / 2 - windowHeight) {
$art4.addClass('active');
}
if (scrollValue > art5FromTop + art5Height / 2 - windowHeight) {
$art5.addClass('active');
}
if (scrollValue > art6FromTop + art6Height / 2 - windowHeight) {
$art6.addClass('active');
}
if (scrollValue > art7FromTop + art7Height / 2 - windowHeight) {
$art7.addClass('active');
}
})
})
I would like to change it into shorter one using each(). I have in mind that I have to use $('.art') for example to select all divs with this class, then I need to add them numbers iterating from 1. This I think I can accomplish alone. But how can I calculate scrolling position for each div? How can I take the position of each div? Do I have to select it the way I am now, or I can use 'this' for it?
As you are performing the same operation use Multiple Selector and then use .filter() to get the matched element based on function used as a test for each element in the set. this is the current DOM element.
$(document).on('scroll', function () {
const windowHeight = $(window).height()
const scrollValue = $(this).scrollTop();
var arts = $('.art1, .art2, ..., .art7'); //better $('.art')
arts.filter(function(){
const $art = $(this);
const artFromTop = $art.offset().top
const artHeight = $art.outerHeight()
return scrollValue > artFromTop + artHeight / 2 - windowHeight;
}).addClass('active');
});

Javascript help, Trying to animate two different sprites at same time

I need some javascript help. I am trying to set up two sprite animations with different frame rates in two separate div.
Here is a fiddle I started and i am very much stuck.
How do I combine the two div IDs into one statement? OR Should I be using ClassName in the statement to run on both divs?
http://jsfiddle.net/akwilinski/3t7d6qbL/1/
<div id="animate" class="animation"></div>
<div id="animate2" class="animation2"></div>
onload = function startAnimation() {
var frameHeight = 400;
var frames = 27;
var frame = 0;
var div = document.getElementById("animate");
setInterval(function () {
var frameOffset = (++frame % frames) * -frameHeight;
div.style.backgroundPosition = "0px " + frameOffset + "px";
}, 100);
}
Thank you for any assistance!
Simplest way to do this using the method you have already started using is to define 2 new variables, 1 for the second div and one for the second frame count. Then you can just add the call to your function.
Updated js:
onload = function startAnimation() {
var frameHeight = 400;
var frames = 27;
var frame = 0;
var div = document.getElementById("animate");
var div2 = document.getElementById("animate2");
setInterval(function () {
var frameOffset = (++frame % frames) * -frameHeight;
var frameOffset2 = (++frame % frames) * -frameHeight - 10;
div.style.backgroundPosition = "0px " + frameOffset + "px";
div2.style.backgroundPosition = "0px " + frameOffset + "px";
}, 100);
}
Fiddle
http://jsfiddle.net/f4v1vy7x/5/
I made a Can object to store the configuration for each can (so you can have different frameHeights, frames and frameRates.
I used window.requestAnimationFrame because it's far more efficient than setInterval. On each available frame I check whether it's time to animate based on each Can's set frame rate:
var Can = function( selector, frameHeight, frames, frameRate )
{
this.domCan = document.getElementById( selector );
this.frameHeight = frameHeight;
this.frames = frames;
this.frameRate = frameRate;
this.frame = 0;
};
onload = function startAnimation() {
var can1 = new Can( 'animate', 400, 27, 20 );
var can2 = new Can( 'animate2', 400, 27, 100 );
var cans = [ can1, can2 ];
window.requestAnimationFrame( function() {
can1.start = can2.start = new Date();
animate( cans );
} );
};
var animate = function( cans ) {
for( var i = 0; i < cans.length; i++ ) {
var now = new Date();
var can = cans[i];
if( now - can.start >= 1000 / can.frameRate ) {
can.start = now;
var frameOffset = (++can.frame % can.frames) * -can.frameHeight;
can.domCan.style.backgroundPosition = "0px " + frameOffset + "px";
}
}
window.requestAnimationFrame( function() {
animate( cans );
} );
}
You could do something like this:
var div = document.getElementById("animate");
var div2 = document.getElementById("animate2");
function anim(div) {
setInterval(function () {
var frameOffset = (++frame % frames) * -frameHeight;
div.style.backgroundPosition = "0px " + frameOffset + "px";
}, 100);
}
anim(div);
anim(div2);
You could then pass in additional parameters like frameHeight, frame, and frames to further customize each animation.

How do I transition the changing of CSS values?

I'm using JavaScript to change CSS values to make a particular div fill the page when a button is clicked. But I would like make the change from small to filling the screen smooth. How do I do this with CSS or Javascript? This is currently how I'm changing the size of that div
function fullscreen(){ // called when button is clicked
var d = document.getElementById('viewer').style;
if(!isFullscreen){ // if not already fullscreen change values to fill screen
d.width = "100%";
d.height="100%";
d.position= "absolute";
d.left="0%";
d.top="0%";
d.margin="0 0 0 0";
isFullscreen = true;
}else{ // minimizie it
d.width="600px";
d.height="400px";
d.margin="0 auto";
d.position="relative";
isFullscreen = false;
}
}
How do I code the change from the full screen values to the minimized values to be a smooth transition instead of instantaneous?
Use jQuery'sanimate() function!
For example:
function fullscreen(){ // called when button is clicked
var o = {} // options
var speed = "fast"; // You can specify another value
if(!isFullscreen){ // if not already fullscreen change values to fill screen
o.width = "100%";
o.height="100%";
o.left="0%";
o.top="0%";
o.margin="0 0 0 0";
$("#viewer").animate(o,speed);
isFullscreen = true;
}else{ // minimize it
o.width="600px";
o.height="400px";
o.margin="0 auto";
$("#viewer").animate(o,speed);
isFullscreen = false;
}
}
You can do this by using Jquery, .animate() API see the reference .animate()
I have created a small demo using .animate() click the Demo to see the example.
What you want to do is rather complicated, first you need to get the absolute position and dimension of your element in the document, also the dimension of the document itself, there is no native cross-platform javascript functions for that but there are known techniques to find out those values, do a search. So assuming you will implement these functions yourself: getAbsoluteLeft(), getAbsoluteTop(), getWidth(), getHeight(), getDocWidth() and getDocHeight() here is the animating code (not tested):
function fullscreen(){ // called when button is clicked
var e = document.getElementById('viewer');
var d = e.style;
if(!isFullscreen){ // if not already fullscreen change values to fill screen
var duration = 1000 //milliseconds
var framesPerSecond = 24;
var beginLeft = getAbsoluteLeft( e );
var beginTop = getAbsoluteTop( e );
var beginRight = beginLeft + getWidth( e );
var beginBottom = beginTop + getHeight( e );
var endLeft = 0;
var endTop = 0;
var endRight = getDocWidth();
var endBottom = getDocHeight();
var totalFrames = duration / (1000/framesPerSecond);
var frameNo = 0;
var leftStep = (beginLeft - endLeft) / totalFrames;
var topStep = (beginTop - endTop) / totalFrames;
var rightStep = (endRight - beginRight) / totalFrames;
var bottomStep = (endBottom - beginBottom) / totalFrames;
var func = function () {
var left = beginLeft - leftStep * frameNo;
var top = beginTop - topStep * frameNo;
d.left = left+'px';
d.top = top+'px';
d.width = (beginRight + rightStep * frameNo - left)+'px';
d.height = (beginBottom + bottomStep * frameNo - top)+'px';
++frameNo;
if( frameNo == totalFrames ) {
clearInterval( timer );
d.width = "100%";
d.height="100%";
d.left="0%";
d.top="0%";
isFullscreen = true;
}
}
d.position= "absolute";
d.margin="0 0 0 0";
timer = setInterval( func, 1000 / framesPerSecond );
} else { // minimizie it
d.width="600px";
d.height="400px";
d.margin="0 auto";
d.position="relative";
isFullscreen = false;
}
}

Categories

Resources