自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Node.js 控制臺(tái)動(dòng)畫,繪制跨年祝福

開發(fā) 前端
Node.js 里面可以通過 process.stdout.isTTY 來(lái)查看是否是 TTY 類型的標(biāo)準(zhǔn)輸出流,然后提供了 readline 這個(gè)包來(lái)操作它。

[[443318]]

今天是 2021 年的最后一天了,明天就是 2022 年?;仡欉^去一年,要特別感謝大家對(duì)我的支持。

人生不過幾十年,每一年都值得紀(jì)念和祝福,所以我想用 Node.js 控制臺(tái)動(dòng)畫送上一份我的新年祝福:

視頻

2021 年的最后一天,我們來(lái)學(xué)點(diǎn) cli 的技術(shù)吧。

實(shí)現(xiàn)原理

動(dòng)畫都需要一幀幀的刷新,控制臺(tái)動(dòng)畫也不例外。

那控制臺(tái)是怎么刷新的呢?

控制臺(tái)中有一種叫做 TTY,特點(diǎn)是可以設(shè)置顏色,可以清除或修改某個(gè)位置的內(nèi)容。平時(shí)我們用的 Terminal 大多都是這種。

Node.js 里面可以通過 process.stdout.isTTY 來(lái)查看是否是 TTY 類型的標(biāo)準(zhǔn)輸出流,然后提供了 readline 這個(gè)包來(lái)操作它。

比如用 readline.cursorTo(stream, x, y) 來(lái)移動(dòng)光標(biāo)位置, readline.clearLine(stream) 來(lái)清除某行的內(nèi)容,用 readline.clearScreenDown(stream)來(lái)清除某個(gè)位置之后的所有內(nèi)容。

能夠移動(dòng)光標(biāo)位置,能夠清除內(nèi)容,也就能夠刷新、能夠做任意的繪制,這是控制臺(tái)動(dòng)畫的基礎(chǔ)。

繪制用 readline.wrtie(data) 來(lái)輸出字符,可以指定字符的顏色(用 chalk 這個(gè)包)。

只是輸出帶顏色的字符么?那張圖片和那個(gè)藝術(shù)字呢?

其實(shí)那也是字符來(lái)做的,只不過給上了不同的顏色而已,控制臺(tái)只能顯示字符。

左邊的這張圖片的顯示原理是拿到圖片的像素信息,然后轉(zhuǎn)成不同顏色的字符??梢杂?console-png 這個(gè)包。

右邊的藝術(shù)字的顯示原理是固定的一些字符信息,設(shè)置上顏色。用的是 cfonts 這個(gè)包。

小結(jié)一下:

TTY 類型的控制臺(tái)可以設(shè)置顏色、可以在任意位置清除和修改內(nèi)容,這是控制臺(tái)動(dòng)畫能一幀幀刷新的基礎(chǔ),Node.js 提供了 readline 模塊來(lái)做這些。

控制臺(tái)只能顯示字符,圖片可以拿到像素信息然后用帶顏色的字符來(lái)顯示,藝術(shù)字是提前準(zhǔn)備好字符數(shù)組來(lái)繪制,綜合把這些內(nèi)容繪制在不同的位置,然后定時(shí)一幀幀刷新就構(gòu)成了控制臺(tái)動(dòng)畫。

思路通了之后,我們來(lái)寫代碼實(shí)現(xiàn)一下。

代碼實(shí)現(xiàn)

首先,我們會(huì)用到 readline 這個(gè)內(nèi)置模塊,用它來(lái)做一幀幀的刷新。

調(diào)用 readline.createInterface 來(lái)創(chuàng)建一個(gè)實(shí)例,指定輸入輸出流為 stdin、stdout。

stdin 是標(biāo)準(zhǔn)輸入流,是指鍵盤。

stdout 是標(biāo)準(zhǔn)輸出流,是指顯示器。

  1. const readline = require('readline'); 
  2.  
  3. const outStream = process.stdout; 
  4.  
  5. const rl = readline.createInterface({ 
  6.     input: process.stdin, 
  7.     output: outStream 
  8. }); 

