Temperatures as You Like

So here’s a short one for you: Do you like your temperatures expressed as °F, or °C?1

Well, there’s one fundamental issue with me writing like the way I have been. I can put, say, “I decreased temperatures by 20°F by cleaning the fans,” but if you’re a °C person, then you need to take a quick detour to convert that to units that you’re more familiar with. A common way to do this would be to notate that as “20°F (11.11 °C)”, which works, but I’m effectively stating myself twice, and hoping that I actually got my numbers right. Plus that opens up the possibility for writing °F (°C) one time, and °C (°F) another. So for basically no benefit except me getting to be proud of myself, let’s improve on that.

Here’s the end product: “After cleaning the fans, the internal temperature dropped from 26.667°C to 15.556°C .” See how they’re underlined? Click on one. That should toggle displaying temperature units in °F or °C, and since this is stored in your browser’s localStorage, that means it’s persistent across all pages! As with everything else in Hugo, there’s a two part solution: The HTML generation, and the code.

JavaScript


// Fired on clicking a temperature figure
function change_temp_unit() {
	var temp_in_f = (localStorage.getItem('temp_in_f') === 'false');
    localStorage.setItem('temp_in_f', temp_in_f); // Toggle F <-> C and store
	update_temps()
}

function update_temps() {
	var temp_in_f = (localStorage.getItem('temp_in_f') === 'true');

	// Default to displaying in °C if unspecified (aka never ran before)
	if (temp_in_f === null) {
	    localStorage.setItem('temp_in_f', false);
	    temp_in_f = false;
	}

	// Process each figure
	var temps = document.getElementsByClassName('temperature-reading');
	for (var i = 0; i < temps.length; i++) {
	    var temp = temps[i];
		var temp_c = parseFloat(temp.getAttribute('data-temp')); // ALWAYS in °C
		if (temp_in_f === true) {
			// Only run conversion math if requested
	        temp.innerHTML = (Math.round(((temp_c * 1.8) + 32) * 100) / 100).toString() + "°" + "F";
		} else {
			temp.innerHTML = (Math.round(temp_c * 100) / 100).toString() + "°" + "C";
		}
	}
}

// On load, run once to process everything
update_temps()

Pretty simple, really. A short event handler is registered as the onclick for every temperature item, and that handler will flip the boolean, save it, and then re-run the display math. The display math, after handling it’s single edge-case, will read every temperature on the page, and, if requested, run your basic Celsius to Fahrenheit conversion: 1.8T + 32. The extra weirdness in there is to round the display to exactly 2 decimal points, since JavaScript’s Math.round() only rounds to the nearest whole number. So, we take a result, say, 80.0118, multiply that to get 8001.18, round, 8001, and then divide to counter that multiplication: 80.01.

Finally, on the initial load, this function is called once, to set everything up correctly.

Shortcode

I defined this as the following snippet:

<span class="temperature-reading" style="border-bottom: 2px dotted" onclick="change_temp_unit()" data-temp="{{ .Get 0 }}"></span>

You’ll notice a few things:

  • I use a custom class, to allow for the JS to loop through them all
  • The onclick is set to the event handler defined above
  • The actual data is stored in an attribute, not in its own markup.

The last point is interesting: The actual reading you see has to be generated, since I leave the span tags empty in page generation. And since, if you look, that attribute is never modified, there’s never any successive rounding errors or anything from repeatedly switching back and forth.

Usage

Now if you read the code close, you’d see that I mentioned that all temperatures, as written, and therefore, the value of the data-temp attribute in the HTML, are in °C. Therefore, the above example was written like this:2

After cleaning the fans, the internal temperature dropped from {{< temp 26.667 >}} to {{< temp 15.556 >}}.

And with that, a very tiny, not really required accessibility was thus implemented: users may choose, for themselves, their preferred temperature units, without requiring me, the author, to take up extra page space putting both down.


  1. No, I’m not supporting Kelvin with this. Sorry, but if you want K measurements, just look it up… or use the formula, T + 237.15. I kid you not, K is °C, but 273.15 higher. ↩︎

  2. I use an extra place after the decimal here just because I wanted the °F representations to be a perfectly round 80 and 60, not 80.01 and 60.01 ↩︎