Build Command-Line Spinners in Node.js

Build Command-Line Spinners in Node.js

  • 250

we saw how to implement a progress bar in the terminal using Nodejs. Here, we will continue with the CLI streak and implement spinners in the terminal using Nodejs.

The Concept

The question is how do we make something like Material Design, Bootstrap progress-bars in a terminal. It seems impossible but it could be done.

In my previous article, we know that the terminal is divided into cells in an x-y plane like a graph with x and y-axis.

It starts with (x, y) (0, 0) in a positive plane. The terminal by default starts at 0, 0 i.e the cursor is placed at 0, 0. The cursor current position determines where data will be written to next.

If we place the cursor at (x, y) (9, 5), data will start from the (x, y) (9, 5) position. And this can be done with the readline API readline#cursorTo(stdout, int x: Number, int y: Number) in Nodejs.

Now, we have this knowledge.

To have a spinning line effect like this:

This is image title

We know to spin a line, we start with this -, then anticlockwise, we have \, then | and last /. Then we start again from - to /. Now if we can do the above pretty quickly we will have a spinning effect in our terminal.

- \ | /

So all we have to do is to write -,\,|, / in the same cell rapidly.

To do this in JavaScript, first, we will hold the -,\,|, / in an array. We will set up an index variable to hold the current index position in the array. Then we will set up a time interval with the setInterval API.

We will give a time of 100ms, this is to make it execute the function callback very fast to achieve the spinning effect. The function callback will retrieve the current line type from the array using the index we declared previously. Then we write the line type with the process.stdout.write API. Using this API will make the cursor to advance to the next cell, no we don’t want that. So, we use the readline#cursorTo API to set the cursor back to the previous cell, so on the next call, the next line type in the array will be written to the same cell.

So with all these executing at speed 100ms, we will see the spinning effect.

Making the spinner in Nodejs

Scaffold a Node project, open the index.js file and add the following code:

This is image title

Run the file to see the effect:

node . 

This is image title

Adding many Effects

Let’s go stylish. We can’t have the only effect ['-', '\', '|', '/']. We can make our Spinner class display different effects, to do that we will create a spinners.json file.

This will hold different effects:

spinners.json:

This is image title

See this as an object that holds different effects. See each effect comes with its time interval. The frames property holds the sequence in which it will be displayed. See the arc object has frames that when rendered at 100ms will produce an arc effect.

We have the dots objects, these dots objects display the dots effect when displayed rapidly at 80ms frame rate.

Now, we will refactor our Spinner class to contain our new addition.

This is image title

As we have spinners.json, we use the fs#fsReadSync API to pick up the json file and read the contents to the spinners variable.

The spin method now has an argument spinnerName that holds the name of the effect in the spinners.json file. With the effect name, we extract from the spinners variable the effect and store the frames and interval values in spinnerFrames and spinnerTimeInterval respectively.

The spinnerFrames will now be referenced from to get the next frame style and the spinnerTimeInterval will be passed to setInterval to set time interval for the function callback execution.

Now, to run the Spinner, we create an instance and call the spin method with the name of the effect we want.

// index.js
...
new Spinner().spin("dots")

Here, the dots effect will be spinning.

This is image title

// index.js
...
new Spinner().spin("dots2")

The dots2 effect will be shown.

This is image title

// index.js
...
new Spinner().spin("line")

This will show our prev line effect.

This is image title

// index.js
...
new Spinner().spin("arc")

This will show the arc effect.

This is image title

Conclusion

You see, how easy it was. We used the setInterval API, process.stdout.write and readline#cursorTo and the style frames to produce the effect.

You can go forth and add the effects of your own. You can also write your implementation better than mine. I would like to see what you will come up with.

If you have any questions regarding this or anything I should add, correct or remove, feel free to comment, email or DM me.

Thanks !!!