It's the Season of Love, folks! Valentine's Day is approaching!
This Valentine's Day, I have a web tutorial that's both simple and exciting. We will be playing with jQuery and
jQuery UI.
What, jQuery?
Yes, jQuery. You didn't think I was going to do this the old-fashioned way, did you? Too much like work. Trust me, it'll be fun.
Here we go...
For this, we'll begin with a basic HTML page with a simple
black background. Remember to add script links to jQuery and jQuery UI.
<!DOCTYPE html>
<html>
<head>
<title>Hearts</title>
<style>
body
{
background-color: #000000;
}
</style>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
</script>
</head>
<body>
</body>
</html>
Nothing much to see here... yet.
Let's put a div in the HTML, and give it an id of
placeholder.
<body>
<div id="placeholder"></div>
</body>
Now, we style
placeholder.
margin properties are set for it to be squarely in the middle of the screen. Note that we're not going to define
height and
width properties yet. Let's also give it a
white outline so we can see what we're dealing with.
<style>
body
{
background-color: #000000;
}
#placeholder
{
margin: 10% auto 0 auto;
outline: 1px solid #FFFFFF;
}
</style>
And all the divs within it. Yes, there will be divs. All of them will float left. They'll all have
orange outlines for visibility.
<style>
body
{
background-color: #000000;
}
#placeholder
{
margin: 10% auto 0 auto;
outline: 1px solid #FFFFFF;
}
#placeholder div
{
text-align: center;
float: left;
outline: 1px solid #FF4400;
}
</style>
See that thick
white line? That's actually a div with a
white outline and a height of 0 pixels (because we didn't specify height) and 100% width (because we didn't specify width).
For the purposes of this web tutorial, we'll do most of our animation from an object, named
objAnimation. Now after declaring that object, use the
ready() method, but don't place anything in there right now. It's a placeholder for more code to be executed later on. For that to happen, we must first get the
objAnimation object in order.
<script>
var objAnimation =
{
}
$(document).ready
(
function()
{
}
);
</script>
One of the properties of
objAnimation will be a method named
generateRandomNo(). You guessed it, it generates a number between
min and
max.
var objAnimation =
{
generateRandomNo: function(min, max)
{
return Math.floor((Math.random() * (max - min + 1)) + min);
},
}
Next, we specify other properties such as
color (set to
red), a font size and what will be the width and height of each div inside the
placeholder div. The property content is set to "x". We'll change it later on; this is just for simplicity.
var objAnimation =
{
generateRandomNo: function(min, max)
{
return Math.floor((Math.random() * (max - min + 1)) + min);
},
content: "x",
color: "rgba(255, 0, 0, 1)",
fontSize: "30px",
unitSize: 30,
}
OK, we're now going to define
shape, the next property. It's a 10 x 10 matrix... OK fine, it's an array of arrays. You'll notice that the 1s form a heart! That's not a coincidence.
var objAnimation =
{
generateRandomNo: function(min, max)
{
return Math.floor((Math.random() * (max - min + 1)) + min);
},
content: "x",
color: "rgba(255, 0, 0, 1)",
fontSize: "30px",
unitSize: 30,
shape:
[
[0, 0, 1, 1, 0, 0, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0]
],
}
Now for the really big stuff. Declare the next property as
render(), a method.
var objAnimation =
{
generateRandomNo: function(min, max)
{
return Math.floor((Math.random() * (max - min + 1)) + min);
},
content: "x",
color: "rgba(255, 0, 0, 1)",
fontSize: "30px",
unitSize: 30,
shape:
[
[0, 0, 1, 1, 0, 0, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0]
],
render: function()
{
},
}
Remember this block? Well, you can fill it in now. When the page loads,
objAnimation's
render() method will run.
$(document).ready
(
function()
{
objAnimation.render();
}
);
Now, inside
render(), we declare a few variables. The first,
ph, is set to the
placeholder div. The rest are set to properties within the same object, thus the use of
this.
render: function()
{
var ph = $("#placeholder");
var shape = this.shape;
var content = this.content;
var color = this.color;
var fontSize = this.fontSize;
var unitSize = this.unitSize;
},
Now, we set some properties of
ph. What we're trying to create here is a square made out of many smaller squares, to form the shape in
shape. (Remember the heart?) First, we'll define the height and width of
ph here. Since
shape has 10 elements, the
placeholder div will contain 10 squares by 10 squares. Each square will be
unitSize pixels by
unitSize pixels. Therefore placeholder's height and width should be (
unitSize x
shape.length) pixels.
var ph = $("#placeholder");
var shape = this.shape;
var content = this.content;
var color = this.color;
var fontSize = this.fontSize;
var unitSize = this.unitSize;
ph.attr
(
"style", "width:" + (unitSize * shape.length) + "px;"
+ "height:" + (unitSize * shape.length) + "px;"
);
Aren't we clever... we just turned the thick
white line into a box! Specifically, a box (
unitSize x
shape.length = 30 x 10 = 300) pixels in height and width!
Next, let's iterate through each element of
shape...
ph.attr
(
"style", "width:" + (unitSize * shape.length) + "px;"
+ "height:" + (unitSize * shape.length) + "px;"
);
$(shape).each
(
function (index)
{
}
);
Declare variable
shapeRow and make it the current element pointed to by
index. Then iterate through each element of
shapeRow.
shape is a two-dimensional array, remember?
$(shape).each
(
function (index)
{
var shapeRow = shape[index];
$(shapeRow).each
(
function (indexRow)
{
}
);
}
);
And for each element in
shapeRow, we declare a variable
piece and set it to a newly created div. Add classes according to the row and column. This will be useful later.
$(shape).each
(
function (index)
{
var shapeRow = shape[index];
$(shapeRow).each
(
function (indexRow)
{
var piece = $("<div></div>");
piece.addClass("row" + index);
piece.addClass("col" + indexRow);
}
);
}
);
Then set the attributes of
piece, which are the attributes of each and every div within
ph! And then append piece to
ph using the
append() method.
function (indexRow)
{
var piece = $("<div></div>");
piece.addClass("row" + index);
piece.addClass("col" + indexRow);
piece.attr
(
"style", "color:" + color + ";"
+ "font-size:" + fontSize + ";"
+ "width:" + unitSize + "px;"
+ "height:" + unitSize + "px;"
);
ph.append(piece);
}
A
white box filled with
orange boxes!
OK, next let's fill each div with content.
function (indexRow)
{
var piece = $("<div></div>");
piece.addClass("row" + index);
piece.addClass("col" + indexRow);
piece.attr
(
"style", "color:" + color + ";"
+ "font-size:" + fontSize + ";"
+ "width:" + unitSize + "px;"
+ "height:" + unitSize + "px;"
);
if (shapeRow[indexRow] == 1)
{
piece.html(content);
}
ph.append(piece);
}
You can now see the heart being formed.
Let's get rid of the outlines...
#placeholder
{
margin: 10% auto 0 auto;
outline: 0px solid #FFFFFF;
}
#placeholder div
{
text-align: center;
float: left;
outline: 0px solid #FF4400;
}
And change the
content property to use the ♥ symbol.
var objAnimation =
{
generateRandomNo: function(min, max)
{
return Math.floor((Math.random() * (max - min + 1)) + min);
},
content: "♥",
color: "rgba(255, 0, 0, 1)",
fontSize: "30px",
unitSize: 30,
shape:
Ain't this just adorable?!
Animating the heart (or, er, hearts)
You didn't think we were done, did you? What we just did was to lay the groundwork for some truly neat stuff.
After we've rendered the heart of hearts, declare variable
anim and set it to the current object. Then use the
setInterval() function with an interval of, say, 2.5 seconds. Then, in the callback, run the
animateObject() method with 0 passed in as the argument.
$(shape).each
(
function (index)
{
var shapeRow = shape[index];
$(shapeRow).each
(
function (indexRow)
{
var piece = $("<div></div>");
piece.addClass("row" + index);
piece.addClass("col" + indexRow);
piece.attr
(
"style", "color:" + color + ";"
+ "font-size:" + fontSize + ";"
+ "width:" + unitSize + "px;"
+ "height:" + unitSize + "px;"
);
if (shapeRow[indexRow] == 1)
{
piece.html(content);
}
ph.append(piece);
}
);
}
);
var anim = this;
setInterval
(
function()
{
anim.animateObject(0);
},
2500
);
We'll create the
animateObject() method next. It will accept a parameter,
animateId.
var objAnimation =
{
generateRandomNo: function(min, max)
{
return Math.floor((Math.random() * (max - min + 1)) + min);
},
content: "♥",
color: "rgba(255, 0, 0, 1)",
fontSize: "30px",
unitSize: 30,
shape:
[
[0, 0, 1, 1, 0, 0, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 0, 0]
],
render: function()
{
var ph = $("#placeholder");
var shape = this.shape;
var content = this.content;
var color = this.color;
var fontSize = this.fontSize;
var unitSize = this.unitSize;
ph.attr
(
"style", "width:" + (unitSize * shape.length) + "px;"
+ "height:" + (unitSize * shape.length) + "px;"
);
$(shape).each
(
function (index)
{
var shapeRow = shape[index];
$(shapeRow).each
(
function (indexRow)
{
var piece = $("<div></div>");
piece.addClass("row" + index);
piece.addClass("col" + indexRow);
piece.attr
(
"style", "color:" + color + ";"
+ "font-size:" + fontSize + ";"
+ "width:" + unitSize + "px;"
+ "height:" + unitSize + "px;"
);
if (shapeRow[indexRow] == 1)
{
piece.html(content);
}
ph.append(piece);
}
);
}
);
var anim = this;
setInterval
(
function()
{
anim.animateObject(0);
},
2500
);
},
animateObject: function (animateId)
{
}
Again, declare the variables and set them to the properties of this object. Then let's have an
If block to handle
animateId being 0.
animateObject: function (animateId)
{
var shape = this.shape;
var color = this.color;
var fontSize = this.fontSize;
if (animateId == 0)
{
}
}
Next, declare
changeSize,
changeColor and
genRan.
genRan is set to the
generateRandomNo() method of this object.
changeSize and
changeColor are set to the
animateSize() and
animateColor() methods of this object respectively.
animateObject: function (animateId)
{
var shape = this.shape;
var color = this.color;
var fontSize = this.fontSize;
var changeSize = this.animateSize;
var changeColor = this.animateColor;
var genRan = this.generateRandomNo;
if (animateId == 0)
{
}
}
We should, of course, create those methods now. We've already created
generateRandomNo() earlier. Each of these methods accepts three parameters -
obj,
delay and
color or
size. They then run jQuery UI's
animate() method from the object referred to by
obj. The duration of the animation is set by
delay. The property to be manipulated depends on the method.
animateColor() animates the color, changing it to
color. And
animateSize animates the font size, changing it to
size pixels.
animateObject: function (animateId)
{
var shape = this.shape;
var color = this.color;
var fontSize = this.fontSize;
var changeSize = this.animateSize;
var changeColor = this.animateColor;
var genRan = this.generateRandomNo;
if (animateId == 0)
{
}
},
animateColor: function(obj, delay, color)
{
$(obj).animate
(
{
color: color
},
delay
);
},
animateSize: function(obj, delay, size)
{
$(obj).animate
(
{
fontSize: size
},
delay
);
}
Now, back to the
animateObject() method. Declare variable
colorToChange and set it to a new rgba string by running
genRan() for each
red,
green or
blue value. You can use any range of values between 0 to 255. I've chosen these values to keep the heart mostly
red or warm colors.
if (animateId == 0)
{
var colorToChange =
"rgba(" +
genRan(255, 255)
+ "," +
genRan(50, 200)
+ "," +
genRan(50, 200)
+ ", 1)";
}
Now, iterate through each instance of
shape.
if (animateId == 0)
{
var colorToChange =
"rgba(" +
genRan(255, 255)
+ "," +
genRan(50, 200)
+ "," +
genRan(50, 200)
+ ", 1)";
$(shape).each
(
function (index)
{
}
);
}
During each iteration, use the
setTimeout() function with an interval of (
index x 100). This gives variable delays, which will result in a beautiful pattern. Just trust me on this...
And once the interval is reached, run the
changeColor() method using the class name, a delay of 200 milliseconds, and
colorToChange!
if (animateId == 0)
{
var colorToChange =
"rgba(" +
genRan(255, 255)
+ "," +
genRan(50, 200)
+ "," +
genRan(50, 200)
+ ", 1)";
$(shape).each
(
function (index)
{
setTimeout
(
function()
{
changeColor(".row" + index, 200, colorToChange);
},
index * 100
)
}
);
}
Ah, it's changed! Watch! Every 2.5 seconds, the object gradually changes a different color in a vertical cascade!
Now what if we changed it back a slight delay (
index x 200) milliseconds later?
if (animateId == 0)
{
var colorToChange =
"rgba(" +
genRan(255, 255)
+ "," +
genRan(50, 200)
+ "," +
genRan(50, 200)
+ ", 1)";
$(shape).each
(
function (index)
{
setTimeout
(
function()
{
changeColor(".row" + index, 200, colorToChange);
},
index * 100
)
}
);
$(shape).each
(
function (index)
{
setTimeout
(
function()
{
changeColor(".row" + index, 1000, color);
},
index * 200
)
}
);
}
Admit it, this is gorgeous. It changes from
red, to a random color, then back to
red.
Now, if you got the general idea, we can accelerate past the next part. In the
render() method, change this.
setInterval
(
function()
{
anim.animateObject(1);
},
2500
);
In the
animateObject() method, add an
If block for if
animateId is 1. In fact, go ahead and add
If blocks for 2 and 3 as well.
animateObject: function (animateId)
{
var shape = this.shape;
var color = this.color;
var fontSize = this.fontSize;
var changeSize = this.animateSize;
var changeColor = this.animateColor;
var genRan = this.generateRandomNo;
if (animateId == 0)
{
var colorToChange =
"rgba(" +
genRan(250, 255)
+ "," +
genRan(50, 200)
+ "," +
genRan(50, 200)
+ ", 1)";
$(shape).each
(
function (index)
{
setTimeout
(
function()
{
changeColor(".row" + index, 200, colorToChange);
},
index * 100
)
}
);
$(shape).each
(
function (index)
{
setTimeout
(
function()
{
changeColor(".row" + index, 1000, color);
},
index * 200
)
}
);
}
if (animateId == 1)
{
}
if (animateId == 2)
{
}
if (animateId == 3)
{
}
This next one repeats what we did earlier, accept the transition is from left to right! Copy and paste the code from the previous
If block, but instead on operating on
shape, operate on the first element of
shape. Fittingly, we'll change index to
indexCol to reflect what we're doing here - operating on columns. To that end, also make sure the class names are changed in the calls to
changeColor().
if (animateId == 1)
{
var colorToChange =
"rgba(" +
genRan(250, 255)
+ "," +
genRan(50, 200)
+ "," +
genRan(50, 200)
+ ", 1)";
$(shape[0]).each
(
function (indexCol)
{
setTimeout
(
function()
{
changeColor(".col" + indexCol, 200, colorToChange);
},
indexCol * 100
)
}
);
$(shape[0]).each
(
function (indexCol)
{
setTimeout
(
function()
{
changeColor(".col" + indexCol, 1000, color);
},
indexCol * 200
)
}
);
}
Great, right?!
Change this again...
setInterval
(
function()
{
anim.animateObject(2);
},
2500
);
This next one is also a transition from left to right, but this time, it uses the
changeSize() method, thus changing the size! Kind of like a
Kallang Wave. Copy the code from the previous
If block, and instead of using the
changeColor() method, use the
changeSize() method. Of course, instead of
colorToChange, declare and use
sizeToChange.
sizeToChange here is a size between 10 to 25 pixels, but feel free to implement your own.
if (animateId == 2)
{
var sizeToChange = genRan(10, 25) + "px";
$(shape[0]).each
(
function (indexCol)
{
setTimeout
(
function()
{
changeSize(".col" + indexCol, 500, sizeToChange);
},
indexCol * 100
)
}
);
$(shape[0]).each
(
function (indexCol)
{
setTimeout
(
function()
{
changeSize(".col" + indexCol, 500, fontSize);
},
indexCol * 200
)
}
);
}
Sweet!
Change this again!
setInterval
(
function()
{
anim.animateObject(3);
},
2500
);
This one uses both the
changeSize() and
changeColor() methods, passing in random colors and sizes respectively! I'll let you figure out on your own how this is done...
if (animateId == 3)
{
$(shape).each
(
function (index)
{
$(shape[index]).each
(
function (indexCol)
{
setTimeout
(
function()
{
var colorToChange =
"rgba(" +
genRan(250, 255)
+ "," +
genRan(50, 200)
+ "," +
genRan(50, 200)
+ ", 1)";
var sizeToChange = genRan(10, 65) + "px";
changeSize(".row" + index + ".col" + indexCol, 500, sizeToChange);
changeColor(".row" + index + ".col" + indexCol, 300, colorToChange);
},
0
)
}
);
}
);
$(shape).each
(
function (index)
{
$(shape[index]).each
(
function (indexCol)
{
setTimeout
(
function()
{
changeSize(".row" + index + ".col" + indexCol, 500, fontSize);
changeColor(".row" + index + ".col" + indexCol, 300, color);
},
100
)
}
);
}
);
}
Groovy! There are so many different ways you could play with this!
One last change. Instead of passing in an arbitrary number as an argument, pass in a random number between 0 and 3. This way, you get a random animation every 2.5 seconds.
setInterval
(
function()
{
anim.animateObject(anim.generateRandomNo(0, 3));
},
2500
);
We're done!
I went a bit overboard with the animation, but damn that felt good. We could have done it without jQuery, but this web tutorial might have taken twice as long. So yeah, I think it was worth it.
In my heart of hearts, I salute you!
T___T