openui5: How to implement animation only for the first render of custom component - sapui5

I'm implementing some custom components for openui5/sapui5.
For the component, I want to have a css animation when it is initially loaded.
This is quite straight forward as I add the following css:
#-webkit-keyframes card-in-animation {
from {
-webkit-transform: translateY(50em) rotate(5deg);
opacity:0;
}
}
.card {
animation:card-in-animation 0.7s .2s ease-out both;
-webkit-animation:card-in-animation 0.7s .2s ease-out both;
}
The problem arises when the component is re-rendered for some reason by the openui5 framework.
The DOM elements are then destroyed and new ones are created.
This causes the animation to triggered once again.
To see this in practice:
Go to http://elsewhat.github.io/openui5-cards/cdn/latest/example3.html
The initial animation is triggered as wanted
Click on the menu icon in the top right corner of any card
A new unwanted animation is triggered
What's the preferred method of avoiding this in openui5?

Inside of your renderer you can set an flag that this control/component is rendered once.
second time you'll run into this renderer you'll check this flag and doesn't render this specific class.
if(!oControl._renderedOnce) {
oRm.addClass('rotate');
oControl._renderedOnce = true;
}
oRm.writeClasses();

Not sure how to overcome the unwanted re-rendering, but would it be an option to remove the animation class after the cards are rendered? (You may need to trigger it after a few seconds after onLoad for all cards to be set in place)
Something like this:
$("<element_of_your_cards>").removeClass("card")

Related

onDragOver very slow with Angular Material tabs

I'm using Angular 6 and Angular Material. I'm attempting to implement a simple drag and drop list inside of a Material tab (). Drag and drop works fine outside of a material tab, but inside the tab it's very slow (18 seconds to DnD 1 item in a list of 5 items). The onDragEvent fires many many times even when the mouse isn't moving. I've tried detaching (onDragStart) and reattaching (onDrop) the change detector. It doesn't make a difference.
Here's the html:
<div (dragover)="onDragOver($event)">
<div *ngFor="let item of listItems, let i = index"
(drop)="onDrop($event, i)"
[draggable]="true"
(dragstart)="onDragStart(i)">
{{item}}
</div>
</div>
Here are the functions:
onDragStart(i) {
}
onDragOver(event) {
console.log('1')
event.preventDefault();
}
onDrop(event, i) {
}
Thank you.
It appears that as I dragged the item around the screen- even briefly, the Angular engine was overfiring and queuing up a ridiculous number of calls of onDrop and/or onDragEnter. And that when angular hooks those events, it also assumes that something in the angular components has changed and it runs through the change detection routines.
Each... time.
What I did that fixed my problem was to turn off change detection when dragging began and turn it back on when dragging was complete.
Here is a brief hint at what I did:
import ChangeDetectorRef from '#angular/core'
inject ChangeDetector into your constructor:
constructor(private cdr: ChangeDetectorRef)
call detach from the dragStart:
this.cdr.detach();
call reattach from the drop and dragEnd:
this.cdr.reattach();
If your component is buried deep on your page, you may have to detach change detection at a higher level in order to see results.
i was experiencing a similar issue, where dragging when there were many elements on the page was unbearably slow. I found that removing the (dragover) angular binding, and replacing it with pure javascript instantly solved the problem
i switched
(dragover)="this.onDragOver($event)"
to
ondragover="onDragOver(event)"
you also need to declare the function in index.html instead of in your typescript file or html template (hence pure javascript)

CSS transition ease-out not working

Ok, so I don't understand why this doesn't ease out, only in: (for quick view, just paste it in http://htmledit.squarefree.com, for instance)
<style>
#over {
background: url(http://th01.deviantart.net/fs71/150/f/2013/005/0/6/dal_shabet__have__don_t_have_by_awesmatasticaly_cool-d5qkzu8.jpg);
height:150px;
width:150px;
}
#in {
background: url(http://www.mygrafico.com/images/uploads/thumbs/thumb_revidevi_CoolMonsterTruck.jpg);
height:150px;
width:150px;
}
#in:hover {
opacity: 0;
transition: opacity .3s ease-in-out;
}
</style>
<div id="over">
<div id="in"></div
</div>
I'm not sure exactly what you're asking, but I think you are saying that the transition is only occurring in on a mouse over, and not when you mouse out (it just snaps back to the way it was before, instead of transitioning). You need to add your transition property to #in, rather than #in:hover. The transition is only occurring when your #in element is being hovered over. Move the css for the transition under #in and it will work on mouse over and mouse out. You want to leave your desired css for the hover state under #in:hover, in this case, the opacity change, but the actual transition css property will go under #in.
To make it a little more clear:
#in {
background: url(http://www.mygrafico.com/images/uploads/thumbs/thumb_revidevi_CoolMonsterTruck.jpg);
height:150px;
width:150px;
transition: opacity .3s ease-in-out; /* add this here */
}
#in:hover {
opacity:0;
/* and we've removed it from here */
}
The thing to know is that ease-in-out has nothing to do with when it will transition. It may seem that way, that ease-in is on hover, and ease-out is on mouseout, but actually, ease-in-out means that it will ease in and out slowly, rather than something like ease-in, which eases into the transition slowly and then speeds up towards the end. It relates to the style of the transition itself, rather than when it will occur.
Maybe you already understood that, but based on your question it seems you were confused there.
I found #welbornio 's answer worked for me, however ease-in-out didn't work perfectly at first. When applied to the 'img' the ease effect only worked intermittently. I found that in order for the effect to work everytime, I had to apply the ease-in to the 'img' and the ease-out to the 'hover'. I'm not sure why this was happening but that's a solution if anyone runs into the same issue.

