I have an Svg hamburger menu which i'm using to target an event listener,
this invokes the javascript .animate() api & brings the menu pane in from the left,
however when the animation is completed it dissapears(it does not return to it's original position), it just vanishes. I would like it to stay put & then set-up a seperate function to fade it out or slide back.
My HTML is here:
<svg>`Hamburger Code`</svg>
<section id="menuPane" class="lftMenu"
style="position:absolute;
left:-888px;
z-index:18;">
<div class="test">
</div>
<div class="tst2">
</div>
</section>
My CSS is here:
.test{
display:block;
position:absolute;
width:calc(27vw - 7vmax);
height:calc(55vh + 4.8vmin);
top:48.4px; left:8px;
background-image:linear-gradient(-48deg,green,yellow);
border-radius:8.2px;
z-index:19;
}
.test:before{
content:"";
display:block;
position:relative;
width:inherit; height:inherit;
filter:opacity(0.55) hue-rotate(120deg);
background-image:radial-gradient(ellipse at top,blue,green);
border:solid inset 28px transparent;
border-radius:8.2px;
z-index:20;
}
.tst2{
display:block;
position:absolute;
top:48.4px; left:8px;
width:calc(27vw - 7vmax); height:calc(55vh + 4.8vmin);
background-image:url('GalvPlt1.jpg');
background-size:contain;
filter:opacity(0.2);
border-radius:8.2px;
z-index:21;
}
.tst2:hover{
filter:hue-rotate(208deg) opacity(0.44);
}
My Javascript is here:
const menu_pane = document.getElementById("menuPane");
//UiContr.animate([
// Animate opacity to fade in during page load.
//])
let Elem = document.getElementById("Elem"); // This El is the svg box above the menu pane.
Elem.style.position = "absolute";
//Elem.style.willChange = "auto";
Elem.animate({
opacity: ['1', '0.224', '1', '0.498', '1'],
filter: ['hue-rotate(0deg)', 'hue-rotate(-72deg)', 'hue-rotate(0deg)']
// borderRadius: ['8px', '14px']
},{ duration: 4864,
easing: 'ease-in-out',
iterations:7800
// 0.1 hours = 360,000 ms...
// fill: 'reverse'
});
Elem.addEventListener('click',(e) => {
// menu.style.animationFillMode = 'forwards';
menu_pane.animate({
left: ['-888px','8px']
},{ duration: 600,
easing: 'ease-in-out',
iterations:1,
// fill: forwards,
});/*.then(
menu_pane.style.left = "8px";
);*/
});
These are sitting ontop of 3 layered Canvases, one buffer, one menu & the main game window.
All with lower z-index values. I can't figure out where its going to...
I tried this:
menu.style.animationFillMode = 'forwards';
*.tried this in the CSS file aswell none camel case.[nope nothing.]
As a similar question stated animations always return to there initial state.
but that would mean it would slide back to the left, not just pop of the screen & down the pub.. & I also tried chaining a .then() on the end, but this failed also..
Also as an Aside the tutorial I watched, used fill: forwards, reverse, or both & also infinity for iterations as options of .animate() but now I trying these none are being recognised or working.
>.... Partially Solved, Infinity needed Capitolized first letter.
Also, Which is the best way to write these out of the following 2 methods;
Youtube Tutorial Version is:
.animate({property:['from','to']},{',' seperated options});
MDN version is:
.animate([{Property: 'from'},{Property: 'to'}],{',' seperated options});
both of these examples work & animate the same, achieveing about 58fps, but is there a "Correct" or Optimal way to write this.
I would lean more towards the MDN version being more 'Correct' or optimal,
but is there any reason for the two variants, which should I choose?
Although the MDN version you have to write the property name multiple times & with complex, multi parameter animations that might end up being quite a bit more code.? any inputs:
This is the example version of V. Javascript .animate() function.
document.getElementById("tunnel").animate([
// keyframes
{ transform: 'translateY(0px)' },
{ transform: 'translateY(-300px)' }
], {
// timing options
duration: 1000,
iterations: Infinity
});
Thanks in advance any who comments or answers..
Related
I am attempting to animate an svg doughnut circle with gsap. After much testing with code and layering, I am stumped with a glitchy hover effect (which I tried to resolve with pointer events) and the transform origin is only applied to a few of the expanded tabs. I am wondering if this might be that the tabs may have a different bounding box?
Comments added per request:
Side Note: I've tried applying fill-box to entire svg instead, I'm wondering if I need a parent layer thats an exact square so I can apply the transform origin for the child "expandtabs" to the center of that?
I assumed I needed to iterate through an array of both to have the tabs correspond. Unless the tabs were children of each other?
TLDR; Tabs are not scaling from center of circle, and glitchy hover effect
CodePen Example
.expandtab {
pointer-events: none;
transform: fill-box;
transform-origin: -15px 25%;
}
Javascript:
const subTabs = gsap.utils.toArray(".subtab");
const expandTabs = gsap.utils.toArray(".expandtab");
const tl = gsap.timeline({ defaults: { duration: .05, } });
tl.set(expandTabs, {
visibility: "hidden",
opacity: 0,
scale: 0,
});
subTabs.forEach((subTab, index) => {
let expandTab = expandTabs[index];
// Event Listener Hover on
subTabs[index].addEventListener("mouseover", (event) => {
console.log("you clicked region number " + index);
tl.to(expandTab, {
visibility: "visible",
opacity: 1,
scale: 1,
});
});
// Event Listener Hover off
subTabs[index].addEventListener("mouseout", (event) => {
console.log("you exited region number " + index);
tl.to(expandTab, {
opacity: 0,
scale: 0,
visibility: "hidden",
});
});
});
About the glitchy hover effect, the mouseenter and mouseleave will do the job better. mouseover is firering way to much...
For the "growing" effect, it is more complex. The transform-origin CSS property won't be enought. Any way, you will need different values for each five parts of the circle.
Additionnaly, you will need to adjust a transition to "fit" or "keep" the inner part of the circle in place. I suggest you to look at the fromTo method of GSAP. That will allow you to specify explicitely the starting and the landing coordinates.
Be patient! ;)
I'm developing a game engine in HTML5. Characters are div elements using an animated sprite for background. As sprite animation have fluid parameters and must be set by code, they can't be predefined in a static CSS definition, thus I use element.animate to set sprite animations to a given row at a given speed knowing my scales and frame counts.
// Applies the given frame and animation to the sprite
// Frame is an angle, clockwise direction: 0 = up, 1 = right, 2 = down, 3 = left
set_animation(frame, duration) {
const scale_x = this.settings.sprite.scale_x * this.settings.sprite.frames_x;
const pos_y = this.settings.sprite.scale_y * -frame;
// Cancel the existing animation
if(this.data_actors_self.anim) {
this.data_actors_self.anim.cancel();
this.data_actors_self.anim = null;
}
// Play the animation for this row or show the first frame if static
if(duration > 0) {
this.data_actors_self.anim = this.element.animate([
{
backgroundPosition: px([0, pos_y])
}, {
backgroundPosition: px([scale_x, pos_y])
}
], {
duration: duration * 1000,
direction: "normal",
easing: "steps(" + this.settings.sprite.frames_x + ")",
iterations: Infinity
});
this.data_actors_self.anim.play();
} else {
this.element.style.backgroundPosition = px([0, pos_y]);
}
}
Obviously that's a snippet from an actor class function: this.element is the div, this.settings is an object with parameters to be used who's names should make sense in this context, the px() function is a simple converter to turn arrays into pixel strings for HTML (eg: [0, 0] to "0px 0px").
The issue I'm having: While I can always run this function to set a new animation, I want the ability to change the speed of the animation without resetting it. It doesn't need to be a smooth transition, for all I care the new speed can be applied at the next iteration... I only want to avoid a visual snap or any kind of reset upon applying the change. Once an animation is set, I have no idea how to access and update its duration parameter. Does anyone have any suggestions?
When using console.log on this.data.anim I'm rightfully told it's an animation object. I tried using JSON.stringify to get more information but nothing relevant is printed. this.data.anim.duration returns undefined so the setting must be stored under some other property. Even if I know that property, I'd like to be sure web browsers will agree with me changing it like this.data.anim.options.duration = new_duration.
You can wait for the end of an iteration before changing the animation duration if that is what is required.
This snippet only sets an event listener for animationiteration event when you click the button to increase the speed.
function upthespeed() {
const div = document.querySelector('div');
div.addEventListener('animationiteration', function() {
div.style.animationDuration = '1s';
});
document.querySelector('button').style.display = 'none';
}
div {
width: 10vmin;
height: 10vmin;
background-color: magenta;
animation: move 10s linear infinite;
}
#keyframes move {
0% {
transform: translateX(50vw);
}
50% {
transform: translateX(0);
}
100% {
transform: translateX(50vw);
}
}
<div></div>
<button onclick="upthespeed()">Click me to increase the speed at the end of the next iteration (you may have to wait!)</button>
The value for the animation duration isn't in the Animation object itself but in the CSS animation-duration property for the Element: so this.data_actors_self.style.animationDuration = new_duration will do the job. It will however restart the animation if it is being played, but if I understand correctly that isn't a problem for you.
Edit: To change the animation's duration without restarting it, all you have to do is set the value of anim.startTime to what it was before. For example:
const startTime = anim.startTime;
this.data_actors_self.style.animationDuration = new_duration
anim.startTime = startTime;
I'm sure there is a simple fix for this and I just am unable to piece it together... In the event that the link with the id of "light_off" is clicked then I want all the little changes to take place, that part is working, but they're happening too abruptly. How do I slow them down or fade into the changes so the transition looks smoother? Do I fadeIn? Add "slow" duration? Animate? And if so, how would I implement that properly? Gee, I hope that makes sense. Any help would be appreciated! Thank you!!
<script>
$(document).ready(function(){
$("#lights_off").click(function(){
$("#lights_off").fadeOut(1000);
$("#main").addClass(" lights_on");
$('#flavoredesign_logo').attr('src','img/logofinal.png');
$("#nav").css("color","#000000");
$("#nav").css("border-bottom"," #333 solid 1px");
});
});
</script>
You can also use $.animate()
However using animate you can't set color values, but only numeric values or use 'toggle's. w3 has an excellent guide for using it.
$(function() {
var on = true;
$('#lights').on('click', function() {
if ( on ) {
$( "#lights" ).animate({
width: 100,
height: 100
}, 1000 );
} else {
$( "#lights" ).animate({
width: 200,
height: 200
}, 1000 );
}
on = !on;
});
})
I created a fiddle with sizing of an element
you can use setTimeout(function(){ /you code/ }, 200) or use css animations / transitions
As pointed out in the comments, couldn't you use the CSS transition attribute to achieve smooth class changes? You can use this to give a time frame for transitioning between different property values. For example, if you wanted to give an animation time frame for transitioning between colours:
.light {
border-radius: 50%;
width: 100px;
height: 100px;
transition: background-color 1s; //Most properties can be manipulated through the transition attribute, e.g. width 1s
Then toggling between different classes with different values for background-colour:
.lights_off {
background-color: grey;
}
.lights_on {
background-color: yellow;
}
I've created a Fiddle that shows how this could be utilised to create a smooth transition.
I'm trying to make some DOM element rotate smoothly around a fixed point. I'm writing this from scratch using jQuery and no matter what update speed I choose for the setInterval or how small I go with the amount of degrees the orbit advances on each loop, I get this janky staircase animation effect. I've tried using jquery's .animate instead of the .css hoping it would smooth things out but I cant seem to get it to work. Any help is appreciated.
In other words, it's not as smooth as rotating an image in HTML5 canvas. I want to make it smoother.
Here is a jsFiddle demonstrating the issue.
Notice how the animation is not quite smooth?
For reference, here is the code:
HTML
<div id="div"></div>
<div class="dot"></div>
<button class="stop">STOP</button>
<button class="start">START</button>
CSS
#div{
position:absolute;
height: 20px;
width: 20px;
background-color: #000;
}
.dot{
position:absolute;
width: 5px;
height: 5px;
background-color: #000;
}
button{
position:absolute;
}
.stop{
top:200px;
}
.start{
top:225px;
}
THE ALL IMPORTANT JAVASCRIPT
$(document).ready(function(){
$('#div').data('angle', 90);
var interval;
$('.stop').on('click', function(){
if(interval){
clearInterval(interval);
interval = undefined;
}
});
$('.start').on('click', function(){
if(!interval){
interval = setBoxInterval();
}
});
interval = setBoxInterval();
});
function drawOrbitingBox(degrees){
var centerX = 100,
centerY = 100,
div = $('#div'),
orbitRadius = 50;
//dot might not be perfectly centered
$('.dot').css({left:centerX, top:centerY});
//given degrees (in degrees, not radians), return the next x and y coords
function coords(degrees){
return {left:centerX + (orbitRadius * Math.cos((degrees*Math.PI)/180)),
top :centerY - (orbitRadius * Math.sin((degrees*Math.PI)/180))};
}
//increment the angle of the object and return new coords through coords()
function addDegrees(jqObj, degreeIncrement){
var newAngle = jqObj.data('angle') + degreeIncrement;
jqObj.data('angle', newAngle);
return coords(newAngle);
}
//change the left and top css property to simulate movement
// I've tried changing this to .animate() and using the difference
// between current and last position to no avail
div.css(addDegrees(div, degrees), 1);
}
function setBoxInterval(){
var interval = window.setInterval(function(){
drawOrbitingBox(-0.2); //This is the degree increment
}, 10); //This is the amount of time it takes to increment position by the degree increment
return interval;
}
I'd rather not resort to external libraries/plugins but I will if that's the accepted way of doing this kind of stuff. Thank you for your time.
That's because the value you set for top and left properties is rounded up. You should try using CSS Transforms.
Combining CSS Animations/Transitions and CSS Transforms you should also be able to get the animation without JavaScript.
Oh, I run into that myself!
There is actually nothing you can do, the stuttering you see is the pixel size. The pixel is the minimal step for css based animations, you can't do "half pixels" or "0.2 pixels". You will see that the same keeps happening with css3 animations.
The only solution is to speed up your animation, i'm afraid.
Also, cosndsider using rquestAnimationFrame instead of interval: https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame
I am currently working on my portfolio website which uses a very simple navigation.
However what I want to do is have the drop shadow beneath the type become stronger (read: higher opacity/ darker) when the type is being hovered on.
Right now my code looks as follows and does not generate any errors but simply does not do anything either.
For a good understanding of what I mean please have a look at the website with a live example.
/* Work | Play | About | Contact */
/* Shadow Opacity */
$(document).ready(function() {
$('#workShadow', '#playShadow', '#aboutShadow', '#contactShadow').fadeTo( 0, 0.1);
});
/* Shadow Hover effect */
$(document).ready(function() {
$('a#work').hover(function() {
$('#workShadow').fadeTo( 200, 0.5);
}, function() {
$('#workShadow').fadeTo( 400, 0.1);
});
});
/* Type movement on hovering */
$(document).ready(function() {
$('a.shift').hover(function() { //mouse in
$(this).animate({ paddingTop: 85, paddingBottom: 2 }, 200);
}, function() { //mouse out
$(this).stop().animate({ paddingTop: 75, paddingBottom: 12 }, 400);
});
});
Basically I need the opacity of the shadow elements (4 individual ones) to start at 10% opacity and while the user hovers, the type moves down (this part is working) and simultaneously the shadow becomes stronger, increases to 60% opacity. Then revert back to 10% when on mouseOut.
This line is wrong - it is passing a bunch of arguments to the $() function.
$('#workShadow', '#playShadow', '#aboutShadow', '#contactShadow').fadeTo( 0, 0.1);
As the documentation notes, jQuery doesn't expect N arguments as a selector, but 1:
$('#workShadow, #playShadow, #aboutShadow, #contactShadow').fadeTo( 0, 0.1);
It is common (and good) practice to give a set of objects that should do something a common class or to select them in a smarter than just listing all their IDs. Based on your current HTML, this selector gets all the shadow <div>s in the menu, and is much shorter - you won't have to modify your code if you add a new menu element later on, for example:
$('div','#navigationFrame').fadeTo(0, 0.1);
I also see you have this:
<li id="work"><a id="work" ...>
This is really, really, wrong. IDs should be unique in the document. By having more than 1 ID in the document not only are you breaking best practices, ID selection on jQuery will go crazy and won't work as expected. Like the fadeTo selector, you can change the shadow changing code to a cleaner:
$('a','#navigationFrame').hover(function() {
$(this).next('div').fadeTo(200, 0.5);
}, function() {
$(this).next('div').fadeTo(400, 0.1);
});
I tested the website with these changes and it works fine.
What the selectors in my examples are doing is taking advantage of jQuery's context. By doing this:
$('a','#navigationFrame');
Or this:
$('div','#navigationFrame');
We are telling jQuery "only give me the <a> (or <div>) elements inside #navigationFrame.
It is equivalent to this:
$('#navigationFrame').find('a');
It is a good idea to take advantage of this. I see you have a tendency to manually list the elements you're trying to do stuff to do even if they are all similar in some way. Try to shake this habit and let jQuery's powerful selectors get what you want from the document.
I use this:
$(".thumbs img").addClass('unselected_img');
$('.thumbs img').click(function() {
$(this).addClass('selected_img');
if ($(this).is('selected_img')) {
$(this).removeClass('selected_img');
} else {
$('.thumbs img').removeClass('selected_img');
$(this).addClass('selected_img');
}
});
// hover the lists
$('.thumbs img').hover(
function() {
$(this).addClass('selected_img_h');
},
function() {
$(this).removeClass('selected_img_h');
});`
and style:
.selected_img
{
opacity: 1; filter: alpha(opacity = 100);
border:none;
}
.selected_img_h{
opacity: 1; filter: alpha(opacity = 100);
border:none;
}
.unselected_img
{
opacity: 0.6; filter: alpha(opacity = 60);
border:none;
}