Angular.js move animation - javascript

I'm having hard time creating a rather simple move animation.
The effect I want to achieve is similar to this http://jsbin.com/vorub/1/edit?output (which I took from some other SO question).
Now I managed to do it using .animation()
Basically doing this
.animation('.move-to-top', [function() {
return {
addClass: function(element, className, done) {
var el = $(element);
var top = el.position().top;
el
.addClass('move-to-top')
.one('transitionend', function() {
setTimeout(function() {
el.css({
transform: 'scale(1.03) translateY(-' + (top+10) + 'px)'
})
.one('transitionend', function() {
setTimeout(function() {
el
.removeClass('move-to-top')
.css({
transform: 'scale(1) translateY(-' + (top) + 'px)'
})
}, 50);
el.prevAll('.timetracking-item')
.css({
transform: 'translateY(' + el.height() + 'px)'
});
});
}, 100);
});
}
}
}]);
where move-to-top class does this
.move-to-top {
#include vendor(transition, all 400ms ease-in-out);
#include vendor(transform, scale(1.03) translateY(-10px));
position: relative;
z-index: 999;
}
What it does is
add class which scales and move item up a bit
move the item to the top using js
move all previous elements that down to make space using js
remove class that added scaling
BUT that's just for the effect and it's done using transforms, which is of course undesirable, so I'd either need to "cleanup" after the transitions are done and remove trasnsforms and actually move the elements in DOM. Or do it completely differently.
Ideal would by orderBy & ng-move combo, but that would require ng-move to have some ng-pre-move, ng-after-move events, which it as far as I know, doesn't.
Or at least if you could use both addClass: fn() and move: fn() where addClass would fire first(while the element is on the old position), but you can't do this either(addClass doesn't fire when orderBy is applied).
The last option I can think about, and like the least, is broadcast some event from my .animation() after all the transitions are done and catch it inside controller, and sort the array then, but I'd need to remove the style attribute from all the items(to remove items) which could and probably will cause flickers.
Any other ideas?

The pre-move is apparently comming in 1.3 https://github.com/angular/angular.js/issues/7609#issuecomment-44615566
For now, what I've done was apply ng-if, which forces angular to re-render the whole list. Works fine.

Related

How to read size and move hidden element before Vue transition starts on it?

How to read dimensions and move a div that is hidden before Vue transition starts? For example, a user clicks a button and I want to move a hidden div to appear under the button with a fade-in transition. I need to be able to both read the dimensions and move the top/left position of the hidden div before the transition starts.
Let's say I'm using v-show="active" on the div, where active is my reactive data property I want to set to true and be able to move the div before transition starts.
I've tried all these:
Move the div first, then on nextTick set active = true.
Use the javascript hook beforeEnter to try to move the div before transitions start.
Use the javascript hook enter (and 'done' callback) to try to move the div before transition starts.
Tried all the above with updating the DOM immediately with the new position before setting active = true. (In other words, not via data binding, but actually setting element style properties directly like this.$refs.content.style.top = '500px' to avoid any waiting on the virtual DOM.) However, ideally I would like to accomplish this without directly touching the DOM, but using nextTicks instead. Both approaches fail.
Tried with some success with a hacky transition: all .8ms ease-in, top 1ms, left 1ms.
Tried with success with moving the div first then setting active in a setTimeout. This is not the right solution though.
Update
Thanks to the accepted answer I was able to see that I can read dimensions on nextTick (by which time v-show has turned on display). However, it turns out I needed the transition to be all transition all .3s and that would cause the movement to be included. The DOM will gather up all the changes and apply them together, which means they get lumped into the transition that is later added by Vue. The solution ended up being that I needed to make the movements, then trigger the DOM to repaint first, then trigger the v-show to turn on. Here's an example method:
startTransition () {
this.$refs.content.offsetHeight // <-- Force DOM to repaint first.
this.isContentActive = true // <-- Turns on v-show.
},
Use v-bind:style to move your window and it all works as intended.
Update: To check the size of the popup itself, it has to be shown, so I'm using v-show instead of v-if. The first thing I do is make it visible; on the next tick, I can measure it and place it.
new Vue({
el: '.container',
data: {
top: 0,
left: 0,
width: 0,
show: false
},
methods: {
showFloater: function(evt) {
const t = evt.target;
this.show = true;
Vue.nextTick(() => {
const fEl = this.$el.querySelector('.floating');
this.top = t.offsetTop + 30;
this.left = t.offsetLeft;
this.width = fEl.offsetWidth;
setTimeout(() => this.show = false, 1000);
});
}
}
});
.container {
position: relative;
}
.floating {
border: thin solid black;
padding: 3em;
position: absolute;
}
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-to /* .fade-leave-active in <2.1.8 */ {
opacity: 0
}
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.2.1/vue.js"></script>
<div class="container">
<button #click="showFloater">Could go here</button>
<button #click="showFloater">Or here</button>
<transition name="fade">
<div v-show="show" class="floating" v-bind:style="{
top: top + 'px',
left: left + 'px'
}">
This window is {{width}}px wide.
</div>
</transition>
</div>

