31 Jul 2013

HTML5 Lux Meter Tutorial

In this tutorial, I’m going to (try to) show you how to make a lux meter using HTML, CSS and a little bit of JavaScript. The JavaScript API we are going to be using is the DeviceLightEvent API; it’s an experimental API so it has relatively little support.

Unfortunately, the JavaScript will only work on Firefox on Mac, Firefox on Android or Firefox OS. Obviously your device will need to have a light sensor, but don’t worry, pretty much all Macs and Droids do. And if you’ve managed to get your hands on a Firefox OS device, then you’re probably already acquainted with what hardware you’ve got. Lucky devils.

View Demo

The CSS

Okay, let’s get started. First we’ll add a div tag with the class lux meter. This will be the main shape of the lux meter and will contain all of the other elements. We’ll need to set it as overflow hidden to mask out any shapes we put inside it, and use a little bit of CSS3 border-radius magic to get a sexy-looking shape.

[CodePen height=650 show=css href=IrfEL user=lukechilds ]

Now that we’ve got our basic shape, it’s time to add a little depth. If we add another div tag inside .lux-meter – let’s call this .lux-meter-inner – we can steal most of the styles from the .lux-meter class and change what we need to change to give it some edge.

[CodePen height=650 show=css href=eJEmI user=lukechilds ]

So we’ve basically just duplicated the lux meter shape inside of itself, made it smaller, made it transparent with a RGBA background colour and faded out the edges with a box shadow to give the illusion of a curved edge.

Now let’s add a little section for our screen to sit in. We’re just gonna create a huge circle and then position it way, way up to the top right. The overflow hidden on .lux-meter-inner will cut everything else out apart from the shape of the top of the lux meter, so where the two overlap, we’re left with a cool abstract-looking shape.

[CodePen height=650 show=css href=qspfr user=lukechilds ]

The orange kind of looks a bit flat just slapped on top of the grey, so let’s add a little indent effect. We can achieve this by creating another circle behind it, nicking some of the styles but making it much smaller and poking out of the bottom.

[CodePen height=650 show=css href=yJnor user=lukechilds ]

Now it’s time to add a screen to this bad boy. Nothing special going on here; I’ve used that awful greyish-green background colour that LCDs always seem to have, with a drop shadow to make it look like it’s sitting behind the plastic a little bit. This would be a good element to set our LCD font on so that everything inside it will inherit the font styles. I found an awesome free LCD font by a guy called Dusit Supasawat; you can convert it to a webfont kit over at Font Squirrel.

Normally you would just include the font files, but as Firefox won’t load fonts from another domain, I wont be able to include the font files in these examples. For the sake of the tutorial, I’ve done it properly in the Pen below, but all other Pens from now will have another @font-face rule at the bottom of the CSS containing the base64 encoded font to overwrite the normal styles.

[CodePen height=650 show=css href=bHckF user=lukechilds ]

We can now add a div inside our screen element to contain our text. To make it slightly more ‘LCDish’, give it a CSS3 text-shadow with no blur and some slight transparency. Notice how we are using an id to name this div rather than a class? This will make it much easier to update the value with JavaScript.

[CodePen height=650 show=css href=mKpaF user=lukechilds ]

Now let’s add a bit more of a shiny glass/plastic look to the whole screen. We can do this by creating another massive circle on top of the .screen-surround (the orange bit) and moving it up a bit. If we then give it a radial gradient going from completely transparent at about 90% away from the center of the circle, to slightly transparent at 100% away from the center, we get a pretty ‘applesque’ light glare effect.

[CodePen height=650 show=css href=fBvjd user=lukechilds ]

Finishing touches now. Let’s add a little orange knobbly bit to the bottom, because why not? Use the same technique as we used for the screen surround, but add the element directly inside .lux-meter, not .lux-meter-inner, so it appears to stretch around the bottom.

[CodePen height=650 show=css href=oyxJL user=lukechilds ]

Finally, what would a lux meter be without a strange name with lots of numbers? Slap that name on.

[CodePen height=650 show=css href=xIzJv user=lukechilds ]

Ok, now you’ve mastered the CSS, it’s time to implement the JavaScript.

