Friday, 27 February 2015

A Tale of Two Staff Appraisals

It was the best of times; it was the worst of times.

OK, that's as far as I go with this cheap imitation of the Charles Dickens classic. Today, I want to talk about staff appraisals. In particular, the one that I went through in my last job and the one that  I encountered in my current job. They were both memorable because of the stark contrast to each other.

Before I continue, let's just ascertain what a staff appraisal is: a period of time, perhaps thirty minutes to an hour, set aside for an employee (the interviewee) and his immediate superior (the interviewer), to sit down and discuss the employee's performance and conduct over the course of the past year, ways in which he can improve, and so on. After which the interviewer will have a discussion with the CEO regarding possible promotions, pay raises and bonuses.

The Staff Appraisal - previous company (A)

There was no standard form provided. The interviewer used a piece of foolscap, drew lines and scribbled down key indicators such as Attire, Punctuality, Attitude and etc. And ratings from 1 to 5, 1 being the worst and 5 being the best. I got a score of 3 to 4 in all areas. The process was pretty perfunctory.

Most tellingly, I was given a score of 3 in Attendance.

"3?" I remember asking then, in disbelief. "I haven't taken MC since I joined the company more than a year ago. What do I have to earn a 5? Forfeit all my annual leave and stay in the office 24/7?" The interviewer gave me a look of amused tolerance, and I understood then. This was a sham. It was what they call Wayang.

Wayang Kulit


For those not in the know, the term Wayang originated from Wayang Kulit, a form of shadow puppetry originating from Java, Indonesia. In local parlance, it's primarily used as a descriptive term for "smoke and mirrors". And this staff appraisal was a Wayang.

The Staff Appraisal - present company (B)

When I went through this company's staff review, the first thing that struck me was that there was a proper standard form for it, with the company letterhead, official signatures and all the trappings. There was even a questionnaire for the interviewee to fill up. Not just multiple choice questions, but essay questions. They actually expected feedback, and expected some thought to be put into it!

For every staff member being interviewed, the HOD, HR, COO and CEO would sit in and go through each and every question. They would discuss the interviewee's current scope of work, suggestions for improvement, and so on. The entire process took days.

And the difference is...

Aside from the availability of standard documentation and the appearance of objectivity, you mean?

Company A was going through the motions of making it look like the employee's performance over the course of the past year made a difference to whether the employee would receive a significant pay increment, bonus or promotion. In truth, the CEO had already mapped all this out in his mind - which staff members he valued more (and thus would reward more) and which he was willing to risk leaving due to discontent. The actual performance indicators, to put it indelicately, meant jackshit. The interviewer's feedback to the CEO was meant merely to enforce his preconceptions, not challenge them. Because God forbid that the CEO would actually have to pay attention. Thus a middling score for every area. Safe, nondescript and non-threatening.

Just for the record, I am not against this. The position of CEO comes with a great amount of pressure. There is much that hinges upon his decisions. He can play favorites if he wants to. I support the CEO's right to judge you based on how pretty you look in a skirt or how many hours you spend - apparently hard at work - in the office, how close a friend you are to his wife, and so on. If you don't like it, tough titty. Leave!

And let's face it - there's no point in having all that power if you can't let it go to your head every now and then, eh?

I'm also not against it being a Wayang. Appearances have to be kept up, after all. It's only right and proper. Employers need employees to think that management is fair, and that the hard work they put in, the loyalty they demonstrate and the results they produce will eventually pay off. This serves to keep them on their toes and their noses enthusiastically to the grindstone. It's a sound management practice.


Not much of a Matrix

My real point of contention is: What's the point of a Wayang if it's executed in such a sloppy fashion? The performance was a spectacular fail. In this Matrix, everyone but the dullest blockhead is a Morpheus. You score a staggering 1 for Presentation, pal. This smacks of complacency. Do it like you mean it, or don't do it at all.

Compare this to Company B's effort. They actually took the effort to present the staff appraisal like it actually meant something. Like it actually mattered.

Of course, it could all still have been a Wayang. Even if not meant to be a Wayang, personal sentiment could still get in the way and color the end result. These are human beings we're talking about, even if they are professionals. But if this was a Wayang, kudos to the performers, this was one hell of a Wayang! That was a lot of time and effort to spend on an illusion.

