Blog
Posts tagged with “play”
Analogue flip-clock wiith CSS3 and jQuery
After creating pie charts and international flags with CSS3's border-radius and transform:rotate, I figured I'd try the other transformations available; specifically, skew and scale. By combining these two features with a bit of jQuery to animate, I created a rather nifty retro-styled analogue flip-clock.
Now, this is just a proof of concept, but it could fairly easily be turned into a count down clock, or dynamically incrementing "total donations" type display. To show this functionality, I've added a reset to start the clock at 12:00;00 am, making it flip forward to the current time.
As with the other CSS3 experiments, it currently only works in Firefox, Google Chrome, and Safari (which loses the rounded corners due to an interaction bug with transform-origin and border radius) UPDATE and Opera 10.5. One the nice thing about this experiment, as opposed to the other two, is that the clock still works in IE, even though the flip animation is missing.
Creating Pie Charts with CSS3
After playing around and creating flags with CSS3, it dawned on me that the same methods used there could be used to create Pie charts. Keep in mind that this technique is currently cutting-edge. It only works in the latest versions of Firefox, Chrome,and Safari UPDATE and Opera; and requires browser-specific extensions to CSS to pull off, but it does use elements in the current CSS3 specification, so it stands that eventually the rest of the web will catch up.
First off, you need to draw a circle, which is easy enough, simply create a square <div> and set border-radius to be half it's height/width
.circle {
position:absolute;
background-color:red;
width:200px;
height:200px;
-moz-border-radius:100px;
-webkit-border-radius:100px;
border-radius:100px;
}
Next, we have to cut that in half. Normally, one would smply draw a half circle like so:
.half-circle {
position:absolute;
background-color:red;
width:100px;
height:200px;
-moz-border-radius:100px 0 0 100px;
-webkit-border-radius:100px 0 0 100px;
border-radius:100px 0 0 100px;
}
However, this method becomes problematic, since we'll have to rotate it. The half-circle above would rotate at it's centre (left-50,top-100). Combine that with the difference in width and length, it would require a lot of horizontal shifting to ensure the centres line up properly. That's a bunch of math or annoying trial and error. Thankfully, there's an easier way. Draw a full circle and use the old-school clip property to only show half:
.pie {
position:absolute;
width:200px;
height:200px;
clip:rect(0px,100px,200px,0px);
-moz-border-radius:100px;
-webkit-border-radius:100px;
border-radius:100px;
}
NOTE: you could use the original half-circle method and set the CSS3 transform-origin property to right, center to move the rotation point. But experimentation with this method revealed that using transform-origin in Safari caused that browser to ignore the border-radius setting (in Safari ver. 4.04 on Windows at least). So for now, stick with full circle and clip.
Now we have a half circle that will rotate around the centre of it's flat edge.
Next, we need to hide it in a way that allows us to show only the part we need to see. So we drop it into another square <div> and clip it too, to display the opposite half.
.hold {
position:absolute;
width:200px;
height:200px;
clip:rect(0px,200px,200px,100px);
}
We're clipping the hold <div>, because we need it to rotate around the same point as the circle.
now we stack all the pie elements on top of each other, and rotate the pie pieces by their appropriate percentage amount — (360*(x*100)) where x is the percentage value — and also rotate each hold div the cumulative amount of each previous pie piece's rotation. So given the following html:
<div id="piece1" class="hold">
<div class="pie"></div>
</div>
<div id="piece3" class="hold">
<div class="pie"></div>
</div>
<div id="piece3" class="hold">
<div class="pie"></div>
</div>
we can add the following CSS to create a pie chart with three equal pieces:
#piece1 {
}
#piece1 .pie {
color:red;
-moz-transform:rotate(120deg);
-webkit-transform:rotate(120deg);
-o-transform:rotate(120deg);
transform:rotate(120deg);
}
#piece2 {
-moz-transform:rotate(120deg);
-webkit-transform:rotate(120deg);
-o-transform:rotate(120deg);
transform:rotate(120deg);
}
#piece2 .pie {
color:green;
-moz-transform:rotate(120deg);
-webkit-transform:rotate(120deg);
-o-transform:rotate(120deg);
transform:rotate(120deg);
}
#piece3 {
-moz-transform:rotate(240deg);
-webkit-transform:rotate(240deg);
-o-transform:rotate(240deg);
transform:rotate(120deg);
}
#piece3 .pie {
color:blue;
-moz-transform:rotate(120deg);
-webkit-transform:rotate(120deg);
-o-transform:rotate(120deg);
transform:rotate(120deg);
}
Now, the more astute readers will notice that this works great for pie pieces that are 50% of the pie or less. How can you draw larger pieces? There are two methods. The easiest is to simply draw a full circle and then overlay the other pieces on top. But if you want a discrete piece that you can potentially move out for emphasis, you'll need to do two things: remove the clip on the hold <div>, and add a second pie piece as filler.
.hold.gt50 {
clip:rect(auto, auto, auto, auto);
}
.pie.fill {
-moz-transform:rotate(180deg) !important;
-webkit-transform:rotate(180deg) !important;
transform:rotate(180deg) !important;
}
That's it.
Pure CSS3 Canadian Flag (and a few others)
I happened upon a few impressive international flags made out of XHTML and CSS through Smashing Magazine's twitter feed and noticed that there was a certain flag near and dear to my heart was missing. So I created a pure CSS3 Canadian flag.
As you might be able to tell, I found it easier to draw the white outline around the center leaf, instead of the leaf itself. It's done primarily with border-radius and transform:rotate CSS3 properties, so it only works with the latest versions of Firefox, Safari (which does the best job of rendering it) and Chrome right now. UPDATE 2010.03.02: It works in just released Opera 10.5 now too. I had to add the browser-specific extention for rotate, but it works.
This was so much fun, I decided to do a few others:
The Macedonian CSS3 Flag. - This is barely CSS3 as it only uses border-radius for the center. It looks best in Firefox, but works relatively well in Safari and Chrome too.
The Kenyan CSS3 Flag. Which is actually more impressive than the Canadian flag, if I say so myself. It looks awesome in Firefox and Chrome. Oddly, it failed badly in my version of Safari (4.04 Windows) though. I think it has to do with the fact that I'm combining the border-radius property and a bit of rotating with some old school clip'ing It appears that Safari doesn't yet support the dual value ( r1 / r2 ) eliptical border-radius sttings.
And for those of you using IE, here's some classic CSS flags to look at:
Recreating Grant Skinner's sphereTest Part 3 — actually getting it done the easy way.
After a massive amount of experimentation, trying to recreate Grant's Skinner's original sphereTest using the displayObject class's rotationY, rotationX and rotationZ properties, I realized that:
1) this was a royal pain in the ass, and
2) there had to be an easier way to do it.
That easier way was the Matrix3D, and Vector3D objects. Once an object had been positioned in 3D space by giving it a z position, Flash lets you manipulate it in 3D space via <object>.transform.matrix3D. Not only that you can get a Matrix3D object that relative to any other object on the stage, via var rel3D:Matric3D = <object>.transform.getRelativeMatrix3D(<RelativeObject>);. So I could position each disc in the sphere object and simply rotate them incrementally with disc.transform.matrix3D = rel3D.appendRotation(degrees,[Vector3D.X_AXIS|Vector3D.Y_AXIS]);. The number of degrees to rotate and which axis to rotate around can quickly be calculated by getting the relative position and distance of the mouse pointer from the center of the sphere. Not only that, the true z position, needed for stacking of the object is available through rel3D.position.z. Bang. Dead simple. I even simplified the stacking by creating 2 container objects for each original z position — one for the front of the sphere and one for the back — that were pre-stacked at creation time. With those there, I was able to move each disc into the appropriate container immediately after rotation, instead of sorting the array and re-iterating to stack. This also allowed me to drop in the larger inner-sphere object between the sphere half containers and just leave it there to do nothing but look pretty. What had taken literally days of trial and error previously, was pounded out in about an hour and a half.
Done. Easily done. Too easily in fact. In order to justify my earlier blind muddling, I felt I need to do something cooler than just redoing Grant's original work. So I used Google to find global land cover information by latitude and longitude, did some rough calculating to find relative diameters of each longitude (Using the Vector3D.distance static method, actually) and made this funky spinning globe:
Now, there's a lot more points to rotate in this one, so I slowed down the frame rate to make sure the math keeps up, but all in all I feel vindicated.
Mostly.
Recreating Grant Skinner's sphereTest Part 2 — almost figuring it out the hard way.
Working off the tests I did previously to try and recreate Grant Skinner's original sphereTest, I drew a bunch of discs, moved them out along the Z-axis randomly between min and max values, and distributed them randomly along the X and Y axes using the rotationX and rotationY attributes. Then I incremented each disc's rotationY value with the onEnterFrame event.
Obviously, the stack order would be need to be worked on, but not a bad start. To get the stack order, I needed to find the relative position of each disc along the Z-axis. To do this, I used the Z position as a circle's radius, and derived approximately how many pixels of movement each degree of rotation along the X axis represented. Once I found that new value, I'd do the calculations again for the Y rotation. To cut down on per-frame math, I figured out the z-position relative to X rotation immediately, and stored it since it wouldn't change. I only did the position relative to Y when needed. Also, I only approximated the Z position by dividing the diameter values by 180 (or, multiplying by 0.005555555556, which is faster and results in the same value), instead of mucking about with the position along the arc. It wasn't exact, but it was a good enough value to sort on. once I had the relative position, Discs that were relatively "closer" to the viewer were then sorted to appear in front of ones that weren't. This involved iterating through the discs to change their Y rotation, sorting the disc array on their derived relative value, and re-iterating to do the stacking. Not great, performance-wise, and still a little jumpy at the poles, but it worked.
To make the stacking appear smoother I ensured that "closer" discs that had an initial maximum Z position were always stacked in front, of other discs, then worked back until the "farther" maximum Z discs were sorted to the back. Next, I made the entire sphere "follow" the mouse. I did this by calculating the angle of the line from the mouse's position and the center of the sphere relative to the x-axis (non-trivial math, to be honest -- at least for me) and rotating the entire sphere around its Z-axis to make the disc's Y rotation move towards the mouse.
This looked fairly good to me. Then I went back to Grant's sphereTest and noticed that his sphere wasn't roting along the Z-axis. Each individual disc simply moved towards the mouse regardless of it's position relative to the Y-axis "pole". It was as if the sphere's Y-axis was moving independently of the discs. Actually, it looked as if they were moving around fixed X and Y axes simultaneously. But using each disc's rotationX and rotationY attributes meant the discs' X-axes were all over the map. My initial thought on how to emulate this behaviour was, oddly enough, quite complex. I thought that I would need rotate the sphere towards the mouse around its Z-axis; then correct that Z-rotation by moving the discs in the opposite direction around their own z-axis; then spin the entire sphere around it's own y-axis. Once that was done I'd need to calculate the relative Z of each disc based not only on their internal rotations, but on also on the sphere's rotations as well.
In short, a metric shit-load of math.
For each disc.
For every frame.
Not good.
Then I found the 3DMatrix object in Adobe's Flash CS4 documentation; Swore out loud; and threw out most of my work to this point. I'll let you know what I replaced it with in my next blog post.
