When the membership software people tell you that the HTML that their widget generates cannot be modified to accommodate your nested navigation lists, you override their code with JavaScript and make it do the thing you wanted it to do in the first place.
JavaScript Hacks: Ornamental Globes for the Holidays
With Holidays around the corner and being stuck in a long and boring WebEx I've decided to make a difference in my day and hacked together this UI gadget made out of globes on strings that you can drag and turn around (of course you need it).
There is no true holiday spirit until you're decorating with JavaScript ornamental globes. These didn't sell at the local store and Google shopping or Amazon failed on me too so just like everything good, home made is the answer.
Give it a try here, would suggest using Chrome for performance and this may work on your tablet and smartphones too, just slide, instead of mouse drag:
Ornamental Globes for the Holidays
If interested, read further on how to make something like this.
List of Ingredients
Before going much further, please look at articles like Playing With Spheres and 3D Surfaces Withouth WebGL. These have basics that won't be repeated here.
The main and only visual ingredient is globes. As mentioned in Playing with Spheres, this is a powerful element to play with in JavaScript when working on conveying an illusion or a sense of 3D. Make sure to use an image that has full Alpha transparency around it, will make a reference to it later.
For the coding ingredients, there is little new based on prior examples. Also note that whatever you see here, just like with the other samples, would have worked all the way back to the Internet Explorer 6 days.
So there is a need to draw (place) these globes into a "3 arm" configuration,
then to rotate this configuration around its center, first in 2D then in 3D.
A final step is to add the "spring" like mechanism that you see when you move the 3 arms, as well as some minor enhancements around the perception of speed when rotating the arms.
Drawing the Configuration
There are many ways to go about it and unlike a more generic approach used in the past with a proper 3D coordinates mechanism, there is a way to cheat perspective and work with a flat-like (2D) coordinate system.
Draw simply using Sin and Cos functions with each arm at 120 degrees from the next one. Use a fixed radius for each concentric set of globes and keep placing these outwards. In short, each element is drawn as an X:R*Cos(angle) and Y:R*Sin(angle). That's all there is to it.
Rotating the Configuration
"Moving" something visually is a step that's uncomfortable for many. In reality, your mind plays tricks on you, it's always simpler than you thin. If you've placed your globes using a nicely labeled structure of images and a proper loop, all that's left is to add a small Delta value to the angles. So changing R*Sin(120) to R*Sin(120+delta) and repainting everything will rotate the entire configuration around it's center. Increasing the delta with every redraw in a loop via SetInterval results in motion. Fine tune it to your liking and when tired of it, let's try the 3D version.
Moving from 2D to 3D can generally result in all sorts of problems based on what was started with. This example here is set up to avoid most problems, reflective globes are placed into a spherically symmetrical arrangement which gives all sorts of benefits.
The simplest way to introduce 3D is by including a second rotating angle (first being that "delta" above). Multiply this to the X component (Cosine) of all your coordinates, something like X:R*cos(120+delta)*cos(delta2). Turning this angle into a looping variable, you've achieved the illusion of 3D.
It does have problems though and one of them is the overlap as the globes move about. Thanks to the zIndex property of JavaScript, we're in luck. Determine a relationship between the positions of the globes at a given time and their relative "depth" placement. As the screen gets repainted, the proper zIndex is set on each element. Setting the display priority via zIndex is one those things that opened doors for 3D illusions in JavaScript. It was never meant for this I'm sure but that's what drives innovation, finding the unusual in an otherwise non eventful setting.
There are still two obvious problems at this point. One, if the globes were not PNG with Alpha transparency (as indicated earlier), then the result would be just white squares with drawings of globes around the screen. The second problem would be odd clipping around images. That gets resolved by placing the globes at the perfect distance from each other so there is just touch, but not overlap, or white space.
Done: a convincing 3D rotation. The limitation that is still present is no perspective correction on distances and sizes of objects (which I will leave as is because after all these are just ornaments for the holiday).
Imagine a picture of a hallway. If you measure the width of it on the paper, close to you vs the furthest end, the measurements are very different, however the hallway is the same width in reality. Also if there is a light switch far on a wall, it would be tiny vs one near you, which is again perspective related. But if you were holding a cube in your hand, or an apple, you really wouldn't be able to see that much difference in measurements. Small or close objects have almost no perspective to work with, that's often why abstract art fascinates your brain as you automatically try to resolve shapes into objects.
Should you have wanted to add perspective correction to this code you'd have been better of starting with a proper 3D coordinate system, as used in some of the previous articles.
"Spring" Like Motion
This can be simpler than what the visual response indicates, another signature of coding visual illusions. A tuned loop was used to draw all these globes then the angles were varied. What's next is to vary the radius on each concentric set of globes. Imagine adding and subtracting a bit every few times, would make them move outwards and inwards. So what's missing is a proper formula to give the spring feel. A bit of math comes into place here, a very important component if doing any kind of animation. All the organic or realistic feeling demos, websites, cartoons etc, rely heavily on non linear types of movements.
Spring-like motion involves varying the speed/acceleration as the object moves. A compressed spring being released moves much faster at first, then it slows down while reaching a fully extended state and this process repeats until it stops, just like a pendulum. In computer graphics, it's usually bad to control the "time" component, in other words you're rendering at 30-60fps and you don't want to change that just to simulate changes of speed. You translate that into modulating the distance accordingly, so the question to ask yourself is where would that object need to be in frame 23? This also avoids performance lag, for example you can rotate these globes really really fast and it feels as if they fly around on the screen, yet they skip frames, just like your vision processing does. In real life, if you take a picture at a nanosecond level of a fast moving object, the object is simply, "there". But not so with displays, the object only exists within the frames and your eyes just never know the difference.
Now that we're varying the distances and not the time, there are many functions to consider for that. A Cosine can do that, and in general one can do very well with a square polynomial or in the case here I've used a dampener type of function with constants that converges non-linearly from a start X0 to a finish X1. If Springs discussions do turn you on, don't forget to check Hooke's law.
Putting it All Together
Like everything else, the last 5% (or details) is what most of the results come from. This example could itself use hours and hours of more tuning, but I went on to practice what I preach and only spent enough time that I would otherwise use to browse the web or watch viral YouTube clips.
Allowing the user to drag or slide on a tablet is also involved here yet is not something innovative and worth describing. While not the simplest thing to do, Google search has you covered.
To conclude, fine tune all the parameters until you reach your perfect Holiday Ornamental configuration like I did with mine.
If you follow some of the "tricks" from Google around HTML5, more recently they're allowing you to type a mathematical formula in the search bar and that would get charted for you in 3D in the browser. So for example you could type:
sin(x*x+y*y)
And it will (should) show a pretty 3D visualization of the formula.
What's nice is that is HTML5, not Flash, which follows Google's general coding practices for client web. However, that's done using WebGL. That means lots of us won't be able to see it, and especially those on tablets or phones. Also, it has a feel of using a cannon to shoot a rabbit because WebGL is far more powerful than just drawing some 3D surfaces.
In my sample here I'm showing how you can generate 3D surfaces just as well without WebGL and still remaining fairly compatible with most browsers and hardware. As with many of my other examples, this one too could have been running well before HTML5. Take a look here at a
3D surface without WebGL
and read further if you're interested.
So How Is This One Made?
As mentioned in other JavaScript Hacks from the past, before attempting to code something like this, you need to identify if you have the basic ingredient in the platform you're intending to work with (platform being JavaScript in this case).
The key ingredient here is the ability to draw shaded polygons. Nothing more, nothing less.
Since I knew that there is a way to do that either through SVG or VML, that gave me the confidence to go forward and also support most browsers.
Let's break this down into incremental steps.
Drawing surfaces (or most 3D shapes ni general) comes down to being able to draw (and shade) triangles. Most elements can be broken down efficiently into that and even in some of the very expensive 3D rendering applications, all those smooth and shinny surfaces are in fact a multitude of tiny well coordinated and colored triangles.
That's not to say that you could not generate a shape from a bigger N-gon though you may lose details and performance. In this case, I actually went with polygons made of 4 points instead of 3, because it simplified a bit the coding and I was looking for a proof of concept only. One other downside worth mentioning is in 3D you can't guarantee that 4 points are in the same plane so this sample shows some of this problem as you move the surface around (happens as the surface turns "in or out").
But let's go even simpler because in the interest of keeping you close to the visuals I jumped the basics.
You always start drawing something in 3D just from points (dots, or once connected become vertices). The SIN function listed above, will provide you the points for third (3D) component, all you need to do is iterate over a an XY planar set of value.
The more dots, the better effect you obtain in visualizing the function. In my sample, I went for a set of X and Y from -5 to 5 in increments of 1, for a total of 25 dots. Sure you could draw your entire surface from dots, but would be extremely slow.
For the 3D basics in coordinates, you could use one of the previous samples at this point such as the 3D Rotating Spheres or the 3D Globe and just draw these points. The functions are actually copied over from there so they are the same.
The obvious problem is you won't have something pretty, would be hard to visually convey what the surface is.
So that's what this new sample brings in. You will see that a poly-line function has been defined to work both for SVG and VML. This then is called for every 4 adjacent points that the SIN function has generated (and the 3d coordinates system reduced to 2d).
You're not done though. You would generally start seeing a lot of overlaps, because most surfaces have their "back" faces and drawing all the lines between dots, will add to a messy image. Normally, in a 3D software package you're going to reach into so called "clipping". That's something you don't want to work out in JS because math aside, is too taxing on performance (remember, don't forget to always show the FPS as you code ahead).
What you'll do instead to solve this problem, is try to draw things from back to forward and fill (shade) the polygons with color. That way, the last drawn polygon ends up covering fully the overlapping section of the ones in the back. That's what I was counting as a key ingredient at the beginning of this sample, and without it, all the work would remain visually questionable.
What's left? add motion response to it based on your mouse coordinates. Just like in the previous samples, this is a fairly easy step yet highly rewarding visually, because now you can "turn" the surface in 3D. I've also added transparency which shows a nicer effect in some browsers such as Chrome which you should be using anyway.
That's all there is to it. Depending on the function you would choose to chart, you may also need to zoom it and scale it to present itself properly on the screen.