I tried to find a solution for this one but I can't. There s something that I keep missing... not sure what.
I have a project that when I click a image, the image will get an translate and also a text description.
The text description has a smooth transition and it looks cool.
Well, the question is.. how to make the reset(click on body or another image) to have the same transition for that text description?
This is how it look right now: https://im3.ezgif.com/tmp/ezgif-3-5150d8ffbf.gif
function resetEnlargeEntityImage() {
if(enlargedEntity != null) {
enlargedEntity.style.transform = null;
enlargedEntity.style.transition = null;
enlargedEntity.classList.add("planet-svg-hover");
document.getElementById("planets-description-paragraph").innerHTML = null;
document.getElementById("planets-description-paragraph").classList.add("entity-description-js");
document.getElementById("planets-description-paragraph").classList.remove("entity-description-appear-js");
}
}
function enlargeEntityImage(clickedImage, clickedImageId) {
let mediaQuery = window.matchMedia('(max-width: 375px)');
if(mediaQuery.matches) {
window.location.href = `./${planetsName[clickedImageId]}.html`;
} else {
resetEnlargeEntityImage();
var xToMove = 260 - 130 * clickedImageId; //260
clickedImage.style.transform = "translate(" + xToMove + "px, 320px) scale(4.0)";
clickedImage.style.transition = "transform 1s ease-in-out";
clickedImage.classList.remove("planet-svg-hover");
document.getElementById("planets-description-paragraph").innerHTML = descriptionSpaceObjects[clickedImageId];
document.getElementById("planets-description-paragraph").classList.remove("entity-description-js");
document.getElementById("planets-description-paragraph").classList.add("entity-description-appear-js");
enlargedEntity = clickedImage;
}
}
.planets-description {
color: white;
font-family: "Barlow";
font-size: 30px;
width: 600px;
position: relative;
top: 100px;
left: 700px;
}
.entity-description-js {
position: absolute;
transition-delay: 1s;
transition: 1s;
width: 600px;
left: 0;
visibility: hidden;
opacity: 0;
}
.entity-description-appear-js {
position: absolute;
transition: 1s;
width: 600px;
left: 100px;
visibility: visible;
opacity: 1;
}
<div class="planets-description">
<p id="planets-description-paragraph" class="entity-description-js"></p>
</div>
The Code you provided isnt showing anything, but maybe you could try uesing the "transition" property in css.
Related
I have managed to put together a custom cursor that changes when hovering on different data-type. For this example, when you hover on the first image the cursor changes to a pause icon, when you hover on the second image the cursor changes to a play icon, I would like to change the play icon to just the text "play" instead of the icon.
const cursor = document.getElementById("cursor");
const animateCursor = (e, interacting) => {
const x = e.clientX - cursor.offsetWidth / 2,
y = e.clientY - cursor.offsetHeight / 2;
const keyframes = {
transform: `translate(${x}px, ${y}px) scale(${interacting ? 8 : 1})`
}
cursor.animate(keyframes, {
duration: 800,
fill: "forwards"
});
}
const getCursorClass = type => {
switch(type) {
case "video":
return "fa-solid fa-play";
case "image":
return "fa-solid fa-pause";
default:
return "fa-solid fa-arrow-up-right";
}
}
window.onmousemove = e => {
const interactable = e.target.closest(".interactable"),
interacting = interactable !== null;
const icon = document.getElementById("cursor-icon");
animateCursor(e, interacting);
cursor.dataset.type = interacting ? interactable.dataset.type : "";
if(interacting) {
icon.className = getCursorClass(interactable.dataset.type);
}
}
body {
background-color: rgb(20, 20, 20);
height: 100vh;
margin: 0px;
display: flex;
align-items: center;
justify-content: center;
gap: clamp(10px, 4vw, 100px);
}
body:hover > #cursor {
opacity: 1;
}
#cursor {
height: 20px;
width: 20px;
background-color: white;
border-radius: 20px;
position: fixed;
left: 0px;
top: 0px;
z-index: 10000;
pointer-events: none;
opacity: 0;
transition: opacity 500ms ease;
display: grid;
place-items: center;
}
#cursor:not([data-type=""]) > #cursor-icon {
opacity: 1;
}
#cursor-icon {
font-size: 6px;
line-height: 0px;
opacity: 0;
transition: opacity 400ms ease;
}
.interactable {
aspect-ratio: 1 / 1.5;
width: clamp(120px, 40vmin, 600px);
background-position: center 50%;
background-size: 100%;
opacity: 0.4;
transition: background-size 400ms ease, opacity 400ms ease;
}
.interactable:hover {
background-size: 105%;
opacity: 0.8;
}
<script src="https://kit.fontawesome.com/944eb371a4.js"></script>
<div id="cursor">
<i id="cursor-icon" class="fa-solid fa-arrow-up-right"></i>
</div>
<div
class="interactable"
data-type="image"
style="background-image: url(https://images.unsplash.com/photo-1657739774592-14c8f97eaece?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyfHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=500&q=60)">
</div>
<div
class="interactable"
data-type="video"
style="background-image: url(https://images.unsplash.com/photo-1657779582398-a13b5896ff19?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwzNXx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60)">
</div>
Add a new class named play in the css file
.play::after {
content: "Play";
font-style: normal;
}
Then add the new class name in the following portion of the JS file.
const getCursorClass = type => {
switch(type) {
case "video":
return "play"; // <--- add the class name here
case "image":
return "fa-solid fa-pause";
default:
return "fa-solid fa-arrow-up-right";
}
}
Codepen URL
There is no built-in way to do this, but it is possible with a little bit of CSS.
First, you need to add a span element after the cursor. This will be the element that contains the text that you want to display on hover.
<span class="cursor-text">Text that appears on hover</span>
Then, you need to add some CSS to position the span element and to hide it by default.
.cursor-text { position: absolute; top: 0; left: 0; opacity: 0; }
Finally, you need to add a CSS rule to show the span element on hover.
.cursor:hover .cursor-text { opacity: 1; }
I am working with JavaScript to move an HTML div across the page. Below is the movement that I want the element to follow:
It should be starting and following routes 1, 2, 3 and 4. It should only change the route once the element reaches the max width/height of the page. I am using the below code and I am stuck on how to continue further.
var box = document.getElementById("box");
var height = document.getElementById("container").offsetHeight;
var widht = document.getElementById("container").offsetWidth;
window.setInterval(() => {
let addPosition = (parseInt(box.style.top) + 10);
let subPosition = (parseInt(box.style.top) - 10);
if (addPosition > height)
box.style.top = subPosition + 'px';
else
box.style.top = addPosition + 'px';
}, 100);
#container {
position: absolute;
background: purple;
width: 100%;
height: 100%;
}
#box {
position: absolute;
background: red;
width: 30px;
height: 30px;
}
<div id="container">
<div id="box" style="top: 0px; left: 0px;"></div>
</div>
No JS is needed to make this animation. You can use CSS-Animations for this.
For that, you use keyframes and change the position where the element should move to. You can define the speed with the animation-duration property and repeat it with animation-iteration-count
body {
margin: 0;
height: 100vh;
}
div {
height: 50px;
width: 50px;
background-color: red;
position: fixed;
animation-name: moveBox;
animation-duration: 5s;
animation-iteration-count: infinite;
}
#keyframes moveBox {
0% { top: 0; left: 0; }
20% { top: calc(100% - 50px); left: 0; }
50% { top: 0; left: calc(100% - 50px); }
70% { top: calc(100% - 50px); left: calc(100% - 50px); }
100% { top: 0; left: 0; }
}
<div></div>
As someone else mentioned, this is normally done with CSS animations, but if you have to use javascript you basically want a state system that keeps track of what your current target is.
Here's roughly how you could do it:
let box = document.getElementById("box");
let height = document.getElementById("container").offsetHeight;
let width = document.getElementById("container").offsetWidth;
let getAngle=function(x1,y1,x2,y2)
{
return Math.atan2(y2-y1,x2-x1);
}
let state=0;
let speed=10;//how many pixels to move per interval
let x=0,y=0;
let xTarget=0,yTarget=0;
window.setInterval(() => {
//we do not account for the box's size here, but if we needed to we could add or subtract it to the target as needed
switch(state) {
case 0:
xTarget=0;
yTarget=height;
break;
case 1:
xTarget=width;
yTarget=0;
break;
case 2:
xTarget=width;
yTarget=height;
break;
case 3:
xTarget=0;
yTarget=0;
break;
}
//do we still have more steps left? calculate the angle to the target, then step in that direction
if (state<4)
{
var angle=-getAngle(x,y,xTarget,yTarget)+Math.PI/2;
x+=Math.sin(angle)*speed;
y+=Math.cos(angle)*speed;
}
//are we close enough to the target? snap to the target, then switch to the next state
//note: you may want to calculate the actual distance here instead
if (Math.abs(xTarget-x)<speed && Math.abs(yTarget-y)<speed)
{
x=xTarget;
y=yTarget;
state++;
}
if (state>=4) state=0;//if you want the movement to loop
box.style.left=x+'px';
box.style.top=y+'px';
}, 100);
#container {
position: absolute;
background: purple;
width: 300px;
height: 200px;
}
#box {
position: absolute;
background: red;
width: 30px;
height: 30px;
}
<div id="container">
<div id="box" style="top: 0px; left: 0px;"></div>
</div>
I looked for a solution in the web, without success. I don’t understand why this code fires only once:
$("#d").click(function() {
var h = $(".cont");
var f = h.offset();
if (f.left < 1) {
h.addClass('anim');
} else {
h.addClass('anim2');
}
});
body{
margin: 0;
}
#d {
width: 50px;
height: 50px;
background: #999;
}
.cont {
width: 200px;
height: 200px;
opacity: 1;
background: #333;
position: absolute;
-webkit-transition: all 1s ease-in-out;
}
.anim {
-webkit-transform: translate(50px, 0px);
}
.anim2 {
-webkit-transform: translate(0px, 0px);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="d"></div>
<div class="cont"></div>
Here’s a JSFiddle demo.
What you need is this
$("#d").click( function() {
var h = $(".cont");
var f = h.offset();
if (f.left < 1) {
h.addClass('anim');
h.removeClass('anim2');
} else {
h.addClass('anim2');
h.removeClass('anim');
}
});
after the first click you never remove the classes so they still have effect
I want to do a simple transition between two pages. The animation should be a movement from right to left to go to the second page, and then, left to right to return to the first page.
I've made this, but the problem is that duplicates the width of the page.
const screen1 = document.getElementsByClassName('screen1')[0];
const screen2 = document.getElementsByClassName('screen2')[0];
document.getElementById('toggle1').addEventListener('click', () => {
screen1.style.transform = 'translatex(-100%)';
screen2.style.transform = 'translatex(0)';
});
document.getElementById('toggle2').addEventListener('click', () => {
screen1.style.transform = 'translatex(0)';
screen2.style.transform = 'translatex(100%)';
});
body {
margin: 0;
}
.container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.screen1 {
position: absolute;
width: 100%;
height: 100%;
background-color: blue;
transition: transform .5s;
}
.screen2 {
position: absolute;
width: 100%;
height: 100%;
background-color: red;
transform: translatex(100%);
transition: transform .5s;
}
<div class="container">
<div class="screen1">
<button id="toggle1">Toggle</button>
</div>
<div class="screen2">
<button id="toggle2">Toggle</button>
</div>
</div>
The problems that I've with this:
In an element with 100% of width I must to use the viewport units. In other case, the 100% will be two screens.
An element with fixed position, positioned to the right of the screen, will take the right value of the second screen. So it won't be displayed.
I can hide the scroll bar with overflow-x: hidden but the user can scroll to the next screen anytime.
There is some way to fix this problems and maintain the "slide" transition?
Just add overflow: hidden to your container.
const screen1 = document.getElementsByClassName('screen1')[0];
const screen2 = document.getElementsByClassName('screen2')[0];
document.getElementById('toggle1').addEventListener('click', () => {
screen1.style.transform = 'translatex(-100%)';
screen2.style.transform = 'translatex(0)';
});
document.getElementById('toggle2').addEventListener('click', () => {
screen1.style.transform = 'translatex(0)';
screen2.style.transform = 'translatex(100%)';
});
body {
margin: 0;
}
.container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
}
.screen1 {
position: absolute;
width: 100%;
height: 100%;
background-color: blue;
transition: transform .5s;
}
.screen2 {
position: absolute;
width: 100%;
height: 100%;
background-color: red;
transform: translatex(100%);
transition: transform .5s;
}
<div class="container">
<div class="screen1">
<button id="toggle1">Toggle</button>
</div>
<div class="screen2">
<button id="toggle2">Toggle</button>
</div>
</div>
Add overflow:hidden property to your .container
I try to build a Slideshow in JS + CSS and it works pretty well except one visual glitch. The Transition to the last slides seems somehow broken.
But I couldn't figure out what the problem is. If I comment out the "offset" transition on the last slide, the error doesn't occure.
This is the codeine I am talking about: https://codepen.io/marianbreitmeyer/pen/paeYgZ
The Block of code I mentioned is this one:
const showNext = function() {
clicked = true;
for (i = 0; i <= slides.length-1; i++) {
if( parseInt(slides[i].style.zIndex) === slides.length) {
console.log(slides[i].innerHTML);
triggerAnimation(slides[i], 'offcanvas');
} else if (parseInt(slides[i].style.zIndex) === slides.length-1) {
//the line below triggers the problem
triggerAnimation(slides[i], 'offset');
}
}
};
Maybe someone with more experience could help me :)
Your code might be more simple:
const btn = document.getElementsByClassName('arrow')[0];
const slides = document.getElementsByClassName('slide');
slides[slides.length - 1].classList.add('offset', 'next');
btn.addEventListener("click", function(e) {
var o, n;
for (var i = 0; i < slides.length; i++) {
if (slides[i].classList.contains('offset')) {
slides[i].classList.remove('offset', 'next')
slides[i].classList.add('offcanvas');
o = (slides[i - 1] || slides[slides.length - 1]);
n = (slides[i - 2] || slides[slides.length + i - 2]);
}
if (slides[i].offsetLeft < -slides[i].offsetWidth) {
slides[i].classList.remove('offcanvas', 'next');
}
}
o.classList.add('offset');
n.classList.add('next');
}, false);
.container {
width: 100%;
height: 100vh;
background: brown;
position: relative;
}
body {
text-align: center;
font-size: 2rem;
}
.slide {
position: absolute;
top: 0;
left: 90%;
width: 100%;
height: 100%;
}
.slide:nth-child(1) {
background: pink;
}
.slide:nth-child(2) {
background: blue;
}
.slide:nth-child(3) {
background: green;
}
.slide:nth-child(4) {
background: grey;
}
.slide:nth-child(5) {
background: yellow;
}
.slide.next {z-index:1}
.slide.offset {
left: -10%;
z-index: 2;
transition: left .65s ease-in-out;
}
.slide.offcanvas {
left: -110%;
z-index: 2;
transition: left .65s ease-in-out;
}
.arrow {
position: absolute;
right: 5%;
top: 25px;
z-index: 9;
height: 50px;
width: 50px;
cursor: pointer;
}
.arrow:hover path {
transform: translate(16px, 0px);
}
path {
position: absolute;
top: 0;
left: 0;
transition: all .2s ease-in-out;
}
<div class="container">
<div class="slide">1 = pink</div>
<div class="slide">2 = blue</div>
<div class="slide">3 = green</div>
<div class="slide">4 = grey</div>
<div class="slide">5 = yellow</div>
<svg xmlns="http://www.w3.org/2000/svg" class="arrow"><path d="M19.443 5.17L30.138 15.5H-.095v1h30.233L19.443 26.829l.696.719L32.095 16 20.139 4.451z"/></svg>
</div>