Interpolation (fading) between two colors in JavaScript - javascript

I have a project in which I have to modify code to fade the background color of a piece of text between two different colors, or like rotate between them using their RGB values. But I have no clue how to accomplish this, we are told to use requestAnimationFrame and a clock essentially to make this happen. Attached I will have the code which I need to modify. At present, the code just blinks between white and red, and as I said, it needs to fade between the two, more like a pulse or a throb if you will.
function makeThrob(id, rate, blinkColors) {
rate = rate ? rate : 1000;
blinkColors = blinkColors ? blinkColors : ["red","white"];
let toblink = document.getElementById(id);
let lastBlinkTime = 0;
let lastBlinkColor = 0;
function blinker(time) {
if ((time-lastBlinkTime) > rate) {
lastBlinkTime = time;
toblink.style.backgroundColor =
blinkColors[lastBlinkColor % blinkColors.length];
lastBlinkColor++;
}
window.requestAnimationFrame(blinker);
}
window.requestAnimationFrame(blinker);
}
makeThrob("ex3-span");

Related

Rotating font family with js

I'm very new to JS, I have a problem that could easily be solved I think but I can't figure it out :
I would like to find a way to change the font-family of an html element every 0.1 seconds without having to trigger something.
Basically I would like the html element to change font every 0.1 sec, rotating amongst 6 font families.
really thankful if you guys can find a way.
Louis
Try something like :
function changefontFamily() {
var doc = document.getElementById("elementID");
var font= ["Arial", "Verdana", "Helvetica ", "Tahoma"];
doc.style.fontFamily= font[i];
i = (i + 1) % font.length;
}
setInterval(changefontFamily, 100);
<div id="elementID">text</div>
I set 1 second (1000 ms), for clarity, because 100ms is too fast 🙂
(async()=>{
const elem = document.getElementById('elementID');
const fonts = ['Arial', 'Tahoma', 'Verdana'];
let k = fonts.length;
setInterval(()=>{
k--;
elem.style.fontFamily = fonts[k];
console.log('Now:', fonts[k], k);
if(k === 0)k = fonts.length;
}, 1000);
})();
<div id="elementID">Some Text to test it OUT</div>

How to use .onclick event for multiple times?

