Javascript transition works only after second hover - javascript

I am new to Javascript. I want to make my image gradually get smaller, and then resize back to its original size. What I have works, but only after hovering over the image 2 times or more.
To be clearer, when I hover my mouse over the image for the first time, it makes a very abrupt transition, but works after that. It did the same thing when using CSS instead.
What I have is this:
function enlargeImage() {
var logo = document.getElementById('logoname');
logo.style.opacity = '0.7';
logo.style.height = 'auto';
logo.style.width = '800px';
logo.style.transition = '0.7s';
}
function resizeImage() {
var logo = document.getElementById('logoname');
logo.style.opacity = '1';
logo.style.height = 'auto';
logo.style.width = '900px';
}
Should this work? Or have I coded in a way in which I shouldn't have?

Personally I like to leave animations and effects like these to CSS and leave the functionality to Javascript.
#yourImage {
width: 150px;
height: 150px;
transition: transform .25s ease, opacity .5s ease;
}
#yourImage:hover {
opacity: 0.5;
transform: scale(0.5);
}
<img src="http://www.w3schools.com/css/trolltunga.jpg" alt="" id="yourImage">
When the image is hovered over I transform and resize the image to 0.5% of it's original size and 0.5% of it's original opacity.
I am also using the transition property to set how fast the image transitions when it is resized or when the opacity is changed.

The abruption was because of the height tag inside javascript code. change this
height: auto
Into height:400px or some value instead of auto.
function enlargeImage() {
var logo = document.getElementById('logoname');
logo.style.opacity = '0.7';
logo.style.height = '300px';
logo.style.width = '400px';
logo.style.transition = '0.7s';
}
function resizeImage() {
var logo = document.getElementById('logoname');
logo.style.opacity = '1';
logo.style.height = '600px';
logo.style.width = '600px';
logo.style.transition = '0.7s';
}
img {
height:300px;
width:400px;
}
<img onmouseover="resizeImage()" onmouseout="enlargeImage()" src='http://imgsv.imaging.nikon.com/lineup/lens/zoom/normalzoom/af-s_dx_18-140mmf_35-56g_ed_vr/img/sample/sample1_l.jpg' id="logoname">

Related

How to animate text via CSS with vertically centered anchor point

