It's common to see data presented in a tag cloud formatβwhich is to say, a chunk of keywords or terms displayed inline, with each term sized to show its relative importance or frequency out of all the existing terms.
A lot of times we see these tag clouds built into content management systems or generated via plugins, but how do we make something like this if we want to do it from scratch? In this tutorial I'll walk through how I built this feature for my own website, to display the relative amounts of time I've worked with different technologies.
Setting up
I tried to keep the markup pretty simple:
<ul>
<li data-year="2001">HTML</li>
<li data-year="2002">CSS</li>
<li data-year="2003">PHP</li>
<li data-year="2010">Javascript</li>
<li data-year="2012">Ruby</li>
<li data-year="2010">Python</li>
<li data-year="2017">Node.js</li>
<li data-year="2010">MySQL</li>
</ul>
It's a simple unordered list. The only thing here that's special is that each <li>
has a data-attribute, data-year
, which denotes the year I started working with that particular technology. If you were creating a tag cloud for the number of articles with a given tag on your blog, you might instead call the data-attribute data-count
, and set it to the number of articles with that tag.
Moving on to the styles, again keeping it pretty simple. Mostly I stripped out the default formatting, aligned the content to the center, and set list-items to display: inline-block
so they coalesce into one block of text.
ul {
list-style: none;
margin: 0 auto;
padding: 0;
text-align: center;
}
ul li {
margin: 0 5px;
display: inline-block;
vertical-align: middle;
}
The Scripting
First, let's wrap everything in an event handler for the window's load
event, just to make sure everything's in place before we start applying our font-sizing. I'm using a bit of jQuery here to speed the process along, but there's no reason you couldn't do it in vanilla Javascript.
$(window).on('load', function() {
//...
});
If your font sizes change at certain screen size breakpoints, you may also want to re-trigger this on resize
as well as load
.
Now that we've got that done, we need to get the range of numbers represented in our tag cloud.
var nums = $('ul li').map(function() {
return parseInt($(this).data('year'));
}).get();
var maxVal = Math.max(...nums);
var minVal = Math.min(...nums);
The map
function iterates over every list item and returns the value of the data-year
attribute, parsed as an integer; the .get()
method formats the output into an array.
We then pass the numbers into Javascript's Math.max
and Math.min
functions to get the largest and smallest values, respectively. (nums
preceded by the ...
to denote that it should be read as an array.)
Now, we'll calculate the sizing for the fonts.
var currentDate = new Date();
var currentYear = currentDate.getFullYear();
var baseFont = $('ul li').css("font-size");
var fontsplit = baseFont.match(/([0-9\.]+)\s?([a-z\%]+)/);
var minFont = parseInt(fontsplit[1]);
var maxFont = parseInt(fontsplit[1])*3;
var fontUnits = fontsplit[2];
In this case, we're getting the value of the current year since we want to have the program do the math on how long I've worked with a technology. If you're getting something like a number of blog posts or inventory count instead, you can skip that step!
Then we get the base font size from the CSS. It comes with the units, so I've inserted a regular expression to match a number and a unit abbreviation. The current font size becomes the minimum font size for the tag cloud, assigned to minFont
; the maximum font size is the minimum times three. You can adjust these to tasteβfor example, if you want your minimum to be 80% of the base font size, you'd set minFont = parseInt(fontsplit[1])*.8
.
Now it's time to actually apply the font sizes!
$('ul li').each(function() {
var itemYear = parseInt($(this).data('year'));
if (itemYear) {
var num = currentYear - itemYear;
var fontSize = (((maxVal - itemYear )/(maxVal - minVal)) * (maxFont - minFont)) + minFont;
$(this).css("font-size", fontSize+fontUnits);
$(this).attr("title", (currentYear - itemYear)+" years");
} else {
// if we can't determine the year, just set it to 90% size
$(this).css("font-size", (minFont*.9)+fontUnits);
}
});
});
First it performs a quick check to make sure that data-year
is actually set before trying to access it. Then we do a little math, subtracting the value of data-year
from the current year to determine the years experience (again, this step is skippable if you're not trying to determine years since).
We determine the font size by figuring out what percentage the current number is between the minimum and maximum value, multiplying that by the difference between maxFont
and minFont
, and then adding that to minFont
. We then set the css font-size
value to that number and tack the units back on at the end.
Also, just to make sure that the information is represented in a way that's accessible to non-visual media, we set the list item's title attribute to "[N] years."
Final Product
All of this adds up to a result that looks a bit like this!
You can also see a live data version on my personal website if you scroll down to the bottom.
Top comments (0)