CSS3 - Transition on DOM Removal

Using keyframes, it is possible to animate an element as soon as it is inserted into the DOM. Here's some sample CSS:
#-moz-keyframes fadeIn {
from {opacity:0;}
to {opacity:1;}
}
#-webkit-keyframes fadeIn {
from {opacity:0;}
to {opacity:1;}
}
#keyframes fadeIn {
from {opacity:0;}
to {opacity:1;}
}
#box {
-webkit-animation: fadeIn 500ms;
-moz-animation: fadeIn 500ms;
animation: fadeIn 500ms;
}
Is there some similar functionality available to apply an animation (via CSS, no JavaScript) to an element right before it is removed from the DOM? Below is a jsFiddle I made to play around with this idea; feel free to fork it if you know of a solution.
jsFiddle - http://jsfiddle.net/skoshy/dLdFZ/
Create another CSS animation called fadeOut, say. Then when you want to remove the element, change the animation property on the element to that new animation, and use the animationend event to trigger the actual removal of the element once the animation is done:
$('.hide').click(function() {
if (!$(this).hasClass('disabled')) {
$('#fill').css('-webkit-animation', 'fadeOut 500ms');
$('#fill').bind('webkitAnimationEnd',function(){
$('#fill').remove();
$('.show, .hide').toggleClass('disabled');
});
}
});
See also my updated version of your jsFiddle. That works for me in Safari, at least.
Well, you should be using a class instead of that .css().
I don't think jQuery has any "real" support for CSS animations yet, so I don't think you can get rid of that webkitAnimationEnd. In Firefox it's just called animationend.
I'm pretty sure there's no way to do this in just CSS.
I've been working on a component library for javascript and I ran into this problem myself. I have the benefit of being able to throw a ton of javascript at the problem, but since you're already using a bit, consider the following for a gracefully degrading solution:
On removal of any component/dom node, add a class called 'removing'.
Then in the css you can define your animation using that class:
.someElement.removing {
-webkit-animation: fadeOut 500ms;
-moz-animation: fadeOut 500ms;
animation: fadeOut 500ms;
}
And back in the javascript, just after you add the 'removing' class, you should be able to check for the 'animation' css property, and if it exists, then you know that you can hook on 'animationEnd' and if it doesn't, then just remove the element right away. I remember testing this a while back, it should work; I'll see if I can dig up the example code.
Update:
I've dug up this technique and started writing a really cool plugin for jQuery that allows you to use CSS3 animations for DOM elements that are being removed. No additional Javascript required: http://www.github.com/arthur5005/jquery.motionnotion
It's very experimental, use at your own risk, but would love some help and feedback. :)
ideally for something like fadeIN and fadeOUT you should be using css transitions not css animations..

Gtk Spinner Not Appearing