I have a simple JS script which listens to keyboard input and displays, at a random position, a short animation of every typed letter fading out and getting smaller.
'use strict'
const body = document.querySelector('body')
const ignoreKeys = [
'Alt', 'Shift', 'Control', 'CapsLock', 'Tab', 'Backspace', 'Escape', 'Meta',
'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'
]
document.addEventListener('keydown', function(e) {
if (!ignoreKeys.includes(e.key)) {
// Values 400 & 200 keep the div completely inside the window
const maxHeight = window.innerHeight - 400
const maxWidth = window.innerWidth - 200
const div = document.createElement('div')
div.className = 'anim'
div.textContent = e.key
div.style.top = getRandomInt(0, maxHeight) + 'px'
div.style.left = getRandomInt(0, maxWidth) + 'px'
body.append(div)
setTimeout(function() { div.remove() }, 3000)
}
})
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min) + min)
}
.anim {
position: fixed;
text-align: center;
animation-name: fade;
animation-duration: 2s;
animation-timing-function: ease-in-out;
opacity: 0%;
}
#keyframes fade {
0% { opacity: 100%; font-size: 300px;}
100% { opacity: 0%; font-size: 100px;}
}
By animating the font-size property, each letter gets smaller. However, since its "anchor point" is the top of the div, the visible effect is a letter getting smaller and moving slightly upwards. I would like each letter to shrink towards the vertical center of the div instead.
I can calculate the center the div easily and add the proper top coordinate to the #keyframe property, but I don't know how to modify that property in JS, individually for each div. Is this possible at all via CSS? Or should I rewrite the whole thing in pure JS?
You don't need to adjust the div's top value at all. As there is no border or anything else displayed for the DIV tag itself - just the letter within it - you can adjust either the margin, the border and/or the padding to achieve the same effect as increasing the top value for the DIV. As each of these can be handled within the css transition, you could do something like:
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min) + min)
}
document.addEventListener('keydown', function(e) {
const body = document.querySelector('body')
const ignoreKeys = [
'Alt', 'Shift', 'Control', 'CapsLock', 'Tab', 'Backspace', 'Escape', 'Meta',
'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'
]
if (!ignoreKeys.includes(e.key)) {
// Values 400 & 200 keep the div completely inside the window
const maxHeight = window.innerHeight - 400
const maxWidth = window.innerWidth - 200
const div = document.createElement('div')
div.className = 'anim'
div.textContent = e.key;
div.style.top = getRandomInt(0, maxHeight) + 'px'
div.style.left = getRandomInt(0, maxWidth) + 'px'
body.append(div)
setTimeout(function() { div.remove() }, 3000)
}
})
.anim {
display:block;
position: fixed;
text-align: center;
width:200px;
animation-name: fade;
animation-duration: 2s;
animation-timing-function: ease-in-out;
opacity: 0;
margin:0px;
}
#keyframes fade {
0% { opacity:1; font-size: 300px;}
100% { opacity:0; font-size: 100px; margin-top:100px;}
}
The initial state of the DIV is with margin:0px. Adding a margin-top setting to the keyframes css, increases this from 0 to 100 during the transition. The effect of that is to push the DIV down - and, as noted above, as nothing is being displayed for the DIV itself, the user will not see it move. Note that I have fixed the width of the DIV at 200px so ensure that everything is always centered horizontally - otherwise the DIV width is based on the width of the character, so would change during transition and the character would move to the left as the centre line changes. I've moved some of the code around to make it easier to test - but the only actual change is in the CSS styling. Also note that opacity is a value from 0 to 1, so should not be shown as a percentage.
UPDATE
Have a look at the following snippet. I think that it may be possible to have random font sizes AND random positions using transform rather than animate.
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min) + min)
}
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split("");
function zoomOUT(){
let d = document.getElementById("test");
d.classList.remove("zoomIN");
d.classList.add("zoomOUT");
}
function zoomIN(){
let d = document.getElementById("test");
let dletter = document.getElementById("testletter");
let t = getRandomInt(20, 60) * 10;
let l = getRandomInt(20, 100) * 10;
let fs = getRandomInt(10, 20) * 10;
dletter.innerHTML = letters[getRandomInt(0, 61)];
d.style.top = t + "px";
d.style.left = l + "px";
d.style.fontSize = fs + "%";
d.classList.remove("zoomOUT");
d.classList.add("zoomIN");
}
#test {
position:absolute;
padding: 50px;
margin: 0 auto;
text-align:center;
vertical-align:middle;
}
.zoomIN {
opacity:1;
transform: scale(3);
transition: transform 2s;
}
.zoomOUT {
opacity:0.5;
transform: scale(0.1);
transition: transform 3s;
}
<button onclick="zoomOUT();" z-index=1>Play</button><button onclick="zoomIN();" z-index=1>Restart</button>
<div id="test" class="zoomIN" style="top:300px; left:300px;" z-index=0><div id="testletter" style="font-size:600%; width:100%; height:100%">A</div></div>
Transform seems to keep things in the same place, so there is no need to adjust any top/margin/border/padding settings at all. In fact, the only things that change are the font-size (using scale(..)) and opacity. The size of the font is determined by the code. Note that this requires the character to be in a div within a div. This is just a test, but should give you enough to convert things into your code requirements.

Stuttery CSS animation for enlarging images in Safari

