How to make this text fill animation in flutter - html

I want to make a flutter timer app which will fill the screen from bottom to top with a color. I think i can do that by incrementing the size of the container with respect to time but i want the text as shown in the image. Please someone help me with this.
It changes the color of the text as the size of the container, which fills the screen, increases.

I can offer a solution for css. The timer counter will be displayed with rule content: '', with a cycle of 10 seconds and a delay of 1 second before this animation starts.
.timer:after {
content: "0";
animation: timer 10s 1s forwards;
}
The complete css code shows how 10 seconds are distributed over a percentage of 100%.
#keyframes timer {
10% {
content: "1";
}
...
100% {
content: "10";
}
}
I used rule mix-blend-mode: difference to invert the background color.
The mix-blend-mode CSS property sets how an element's content should blend with the content of the element's parent and the element's background.
I changed the height of the dynamic background element using rule top, and animated it in a similar way using rule animation and #keyframes.
#keyframes background_top {
from {
top: 100%;
}
to {
top: 0%;
}
}
The #keyframes rule sets keyframes when animating an element. A keyframe is an element's properties (transparency, color, position, etc.) that should be applied to an element at a given moment in time. Thus, animation is a smooth transition of style properties from one keyframe to another. The calculation of intermediate values between such frames is taken over by the browser.
body {
margin: 0;
}
.wrapper {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: lightgrey;
position: relative;
}
.background {
position: absolute;
left: 0;
right: 0;
bottom: 0;
background: brown;
mix-blend-mode: difference;
animation: background_top 10s 1s forwards;
}
.timer:after {
content: "0";
animation: timer 10s 1s forwards;
font-size: 10em;
color: lightseagreen;
}
#keyframes timer {
10% {
content: "1";
}
20% {
content: "2";
}
30% {
content: "3";
}
40% {
content: "4";
}
50% {
content: "5";
}
60% {
content: "6";
}
70% {
content: "7";
}
80% {
content: "8";
}
90% {
content: "9";
}
100% {
content: "10";
}
}
#keyframes background_top {
from {
top: 100%;
}
to {
top: 0%;
}
}
<div class="wrapper">
<div class="timer"></div>
<div class="background"></div>
</div>

There is a simple way of doing this in flutter with CustomPaint.
The only thing you have to change is the StatelessWidget to a StatefulWidget so that the animation is possible, however I would recommend using something like hooks this package can make animation pretty simple.
class TextWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: CustomPaint(
size: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height),
painter: TimerPainter(text: "6", height: 500),
));
}
}
class TimerPainter extends CustomPainter {
TimerPainter({required this.text, required this.height});
final String text;
final double height;
#override
void paint(Canvas canvas, Size size) {
// ========================================== TextPainter
final TextPainter textPainter = TextPainter(
textDirection: TextDirection.ltr,
text: TextSpan(
text: text,
style: TextStyle(
color: Colors.greenAccent,
fontSize: 500,
),
))
..layout();
textPainter.paint(
canvas,
Offset(size.width / 2 - textPainter.width / 2,
size.height / 2 - textPainter.height / 2));
// ============================================== Rect
final rectPaint = Paint()
..color = Colors.greenAccent
..blendMode=BlendMode.difference;
canvas.drawRect(
Offset(0, size.height / 2) & Size(size.width, height), rectPaint);
final rectPaint2 = Paint()
..color = Colors.white
..blendMode=BlendMode.difference;
canvas.drawRect(
Offset(0, size.height / 2) & Size(size.width, height), rectPaint2);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
this is how it looks

Related

How do I decrease load time for generating around 1000 divs?

I'm working on my portfolio website so, I was trying some animation for the landing page. Everything is working fine but the animation takes very long time to load. I was generating a matrix of divs using JS and appling CSS and animation to each one of them. Please suggest something to decrease the load time.
My Website
Javascript
let holder = document.getElementById("hero");
let gs = 25;
window.onload = () => {
for (let i = 0; i < gs; i++) {
for (let j = 0; j < gs; j++) {
let dot = document.createElement("div");
dot.classList.add("dot");
dot.style.animationDelay = `${Math.sin(i * j) / 2}s`;
holder.appendChild(dot);
}
}
};
CSS
.hero {
/* background-image: url(media/Background.jpg); */
height: 100vh;
position: absolute;
width: 100%;
display: grid;
grid-template-columns: repeat(50, 90px);
grid-template-rows: repeat(50, 90px);
overflow: hidden;
text-align: left;
}
.dot {
width: 2px;
height: 2px;
animation-name: wavyDots;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-direction: alternate-reverse;
z-index: -1;
}
.dot:nth-child(odd) {
background-color: #0cf5d5;
}
.dot:nth-child(even) {
background-color: #e0017a;
}
#keyframes wavyDots {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(30px, 30px);
}
}
I tried decreasing the matrix size but didn't help much, if I decrease more then I don't have enough divs to cover my entire page.