How to combine jQuery animate with css3 properties without using css transitions?

In this example; i am trying to create a jQuery animation with css3 rotate property. I can manage this animation with css3 transition and jQuery css() but i want to do this with jQuery animate() for rotating deg value according to my jQuery variatons.
Is it possible use animate with css3 property value with jQuery 1.8.0?
Here is jsFiddle to inspect.
jQuery:
var rotateVal = 90;
//this method isn't working
$('.red').animate({
'transform':'rotate('+rotateVal+'deg)'
},500);
//this way works but i don't want to do this with transitions
$('.black').css({
'transform':'rotate('+rotateVal+'deg)',
'transition':'1s'
});​
html:
<span class="black"></span>
<span class="red"></span>
Edit: Vendor prefixes removed, like -webkit-. Thanks to Kevin B.
It is possible, but it isn't easy.
var red = $(".red"),
rotateVal = 90;
$("<div />").animate({
height: rotateVal
},{
duration: 500,
step: function(now){
red.css('transform','rotate('+now+'deg)');
}
});
This basically creates a fake animation of a detached div, then on each step, updates the rotation of the target div.
Edit: Oops! wrong argument order. Here's a demo. http://jsfiddle.net/qZRdZ/
note that in 1.8.0 i don't think you need to specify all the vendor prefixes.
Using this method, you can animate almost anything as long as you keep in mind that things like += and -= won't work properly unless coded for.
Update: Here's a combination of my solution and cuzzea's solution abstracted behind a function. http://jsfiddle.net/qZRdZ/206/
$.fn.rotate = function(start, end, duration) {
console.log(this);
var _this = this;
var fakeDiv = $("<div />");
_this.promise().done(function(){
_this.animate({"a":end},{duration:duration});
fakeDiv.css("height", start).animate({
height: end
}, {
duration: duration,
step: function(now) {
_this.css("transform", "rotate(" + now + "deg)");
},
complete: function() {
fakeDiv.remove();
}
});
});
return _this;
};
var red = $('.red');
red.click(function() {
if ( !$(this).is(':animated') ) {
red.rotate(45,135,500);
setTimeout(function(){
red.rotate(135,190,500);
},750);
setTimeout(function(){
red.rotate(190,45,500);
},1500);
}
});
});
Kevin is corect, almost. :)
Here is working jsFiddle.
You don't have to use another element and height, you can do something like:
var red = $('.red'),
max_rot = 45,
start_from = 90;
red.css({a:0}).animate(
{'a':1},
{ step: function(value,tweenEvent)
{
rotateVal = start_from + max_rot * value;
red.css({
'transform':'rotate('+rotateVal+'deg)',
});
}
},
1000);​
The ideea is simple. First we create a bogus css property 'a' and set it to 0, and then we animate it to 1, so the step function will give you a value of 0 to 1 that you can use to set the custom transform.
An alternative method would be to use jQuery to change the dom to something that css would respond to.
We can set our css to look like this:
.object {
-webkit-transition:all .4s;
-moz-transform:all .4s;
-o-transform:all .4s;
-ms-transform:all .4s;
transform:all .4s;
}
.object[data-rotate="false"] {
-webkit-transform:rotate(0deg);
-moz-transform:rotate(0deg);
-o-transform:rotate(0deg);
-ms-transform:rotate(0deg);
transform:rotate(0deg);
}
.object[data-rotate="true"] {
-webkit-transform:rotate(90deg);
-moz-transform:rotate(90deg);
-o-transform:rotate(90deg);
-ms-transform:rotate(90deg);
transform:rotate(90deg);
}
Our jQuery would look like this:
$('#trigger').live('click',function(){
if($('.object').attr('data-rotate') = true) {
$('.object').attr('data-rotate',false);
}
else {
$('.object').attr('data-rotate', true);
}
});
Obviously, the browser has to support the ability to transform whatever animation you want to run, so its its hit or miss depending on the type of animation, but its nicer to work with if you have a ton of stuff going on or you have some children you want to animate concurrently.
Example fiddle:
http://jsfiddle.net/ddhboy/9DHDy/1/

How to implement jquery like slideDown() in zepto