Take note, CEO of Company A. This is how you keep up appearances.

May the Farce be with you!
T___T

Tuesday, 24 February 2015

Dissecting the RGB Color Model

Need a quick-and-dirty website layout? Need to create a basic color scheme? Normally, with HTML and perhaps CSS, you would need to supply the hexadecimal color codes or the RGB values. And you would obtain said values from an online color picker such as ColorPicker.com or an IDE such as Adobe Dreamweaver, or even an Image Editing Tool such as Adobe Photoshop.

What if you don't have an online connection, or simply can't be arsed to fire up a memory-intensive program just to pick a color? You would have to have a good grasp of the RGB Color Model, so as to get a decent approximation of the color code needed.

Color codes are the bread and butter of layout designers. They are based off R, G and B values which make up every color in the RGB Color Model. These stand for Red, Green and Blue respectively. Each R, G and B component has 256 possible intensity values (00 to FF in Hexadecimal, 0 to 255 in Decimal), and in turn this allows for more than 16 million possible combinations. Cool, eh?

For instance, to obtain a lovely Blue-green, you would need Hexadecimal code #006699 or Decimal rgba(0,102,153,1). For ease of conversion between Hexadecimal and Decimal, check this table out.

Intensity plays a very important part in color-guessing. The lower the value, the less intense the RGB component is. So having all values at the lowest (Hexadecimal code #000000 or Decimal rgba(0,0,0,1)) would give you Black, and having all values at the highest (Hexadecimal code #FFFFFF or Decimal rgba(255,255,255,1)) would give you White.

Color Hexadecimal Decimal
R G B R G B A
White FF FF FF 255 255 255 1
Black 00 00 00 0 0 0 1

Incidentally, having all RGB components at the same values, would give you varying shades of grey.

Hexadecimal Decimal
#FFFFFF rgba(255,255,255,1)
#E0E0E0 rgba(224,224,224,1)
#AAAAAA rgba(170,170,170,1)
#6F6F6F rgba(111,111,111,1)
#444444 rgba(68,68,68,1)
#000000 rgba(0,0,0,1)

Yes, excluding Black and White, there would be 254 possible shades of grey in the RGB Color Model. Now, we're going to see what happens when we manipulate the intensity values of existing color codes. For example, Red would be #FF0000 or rgba(255,0,0,1), Green would be #00FF00 or rgba(0,255,0,1) and Blue would be #0000FF or rgba(0,0,255,1).

Hexadecimal Decimal
#FF0000 #00FF00 #0000FF rgba(255,0,0,1) rgba(0,255,0,1) rgba(0,0,255,1)
#FF4444 #44FF44 #4444FF rgba(255,68,68,1) rgba(68,255,68,1) rgba(68,68,255,1)
#FF9999 #99FF99 #9999FF rgba(255,153,153,1) rgba(153,255,153,1) rgba(153,153,255,1)
#FFA0A0 #A0FFA0 #A0A0FF rgba(255,160,160,1) rgba(160,255,160,1) rgba(160,160,255,1)

See what happened there? We manipulated the other RGB values, upping their intensity. This gave us lighter shades of Red, Green and Blue. So, what do you do when you want darker shades?

Hexadecimal Decimal
#FF0000 #00FF00 #0000FF rgba(255,0,0,1) rgba(0,255,0,1) rgba(0,0,255,1)
#A00000 #00A000 #0000A0 rgba(160,0,0,1) rgba(0,160,0,1) rgba(0,0,160,1)
#990000 #009900 #000099 rgba(153,0,0,1) rgba(0,153,0,1) rgba(0,0,153,1)
#440000 #004400 #000044 rgba(68,0,0,1) rgba(0,68,0,1) rgba(0,0,68,1)

What we did here was to keep the other RGB values at 0 while lowering the intensity in general. That was simple! Now, how about composite colors, where you combine intensities of more than one R, G or B component?

Color Hexadecimal Decimal
R G B R G B A
Yellow FF FF 00 255 255 0 1
Magenta FF 00 FF 255 0 255 1
Cyan 00 FF FF 0 255 255 1

So combining R and G gives us Yellow, combining R and B gives us Magenta, and combining G and B gives us Cyan! Now what happens if you want a color not in those combinations, for example, Orange? Well, Yellow is the closest color, so we'll extrapolate from there. There's more Red than Green in Orange, so what we'll do here is tinker with the RGB components and ensure that the R component is higher in intensity than the G component.

Hexadecimal Decimal
#FFFF00 rgba(255,255,0,1)
#FFD000 rgba(208,208,0,1)
#FF9900 rgba(153,153,0,1)
#FF4400 rgba(68,68,0,1)
#FF0000 rgba(255,0,0,1)

Voila! Orange! Various shades of orange, from blazing fire to pale sunshine! So the same principle applies to other colors - if you wanted a Deep Purple, you could tinker with the Magenta. If you wanted Blue-green (as with the very first color mentioned in this post), go mess with the Cyan!

Well done, lads. Let's go paint the town #FF0000!
T___T

Tuesday, 17 February 2015

Web Tutorial: Year of the Goat

May fortune befall you in the Year of the Goat!

Happy Lunar New Year!

It's The Lunar New Year, and I'm in a festive mood.

Did I mention that I used to design Flash greeting cards for such occasions, and sometimes even get paid for them? Well, my Flash days are over, but CSS3 is a close second!

I'll be showing you an animated greeting card I designed for this Lunar New Year. No images, minimal programming. 90% CSS3! The code listing is here. There's a LOT of CSS in there, and I don't feel like reproducing all of it here, since it can get rather repetitive. So for the purposes of this web tutorial, I'm going to assume you have the link open where you can refer to the code.

The code's also rather sloppy. I never intended for this to be a web tutorial, but I figured later, why the hell not? Just bear with me, a lot of stuff here is not what industry experts would consider "best practice". I also won't be going too much into detail. This is one of those web tutorials where the concept matters more than the execution.

Here's the beginning HTML and CSS:
<!DOCTYPE html>
<html>
    <head>
        <title>Yang</title>
        <meta charset="utf-8">
        <style type="text/css">
            #character_wrapper
            {
                width:500px;
                height:700px;
                margin:100px auto 0px auto;
            }

            .stroke_yang
            {
                position:absolute;
                width:0px;
                height:0px;
                -webkit-transition: width 0.5s, height 0.5s,-webkit-transform 0.5s;  /* For Safari 3.1 to 6.0 */
                transition: width 0.5s, height 0.5s, transform 0.5s;
                -webkit-transition-timing-function: ease-in-out; /* Safari and Chrome */
                transition-timing-function: ease-in-out;
            }

            .stroke_couplet
            {
                position:absolute;
            }

            .
            .
            .
            .
            (for the rest of the CSS code, click here)
            .
            .
            .
            .
            .
            .

            .boxframe
            {
                position:absolute;
                width:70px;
                height:70px;
                background-color:#FFDD00;
                border:5px solid #AA0000;
                color:#FF0000;
                font-size:65px;
                font-weight:bold;
                opacity: 0;
                filter: alpha(opacity=0); /* For IE8 and earlier */
                -webkit-transition: all 4s;  /* For Safari 3.1 to 6.0 */
                transition: all 4s;
                -webkit-transition-timing-function: ease-in-out; /* Safari and Chrome */
                transition-timing-function: ease-in-out;
            }

            .boxframe_rotate
            {
                -webkit-transform: rotateY(360deg); /* Chrome, Safari, Opera */
                transform: rotateY(360deg);
                opacity: 1;
                filter: alpha(opacity=100); /* For IE8 and earlier */
            }
        </style>

    </head>

    <body>
        <div id="character_wrapper">
            <div id="stroke0a" class="stroke_yang"></div>
            <div id="stroke0b" class="stroke_yang"></div>   
            <div id="stroke1" class="stroke_yang"></div>   
            <div id="stroke2" class="stroke_yang"></div>
            <div id="stroke3" class="stroke_yang"></div>
            <div id="stroke4" class="stroke_yang"></div>   

            <div id="box1" class="boxframe">       
                <div id="gong_stroke1" class="stroke_couplet"></div>
                <div id="gong_stroke2" class="stroke_couplet"></div>
                <div id="gong_stroke3" class="stroke_couplet"></div>
                <div id="gong_stroke4" class="stroke_couplet"></div>
                <div id="gong_stroke5" class="stroke_couplet"></div>
                <div id="gong_stroke6" class="stroke_couplet"></div>
                <div id="gong_stroke7" class="stroke_couplet"></div>
                <div id="gong_stroke8" class="stroke_couplet"></div>
                <div id="gong_stroke9" class="stroke_couplet"></div>
                <div id="gong_stroke10" class="stroke_couplet"></div>
            </div>
            <div id="box2" class="boxframe">
                <div id="xi_stroke1" class="stroke_couplet"></div>
                <div id="xi_stroke2" class="stroke_couplet"></div>
                <div id="xi_stroke3" class="stroke_couplet"></div>
                <div id="xi_stroke4" class="stroke_couplet"></div>
                <div id="xi_stroke5" class="stroke_couplet"></div>
                <div id="xi_stroke6" class="stroke_couplet"></div>
                <div id="xi_stroke7" class="stroke_couplet"></div>
                <div id="xi_stroke8" class="stroke_couplet"></div>
                <div id="xi_stroke9" class="stroke_couplet"></div>
                <div id="xi_stroke10" class="stroke_couplet"></div>
                <div id="xi_stroke11" class="stroke_couplet"></div>
                <div id="xi_stroke12" class="stroke_couplet"></div>
            </div>
            <div id="box3" class="boxframe">
                <div id="fa_stroke1" class="stroke_couplet"></div>
                <div id="fa_stroke2" class="stroke_couplet"></div>
                <div id="fa_stroke3" class="stroke_couplet"></div>
                <div id="fa_stroke4" class="stroke_couplet"></div>
                <div id="fa_stroke5" class="stroke_couplet"></div>
                <div id="fa_stroke6" class="stroke_couplet"></div>
                <div id="fa_stroke7" class="stroke_couplet"></div>
            </div>
            <div id="box4" class="boxframe">
                <div id="cai_stroke1" class="stroke_couplet"></div>
                <div id="cai_stroke2" class="stroke_couplet"></div>
                <div id="cai_stroke3" class="stroke_couplet"></div>
                <div id="cai_stroke4" class="stroke_couplet"></div>
                <div id="cai_stroke5" class="stroke_couplet"></div>
                <div id="cai_stroke6" class="stroke_couplet"></div>
                <div id="cai_stroke7" class="stroke_couplet"></div>
            </div>
        </div>   
    </body>
</html>


What the CSS does

The character_wrapper element simply holds everything together where I want it, which is somewhere middle of the screen.

The Calligraphy

The Yang character is rendered in red. I used the egg shape from this link and adjusted the box-shadow (and sometimes the transform) property to shape individual strokes. But all the strokes have something in common, thus the stroke_yang class. You'll notice that the width and height properties of each individual stroke are set to 0px, which makes them effectively invisible. That's because we'll be animating them later.

The position property is set to "absolute", because the strokes need adjusting here and there, and setting them to "relative" would mean that if I adjust stroke 1, I have to redo a whole lot of adjustment to strokes 2,3 4, etc. The transition properties are also set for maximum awesomeness.

The Gong, Xi, Fa and Cai characters are in black, and encased in small colored squares.  The CSS for each stroke (the stroke_couplet class) means...

position: absolute for easier adjustment later on. And that's no small thing, considering how many different strokes each character has!

The CSS for each square (the boxframe class) means...

position: absolute for easier adjustment later on.
width, height set to 70px to form a square.
border has been set to 5px so each box has a frame.
opacity has been set to 0 so that it's invisible at the start. We'll be animating this later.

There's a lot more CSS for individual character strokes, and the like. They're in the code listing. But for the purpose of this web tutorial, we're not going to get into those.

Now for the JavaScript!

Basically, in this code, I animate the four boxes containing the Gong, Xi, Fa and Cai characters.

        <script>
        function writeword()
        {
            document.getElementById("box1").className="boxframe boxframe_rotate";
            document.getElementById("box2").className="boxframe boxframe_rotate";
            document.getElementById("box3").className="boxframe boxframe_rotate";
            document.getElementById("box4").className="boxframe boxframe_rotate";
        }
        </script>


Then I set the width and height properties for each stroke in the Yang character, and the times they would be "written".

        <script>
        function writeword()
        {
            document.getElementById("stroke0a").style.width="40px";document.getElementById("stroke0a").style.height="80px";
            document.getElementById("stroke0b").style.width="20px";document.getElementById("stroke0b").style.height="60px";
            document.getElementById("stroke1").style.width="100px";document.getElementById("stroke1").style.height="20px";
            document.getElementById("stroke2").style.width="80px";document.getElementById("stroke2").style.height="10px";
            document.getElementById("stroke3").style.width="120px";document.getElementById("stroke3").style.height="20px";
            document.getElementById("stroke4").style.width="20px";document.getElementById("stroke4").style.height="200px";
            document.getElementById("box1").className="boxframe boxframe_rotate";
            document.getElementById("box2").className="boxframe boxframe_rotate";
            document.getElementById("box3").className="boxframe boxframe_rotate";
            document.getElementById("box4").className="boxframe boxframe_rotate";
        }
        </script>


Replaying the card

So now we have a nifty greeting card. But it'll be a pity if we could only play it once. So I created a Replay button. I took the lazy way out, and just added the button to the HTML, like this:
<body onload="writeword();">
        <input type="button" value="click here for T___T's Lunar New Year message!" onclick="location.reload();">

This basically means the page will reload when the button is clicked. And since I added onload="writeword();" to the body tag, the animation will start when the page is loaded or reloaded. Yes, the proper way would be to reverse the changes I made to the properties in the writeword() function... but what the hell, it's the festive season and I really can't be arsed. This works just as well for our purposes.

It works. Click it, try it!



And the beauty of this is - it's all HTML, CSS and JavaScript. No clunky images to deal with. Sleek and elegant!

Don't be afraid to experiment! You're only Yang once!
T___T

Wednesday, 11 February 2015

Web Tutorial: Trail of Hearts

Happy Valentine's Day!

If you're reading this, how come you're not on some hot date? Yes, I don't have a life either, but I'm a geek. What's your excuse?

Anyway, in the absence of a hot date, we can have some geeky fun instead. We're going to turn your mouse cursor into a trail of hearts.

How is this useful?

It isn't. It literally is just a bunch of little mini-hearts replacing your mouse cursor. But it will highlight certain CSS and JavaScript tricks which you may want to use for something else.

There's not a whole lot of HTML markup in this tutorial. The bulk of it is CSS and JavaScript. So here you go, get the HTML up!
<!DOCTYPE html>
<html>
    <head>
        <title>VDay test</title>
    </head>

    <body>
        <div id="container">

        </div>
    </body>
</html>


That's it for the HTML! Seriously, that's all there is. The container div is just an overlay on the body, to detect your mouse movement. With that in mind, let's style the container div.
<!DOCTYPE html>
<html>
    <head>
        <title>VDay test</title>
        <style type="text/css">
            #container
            {
                background-color:rgba(254,200,150, 0.7);
                width:100%;
                height:100%;
                position:absolute;
                z-index:500;
                left:0px;
                top:0px;
                cursor:none;
            }
        </style>
    </head>

    <body>
        <div id="container">

        </div>
    </body>
</html>


Here's what we did.

background-color:rgba(254,200,150, 0.7) gives the container div a nice pastel pink.
width: 100% and height: 100% makes it fit the entire screen.
position:absolute,z-index:500, left:0px and top:0px makes the container div fit snugly into the top left corner.
cursor:none hides your mouse cursor.

So far so good? I'm going to show you how to draw a heart using CSS.

The Heart's basic shapes

When you break it apart, the heart's basically one square and two circles, artfully arranged. So the wireframe looks like this.


Wireframe for Heart shape


So we'll start by drawing the square.
        <style type="text/css">
            #container
            {
                background-color:rgba(254,200,150, 0.7);
                width:100%;
                height:100%;
                position:absolute;
                z-index:500;
                left:0px;
                top:0px;
                cursor:none;
            }

            .heart
            {
                background-color:#FF0000;
                position:absolute;
                z-index:1000;
                width:10px;
                height:10px;
            }
        </style>


Here, we basically have a red square of 10x10 pixels. The z-index property has been set to higher than that of the container div, so it'll be displayed over the container div.

Now for the circles. We're going to use the before and after selectors.

For more on CSS selectors: (http://www.w3schools.com/cssref/css_selectors.asp)

        <style type="text/css">
            #container
            {
                background-color:rgba(254,200,150, 0.7);
                width:100%;
                height:100%;
                position:absolute;
                z-index:500;
                left:0px;
                top:0px;
                cursor:none;
            }

            .heart
            {
                background-color:#FF0000;
                position:absolute;
                z-index:1000;
                width:10px;
                height:10px;
            }

            .heart:before,.heart:after
            {
                content:"";
                border-radius:50%;
                width:10px;
                height:10px;
                display: block;
                position:absolute;
                background-color:#FF0000;
            }

            .heart:before
            {
                margin-left:-5px;
            }

            .heart:after
            {
                margin-top:-5px;
            }
        </style>

This adds two circles, both in red, within the square. Both circles are the same size as the square. Since they have so many things in common, before and after are styled together for the most part. And since the position property is set to absolute, they're nicely overlapping one another within the square. But the before circle needs to move left, and the after circle needs to move right. Hence the adjustments to the margin-top and margin-left properties.

If you do a <div class="heart"></div> now, this is what you should see.


Now it's lying on its side. All you need to do is rotate the thing 45 degrees, you're all set! But let's hold off on that. Now that you've learned how to draw a heart, we're gonna start making a trail of them. For that, you'll need to learn about mouse events.

JavaScript mousemove event (http://www.quirksmode.org/js/events_mouse.html#mousemove)

The idea here is to detect whenever there's a mouse movement, then draw hearts. Insert the following JavaScript into your HTML head.
        <script>
            document.onmousemove=makeheart;

            function makeheart(e)
            {
                        if (!e)
                        {
                                var e=window.event;
                        }
            }
        </script>

The makeheart() function will fire off whenever the page detects a mouse movement. e here stands for "event". A mousemove is an event, and you'll need to capture the details of that event.
        <script>
            document.onmousemove=makeheart;

            function makeheart(e)
            {
                        if (!e)
                        {
                                var e=window.event;
                        }
                       
                        var x=parseInt(e.screenX);
                        var y=parseInt(e.screenY);

                        var heartsize=Math.floor((Math.random() * 3));
            }
        </script>

e.screenX gets you the x coordinate of the mouse pointers current location, and e.screenY gives you the y coordinate. For fun, we're going to randomize the size of the heart. Math.floor((Math.random() * 3)) gives you a number from 0 to 3, which means your hearts will either stay the same size or go up to 3 times in size.

Next, we do this.
        <script>
            document.onmousemove=makeheart;

            function makeheart(e)
            {
                        if (!e)
                        {
                                var e=window.event;
                        }
                       
                        var x=parseInt(e.screenX);
                        var y=parseInt(e.screenY);

                        var heartsize=Math.floor((Math.random() * 3));

                        var heart = document.createElement("div");                
                        document.getElementById("container").appendChild(heart);
                        heart.className="heart";
                        heart.style.left=x+"px";
                        heart.style.top=y+"px";
                        heart.style.transform="rotate(45deg) scale("+heartsize+","+heartsize+")";
            }
        </script>

Here, we create a div element and assign it to the heart variable. Then we add heart to the container div as a nested div with the appendChild() method. Now that the heart is created, assign the value "heart" to its className property, so that the styling you did earlier now kicks in! And since it's supposed to be where your mouse pointer is, set its left and top property to the mouse pointer's x and y coordinates, respectively. And while you're at it, rotate the heart 45 degrees and scale it to the random size!

Now open your page in a browser and run your mouse pointer over it. This is what you should see - a lovely trail of hearts!


Beautiful, eh? What next?

It would work much better as a trail if the previous hearts disappeared. Also, appending too many hearts to the page may eventually cause your system to slow down. So we're gonna make the earlier hearts disappear.

Create a few function deleteheart().
        <script>
            document.onmousemove=makeheart;

            function makeheart(e)
            {
                        if (!e)
                        {
                                var e=window.event;
                        }
                       
                        var x=parseInt(e.screenX);
                        var y=parseInt(e.screenY);

                        var heartsize=Math.floor((Math.random() * 3));

                        var heart = document.createElement("div");                
                        document.getElementById("container").appendChild(heart);
                        heart.className="heart";
                        heart.style.left=x+"px";
                        heart.style.top=y+"px";
                        heart.style.transform="rotate(45deg) scale("+heartsize+","+heartsize+")";
            }

            function deleteheart()
            {
                var hearts=document.getElementsByClassName("heart");           
            }
        </script>

With document.getElementsByClassName("heart"), you're referencing all elements with the className of "heart", which is essentially all the lovely red hearts floating over your screen, and then assigning it to the array hearts. Next, we have a few conditions and iterations to implement. Add the following code.
        <script>
            document.onmousemove=makeheart;

            function makeheart(e)
            {
                        if (!e)
                        {
                                var e=window.event;
                        }
                       
                        var x=parseInt(e.screenX);
                        var y=parseInt(e.screenY);

                        var heartsize=Math.floor((Math.random() * 3));

                        var heart = document.createElement("div");               
                        document.getElementById("container").appendChild(heart);
                        heart.className="heart";
                        heart.style.left=x+"px";
                        heart.style.top=y+"px";
                        heart.style.transform="rotate(45deg) scale("+heartsize+","+heartsize+")";            }

            function deleteheart()
            {
                       var hearts=document.getElementsByClassName("heart");

                       if (hearts.length>10)
                       {
                           for (i = 0; i < hearts.length; i++)
                           {
                                if (i<=5)
                                {
                                    document.getElementById("container").removeChild(hearts[i]);
                                }
                           }
                       }           
            }
        </script>


What the code here means is - if there are more than 10 hearts on the screen, start trimming the trail of hearts. But only trim off 6 at a time! Examine the code at your own leisure. You may want to do some additional reading.

JavaScript appendChild (http://www.w3schools.com/jsref/met_node_appendchild.asp)
JavaScript removeChild (http://www.w3schools.com/jsref/met_node_removechild.asp)

We're not done yet, though. You've only written the function deleteheart(), not called it. So call it like this, just under the line that calls makeheart().

            document.onmousemove=makeheart;
            setInterval(function(){deleteheart();},100);

Here we assign the deleteheart() function to an interval of 100 milliseconds. So the browser constantly checks for hearts and trims the trail accordingly. Refresh the browser, try it!

Just in case you feel the need to read even more extra material, here's a link for the JavaScript timing functions. (http://www.w3schools.com/js/js_timing.asp)

Final touches

Always room for improvement. We're going to add a little life to the trail of hearts.

First, we set the hearts to 50% opacity. So we can see each heart individually. Next, we're going to define an animation!

For more on CSS3 animations: (http://www.w3schools.com/css/css3_animations.asp)
        <style type="text/css">
            #container
            {
                background-color:rgba(254,200,150, 0.7);
                width:100%;
                height:100%;
                position:absolute;
                z-index:500;
                left:0px;
                top:0px;
                cursor:none;
            }

            .heart
            {
                background-color:#FF0000;
                position:absolute;
                z-index:1000;
                opacity: 0.5;
                filter: alpha(opacity=50); /* For IE8 and earlier */
                width:10px;
                height:10px;
                -webkit-animation: heartpop 0.5s infinite alternate; /* Chrome, Safari, Opera */
                animation: heartpop 0.5s infinite alternate;
            }

            /* Chrome, Safari, Opera */
            @-webkit-keyframes heartpop 
            {
                from {margin-top:5px;}
                to {margin-top:-5px;}
            }

            /* Standard syntax */
            @keyframes heartpop 
            {
                from {margin-top:5px;}
                to {margin-top:-5px;}
            }

            .heart:before,.heart:after
            {
                content:"";
                border-radius:50%;
                width:10px;
                height:10px;
                display: block;
                position:absolute;
                background-color:#FF0000;
            }

            .heart:before
            {
                margin-left:-5px;
            }

            .heart:after
            {
                margin-top:-5px;
            }
        </style>

The heartpop animation is set to repeat infinitely and reverse after each animation. Here, I'm just making the hearts bounce up and down, so I choose to alter the margin-top property.

This is what you should be seeing now!


Cool, eh? Just think, we used to have to write Java applets to do this!

Sincerely (with all my heart),
T___T