How to Create a Tag Cloud With JavaScript and CSS
A tag cloud is a visual depiction of textual data. It uses varying font sizes to convey the importance, priority, significance, weight etc. of the data it represents.
This is a tutorial on how to build a tag cloud with pure JavaScript and CSS.
THE PLAN
Before jumping into the JavaScript and CSS, I think its best to understand what we will be doing.
The only HTML tag we need for making our tag cloud is, <ul>
. And to make it unique, we will give it an id
with the value "tag-cloud"
.
<ul class="tag-cloud"> </ul>
We will use JavaScript to populate this tag with the contents from this JSON file. The JSON file contains details like the tag title, the URL, and a list of article titles. Shown below is one entry from the JSON file:
{ "title": "Fortran", "url": "https://example.com/tags/fortran", "articles": [ "Fortran article one", "Fortran article two" ] }
We will use AJAX to fetch and process the JSON file. We need to make an <li>
entry inside <ul id="tag-cloud">
for each entry in the JSON file and set the proper font size for it depending on the number of articles that particular tag name has. Essentially, we want all our <li>
elements to look similar to this,
<li> <a href="https://..." style="font-size: 1.1em"> Fortram [2] </a> </li>
THE JavaScript
First, let's create some variables.
var jsonURL = "https://gist.githubusercontent.com/reiri-k/94ea88d5709f32711555c1dd73a62d0f/raw/d0550f4d39d40eac0550922133f983e02915b1da/tags.json" var ulTag = document.getElementById("tag-cloud") var minFontSize = 1 var maxFontSize = 2 var liTags = "" var weights = []
The minFontSize
and maxFontSize
sets the font size (in em) of the smallest and largest tag in our tag cloud. The liTags
variable is for holding all the <li>
entries that we will put inside <ul id="tag-cloud">
. And finally, the weights
variable will hold an array of weights of tags.
Note: The weight of a tag is the number of articles it has. So, the weight of a tag with only 1 article is 1. And the weight of a tag with 12 articles is 12.
THE AJAX REQUEST
We will be using pure JavaScript for our AJAX handling. If you're totally unfamiliar of the old sacred ways, it is recommended that you take your time to read and understand it.
Extra Reading: Ajax without Jquery
var ajax = new XMLHttpRequest() ajax.open('get', jsonURL) ajax.addEventListener('load', (e) => { // EVERYTHING HAPPENS IN HERE }, false) ajax.send()
We start by populating the weights
array. This variable is needed for calculating the font size later. We can't have duplicate values in it, and it should be sorted in ascending order, from the least to the highest weight.
jsonData = JSON.parse(e.currentTarget.response) // populating weights jsonData.forEach((result) => { numberOfArticles = result.articles.length if (!weights.includes(numberOfArticles)) { weights.push(numberOfArticles) } }) // sorting contents of weights in assending order weights.sort((a, b) => a - b)
Next, we calculate the font size, generate all the <li>
elements and stuff them inside <ul class="tag-clouds>
. We calculate the font size by normalizing the weights of the tags and then scaling them to values between minFontSize
(1em) and maxFontSize
(2em).
// generating <li> tags and putting them in 'liTags' jsonData.forEach((result) => { title = result.title url = result.url numberOfArticles = result.articles.length m = weights.indexOf(numberOfArticles) + 1 a = ((m - weights[0]) / (weights.length - weights[0])) b = (maxFontSize - minFontSize) c = minFontSize font_size = a * b + c liTags = liTags.concat( `<li> <a href="${url}" style="font-size: ${font_size}em;"> ${title} [${numberOfArticles}] </a> </li>` ) }) /* end of jsondata.forEach() */ // inserting generated <li> tags into <ul> ulTag.innerHTML = liTags
If anyone is curious about the formula used to get the font size:
$$ \frac{w-w_{\text{min}}}{w_{\text{max}}-w_{\text{min}}}\times (t_{\text{max}}-t_{\text{min}}) + t_{\text{min}} $$Now, the complete AJAX request would look like this,
var ajax = new XMLHttpRequest() ajax.open('get', jsonURL) ajax.addEventListener('load', (e) => { jsonData = JSON.parse(e.currentTarget.response) // populating weights jsonData.forEach((result) => { numberOfArticles = result.articles.length if (!weights.includes(numberOfArticles)) { weights.push(numberOfArticles) } }) // sorting contents of weights in assending order weights.sort((a, b) => a - b) // generating <li> tags and putting them in 'liTags' jsonData.forEach((result) => { title = result.title url = result.url numberOfArticles = result.articles.length m = weights.indexOf(numberOfArticles) + 1 a = ((m - weights[0]) / (weights.length - weights[0])) b = (maxFontSize - minFontSize) c = minFontSize font_size = a * b + c liTags = liTags.concat( `<li> <a href="${url}" style="font-size: ${font_size}em;"> ${title} [${numberOfArticles}] </a> </li>` ) }) /* end of jsondata.forEach() */ // inserting generated <li> tags into <ul> ulTag.innerHTML = liTags }, false) ajax.send()
THE CSS
As for the CSS, for giving you more freedom to experiment with, I will keep it nice and clean with nothing unnecessary.
#tag-cloud { display: block; } #tag-cloud li { display: inline-block; padding-right: 20px; } #tag-cloud li:nth-last-child(1) { padding-right: 0px; } #tag-cloud li a { text-decoration: none; color: grey; } #tag-cloud li a:hover { color: black; }
FINAL RESULT
Here is a preview of what we have created. If you like it, use JSfiddle to fiddle around with the source code. Experiment and learn new things!
That is all! Creating a simple and functional tag cloud from scratch with pure JavaScript and CSS is this simple and easy.