I am creating a Polyline component using two positions with Typescript based on the react-leaflet. I want to make an animation from the source to the destination. It should look like something is flowing between source to destination. I'm able to set the animation with CSS Animation however, I have the issue that the transition between the last color( yellow at 100%) and return to the initial position (blue at 0%) is happening very abruptly, not smooth like other changes in between. I want these last changes also smooth like others so that it looks like a continuous flow. Here is my code,
React-leaflet Polyline
<Polyline
key={eachConnection.id}
weight={4}
className="water-flow"
positions={[[source.lat, source.long],[target.lat, target.long]]}
/>
CSS for the Polyline
.water-flow{
stroke: lime;
stroke-width: 3;
animation: 3s ease infinite Anim;
}
#keyframes Anim {
0%{
stroke : blue;
}
2%{
stroke: green;
}
50%{
stroke: red;
}
98%{
stroke: cyan;
}
100%{
stroke: yellow;
}
}
Recently I used React Leaflet Drift Marker https://github.com/hugobarragon/react-leaflet-drift-marker (for animating the marker) combined with Polyline https://react-leaflet.js.org/docs/example-vector-layers/ component (for showing the trail) but the effort is not simple
I found a great Leaflet library that combined animation marker and trail here https://github.com/Igor-Vladyka/leaflet.motion
Here is the demo https://igor-vladyka.github.io/leaflet.motion/
Currently, I only found the library using Vanilla Js (we could use it for any frontend framework like React Js, Vue Js, and Angular Js) but hope that in the near future the library would be available directly for each framework
Related
I want to create a smooth transition between 2 images with a legend.
The images come from an object-array of images.
Because works only on single tags and components, I've created a component to define the image+legend.
<transition>
<home-image :slide="slide" :key="slide"></home-image>
</transition>
The classes I define are like this
.v-enter-active,
.v-leave-active {
transition: opacity 2s ease-in-out;
}
.v-leave,
.v-enter-to {
opacity: 1;
}
.v-enter,
.v-leave-to {
opacity: 0;
}
The new image is returned by a method
updateSlide() {
this.slide = this.entries[ Math.floor( Math.random() * this.entries.length ) ];
}
where entries is my array defined in data
this.slide is updated in regular intervals, every 10seconds like this, which is defined in the created() section
this.updateSlide();
this.uSlide = setInterval( this.updateSlide, 10000);
The code works, in the sense that a new image is loaded in this.slide every 10 seconds.
However, the transitions work only "half-way".
There is no transition fading out: the "old image" disappears and makes way for the new image fading in.
However, what I'd like is a smooth transition from one to the other.
I've tried more than a couple of ideas including using mode="out-in" and "in-out" but nothing works as I want.
What am I overlooking?
I have added Angular universal to my app and followed the guide on https://angular.io/guide/universal
It was realy simple, I'm just struggling with this Error:
ERROR Error: Unable to build the animation due to the following errors: The provided animation property "transform" is not a supported CSS property for animations
The provided animation property "transform" is not a supported CSS property for animations
The reason for this is a simple Button with a keyframe animation which uses transform: rotate(0deg);
The button is round and rolls from the right to the left side after loading.
Is there any workaround to solve this issue? I'm sure that transform is quite a valid CSS property for animations.
Edit:
I use the transform Property inside of a components scss file. The content is static and the component shows a whole site. The css code is this:
.roll-in { animation: 2s linear 0s 1 animation;
animation-fill-mode: both;
}
#keyframes animation {
0% {
left: 110%;
}
10% {
transform: rotate(0deg);
left: 110%;
}
100% {
transform: rotate(-720deg);
left: 0px;
}
}
After running the app with serve:ssr the element has no animation attribute.
I think, it happens when the animation starts on server side rendering itself. Since this is SSR, there is no meaning of loading the animations on server version.
Load the animations only in Browser platform version. So, animations will start only after the page rendered in browser view. For example,
component.ts
import { Component, Inject } from '#angular/core';
import { PLATFORM_ID } from '#angular/core';
import { isPlatformBrowser } from '#angular/common';
#Component({
selector: 'my-animated-component',
templateUrl: './my-animated-component.html'
})
export class MyAnimatedComponent{
isBrowser: boolean;
constructor( #Inject(PLATFORM_ID) platformId: Object) {
this.isBrowser = isPlatformBrowser(platformId);
}
}
In markup
<div *ngIf="isBrowser">
<my-animated-component></my-animated-component>
</div>
It's recommended to use Angular native animations rather than CSS animations. A working example is here: https://stackblitz.com/edit/angular-animate-keyframes
Below is a minimum mockup of a bug that I'm experiencing in Safari.
Expected behaviour: The code is supposed to display a placeholder while another image loads and then fade-in that image while removing the placeholder.
placeholder -> fading in loaded image
Actual behaviour:
Works as expected in Chrome and Mozilla but fails in Safari, resulting in the following effect:
placeholder -> white screen -> loaded image
Can somebody help me figure out why this is happening in Safari please? (try running below example in chrome or mozilla vs safari to see for your self.)
const image = new Image();
image.onload = () => {
document.getElementById('placeholder').remove();
const el = document.createElement('img');
el.setAttribute('src', 'http://deelay.me/1000/https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_1280.jpg');
el.setAttribute('width', '150');
el.setAttribute('height', '150');
el.style = `
animation-name: testAnimation;
animation-duration: 0.3s;
animation-iteration-count: 1;
animation-timing-function: ease-in;
background: red;
`;
document.body.appendChild(el);
}
image.src = 'http://deelay.me/1000/https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_1280.jpg';
#placeholder {
background: #eee;
}
#-webkit-keyframes testAnimation {
0% {
opacity: 0.25;
}
50% {
opacity: 0.5;
}
100% {
opacity: 1;
}
}
<img id="placeholder" src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' width%3D'200' height%3D'300' viewBox%3D'0 0 200 300'%2F%3E" width="150" height="150">
(
Another weird behaviour is that if animation-duration gets increased to around 3-4 seconds then the image does fade-in but the white screen is still there, i.e.
placeholder -> white screen -> fading in loaded image
)
update:
After playing around with img’s background color it seems like in Safari the animation begins taking effect around 1s before the image even begins getting rendered to the screen.
hence the white flick if the real image doesn't have a background color like the placeholder image does and hence why after adding a background color to the real image that background color becomes visible around 1 sec earlier before the image even starts displaying
and hence the fade effect starting to take place around 1 sec earlier before the image even starts displaying
Whereas in Chrome and Mozilla the animation appears to be perfectly in sync with the image.
Run updated code to see for yourself
(it also only seems to happen with <img>, I've tested it with some other elements (still inside of image.onload) and they work as expected.)
update 2: See the fix in the answer below together with an explanation
This was fixed by adding another onload event this time on the image element rather than on the explicit Image object and putting the image.onload listener inside of it.
Which seems to suggest that in Safari, animation and styles are applied as soon as the <img> is added to the DOM - before it is fully loaded (its onload event called.)
This can be tested by giving the <img> a background color and seeing it show up together with the animation as soon as the element is added to the DOM and seeing that it takes an extra second until the image itself becomes visible
You can also see the same effect happen without using any animation at all just by giving the <img> a background color
(a bug in Safari? My Safari version: Version 11.0.2 (13604.4.7.1.3))
Edit: Actually the problem seems to be caused by caching, Safari doesn't seem to cache the pre-loaded proxied image while other browsers do cache it. Safari seems to fire another request for that image when it gets rendered to the screen - hence the styles being visible prior to seeing the actual image since the image is still being downloaded.
Edit 2: Upon further investigation it seems like Safari is actually the only one out of those 3 browsers that is behaving as expected - this is because the image's HTTP response contains a Cache-Control: no-cache, must-revalidate header explicitly instructing the browser to not cache the image.
const image = new Image();
const el = document.createElement('img');
el.setAttribute('src', 'http://deelay.me/500/https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_1280.jpg');
el.setAttribute('width', '150');
el.setAttribute('height', '150');
el.style = `
animation-name: testAnimation;
animation-duration: 1s;
animation-iteration-count: 1;
animation-timing-function: ease-in;
background-color: red;
`;
el.onload = () => {
image.onload = () => {
document.getElementById('placeholder').remove();
document.body.appendChild(el);
}
}
image.src = 'http://deelay.me/500/https://cdn.pixabay.com/photo/2014/06/03/19/38/board-361516_1280.jpg';
#placeholder {
background: #eee;
}
#-webkit-keyframes testAnimation {
0% {
opacity: 0.25;
}
50% {
opacity: 0.5;
}
100% {
opacity: 1;
}
}
<img id="placeholder" src="data:image/svg+xml;charset=utf-8,%3Csvg xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' width%3D'200' height%3D'300' viewBox%3D'0 0 200 300'%2F%3E" width="150" height="150">
This appears to be related to the specific server/image you are using. I tried changing just the image URL (to something on wikimedia.org, just for testing purposes), and the animation began working as expected in Safari 11.0.2 (13604.4.7.1.6).
Pre-loading the image may help... or even better (all of this assuming you have proper usage rights, of course), you can try copying the image to your web server so it can be loaded locally. Essentially, you're just remedying the fact that Safari has finished running the animation by the time it can load the image from the remote server. You could also try using window.onload instead of image.onload, to force all external resources to be loaded before it runs.
I've used two keyframe animations in CSS. One moves from left to right and the other one uses exact the same values - but reversed.
#keyframes moveLeft
{
from {transform: translate3d(50px, 0, 0);}
to {transform: translate3d(0px, 0, 0);}
}
#keyframes moveRight
{
from {transform: translate3d(0px, 0, 0);}
to {transform: translate3d(50px, 0, 0);}
}
However, I wonder whether it's possible to use one keyframe animation only. but as soon as I add animation-direction: reverse, the animation does only play once. It probably saves the information that it has been used once before.
So: can I reset this information somehow? Or is there any possibility to use one animation twice in different directions? (without using JS)
http://jsfiddle.net/vrhfd66x/
No, there is no way to restart the animation using CSS alone. You'd have to use JavaScript to remove the animation from the element and then re-apply it to the element (after a delay) for it to restart.
The below is what the W3C's CSS3 Animation Spec says (in a different context, but the point should hold good for this case also):
Note also that changing the value of ‘animation-name’ does not necessarily restart an animation (e.g., if a list of animations are applied and one is removed from the list, only that animation will stop; The other animations will continue). In order to restart an animation, it must be removed then reapplied.
emphasis is mine
This CSS Tricks Article by Chris Coiyer also indicates the same and provides some JS solutions for restarting an animation. (Note: The article has a reference to Oli's dabblet which claims that altering properties like duration, iteration count makes it restart on Webkit but it seems to be outdated as they no longer work on Chrome).
Summary:
While you have already touched upon the following, I am going to re-iterate for completeness sake:
Once an animation is applied on the element, it remains on the element until it is removed.
UA does keep track of the animation being on the element and whether it has completed or not.
When you apply the same animation on :checked (albeit with a different direction), the UA does nothing because the animation already exists on the element.
The switch of positions (instantaneous) while clicking the checkbox is because of the transform that is applied within the :checked selector. The animation's presence makes no difference.
Solutions:
As you can see from the below snippet, achieving this with a single animation is pretty complex even when using JavaScript.
var input = document.getElementsByClassName("my-checkbox")[0];
input.addEventListener('click', function() {
if (this.checked) {
this.classList.remove('my-checkbox');
window.setTimeout(function() {
input.classList.add('anim');
input.classList.add('checked');
}, 10);
} else {
this.classList.remove('anim');
window.setTimeout(function() {
input.classList.remove('checked');
input.classList.add('my-checkbox');
}, 10);
}
});
input {
transform: translate3d(50px, 0, 0);
}
.my-checkbox {
animation: moveLeft 1s;
animation-direction: reverse;
}
.checked {
transform: translate3d(0px, 0, 0);
}
.anim{
animation: moveLeft 1s;
}
#keyframes moveLeft {
from {
transform: translate3d(50px, 0, 0);
}
to {
transform: translate3d(0px, 0, 0);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<input type="checkbox" class="my-checkbox">
So, the best option (if you want to stick to CSS animations) is to use two different animations.
Alternately, you could also have a look at Marcelo's comment. If the actual use-case is exactly what is provided in the fiddle then transition would suffice and animation isn't required. Transitions can work both in forward and reverse directions by nature and hence would be a safer bet.
The site where I want my animation to work adds #user-space before any of my tags. So, my animation looks like this:
#user-space #-webkit-keyframes animation-name {
from {
style definition ["Before"-state]
}
to {
style definition ["After"-state]
}
And that #user-space declaration is breaking the css statement and animation is not working. Is there any way, to do that otherwise? For exaple put my keyframes insine -webkit-animation: animation-name 1.1s ease infinite; like
webkit-animation: from {
style definition ["Before"-state]
}
to {
style definition ["After"-state]
} 1.1s ease infinite; like
The solution I see is to get around your problem and do it with javascript.
Simply add a new style in your html file (in the header) and add the #-webkit-keyframes animation inside.
There is a thread which explains it well (see accepted solution): Set the webkit-keyframes from/to parameter with JavaScript