Remove/Hide div from DOM after animation completes using CSS?

I have an animation where a div slides out the view, however when the animation is completed, the div just returns to its origin position in the view. How do I totally remove the div or hide it after the animation ends using just CSS?
Here is the markup:
<div class="container">
<div class="slide-box" id="slide-box""></div>
</div>
and the css:
.slide-box {
position: relative;
width: 100px;
height: 100px;
background-image: url(../pics/red.png);
background-position: center;
background-size: cover;
background-repeat: no-repeat;
animation: slide 5s linear 1;
}
#keyframes slide {
0% {
left: 0;
}
20% {
left: 20%;
}
40% {
left: 40%;
}
60% {
left: 60%;
}
80% {
left: 80%;
}
100% {
left: 100%;
overflow: hidden;
visibility: hidden;
}
}
I don't want it to fade out over the duration of the animation, i just want it to disappear once it hits 100% in the keyframe. Thanks ahead of time!
Use the animation-fill-mode option. Set it to forwards and the animation ends at it's final state and stay like that.
Altered based upon comments Set opacity fade to just last 1% of animation... simplified keyframes. Added a jquery option to literally remove the div from the DOM. CSS alone won't alter the markup, where jQuery will.
Although you can't animate the display property. If you want the div totally gone, after the opacity fades to zero, you can then add the display property to remove the div. If you don't wait for opacity to end, the div will just vanish without any transition.
/*
This jquery is added to really remove
the div. But it'll essentially be
VISUALLY gone at the end of the
animation. You can not use, or
delete the jquery, and you really
won't see any difference unless
you inspect the DOM after the animation.
This function is bound to animation
and will fire when animation ends.
No need to "guess" at timeout settings.
This REMOVES the div opposed to merely
setting it's style to display: none;
*/
$('.slide-box').bind('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function(e) { $(this).remove(); });
.slide-box {
display: block;
position: relative;
left: 0%;
opacity: 1;
width: 100px;
height: 100px;
background: #a00;
animation: slide 1s 1 linear forwards;
/*
animation-name: slide;
animation-duration: 1s;
animation-iteration-count: 1;
animation-timing-function: linear;
animation-fill-mode: forwards;
*/
}
#keyframes slide {
0% {
left: 0%;
opacity: 1;
}
99% {
left: 99%;
opacity: 1;
}
100% {
left: 100%;
opacity: 0;
display: none;
}
}
#-webkit-keyframes slide {
0% {
left: 0%;
opacity: 1;
}
99% {
left: 99%;
opacity: 1;
}
100% {
left: 100%;
opacity: 0;
display: none;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="slide-box" id="slide-box"></div>
</div>
animation: slide 5s linear forwards;
at 100%
opacity: 0;
display: none;
Try this.
Working fiddle: https://jsfiddle.net/jbtfdjyy/1/
UPDATE: JS mani
var slideBox = document.getElementById('slide-box');
setTimeout(function(){
slideBox.style.display = 'none';
}, 5000);
Try this. https://jsfiddle.net/jbtfdjyy/2/
Add something at 99% or so to your keyframes, and set opacity to 1 in that. If you have opacity: 1 at the start, then it will stay that way until 99%. Only at 100% will it change.
It's not technically fired at 100%. If you want that, I'd recommend using some JavaScript here, but this will at least give the illusion you want.
#keyframes slide {
0% {
left: 0;
}
20% {
left: 20%;
}
40% {
left: 40%;
}
60% {
left: 60%;
}
80% {
left: 80%;
}
99% {
opacity: 1;
}
100% {
left: 100%;
overflow: hidden;
opacity: 0;
display: none;
visibility: hidden;
}
}
UPDATE:
As per your request, here is a JavaScript version. Keep in mind, there are endless ways to accomplish such a task. I am using vanilla JS (no jQuery, etc.), and using ES6 syntax.
What we do here is set a timeout, and at the end of that timeout I broadcast an event animation_end. That event listener will handle the end of the animation (in this case, it adds a class which will handle the fading out). This is much more granular than you need it to be, you could simply do the adding of the class within the setTimeout, but I think it is slightly better this way as you can abstract you can do other things with events such as animation start, etc.
Here is the fiddle: https://jsfiddle.net/vmyzyd6p/
HTML:
<div class="container">
<div class="slide-box" id="slide-box""></div>
</div>
CSS:
.slide-box {
position: relative;
width: 100px;
height: 100px;
background-color: blue;
animation: slide 3s linear 1;
-webkit-transition: opacity 2s ease-in-out;
-moz-transition: opacity 2s ease-in-out;
transition: opacity 2s ease-in-out;
}
.animationEnd {
opacity: 0;
}
#keyframes slide {
0% {
left: 0;
}
20% {
left: 20%;
}
40% {
left: 40%;
}
60% {
left: 60%;
}
80% {
left: 80%;
}
100% {
left: 100%;
}
}
JavaScript:
// Create a function that handles the `animation_end` event
const animationEnd = () => {
// Grab the slidebox element
let slideBox = document.getElementById('slide-box');
// Get the class of the slidebox element
let slideClass = slideBox.getAttribute('class');
// Add the animation end class appended to the previous class
slideBox.setAttribute('class', slideClass + ' animationEnd');
};
// Create the animation end event
let animationEndEvent = new Event('animation_end');
// Cross browser implementation of adding the event listener
if (document.addEventListener) {
document.addEventListener('animation_end', animationEnd, false);
} else {
document.attachEvent('animation_end', animationEnd);
}
// Set the timeout with the same duration as the animation.
setTimeout(() => {
// Broadcast the animation end event
document.dispatchEvent(animationEndEvent);
}, 3000);