然后清除整個(gè)控制臺(tái)的內(nèi)容,把光標(biāo)移動(dòng)到開始,然后 clear:

  1. readline.cursorTo(outStream, 0, 0); 
  2. readline.clearScreenDown(outStream); 

然后開始繪制文字:

準(zhǔn)備一個(gè)數(shù)組放要繪制的文字,然后定時(shí)在不同的位置顯示這些文字

  1. const textArr = ['2021''感謝''大家的''支持','2022''我們','一起','加油!']; 
  2.  
  3. (async function () { 
  4.     for(let i = 0; i< textArr.length; i++) { 
  5.         readline.cursorTo(outStream, ...randomPos()); 
  6.         rl.write(randomStyle(textArr[i])); 
  7.  
  8.         await delay(1000); 
  9.         readline.cursorTo(outStream, 0, 0); 
  10.         readline.clearScreenDown(outStream); 
  11.     } 
  12. })(); 
  13.  
  14. function delay(time) { 
  15.     return new Promise((resolve) => setTimeout(resolve, time)); 

我用了 async await 的方式來(lái)組織代碼,基于封裝了一個(gè) delay 方法。

其中位置、樣式都是隨機(jī)的:

  1. const chalk = require('chalk'); 
  2.  
  3. function randomPos() { 
  4.     const x = Math.floor(30 * Math.random()); 
  5.     const y = Math.floor(10 * Math.random()); 
  6.     return [x, y]; 
  7.  
  8. function randomStyle(text) { 
  9.     const styles = ['redBright','yellowBright''blueBright''cyanBright','greenBright''magentaBright''whiteBright']; 
  10.     const color = styles[Math.floor(Math.random() * styles.length)]; 
  11.     return chalk[color](text); 

前面的文字動(dòng)畫就做完了:

然后是圖片和藝術(shù)字的顯示:

圖片需要用 console-png 來(lái)把圖片像素信息取出來(lái)轉(zhuǎn)成字符的形式:

  1. const consolePng = require('console-png'); 
  2. consolePng.attachTo(console); 
  3.  
  4. const image = fs.readFileSync(__dirname + '/headpic.png'); 
  5. console.png(image); 

藝術(shù)字用 cfonts 來(lái)繪制,拿到字符之后顯示在右邊的位置:

  1. const CFonts = require('cfonts'); 
  2.  
  3. const prettyFont = CFonts.render('|HAPPY|NEW YEAR', { 
  4.     font:'block',  
  5.     colors: ['blue''yellow'
  6. }); 
  7.  
  8. let startX = 60; 
  9. let startY = 0; 
  10. prettyFont.array.forEach((line, index) => { 
  11.     readline.cursorTo(outStream, startX + index, startY + index); 
  12.     rl.write(line); 
  13. }); 

cfont.render 的第一個(gè)參數(shù)里的豎線是指換行,第二個(gè)參數(shù)的 font 是指定樣式,colors 指定顏色。

然后對(duì)返回的字符數(shù)組做光標(biāo)的偏移之后再顯示。

最后,在右下方顯示公眾號(hào)的標(biāo)記:

  1. readline.cursorTo(outStream, 120, 25); 
  2. rl.write(chalk.yellowBright('---神光的編程秘籍')); 

這樣,最后這一幀就繪制完了:

大功告成!我們?cè)賮?lái)看下整體的效果:

視頻

代碼上傳到了 github:https://github.com/QuarkGluonPlasma/cli-exercise

也在這里貼一份:

  1. const readline = require('readline'); 
  2. const chalk = require('chalk'); 
  3. const CFonts = require('cfonts'); 
  4. const consolePng = require('console-png'); 
  5. const fs = require('fs'); 
  6.  
  7. consolePng.attachTo(console); 
  8.  
  9. const outStream = process.stdout; 
  10.  
  11. const rl = readline.createInterface({ 
  12.     input: process.stdin, 
  13.     output: outStream 
  14. }); 
  15.  
  16. function delay(time) { 
  17.     return new Promise((resolve) => setTimeout(resolve, time)); 
  18.  
  19. function randomStyle(text) { 
  20.     const styles = ['redBright','yellowBright''blueBright''cyanBright','greenBright''magentaBright''whiteBright']; 
  21.     const color = styles[Math.floor(Math.random() * styles.length)]; 
  22.     return chalk[color](text); 
  23.  
  24. function randomPos() { 
  25.     const x = Math.floor(30 * Math.random()); 
  26.     const y = Math.floor(10 * Math.random()); 
  27.     return [x, y]; 
  28.  
  29. readline.cursorTo(outStream, 0, 0); 
  30. readline.clearScreenDown(outStream); 
  31.   
  32. const image = fs.readFileSync(__dirname + '/headpic.png'); 
  33.  
  34. const textArr = ['2021''感謝''大家的''支持','2022''我們','一起','加油!']; 
  35.  
  36. (async function () { 
  37.     for(let i = 0; i< textArr.length; i++) { 
  38.         readline.cursorTo(outStream, ...randomPos()); 
  39.         rl.write(randomStyle(textArr[i])); 
  40.  
  41.         await delay(1000); 
  42.         readline.cursorTo(outStream, 0, 0); 
  43.         readline.clearScreenDown(outStream); 
  44.     } 
  45.  
  46.     console.png(image); 
  47.  
  48.     await delay(1000); 
  49.     const prettyFont = CFonts.render('|HAPPY|NEW YEAR', {font:'block', colors: ['blue''yellow']}); 
  50.  
  51.     let startX = 60; 
  52.     let startY = 0; 
  53.     prettyFont.array.forEach((line, index) => { 
  54.         readline.cursorTo(outStream, startX + index, startY + index); 
  55.         rl.write(line); 
  56.     }); 
  57.  
  58.     readline.cursorTo(outStream, 120, 25); 
  59.     rl.write(chalk.yellowBright('---神光的編程秘籍')); 
  60. })(); 

總結(jié)

TTY 類型的終端支持設(shè)置字符顏色和在任意位置清除和修改內(nèi)容,這是控制臺(tái)動(dòng)畫可以刷新的基礎(chǔ)。

我們通過把圖片的像素轉(zhuǎn)為有顏色的字符來(lái)顯示圖片,通過預(yù)置的字符數(shù)組來(lái)顯示藝術(shù)字,在不同的位置繪制這些內(nèi)容就可以達(dá)到豐富的顯示效果。

其中,控制臺(tái)的光標(biāo)位置修改和內(nèi)容的清除使用 Node.js 的 readline 內(nèi)置模塊,其余的是第三方的包。藝術(shù)字使用 cfonts 的包,圖片顯示使用 console-png,字體顏色使用 chalk。

控制臺(tái)是我們每天都用的,前端的大多數(shù)工具都是 cli 的形式。深入學(xué)習(xí) cli 顯示各種內(nèi)容和做動(dòng)畫的知識(shí),有助于更好的理解一些 cli 工具和寫出更好的 cli 工具。 

最后,再次感謝大家過去一年的支持,明年一起加油呀~

 

責(zé)任編輯:武曉燕 來(lái)源: 神光的編程秘籍
相關(guān)推薦

2011-12-23 10:51:24

Node.js

2013-11-01 09:34:56

Node.js技術(shù)

2015-03-10 10:59:18

Node.js開發(fā)指南基礎(chǔ)介紹

2014-04-10 09:43:00

Node.jsTwilio

2011-09-08 13:53:31

Node.js

2011-07-06 15:25:33

Windows控制臺(tái)

2011-09-09 14:23:13

Node.js

2011-11-01 10:30:36

Node.js

2011-09-08 13:46:14

node.js

2011-09-02 14:47:48

Node

2012-10-24 14:56:30

IBMdw

2011-11-10 08:55:00

Node.js

2010-12-21 14:32:43

操作控制臺(tái)

2021-12-25 22:29:57

Node.js 微任務(wù)處理事件循環(huán)

2020-05-29 15:33:28

Node.js框架JavaScript

2012-02-03 09:25:39

Node.js

2015-06-23 15:27:53

HproseNode.js

2020-10-26 08:34:13

Node.jsCORS前端

2021-02-01 15:42:45

Node.jsSQL應(yīng)用程序

2024-07-08 08:53:52

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)