I am trying to create an animation which takes a image that is anywhere on a page and moves it to the middle while resizing it to full width of the browser window. My solution works, but has some stutters/jumps in it, which I can't really explain. Is there anyone who has tried creating a similar animation already? EDIT: I noticed that the stutter problem only seems to appear in macOS Safari. In other browsers this animation appears to run perfectly smooth.
Here is my js code:
function getWindowWidth() {
return document.documentElement.clientWidth
}
function getWindowHeight() {
return document.documentElement.clientHeight;
}
//at the moment this is hacky and only supports one image to be enlarged
let en_img_left = null;
let en_img_top = null;
function enlargeImage(img) {
let boundingClientRect = img.getBoundingClientRect();
img.style.position = "fixed";
en_img_top = boundingClientRect.y + "px";
img.style.top = en_img_top;
en_img_left = boundingClientRect.x + "px";
img.style.left = en_img_left;
img.style.width = boundingClientRect.width + "px";
img.style.zIndex = "1000";
setTimeout(function() {
img.style.transition = "1s ease-in-out";
setTimeout(function() {
let scaleFactor = getWindowWidth() / boundingClientRect.width;
img.style.transform = "scale(" + scaleFactor + ")";
img.style.left = getWindowWidth() / 2 - (boundingClientRect.width / 2) + "px";
img.style.top = getWindowHeight() / 2 - boundingClientRect.height / 2 + "px";
}, 1);
}, 1);
return img;
}
function delargeImage(img) { //sorry for the function name
img.style.transition = "1s ease-in-out";
setTimeout(function() {
img.style.transform = "scale(1)";
img.style.left = en_img_left;
img.style.top = en_img_top;
}, 1);
return img;
}
example HTML+CSS code, but it can be any image with an ID on a website:
HTML:
<div class="container">
<img id="example" style="width: 100%" src="https://images.pexels.com/photos/1361815/pexels-photo-1361815.jpeg?cs=srgb&dl=blur-bokeh-close-up-1361815.jpg&fm=jpg">
</div>
CSS:
.container {
width: 200px;
}
I also made a jsfiddle displaying the stutter problem quite nicely:
https://jsfiddle.net/robske_110/vhz5Ln4o/11/
You are not using CSS animations or transitions!
The animation itself is executed through JavaScript in your example. Instead of computing every single step of an animation in JS and setting a new CSS property on each iteration, you should setup a CSS animation with the desired start- and end-states or define the properties, that should be transitioned. This way the animation should look smooth while transitioning.
Your example using a CSS transition (without any JS code):
.container {
width: 200px;
transition: width ease-in 1s;
}
.container:hover {
width: 80vw;
}
.container img {
width: 100%;
}
<div class="container">
<img id="example" src="https://images.pexels.com/photos/1361815/pexels-photo-1361815.jpeg?cs=srgb&dl=blur-bokeh-close-up-1361815.jpg&fm=jpg">
</div>

increase font size iteratively using javascript

var text = document.querySelector('p')
for(var i=10px; i<=40px; i++)
text.style.fontSize = i;
I want a script which increases the font size in every iteration of the for-loop. The above code is the prototype of my requirement (which won't work since pixels can't be assigned to a variable). Help me providing the correct code.
You probably want to use setTimeout recursion instead, so the text doesn't increase in size instantly:
var text = document.querySelector('p');
function increaseTextSize(size) {
text.style.fontSize = size + 'px';
if (size <= 40) setTimeout(increaseTextSize, 50, size + 1);
}
increaseTextSize(10);
<p>my text</p>
You can also try out this demo using CSS transition effect:
// After 500ms change the font from 10 to 60px
// and css will take care of the rest
setTimeout(() => {
var text = document.querySelector('p');
text.style.fontSize = '60px';
text.style.color = 'blue'; // <-- you can also add color effects, if you want
}, 500);
p {
font-size: 10px;
color: red;
-webkit-transition: all 2.5s ease;
-moz-transition: all 2.5s ease;
-o-transition: all 2.5s ease;
-ms-transition: all 2.5s ease;
}
<p>Hello World!</p>
var text = document.querySelector('p')
for (var i = 10; i <= 40; i++) {
text.style.fontSize = `${i}px`;
}
You cannot append px in the loop since it has to be an integer.

How to use setInterval to enlarge image