For example, I have a rectangle on my html page, and want to rotate it for 90deg by clicking on it:
rectangle.onclick = () => {
rectangle.style.transform = "rotate(90deg)";
When I click once - it rotates,but when i wanna rotate it for the second time - it does not work. Is there any way to to use .onclick event for two or more times?
CSS is not stateful; that is, when you set "rotate(90)" it doesn't rotate the item 90 degrees further, it rotates it to exactly 90 degrees from 0. So, if you want to rotate it, you need to set the correct angle: 90, 180, 270, &c. You can use a simple state variable to keep track of your angle, like this:
let rotation = 0 // rotation angle variable
rectangle.onclick = () => {
if (rotation >= 360) {
rotation = 0
} else {
rotation += 90;
}
rectangle.style.transform = `rotate(${rotation}deg)`;
}
When you set pentangle.style.transform, you're setting a style. That transform is from the baseline, unrotated shape. Your onclick event is likely getting fired multiple times, but each time, it does the same thing: cause the pentangle to be rotated from its default orientation.
You'll need something more like this, which advances the rotation amount based on the current rotation.
pentangle.onclick = () => {
if(pentangle.style.transform == "rotate(90deg)")
pentangle.style.transform = "rotate(180deg)";
else if(pentangle.style.transform == "rotate(180deg)")
pentangle.style.transform = "rotate(270deg)";
else if(pentangle.style.transform == "rotate(270deg)")
pentangle.style.transform = "";
else
pentangle.style.transform = "rotate(90deg)";

Spine multiple animations

So I have 2, or more skeletons for an animation (so, 2 or more json files). I want them to play at the same time and 10 seconds after, to play another animation.
Problem is that there is only one animation playing, and the second isn't displayed.
The way I'm doing it is the following:
<canvas id="animationCanvas" width="240" height="240"></canvas>
<script>
var first = true,
rendererFirst = new spine.SkeletonRenderer('http://someurl.com/images/'),
spineAFirst = /* My JSON Code */,
parsedFirst = JSON.parse(spineAFirst);
rendererFirst.scale = 0.2;
rendererFirst.load(spineAFirst);
rendererFirst.state.data.defaultMix = 1.0;
for (var i in parsedFirst.animations) {
if (first) {
first = false;
rendererFirst.state.setAnimationByName(0, i, true);
} else {
rendererFirst.state.addAnimationByName(0, i, true, 10);
}
}
rendererFirst.skeleton.x = 120;
rendererFirst.skeleton.y = 120;
rendererFirst.animate('animationCanvas');
</script>
And, of course, I'm doing it twice (or more). I tried as well with a single SkeletonRenderer, just loading (and setting or adding) animations as many times as I need, and it didn't worked.
It seems that the renderer is cleaning the canvas each time it is called, the better way to achieve this seems to create a canvas for each animation, and bind a renderer to each one.

Animate color change of shape for certain number of frames EaselJs

I am using EaselJS and want to create a flashing color rectangle that will flash a certain number of times when a button is pressed, displaying random colors from an array. It should stop after 10 color flashes and then I want to extract the final color.
So far the relevant code I have is:
var colorArray = ["#FE7B62","#CB2DD3","#F1FD66","#004CE8","#FFD068", "#02A97E"];
square = new createjs.Shape();
square.graphics.beginFill("#000").drawRoundRect(850, 50, 100, 100, 20);
function pushButton(event) {
square.graphics.inject(animateColor);
}
function animateColor(event) {
this.fillStyle = colorArray[parseInt(Math.random()*6)];
}
This code successfully triggers the flashing of colors from my color array, but I am not sure what the best method of running the animation for a limited number of frames is. I tried pausing the ticker and restarting it on the onclick of the button but that failed. I also tried using a for loop in the pushButton function but that caused a "too much recursion error" in the browser. Here is my full file link https://github.com/RMehta95/sherman-land/blob/master/main.js.
I would suggest creating an event to trigger your action (xamountOfFrames). Here is a link to some information that might help
http://www.w3schools.com/tags/ref_eventattributes.asp
I ended up not using the inject function and instead redrawing the shape each time, creating a couple counter and timer variables to ensure that it looped through the proper amount of times.
function pushButton() {
if (timer === false) {
animate = setInterval(animateColor, 200);
timer = true;
}
}
function animateColor() {
square.graphics.clear();
displayColor = colorArray[Math.floor(Math.random()*colorArray.length)];
square.graphics.beginFill(displayColor).drawRoundRect(850, 50, 100, 100, 20);
counter++;
if (counter===15) {
clearInterval(animate);
counter=0;
movePlayer(displayColor);
timer = false;
return;
}
}

How to vertically scale with Raphael?

Please consider the following code snippet:
jQuery(function ()
{
drawLogo();
});
function drawLogo()
{
var paper = Raphael('logo', 100, 100);//creates canvas width=height=100px
var rect = paper.rect(1,1,98,98, 10);//chessboard background
rect.attr("fill","#efd5a4");
var circle1 = paper.circle(20,20,12);
var circle2 = paper.circle(50,20,12);
var circle3 = paper.circle(80,20,12);
var circle4 = paper.circle(20,50,12);
var circle5 = paper.circle(50,50,12);
var circle6 = paper.circle(80,50,12);
var circle7 = paper.circle(20,80,12);
var circle8 = paper.circle(50,80,12);
var circle9 = paper.circle(80,80,12);
paper.path("M35,0 L35,100");
paper.path("M65,0 L65,100");
paper.path("M0,35 L100,35");
paper.path("M0,65 L100,65");
circle1.animate({scale:"0"}, 2000);
//setTimeout(circle1.animate({scale:"1"}, 2000), 2000);
}
The animation I'd like to achieve is a chain of two parts, first, a vertical scale animation from 100% to 0%, second, a vertical scale animation from 0% to 100%. The above code scales down both vertically and horizontally, so it is incorrect.
I've check Raphael's documentation but couldn't get it, particularly because I cannot see the correct syntax... Any good API reference like that of jQuery's?
Also, if I make the following change, then Firefox shows an error saying too many recursions:
transform(circle1);
function transform(item)
{
item.animate({scale:"0"}, 2000, transform(item));
}
I know this is bad, but what is the correct way to get a infinite "loop" of animation?
Edit: I modified the code to the following
transform([circle1, circle3, circle5, circle7, circle9]);
function transform(elements)
{
for(var e in elements)
{
e.animate({scale:"0"}, 2000);
}
}
in the hope that this would at least run the first part of animation for 5 circles, but unfortunately, it only gives an error saying e.animate() is not a function. Probably the reason is that when elements are retrieved back from the array, it "loses its type"? (just like in Java when you get an elements from plain old ArrayList, you must explicitly downcast or everything will be just of type object.)
2nd Edit before going to bed
At least the following works for once!
var elements = [circle1, circle3, circle5, circle7, circle9];
for(var i = 0; i < elements.length; i++)
transform(elements[i]);
function transform(e)
{
e.animate({scale: 0},2000, function(){this.animate({scale:1},
2000, transform(this));});
}
Achieved parts: chained two scaling animations one after another, for five circles;
Failed parts: Still not an infinite loop, still not only vertical scale.
It seems scaling of circle in just one direction is not possible. Instead use an ellipse. The scale attribute takes a string like "1 0" which means scale 100% for x (horizontally) and 0% for y (vertically). See attr-scale
So your animation can be achieved by
ellipse.animate({"50%": {scale: "1 0"}, "100%": {scale: "1 1"}}, 2000);
see 3rd method (keyframes) in animate
which means at 50% of animation the ellipse should be scaled 0% vertically and at 100% animation scale it back to 100%.
When you call a function, it will be evaluated immediately. Your transform calls transform(item) again before passing it to animate. Instead you should wrap it in a function and pass it.
Here's the full source
jQuery(function ()
{
drawLogo();
});
function drawLogo()
{
var paper = Raphael('logo', 100, 100);//creates canvas width=height=100px
var rect = paper.rect(1,1,98,98, 10);//chessboard background
rect.attr("fill","#efd5a4");
var ellipse1 = paper.ellipse(20,20,12, 12);
var ellipse2 = paper.ellipse(50,20,12, 12);
var ellipse3 = paper.ellipse(80,20,12, 12);
var ellipse4 = paper.ellipse(20,50,12, 12);
var ellipse5 = paper.ellipse(50,50,12, 12);
var ellipse6 = paper.ellipse(80,50,12, 12);
var ellipse7 = paper.ellipse(20,80,12, 12);
var ellipse8 = paper.ellipse(50,80,12, 12);
var ellipse9 = paper.ellipse(80,80,12, 12);
paper.path("M35,0 L35,100");
paper.path("M65,0 L65,100");
paper.path("M0,35 L100,35");
paper.path("M0,65 L100,65");
var elements = [ellipse1, ellipse3, ellipse5, ellipse7, ellipse9];
for(var i = 0; i < elements.length; i++)
transform(elements[i]);
}
function transform(e)
{
e.animate({
"50%": {scale: "1 0"},
"100%": {scale: "1 1", callback: function() {transform(e);}}
}, 2000);
}

Categories

Resources