Reading Time
5 minutes 46 seconds average read (1154 words)So recently I've been building a blog for my partner and I've used Squiz Matrix to do so. I decided it would be a good idea to use my new found JavaScript skills to achieve this. When I finished it I showed it to one of the developers at Squiz and he said: "you know you can do that with Squiz Matrix Keyword Replacements and Modifiers?"
So here I'm going to detail how to achieve the Reading Time with both.
Part 1 Method
Throughout my learning of JavaScript through Wes Bos's course, I've learn that breaking the problem down into chunks makes it easier to solve, so using this I broke down the task into these blocks:
- Find out the Average Reading Speed, this varies on:
- the type of content, technical content takes longer than normal reading considerably
- the type of reading, skimming is way faster than reading for comprehension
- the readers ability, children read slower than adults, the language may not be the readers first language
- I've settled on 200 words per minute in this case, based on this post by the British Psychological Society.
- Count the words on the page and assign it to a
numWords
variable, I've chosen to use the<main>
element for the words to count. - Divide the
numWords
by WPM to work out the time. - Round the time to 2 decimal places.
- Insert into the page:
- Time
- Word Count
Part 2 Using JavaScript
Average Reading Speed
Set a variable with the average reading speed of 200 WPM, this will be set as a const variable as it is not going to change.
const wordsPerMinute = 200;
Count words in the <main>
element
Grab the content of the <main>
element.
// grabs all the content in the <main> element const content = document.querySelector('main');
Count the number of words in the content
variable splitting it on spaces. This grabs the innerText
from content, split
s it into an array
at each space and then outputs the length
of the array, how many items are in the array.
// counts number of words in the content const numWords = content.innerText.split(' ').length;
Divide numWords
by wordsPerMinute
Create a result
variable to store the time in minutes, seconds and number of words, this is done with a let
variable because later it will be updated.
// sets up a result to inject into the page let result;
check that the numWords
is not 0 and that there are actually words on the page.
if(numWords > 0){ // checks to see that there is actuallt some content //code goes here to be run if numWords is greater than 0 (zero) }
Create a let variable called time
to store numWords
divided by wordsPerMinute
.
let time = numWords / wordsPerMinute;
Add the new variables to the result variable
Using backticks and interpolation to create the value of the result variable. In here I'm also rounding time
to 2 decimal places using toFixed(2)
.
result = `~${time.toFixed(2)} min read (${numWords} words)`;
Insert Result into the page
In the page I have a span
element with the class reading-time
.
<span class="reading-time"></span>
I am setting the innerText
of that element to be the value of result
variable.
document.querySelector('.reading-time').innerText = result;
Full code block
// grabs all the content in the element const content = document.querySelector('main'); //counts number of words in the content const numWords = content.innerText.split(' ').length; // Average reading speed. const wordsPerMinute = 200; // sets up a result to inject into the page let result; // checks to see that there is actually some content if(numWords > 0){ let time = numWords / wordsPerMinute; result = `~${time.toFixed(2)} min read (${numWords} words)`; } document.querySelector('.reading-time').innerText = result;
Part 3 Using Squiz Matrix Keyword Replacements and Modifiers
Count words in the <main>
element
In Squiz Matrix, this is the contents of the asset, in the way I've built the blog so I can use the keyword %globals_asset_contents_raw%
, this keyword shows just the contents with no Paint Layout applied, with the keyword modifier ^wordcount
.
%globals_asset_contents_raw^wordcount%
Divide numWords
by wordsPerMinute
to get the minutes
This time I'm going to grab only the minutes and grab the seconds later. To do this I'm going to use ^divide
and ^floor
modifiers.
The ^divide
modifier takes a number to divide by, and I'm using the WPM, so ^divide:200
.
The ^floor
modifier rounds the number down to the integer, with on decimal places, hence giving us the minutes.
%globals_asset_contents_raw^wordcount^divide:200^floor%
Grab the remainder and convert to seconds
To achieve this I'm going to get the raw value of minutes as seen in the step previously without using ^floor
and then ^subtract
the minutes from it. This will give me a fraction of minutes, which I can then ^multiple by 60 to get the value in seconds.
Get full time
%globals_asset_contents_raw^wordcount^divide:200%
^Subtract
minutes from it
Here I am subtracting the previous value using the ^subtract
modifier, because I am inserting a keyword into another keyword I need to do this with curly brackets {}
.
^subtract:{globals_asset_contents_raw^wordcount^divide:200^floor}
Full Keyword so far
%globals_asset_contents_raw^wordcount^divide:200%^subtract:{globals_asset_contents_raw^wordcount^divide:200^floor}
^multiply by 60 to get the seconds
Here I am ^multiply
ing the value by 60 and then using the ^round
keyword modifier to either round the number up or down to an integer.
^multiply:60^round
Full Keyword
%globals_asset_contents_raw^wordcount^divide:200^subtract:{globals_asset_contents_raw^wordcount^divide:200^floor}^multiply:60^round%
Insert into the page
Now that I have everything I can insert it into the page, inside a <span class="reading-time"></span>
element.
This will output minutes, seconds word count, e.g. 2 minutes 30 seconds (500 words):
%globals_asset_contents_raw^wordcount^divide:200^floor% minutes %globals_asset_contents_raw^wordcount^divide:200^subtract:{globals_asset_contents_raw^wordcount^divide:200^floor}^multiply:60^round% seconds read (%globals_asset_contents_raw^wordcount% words)
Conditions
I have decided to put in some conditions to check:
- if the minutes are greater than or equal to 1, if so show the minutes, if not only show the seconds
- if the number of minutes is greater than 1 add an 's' to the end of the word minute making it minutes
Number of minutes is Greater than or equal to 1
%begin_globals_asset_contents_raw^wordcount^divide:200^floor^gte:1% If True // show minutes and seconds %else_globals_asset_contents% If False // show seconds only %end_globals_asset_contents%
Number of seconds is Greater than 1
minute // print the word minute %begin_globals_asset_contents_raw^wordcount^divide:200^floor^gt:1% s // if there are more than 1 minute add an 's' %end_globals_asset_contents%
Full keywords with conditions
// Greater than or equal to 1 true %begin_globals_asset_contents_raw^wordcount^divide:200^floor^gte:1% %globals_asset_contents_raw^wordcount^divide:200^floor% minute // minutes greater than 1 true %begin_globals_asset_contents_raw^wordcount^divide:200^floor^gt:1% s // print 's' %end_globals_asset_contents% %globals_asset_contents_raw^wordcount^divide:200^subtract:{globals_asset_contents_raw^wordcount^divide:200^floor}^multiply:60^round% seconds read // print seconds // if less than 1 minute %else_globals_asset_contents_raw% %globals_asset_contents_raw^wordcount^divide:200^subtract:{globals_asset_contents_raw^wordcount^divide:200^floor}^multiply:60^round% seconds read // print seconds %end_globals_asset_contents_raw% // print number of words (%globals_asset_contents_raw^wordcount% words)