I want to achieve when an image is clicked then it will enlarge for a set amount of time. So far I'm up to here in my JS but it doesn't work
var image = document.getElementById('pic');
function enlarge() {
image.style.height="600px";
}
image.onclick =enlarge;
After I tried to implement.
var image = document.getElementById('pic');
function enlarge() {
image.style.height="600px";
}
image.onclick = setInterval(enlarge; 1000);
How should I implement this? JSFIDDLE
Using setInterval
We want 60fps, so each frame would be 1000 / 60 which equals about 16.667ms long. We need to enlarge the height by 500px. 500 / 60 equals to 8.334. So we need an interval of 16.667 ms, and every iteration, enlarge the image by 8.334px, and stop when the height reaches 600px:
var images = document.querySelectorAll('.pic');
images.forEach(function(image) {
image.addEventListener('click', enlarge);
});
function enlarge(e) {
var image = e.target;
var interval;
var height = 100;
interval = setInterval(function() {
height += 8.334;
if(height >= 600) {
height = 600;
clearInterval(interval);
}
image.style.height = height + 'px';
}, 16.667);
}
.pic {
width: 100px;
height: 100px;
vertical-align: top;
}
<img src='https://placehold.it/100x100' class='pic'>
<img src='https://placehold.it/100x100' class='pic'>
Using requestAnimationFrame
A better way of doing it, will use requestAnimationFrame() that produces smoother animations. According to MDN:
The window.requestAnimationFrame() method tells the browser that you
wish to perform an animation and requests that the browser call a
specified function to update an animation before the next repaint.
The math stays the same, but requestAnimationFrame will handle the calling the next frame after 16.667ms.
var images = document.querySelectorAll('.pic');
images.forEach(function(image) {
image.addEventListener('click', enlarge);
});
function enlarge(e) {
var image = e.target;
var interval;
var height = 100;
function enlargeInner() {
height += 8.334;
if(height >= 600) {
height = 600;
}
image.style.height = height + 'px';
height < 600 && requestAnimationFrame(enlargeInner);
}
enlargeInner();
}
.pic {
width: 100px;
height: 100px;
vertical-align: top;
}
<img src='https://placehold.it/100x100' class='pic'>
<img src='https://placehold.it/100x100' class='pic'>
You just assign same height in an interval. You need to increment it, like:
image.style.height = (+image.style.height + 600) + "px";
But I guess it is not your goal, as it will make your image grow 600px every second. I think what you are looking for is just making it bigger to actual point of size? If so, try using CSS transition combined with javascript, like:
CSS:
img {
width: 300px;
height: 300px;
-webkit-transition: width 1s linear, height 1s linear;
transition: width 1s linear, height 1s linear;
}
.enlarged {
width: 600px;
height: 600px;
}
JS:
document.getElementById('pic').addEventListener("click", function(e){
this.classList.toggle("enlarged");
}
setInterval() only won't work.
Basically what your code is doing, that it waits 1000 milliseconds, and runs the enlarge function.
(by the way, you have a typo, at the last line, there should be a comma between enlarge and 1000)
The way I would do it is to add a css class with an animation, and then add that class to the image on click.
let myImg = document.getElementById("img1");
myImg.addEventListener("click", () => myImg.classList.toggle("enlarge"));
/*
The code above is using ES6 (the newest version of JavaScript) and and a thing called an arrow function. If you don't get it, here is the "normal way" to do it. It will do exactly the same as the above code.
var myImg = document.getElementById("img1");
myImg.addEventListener("click", function(){
myImg.classList.toggle("enlarge")
});
*/
#img1 {
transition: 1s
}
.enlarge {
width: 300px;
height: 300px;
}
<img id="img1" src="https://foswiki.org/pub/Support/Glossary/600px-Example.svg.png" width="100px" height="100px">
I forked your fiddle.
You need to change the way you're approaching the click event like so:
function enlarge() {
setInterval(function() {
// do stuff
}, 1000)
}
image.onclick = enlarge;

CSS transition bug