Css animation random delay

I'm trying to build a webpage for a comic studio and I want one of the characters to come in from the side every so often. So far I have this in the css
.charc {
animation:peek 20s infinite;
left:-500px
}
#-webkit-keyframes peek{
1% {transform:translateX(-500px)}
10%{transform:translateX(100px)}
20% {transform:translateX(-200px)}
100% {transform:translateX(-500px)}
}
and the html
<img src="character.jpg" class="charc"/>
This means the character comes on over and over again. I don't know whether it is possible to get random figures in CSS but I thought if it is, You guys would know
p.s. I know this will only work in chrome but I will be changing that soon.
You need to use js/jQuery for that.
function move() {
$('.charc')
.animate({
left: '-500px'
}, 200)
.animate({
left: '100px'
}, 400)
.animate({
left: '50px'
}, 400)
.animate({
left: '-500px'
}, 100, function() {
var nextIn = Math.floor(Math.random() * 1000);
setTimeout('move()', nextIn);
})
}
$(document).ready(function() {
move();
});
#scene {
width: 500px;
height: 100px;
border: 2px solid black;
margin: 20px;
}
.charc {
position: absolute;
left: -500px;
top: 20px;
width: 20px;
height: 20px;
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="scene">
<div class="charc"></div>
</div>
It is possible with js :
var divElement = document.getElementsByClassName("charc")[0];
var maxValue = 20; //the random value won't exceed 20s
function randomTime(maxvalue){
return Math.round(Math.random() * maxvalue );
}
function changeAnimationTime(maxValue){
var random = randomTime(maxValue);
divElement.style.animation = "peek "+randomTime+"s infinite";
setTimeout(function(){
changeAnimationTime(maxValue);
},random);
}
changeAnimationTime(maxValue);
The advantage of this methode is that you won't use js for animation but just for generating values. So it consumes less ressources.
Not a random delay but you can use a tool I created called WAIT! Animate to add a pause between animations. Here's your animation with a 2 second pause between animations:
.peek.wait2.animated {
animation: peek-wait2 22s linear infinite;
transform-origin: 50% 50%
}
#keyframes peek-wait2 {
0% { transform:translateX(-500px) }
9.09091% { transform:translateX(100px) }
18.18182% { transform:translateX(-200px) }
90.90909% { transform:translateX(-500px) }
100% { transform:translateX(-500px) }
}
Use WAIT! Animate to change the pause duration.
PS. I suggest starting at 0% to avoid a flicker in the animation.