The JavaScript

First off, if you’re a JavaScript novice, don’t worry. This API is ridiculously easy to use. We will go slightly more in depth with formatting the numbers and handling large numbers, but just getting the lux meter to display the value is so simple.

First of all we need to define the global variable ‘screenValue’. ‘screenValue’ is the HTML element with the id ‘value’; it holds the numbers in the screen. Now, by adding an event listener to ‘devicelight’ and passing the event object through, we can set the content in ‘screenValue’ to the value of the event.

[CodePen height=650 show=js href=DjHKJ user=lukechilds ]

BOOM! You just used the DeviceLightEvent API. I told you it was easy.

Now that’s all fine and dandy, but it would look a bit cooler if there were always four digits. So 8 would become 0008, 16 would become 0016 and 128 would be 0128 etc. That way, the LCD font looks cool because you just see certain parts of the LCD display disappear/appear to change into different numbers. We can do this fairly easily. We’re going to need to define another global variable. We’ll call this ‘lux’ and this is going to have the final value written into it.

Next in the listener function, we need to define ‘luxRaw’. This is going to hold the raw unformatted lux value as a string. Then we can count the length of the string. If it’s less than 4, however many digits less than 4 the value is, we set ‘lux’ as that amount of zeros. Then we append ‘luxRaw’ to ‘lux’.

[CodePen height=650 show=js href=lpoCg user=lukechilds ]

That’s looking much better. I don’t know whether you’ve noticed, but whenever there’s a ‘1’ in the value, it messes the LCD effect up. All the characters in the font take up the full space of an LCD character, apart from the number 1. Because it only takes up the two bars on the right hand side of an LCD character, the actual character in the font only takes up that same amount of space. This means that if there’s a number 1, the characters to the left of it appear to jump to the right. There’s no real way of fixing this; ideally the font would have the ‘1’ character sized at the same width as all of the others with the actual ’1′ glyph occupying the right hand side of that space. But it doesn’t.

There is a cheap, dirty fix though. The missing space a ’1′ creates is about the same width of a space. Not exactly, but it’s pretty close. You can still notice the slight shift of characters when there’s a ’1′ but only just. So all we need to do is, after we’ve formatted our lux value to be four digits, check if it contains any ‘1’s and if it does, add a space before them. We can do this by adding a tiny little function on the end of ‘lux’ as we’re setting it as the ‘screenValue’ text.

[CodePen height=650 show=js href=nxyzI user=lukechilds ]

Now we’ve made sure it’s gonna increase the number to four digits and we’ve sorted out the ’1′ spacing issues, but what if the value is more than four digits? We don’t want to display a number with more than four digits so we’ve got room on the screen to add more functionality for other things. But if we just cut off the digits, the lux meter will be producing incorrect readings. We need a way of notifying the user that they are past the character limit. We could do this by displaying dot at the top right of the number, kind of like on a calculator.

So let’s add another element above #value and give it the id ‘too-big’. We can style this similarly to how we styled the text, using box-shadow instead of text-shadow to give it an LCD effect. This needs to be set as ‘display none’ so it’s hidden by default. We then need to define two more global variables. ‘luxTooBig’ and ‘tooBigNotifier’. ‘luxTooBig’ is a Boolean. It’ll either be set to true or false. ‘tooBigNotifier’ is the HTML element we need to display if the value is too big. Now we just need to slightly modify our existing else statement from when we checked how long ‘luxRaw’ was. We need to check if ‘luxRaw’ is larger than four. If it is, we need to set ‘lux’ as the first four digits of ‘luxRaw’ and set ‘luxTooBig’ as true. We need to modify our other statements so that if ‘luxRaw’ is equal or less than four,  ‘luxTooBig’ will be set as false. Finally, after we’ve written ‘lux’ to the document, we need to check if ‘luxTooBig’ is true. If it is, we need to set ‘tooBigNotifier’ to display block. If it isn’t, it needs to be set to display none.

[CodePen height=650 show=js href=sqDAm user=lukechilds ]

There you have it, a cool HTML5 Lux Meter. Feel free to comment below if you have any questions.

The authors

Becca McLaughlin
Developer