I have this pair of divs that should resize on click, it works fine except that every once in a while the div kind of flashes before resizing. I done a lot of research and everybody agrees it should fix with "-webkit-backface-visibility: hidden;" but I've tried it and it doesn't change anything. It fails both in chrome and firefox. I mean sometimes it works fine and other times it just flickers really horribly.
Any ideas on what is wrong?
Is it in the jquery? in the css?
Any help is appreciated.
My JS:
(function($){
setup = function setup(){
var windowWidth;
$('.day').each(function(){
var $this = $(this),
links = $('.links', $this),
images = $('.images', $this),
largeWidth,
smallWidth,
linksWidth,
imagesWidth;
images.click(function(){
windowWidth = $(window).width();
linksWidth = $('.links', $this).width();
imagesWidth = $('.images', $this).width();
largeWidth = Math.max(linksWidth,imagesWidth);
smallWidth = Math.min(linksWidth,imagesWidth);
if (windowWidth < 850){
images.width(largeWidth);
links.width(smallWidth);
}
})
links.click(function(){
windowWidth = $(window).width();
linksWidth = $('.links', $this).width();
imagesWidth = $('.images', $this).width();
largeWidth = Math.max(linksWidth,imagesWidth);
smallWidth = Math.min(linksWidth,imagesWidth);
if (windowWidth < 850){
links.width(largeWidth);
images.width(smallWidth);
}
})
});
}
$(document).ready(setup);
}(jQuery))
And the CSS:
.column {
width: 50%;
float: left;
overflow: hidden;
-webkit-transition: width 0.3s linear;
-moz-transition: width 0.3s linear;
-o-transition: width 0.3s linear;
transition: width 0.3s linear;
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-webkit-perspective: 1000;
-webkit-transform:translate3d(0,0,0);
-webkit-transform: translateZ(0);
}
Here is the jsfiddle: http://jsfiddle.net/cKvYq/2/
Thanks a lot!
The reason why their widths start animating less and less is because you set the width to be changed to based on the current width, so when one is clicked while it is transitioning those values are thrown off. To remedy this you could attempt to calculate the large and small width based on window size initially and on window resize, but what I recommend and the method I used is to disable the clicks using .on and .off with a setInterval the duration of the transition.
The other problem of the right div wrapping to the next line is caused by the width temporarily taking up more than the window width. I assume it's because sometimes the divs are just slightly animated at different times, thus one expands before the other contracts throwing it to the next line. I remedied this problem by lessening the width of both of them by a couple pixels and using a negative margin, increased padding trick to have the right div called images to take up that space that I removed. This part could probably be done in a cleaner way than I did it, such as including that small decrease in the initial calculation somewhere or perhaps in the CSS, but for this demo I didn't figure it was too big of an issue, it functions well and was made to show you the problem
Here is the Updated jsFiddle
Here is the changed jQuery
(function ($) {
setup = function setup() {
var windowWidth;
$('.day').each(function () {
var $this = $(this),
links = $('.links', $this),
images = $('.images', $this),
largeWidth,
smallWidth,
linksWidth,
imagesWidth,
count = 0;
var imagesClick = function () {
images.off('click');
links.off('click');
windowWidth = $(window).width();
if(count === 0)
{
linksWidth = $('.links', $this).width() - 2;
imagesWidth = $('.images', $this).width() - 2;
images.css({'margin-right': "-=4", 'padding-right': "+=4"});
count++;
} else{
linksWidth = $('.links', $this).width();
imagesWidth = $('.images', $this).width();
}
largeWidth = Math.max(linksWidth, imagesWidth);
smallWidth = Math.min(linksWidth, imagesWidth);
if (windowWidth < 850) {
images.width(largeWidth);
links.width(smallWidth);
setTimeout(function () {
images.on('click', imagesClick);
links.on('click', linksClick);
}, 300);
}
}
images.on('click', imagesClick);
var linksClick = function () {
images.off('click');
links.off('click');
windowWidth = $(window).width();
if(count === 0)
{
linksWidth = $('.links', $this).width() - 2;
imagesWidth = $('.images', $this).width() - 2;
images.css({'margin-right': "-=4", 'padding-right': "+=4"});
count++;
} else{
linksWidth = $('.links', $this).width();
imagesWidth = $('.images', $this).width();
}
largeWidth = Math.max(linksWidth, imagesWidth);
smallWidth = Math.min(linksWidth, imagesWidth);
if (windowWidth < 850) {
links.width(largeWidth);
images.width(smallWidth);
setTimeout(function () {
images.on('click', imagesClick);
links.on('click', linksClick);
}, 300);
}
}
links.on('click', linksClick);
});
}
$(document).ready(setup);
}(jQuery))

Categories

Resources