I'm trying to get a Gtk::Spinner object to display while calculations are in progress but nothing appears to be happening. The snippet of code looks like...
{
Gtk::Spinner spinner;
spinner.start ();
// do some work...
spinner.stop ();
}
I'd have thought the spinner needed to know which dialogue it appears over but I can't see any way of feeding that into the object. Does anyone know where I could find a worked example? I can find the Gtk documentation in many places, but that isn't helping much.
In short, here is a quick checklist if Gtk::Spinner is not appearing on screen:
Make sure librsvg is installed.
Check if your currently active Gtk theme has an image file with base name "process-working-symbolic" (e.g. /path/to/your/theme/icons/scalable-up-to-32/status/process-working-symbolic.svg).
In your app code: Make sure you added the spinner object to some parent widget / container: vbox.pack_start(spinner, Gtk::PACK_SHRINK);
In your app code: Ensure all widgets are actually made visible: show_all_children();
In your app code: Finally you need to call spinner.start() for the widget to actually appear and spin on screen.
In detail:
The actual Gtk spinner widget code (see function gtk_spinner_class_init() in gtkspinner.c) is not doing any drawing on its own. In fact its code is very little. All it does is adding CSS code to the gtk widget:
it assigns the CSS class "spinner" to the widget
and it automatically adds and removes the CSS pseudo-class "checked" whenever the widget's boolean gtk property "active" changes.
So the actual look (icon) and the animation is defined by your current theme's CSS file. E.g. in Gtk's default theme's gtk-contained.css file you find the following:
spinner {
background: none;
opacity: 0;
-gtk-icon-source: -gtk-icontheme("process-working-symbolic");
};
Which means it will automatically search for an appropriate image file with base name "process-working-symbolic" in the theme's "icons" directory tree. And the actual spinning animation is defined in the same CSS file by this:
spinner:checked {
opacity: 1;
animation: spin 1s linear infinite;
};
In most other themes these CSS code portions for the spinner widget are pretty much identical.
Now here is a common problem with this: in most themes the spinner image is an SVG file (e.g. typically "process-working-symbolic.svg"), but the stock Gdk pixbuf loaders do not support the SVG format at all. They support a variety of other image file formats, but for actually allowing Gdk/Gtk to load .svg files you need to install a third-party pixbuf loader capable to do so like librsvg.
Alternative:
In case you cannot or don't want to bother to install an SVG capable Gdk pixbuf loader like librsvg, then you can also simply add image file(s) with the same base name, but in another file format like "process-working-symbolic.png" to your theme's icons directory tree. So either draw or download some spinner picture then scale it and place them several times to the resolutions listed in your theme's "icons" directory, e.g.:
/THEMEDIR/icons/8x8/status/process-working-symbolic.png
/THEMEDIR/icons/16x16/status/process-working-symbolic.png
/THEMEDIR/icons/22x22/status/process-working-symbolic.png
/THEMEDIR/icons/24x24/status/process-working-symbolic.png
/THEMEDIR/icons/32x32/status/process-working-symbolic.png
/THEMEDIR/icons/64x64/status/process-working-symbolic.png
/THEMEDIR/icons/256x256/status/process-working-symbolic.png
/THEMEDIR/icons/512x512/status/process-working-symbolic.png
Also you should know: Whenever you do spinner.start() the spinner icon immediately appears on screen, but even on a decent machine it typically takes almost a second before the spinner starts its animation.
Did you call
spinner.show ();
and add it to some window?
Moreover, your calculations may block the UI, so it is not updated. Call
while (Gtk::Main::events_pending ())
Gtk::Main::iteration ();
once in a while.
To change the mouse cursor to "busy" you can do the following:
Glib::RefPtr<Gdk::Window> window = dialog.get_window();
if(window) {
window->set_cursor(Gdk::Cursor(Gdk::WATCH));
Gdk::flush();
}
To change it back, do
window->set_cursor();
instead.
Disclaimer: I usually work with GTK in C, and have translated this on the fly...

Safari on the iPhone & iPad gives colour feedback on touch, I want to stop this

Clicking on an element which has a Javascript handler makes the element go have a 'grey overlay'. This is normally fine but I'm using event delegation to handle the touchdown events of many child elements. Because of the delegation the 'grey overlay' is appearing over the parent element and looks bad and confusing.
I could attach event handlers to the individual elements to avoid the problem but this would be computationally very wasteful. I'd rather have some webkit css property that I can override to turn it off. I already have visual feedback in my app so the 'grey overlay' is not needed.
Any ideas?
-webkit-tap-highlight-color
To disable tap highlighting, set the
alpha value to 0 (invisible)
$('body').bind('touchstart', function(e){
e.preventDefault()
})
For those reading this question, another CSS property which will not only remove the overlay but also prevent the touch device from interacting with the user to assess a tap intention (which delays the timing of the event trigger significantly), is to use the cursor property.
a.notTappable {
cursor:default
}
Also, in the case the asker described where you have descendants of a parent and you only want the descendants to be tappable and you wish to IGNORE ALL MOUSE EVENTS OF THE PARENT, the following solution will you give you the best performance (by completely disabling the bubbling up to the parent). Read the webkit spec here.
.parent {
pointer-events:none;
}
.parent .descendant {
pointer-events:default;
}
I only mention this because the performance difference here is significant.