I am using zepto library for my mobile web site. I have recently learnt that zepto does not have slideDown() plugin like jquery. I would like to implement the same for zepto.
I have tried one on jsfiddle (http://jsfiddle.net/goje87/keHMp/1/). Here it does not animate while showing the element. It just flashes down. How do I bring in the animation?
PS: I cannot provide a fixed height because I would be applying this plugin to the elements whose height property would not be known.
Thanks in advace!!
Demo: http://jsfiddle.net/6zkSX/5
JavaScript:
(function ($) {
$.fn.slideDown = function (duration) {
// get old position to restore it then
var position = this.css('position');
// show element if it is hidden (it is needed if display is none)
this.show();
// place it so it displays as usually but hidden
this.css({
position: 'absolute',
visibility: 'hidden'
});
// get naturally height
var height = this.height();
// set initial css for animation
this.css({
position: position,
visibility: 'visible',
overflow: 'hidden',
height: 0
});
// animate to gotten height
this.animate({
height: height
}, duration);
};
})(Zepto);
$(function () {
$('.slide-trigger').on('click', function () {
$('.slide').slideDown(2000);
});
});​
​
This worked for me:
https://github.com/Ilycite/zepto-slide-transition
The Zepto Slide Transition plugin add to Zepto.js the functions bellow :
slideDown();
slideUp();
slideToggle();
Speransky's answer was helpful, and I'm offering a simplified alternative for a common drop-down navigation list, and separated into slideUp and slideDown on jsfiddle: http://jsfiddle.net/kUG3U/1/
$.fn.slideDown = function (duration) {
// show element if it is hidden (it is needed if display is none)
this.show();
// get naturally height
var height = this.height();
// set initial css for animation
this.css({
height: 0
});
// animate to gotten height
this.animate({
height: height
}, duration);
};
This would work for what you need:
https://github.com/NinjaBCN/zepto-slide-transition

Shade entire page, unshade selected elements on hover

I'm trying to make a page inspection tool, where:
The whole page is shaded
Hovered elements are unshaded.
Unlike a lightbox type app (which is similar), the hovered items should remain in place and (ideally) not be duplicated.
Originally, looking at the image lightbox implementations, I thought of appending an overlay to the document, then raising the z-index of elements upon hover. However this technique does not work in this case, as the overlay blocks additional mouse hovers:
$(function() {
window.alert('started');
$('<div id="overlay" />').hide().appendTo('body').fadeIn('slow');
$("p").hover(
function () {
$(this).css( {"z-index":5} );
},
function () {
$(this).css( {"z-index":0} );
}
);
Alternatively, JQueryTools has an 'expose' and 'mask' tool, which I have tried with the code below:
$(function() {
$("a").click(function() {
alert("Hello world!");
});
// Mask whole page
$(document).mask("#222");
// Mask and expose on however / unhover
$("p").hover(
function () {
$(this).expose();
},
function () {
$(this).mask();
}
);
});
Hovering does not work unless I disable the initial page masking. Any thoughts of how best to achieve this, with plain JQuery, JQuery tools expose, or some other technique? Thankyou!
What you can do is make a copy of the element and insert it back into the DOM outside of your overlay (with a higher z-index). You'll need to calculate its position to do so, but that's not too difficult.
Here is a working example.
In writing this I re-learned the fact that something with zero opacity cannot trigger an event. Therefore you can't use .fade(), you have to specifically set the opacity to a non-zero but very small number.
$(document).ready(function() { init() })
function init() {
$('.overlay').show()
$('.available').each(function() {
var newDiv = $('<div>').appendTo('body');
var myPos = $(this).position()
newDiv.addClass('available')
newDiv.addClass('peek')
newDiv.addClass('demoBorder')
newDiv.css('top',myPos.top+'px')
newDiv.css('left',myPos.left+'px')
newDiv.css('height',$(this).height()+'px')
newDiv.css('width',$(this).width()+'px')
newDiv.hover(function()
{newDiv.addClass('full');newDiv.stop();newDiv.fadeTo('fast',.9)},function()
{newDiv.removeClass('full');newDiv.fadeTo('fast',.1)})
})
}
Sorry for the prototype syntax, but this might give you a good idea.
function overlay() {
var div = document.createElement('div');
div.setStyle({
position: "absolute",
left: "0px",
right: "0px",
top: "0px",
bottom: "0px",
backgroundColor: "#000000",
opacity: "0.2",
zIndex: "20"
})
div.setAttribute('id','over');
$('body').insert(div);
}
$(document).observe('mousemove', function(e) {
var left = e.clientX,
top = e.clientY,
ele = document.elementFromPoint(left,top);
//from here you can create that empty div and insert this element in there
})
overlay();

jQuery: how can I control a div's opacity when hovering over another div?

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;
}

Categories