CSS Animation won't apply for the second time

I am currently having a problem with CSS animations. A random background is called from an array, shows up and changes and so on. I applied two animation for the image caption id, a slide in and a delayed slide out. The slide in and out runs well for the first time, but when the second background shows up, the caption just appears to the screen without any animation.
This is my test page and below is my code.
HTML code:
<script type="text/javascript">
function loadRandomImage(imgs) {
var index = Math.floor(Math.random() * imgs.length);
console.log("loadRandomImages(): index = "+ index);
$.backstretch(imgs[index].url, {duration: 30000, fade: 1200});
$("#caption").html(imgs[index].caption);
}
var images = new Array(); //array of imgs objects
images[0] = {url: "https://s-media-cache-ak0.pinimg.com/736x/a5/47/45/a5474577f4a4ae93c85db719d0cbafd4.jpg", caption: "Caption0"};
images[1] = {url: "https://s-media-cache-ak0.pinimg.com/736x/e6/41/74/e64174e355f78a0f07e951bcec62ca96.jpg", caption: "Caption1"};
images[2] = {url: "https://media.giphy.com/media/3o7abHrsGbV10rCeze/giphy.gif", caption:"Caption2"};
images[3] = {url: "https://media.giphy.com/media/Bbt5FxRiArl3a/giphy.gif", caption:"Caption3"};
// Preload
setTimeout(loadRandomImage, 1000, images);
// Change images every 3 seconds
setInterval(loadRandomImage, 30000, images);
</script>
<div id="pattern"></div>
<div id="pattern2"></div>
<div id="caption"></div>
CSS code:
#caption {
position: relative;
font: 1.5em Trebuchet, sans-serif;
text-align: center;
margin-left: 75%;
z-index: 56;
color: #ffffff;
background: rgba(0, 0, 0, 0.7);
padding: 8px;
animation: slidein 3s, slideout 3s 27s;
}
#caption:empty
{
display: none;
}
#keyframes slidein {
0% {
margin-left: 100%;
width:100%;
visibility:hidden;
opacity: 0;
}
100% {
margin-left: 75%;
width:100%;
opacity: 1;
visibility:visible;
}
}
#keyframes slideout {
0% {
margin-left: 75%;
width:100%;
opacity: 1;
visibility:visible;
}
100% {
margin-left: 100%;
width:100%;
opacity:0;
visibility:hidden;
}
}
CSS animations have iteration count (animation-iteration-count) as only 1 when no value is given for that property. Here since you've not specified any value, the animation executes only once (that is on page load). There is no pure CSS way to re-trigger an animation once it has completed its cycle. It has to be removed from the element and then re-attached for it to start all over again.
So, for your case here is what you have to do - (a) Set the animations on #caption using JS on page load as it makes it easier to remove and re-add them (b) Upon completion of the slideout animation, remove both the animations from the element (that is, set animation-name: none) and also set html of #caption to none because :empty selector would only then hide it. (c) As soon as the next image is set on the element (using loadRandomImage function), set the animations back on the element. This would re-trigger the animation and so during each image switch, the caption would slide-in and out.
Note: I've changed some parts in the HTML and JS that are not relevant to this answer (like removing the two div and replacing them with 1, avoiding the $.backstretch and loading image using css() etc. But these are only auxiliary items and will not affect the crux of this answer (which is, to remove and add the animations).
function loadRandomImage(imgs) {
var index = Math.floor(Math.random() * imgs.length);
$('#img').css('background-image', 'url(' + images[index].url + ')');
$('#caption').css({
'animation-name': 'slidein, slideout',
'animation-duration': '3s, 3s',
'animation-delay': '0s, 7s'
});
$("#caption").html(imgs[index].caption);
}
var images = new Array(); //array of imgs objects
images[0] = {
url: "http://lorempixel.com/100/100/nature/1",
caption: "Caption0"
};
images[1] = {
url: "http://lorempixel.com/100/100/nature/2",
caption: "Caption1"
};
images[2] = {
url: "http://lorempixel.com/100/100/nature/3",
caption: "Caption2"
};
images[3] = {
url: "http://lorempixel.com/100/100/nature/4",
caption: "Caption3"
};
// Preload
setTimeout(loadRandomImage, 1000, images);
$('#caption').on('animationend', function(e) {
if (e.originalEvent.animationName == 'slideout') {
$('#caption').css('animation-name', 'none');
$('#caption').html('');
setTimeout(function() { /* dummy timeout to make sure browser sees animation as none before adding it again */
loadRandomImage(images);
}, 0);
}
});
#caption {
position: relative;
font: 1.5em Trebuchet, sans-serif;
text-align: center;
margin-left: 75%;
z-index: 56;
color: #ffffff;
background: rgba(0, 0, 0, 0.7);
padding: 8px;
}
#caption:empty {
display: none;
}
#keyframes slidein {
0% {
margin-left: 100%;
width: 100%;
visibility: hidden;
opacity: 0;
}
100% {
margin-left: 75%;
width: 100%;
opacity: 1;
visibility: visible;
}
}
#keyframes slideout {
0% {
margin-left: 75%;
width: 100%;
opacity: 1;
visibility: visible;
}
100% {
margin-left: 100%;
width: 100%;
opacity: 0;
visibility: hidden;
}
}
/* Just for demo */
#img {
height: 100px;
width: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="img"></div>
<div id="caption"></div>
The animationend event still requires vendor prefixes in some browsers.
You need to use a callback, which is explained here:
How do create perpetual animation without freezing?
I think the animation direction needs to be altered.
These are the possibilities:
animation-direction: normal|reverse|alternate|alternate-reverse|initial|inherit;
I think you need to do one of these:
alternate
The animation will be played as normal every odd time (1,3,5,etc..) and in reverse direction every even time (2,4,6,etc...)
alternate-reverse
The animation will be played in reverse direction every odd time (1,3,5,etc..) and in a normal direction every even time (2,4,6,etc...)
At the moment it is set as
animation-direction: initial, initial;
Seen here: http://www.w3schools.com/cssref/css3_pr_animation-direction.asp
Rather than the Javascript suggestions already provided, you could do a straight CSS solution.
Just set animation-iteration-count to "infinite" (to continuously alternate the 2 elements, or an integer for a set number of repeats)
If you want staggered / alternating animations:
Use an animation-delay (matching the animation-duration) on the second element so it doesn't appear until the first element animation has completed
Build a delay onto the end of your animation (revert to original state # 50%) so that the first element stays hidden while the second animates.

Can I use these properties in CSS keyframe animation?

Can I use properties such as position:absolute and display:none in CSS keyframe animation? I don't care if they are transitioned smoothly, I just want them to be applied as 25% of the animation such as this :
#-webkit-keyframes expanding {
25% {
width: 50%;
height: 50%;
position: absolute;
}
100% {
width: 100%;
height: 100%;
position: absolute;
}
}
or
#-webkit-keyframes hiding {
0% {
opacity: 1;
}
25% {
opacity: 0;
display: none;
}
}
It appears to ignore position and display in the keyframes and doesn't apply them when I want them applied.
You can get a animationEnd callback when one of the animatable properties finishes its cycle, then use that to set the non-animatable properties:
var anim = document.getElementById("anim");
anim.addEventListener("animationend", function () {
anim.style.display = "none";
}, false);
Unfortunately, there's no keyframe event, so you might need to set up another animation with slightly different timing, synchronised to the 25% moment. For example, it could finish when the main animation gets to 25% or whatever. You could also set up a timeout.