So I have been learning animations with JS,CSS,HTML and I was trying to learn how to animate a scroll similar to a this
I have tried to use jQuery-SlotMachine though I am very lost on how the action is executed even with the JS code next to it. Could someone explain me how I can code this with the same API or another or Code it in vanilla JS.
You can try CSS animations with a little javascript code to control your custom animation state.
I think my sample could help you.
CodePen
$(document).ready(function() {
let $elements = $(".element");
let $transitionList = $(".transition-list");
let currentIndex = 0;
setInterval(function() {
$transitionList.css(
"transform",
"translateY(" + currentIndex * -250 + "px)"
);
currentIndex++;
if ($elements.length - 1 < currentIndex) {
currentIndex = 0;
}
}, 750);
});
body {
display: flex;
align-items: center;
justify-content: center;
}
.container {
display: flex;
width: 50%;
}
.center {
align-items: center;
justify-content: center;
}
.border-container {
border: 25px solid #dfe0a0ed;
border-radius: 30%;
overflow: hidden;
}
.transition-list {
width: 250px;
height: 250px;
background-color: #fefefe;
transition-property: all;
transition-duration: 0.5s;
transition-timing-function: cubic-bezier(0, 1, 0.1, 0.2, 0.7, 1);
}
.element {
background-color: #6f6f6f;
width: 250px;
height: 250px;
font-size: 188px;
display: flex;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css">
<div class="conainer center">
<div class="border-container">
<div class="transition-list">
<div class="element center"><i class="fas fa-clock"></i></div>
<div class="element center"><i class="fas fa-unlock"></i></div>
<div class="element center"><i class="fas fa-th"></i></div>
<div class="element center"><i class="fas fa-american-sign-language-interpreting"></i></div>
</div>
</div>
</div>
1. To begin, you must have a container:
<div id="theContainer" class="container">
</div>
2. Great, now let's put some images in it.
<div id="theContainer" class="container">
<img src="https://picsum.photos/100/?random">
<img src="https://picsum.photos/100/?random">
<img src="https://picsum.photos/100/?random">
</div>
3. Now, let's add two buttons to move it:
<div id="theContainer" class="container">
<img src="https://picsum.photos/100/?image=0">
<img src="https://picsum.photos/100/?image=1">
<img src="https://picsum.photos/100/?image=2">
</div>
<button id="prev" value="Previous">
<button id="next" value="Next">
4. Sweet! We got our HTML, now we just got to add our Javascript:
// Set up previous button
const btnPrev = document.querySelector('#prev');
// Set up Next Button
const btnNext = document.querySelector('#next');
// Set up our container
const el = document.querySelector('#theContainer');
// Create new SlotMachine
const slot = new SlotMachine(el, {});
// Add Event Listeners or do things when we click it
btnPrev.addEventListener('click', () => slot.prev());
btnNext.addEventListener('click', () => slot.next());
<link href="https://cdn.jsdelivr.net/npm/jquery-slotmachine#4.0.0/dist/jquery.slotmachine.min.css"></style>
<div id="theContainer" class="container" style="width: 100px; height: 100px">
<div><img src="https://picsum.photos/100/?image=0"></div>
<div><img src="https://picsum.photos/100/?image=1"></div>
<div><img src="https://picsum.photos/100/?image=2"></div>
</div>
<button id="prev">Previous</button>
<button id="next">Next</button>
<!-- Add script files -->
<script src="https://cdn.jsdelivr.net/npm/jquery-slotmachine#4.0.0/dist/slotmachine.min.js"></script>
5. Notes:
you must add a width & height to #theContainer. (style="width: 100px; height: 100px")
the images must be surrounded by a block element. (<div><img /></div>)
Related
I'm trying to make a smooth, infinite, automatic carousel for my images but I'm stuck. I believe I have the carousel moving (thinking I may be moving the wrong div). The part I'm struggling with is to get the images t0o loop back around when they leave the page, making it infinite. I would love some help.
Thanks
LM
const carousel = document.querySelector(".carousel1");
const imageSection = document.querySelector(".imagesection");
let sliders = document.querySelectorAll('.sliders');
let increment= 0;
let index = 1;
const interval = 100;
const firstClone = sliders[0].cloneNode(true);
const lastClone = sliders[sliders.length -1].cloneNode(true);
let check = sliders.offsetHeight
console.log(check)
// Append the firstclone to the back of the carousel
carousel.appendChild(firstClone);
let timer = setInterval(() => {
increment++
carousel.style.transform = `translateY(-${increment}px)`
console.log('hey')
}, interval);
.imagesection{
width: 50%;
border: 1px solid blue;
display: flex;
flex-direction: row;
overflow: hidden;
}
.carousel1{
border: 1px solid pink;
width: 35%;
margin:0 2.5px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.sliders{
border-radius: 5px;
width: 100%;
height: 300px;
margin: 5px 0;
object-fit: cover;
}
.images{
border-radius: 5px;
width: 100%;
height: 100%;
<div class="container">
<div class="heading">
<h1>Hey Luke</h1>
</div>
<div class="imagesection">
<!-- IMAGE SECTION 1 -->
<div class="carousel1">
<div class="sliders">
<img class="images" src="./images/bekir-donmez-eofm5R5f9Kw-unsplash.jpg" alt="clone">
</div>
<div class="sliders">
<img class="images" src="./images/conscious-design-eZIE5ZFR7Cs-unsplash.jpg" alt="second clone">
</div>
<div class="sliders">
<img class="images" src="./images/dane-wetton-t1NEMSm1rgI-unsplash.jpg" alt="third clone">
</div>
<div class="sliders">
<img class="images" src="./images/ginny-rose-stewart-UxkcSzRWM2s-unsplash (1).jpg" alt="">
</div>
</div>
I am trying to move images inside of a container using Javascript. Ultimately, I want to move it using setTimeout, but for now trying to do it using an event listener on a button click. It seems to work, but only once. I want to keep moving the images when the button is clicked. Any help is helpful and appreciated.
<div class="images">
<img src="https://images.unsplash.com/photo-1596536220655-21429cf12ae0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80"/>
</div>
<div class="images">
<img src="https://images.unsplash.com/photo-1596536220655-21429cf12ae0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80"/>
</div>
<div class="images">
<img src="https://images.unsplash.com/photo-1596536220655-21429cf12ae0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80"/>
</div>
<div class="images">
<img src="https://images.unsplash.com/photo-1596536220655-21429cf12ae0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80"/>
</div>
</div>
<button id="moveIt">MOVE</button>
<style>
.container {
display: flex;
justify-content: space-around;
overflow: hidden;
max-width: 100%;
z-index: 222;
}
.images {
width: 300px !important;
display: block;
text-align: center;
margin-right: 10px;
height: 400px !important;
}
</style>
<script>
let images = document.querySelectorAll('.images');
const moveBtn = document.getElementById('moveIt');
let pleaseWork = () => {
for(i=0; i < images.length; i++) {
images[i].style.marginLeft = "-300px";
}
}
moveBtn.addEventListener('click', pleaseWork);
</script>
You are setting margin-left to a static number rather than incrementing it. Here's an example that accesses the current margin-left, strips it of the 'px', converts that to a number, then increments it and applies it back to the element.
let images = document.querySelectorAll('.images');
const moveBtn = document.getElementById('moveIt');
let increment = -10
let pleaseWork = () => {
for (i = 0; i < images.length; i++) {
let ml = Number(images[i].style.marginLeft.replaceAll('px', ''))
ml += increment
images[i].style.marginLeft = `${ml}px`;
}
}
moveBtn.addEventListener('click', pleaseWork);
.container {
display: flex;
justify-content: space-around;
overflow: hidden;
max-width: 100%;
z-index: 222;
}
.images {
width: 300px !important;
display: block;
text-align: center;
margin-right: 10px;
height: 400px !important;
}
<div class="images">
<img src="https://images.unsplash.com/photo-1596536220655-21429cf12ae0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80" />
</div>
<div class="images">
<img src="https://images.unsplash.com/photo-1596536220655-21429cf12ae0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80" />
</div>
<div class="images">
<img src="https://images.unsplash.com/photo-1596536220655-21429cf12ae0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80" />
</div>
<div class="images">
<img src="https://images.unsplash.com/photo-1596536220655-21429cf12ae0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80" />
</div>
</div>
<button id="moveIt">MOVE</button>
I'm trying to recreate a animation / side scroll effect. The effect is from https://elrond.com/#partners and its located in the partner section. The slow moving circles. I tried to recreate it, but after slamming my head against mine desk for the duration of the weekend I couldn't recreate it. So here I'm asking for some help.
I made a little code pen to show where I'm at now.
.slide-wrapper{
max-width: 800px;
height: 30vh;
position: relative;
margin: 0 auto;
transform: translate3d(0,0,0);
outline: red;
}
.slider{
position: absolute;
top: 0;
left: 0;
height: 200px;
display:flex;
transform: translate3d(0,0,0);
animation: scroll 15s infinite linear;
}
.slider:last-child .slide{
background-color: steelblue;
animation: scroll 13s infinite linear;
margin-top: 5rem;
}
.slide{
background-color:orangered;
height:50px;
width:50px;
margin: 1rem 6rem;
}
#keyframes scroll {
100%{transform: translateX(-66.6666%)}
}
https://codepen.io/tijmenjacobs/pen/LYxrvKq
My main questions are the following:
How can I loop the animation? Now when the animation is done it teleports back to its original position and restarts.
I was wondering how to position the circles. Should I handle JS to random assign the circles or should I hard code the location? Like they seem to do on the original.
Hope you guys could help!
Thanks in advance!
To get the desired effect you need two of the same sliders next to eachother (slider-main and slider-copy in the snippet).
I used CSS variables to make it easier to calculate offsets and whitespace. The offset between the slides is based on the amount per row (--slides-per-row). These are set within the HTML so you can easily reuse the slider somewhere else.
/* Basic reset */
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body > * + * {
margin-top: 2em;
}
/* Slider styling */
.sliders {
display: flex;
}
.slider {
--slide-offset: calc(100vw / var(--slides-per-row, 4)); /* --slides-per-row is set via HTML and uses 4 if nothing is provided */
--slide-size: 5rem;
flex: 0 0 100vw;
animation: scroll 10s linear infinite;
}
.slider-row {
display: flex;
}
/* Offset every odd row */
.slider-row:nth-child(2n+1) {
transform: translateX(
calc((var(--slide-offset) / 2 + var(--slide-size) / 2) * -1)
);
margin-bottom: 2rem;
}
.slide {
width: var(--slide-size);
height: var(--slide-size);
margin: 0 0 0 var(--slide-offset);
background: steelblue;
font-size: 2rem;
color: white;
/* Center content */
display: flex;
align-items: center;
justify-content: center;
}
#keyframes scroll {
100% {
transform: translateX(-100%);
}
}
<h2>4 slides per row</h2>
<div class='sliders' style='--slides-per-row: 4'>
<div class='slider slider-main'>
<div class='slider-row'>
<div class='slide'>1</div>
<div class='slide'>2</div>
<div class='slide'>3</div>
<div class='slide'>4</div>
</div>
<div class='slider-row'>
<div class='slide'>5</div>
<div class='slide'>6</div>
<div class='slide'>7</div>
<div class='slide'>8</div>
</div>
</div>
<div class='slider slider-copy'>
<div class='slider-row'>
<div class='slide'>1</div>
<div class='slide'>2</div>
<div class='slide'>3</div>
<div class='slide'>4</div>
</div>
<div class='slider-row'>
<div class='slide'>5</div>
<div class='slide'>6</div>
<div class='slide'>7</div>
<div class='slide'>8</div>
</div>
</div>
</div>
<h2>2 slides per row</h2>
<div class='sliders' style='--slides-per-row: 2'>
<div class='slider slider-main'>
<div class='slider-row'>
<div class='slide'>1</div>
<div class='slide'>2</div>
</div>
<div class='slider-row'>
<div class='slide'>3</div>
<div class='slide'>4</div>
</div>
<div class='slider-row'>
<div class='slide'>5</div>
<div class='slide'>6</div>
</div>
<div class='slider-row'>
<div class='slide'>7</div>
<div class='slide'>8</div>
</div>
</div>
<div class='slider slider-copy'>
<div class='slider-row'>
<div class='slide'>1</div>
<div class='slide'>2</div>
</div>
<div class='slider-row'>
<div class='slide'>3</div>
<div class='slide'>4</div>
</div>
<div class='slider-row'>
<div class='slide'>5</div>
<div class='slide'>6</div>
</div>
<div class='slider-row'>
<div class='slide'>7</div>
<div class='slide'>8</div>
</div>
</div>
</div>
How do I get the position of the .img class and then move .img-2 class to the same position as .img?
I know I need to get the top and left position of .img based on the window position and then apply those values to my anime.js function, but I'm not doing it correctly...
In the anime.js function I think the translateX & translateY values need to be the values of .img but I'm maybe wrong?
Codepen is here, I'm trying to make this happen when you click the 'BUTTON' link.
Any help is appreciated
<div class="container-fluid">
<div class="row">
<div class="col-lg-6">
<a class="button" href="javascript:;">BUTTON</a>
</div>
<div class="col-lg-6">
<img class="img-2" src="https://picsum.photos/200/300" alt="">
</div>
</div>
<div class="row bottom-row">
<div>
<img class="img" src="https://picsum.photos/200/300" alt="">
</div>
</div>
</div>
.container {
background-color: grey;
height: 100vh;
}
.container-row {
display: flex;
flex-direction: column;
width: 100%;
}
.button {
cursor: pointer;
display: block;
}
.bottom-row {
height: 100vh;
background-color: red;
}
.img {
width: 200px;
height: auto;
marign-top: 100px;
display: block;
}
jQuery(document).ready(function ($) {
const eTop = $('.img').offset().top; //get the offset top of the element
const eLeft = $('.img').offset().left; //get the offset top of the element
$('.button').on('click', function () {
alert(eTop);
alert(eLeft);
anime({
targets: '.img-2',
translateY: eTop,
translateX: eLeft,
scaleX: 1,
scaleY: 1,
});
});
});
Snippit:
jQuery(document).ready(function ($) {
const eTop = $('.img').offset().top; //get the offset top of the element
const eLeft = $('.img').offset().left; //get the offset top of the element
$('.button').on('click', function () {
alert(eTop);
alert(eLeft);
anime({
targets: '.img-2',
translateY: eTop,
translateX: eLeft,
scaleX: 1,
scaleY: 1,
});
});
});
.container {
background-color: grey;
height: 100vh;
}
.container-row {
display: flex;
flex-direction: column;
width: 100%;
}
.button {
cursor: pointer;
display: block;
}
.bottom-row {
height: 100vh;
background-color: red;
}
.img {
width: 200px;
height: auto;
marign-top: 100px;
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js "></script>
<div class="container-fluid">
<div class="row">
<div class="col-lg-6">
<a class="button" href="javascript:;">BUTTON</a>
</div>
<div class="col-lg-6">
<img class="img-2" src="https://picsum.photos/200/300" alt="">
</div>
</div>
<div class="row bottom-row">
<div>
<img class="img" src="https://picsum.photos/200/300" alt="">
</div>
</div>
</div>
First, the top and left offsets were saved in variables before the image had fully loaded. To avoid that, move the eTop and eLeft lines inside the click handler.
Then, you are doing a translation... So you have to subtract the initial position of the "element to be moved" from the "target" one.
jQuery(document).ready(function($) {
$('.button').on('click', function() {
// Target position
const eTop = $('.img').offset().top; //get the offset top of the element
const eLeft = $('.img').offset().left; //get the offset top of the element
// Element to be moved position
const bTop = $('.img-2').offset().top; //get the offset top of the element
const bLeft = $('.img-2').offset().left; //get the offset top of the element
//alert(eTop);
//alert(eLeft);
anime({
targets: '.img-2',
translateY: eTop - bTop,
translateX: eLeft - bLeft,
scaleX: 1,
scaleY: 1,
});
});
});
.container {
background-color: grey;
height: 100vh;
}
.container-row {
display: flex;
flex-direction: column;
width: 100%;
}
.button {
cursor: pointer;
display: block;
}
.bottom-row {
height: 100vh;
background-color: red;
}
.img {
width: 200px;
height: auto;
marign-top: 100px;
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js "></script>
<div class="container-fluid">
<div class="row">
<div class="col-lg-6">
<a class="button" href="javascript:;">BUTTON</a>
</div>
<div class="col-lg-6">
<img class="img-2" src="https://picsum.photos/200/300" alt="">
</div>
</div>
<div class="row bottom-row">
<div>
<img class="img" src="https://picsum.photos/200/300" alt="">
</div>
</div>
</div>
So I have an index page with some bootstrap code to make the columns resize. I want to have a navbar on the left side and the body for the rest. However, I want to have more than one navbar. I want to create a few categories across the top and depending on which one of those you choose, it will load a navbar and a default body page into the bootstrap columns. It's for a tabletop RPG that I am writing.
So if I have Character Creation, Combat, Magic, Vehicles, etc. across the top and you click on Character Creation then it will load the navbar on the left for character creation and the main body would have a default overview page. If you click a link in the navbar, I want it to change the page on the main body.
I know how to do this the slow way and create a huge number of pages with all the navbars and such already in there. If I update one section, I have to go through and update dozens of pages.
I am trying to teach myself javascript and I know that I can do it in there but I am not sure how.
I can't seem to find an example of this to figure out the coding. I assume that there would be a variable that is being changed by the navbar when you click on the navbar links? Not sure.
This is what I have for the test index page:
<!DOCTYPE html>
<html>
<head>
<title>Main Page</title>
<meta name="viewport" content="width = device-width, initial-scale = 1">
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
</head>
<body>
<h1>This is Test 4</h1>
<div class="container-fluid">
<div class="row">
<div class="col-lg-3 col-md-3 col-sm-3 col-xs-3">
<div class="thumbnail">
<div class="caption">
<div class="load-html" id="Navbar" data-source="navBar.html"></div>
</div>
</div>
</div>
<div class="col-lg-9 col-md-9 col-sm-9 col-xs-9">
<div class="thumbnail">
<div class="caption">
<div class="load-html" id="mainBody" data-source="test3.html"></div>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
$(function () {
$(".load-html").each(function () {
$(this).load(this.dataset.source);
});
});
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</body>
I have written a basic JS example for you below which will work ok in a small project, however it would not scale well in a larger project. You would be better learning a framework like vue.js and using the router along side it, or just using a router like the one Jon B linked you to in his comment above.
Anyway, something this will get you going. I have included a couple tricks which you will likely use in the future, for example data attributes, foreach loops and querySelectors and updating the dom. Let me know if you have any questions and enjoy Javascript :)
// Get all the nav items
var navItems = document.querySelectorAll(".nav-item");
var sideNavTitelEl = document.getElementById('side-nav-title');
var containersEls = document.querySelectorAll(".content");
// selected will be set to the nav item that was clicked on
var selected = 0;
// Add an event listener to all the nav items
navItems.forEach(addingEventListener);
function addingEventListener(item, index) {
item.addEventListener('click', function() {
// the item is what nav item we clicked on,
// lets set the side nav and main container value to be what was clicked on
sideNavTitelEl.innerHTML = item.innerHTML;
// Now lets update the main page container
selected = parseInt(item.dataset.value);
// We use the displayNone to show / hide a container.
// In a large scale project, you will want to begin to look at using a router, as this will speed
// up your site. For this example, it will work fine as is here.
// Hide and show the correct content on page
containersEls.forEach(hideContent);
});
}
function hideContent(item, index) {
if(index === selected) {
// we want to show this container
item.classList.remove('displayNone');
} else {
// hide the container
item.classList.add('displayNone');
}
}
body {
box-sizing: border-box;;
margin: 0;
padding: 0;
position: relative;
}
.top-nav {
width: 100%;
height: 60px;
display: flex;
align-items: center;
justify-content: center;
}
.logo {
margin-left: 30px;
margin-right: auto;
}
.nav-item {
margin-left: auto;
margin-right: 30px;
}
.nav-item:hover {
cursor: pointer;
}
.side-nav {
width: 200px;
height: calc(100vh - 60px);
position: absolute;
top: 60px;
left: 0;
display: flex;
align-items: center;
flex-direction: column;
}
.main-container {
width: 200px;
height: 200px;
background-color: yellow;
margin-left: 200px;
width: calc(100% - 200px);
height: calc(100vh - 60px);
display: flex;
justify-content: center;
align-items: center;
}
.content {
width: 100%;
height: calc(100vh - 60px);
display: flex;
justify-content: center;
align-items: center;
}
.displayNone {
display: none;
}
.container-one {
background-color: red;
}
.container-two {
background-color: green;
}
.container-three {
background-color: blue;
}
<div class="top-nav">
<p class="logo">Home</p>
<p class="nav-item item-1" data-value='0'>Item 1</p>
<p class="nav-item item-2" data-value='1'>Item 2</p>
<p class="nav-item item-3" data-value='2'>Item 3</p>
</div>
<div class="side-nav">
<p id="side-nav-title">Home</p>
<p>Something</p>
<p>Something</p>
<p>Something</p>
</div>
<div class="main-container">
<div class="content container-one" data-value='1'>
<h1>Container 1</h1>
</div>
<div class="content container-two displayNone" data-value='2'>
<h1>Container 2</h1>
</div>
<div class="content container-three displayNone" data-value='3'>
<h1>Container 3</h1>
</div>
</div>