控制台的显示艺术(附原理实现)

2018-09-04   |     |     |  

艺术是孤独的产物,因为孤独比快乐更能丰富人的情感。 ——罗丹

不知道从什么时候开始,人们开始对美的追求从页面转移到了控制台,出现了很多有意思的控制台艺术:

20180828153546386298711.png?imageMogr2/thumbnail/750x

2018082815354637464574.png?imageMogr2/thumbnail/750x

人天生对美的追求,让其不满足于控制台只是黑白和ASCII码的世界,除了使用图案去吸引眼光,颜色也是非常常用的工具,色彩+图案,让原本无聊的控制台慢慢有了生机:

20180828153546405712733.png?imageMogr2/thumbnail/750x

人都是视觉动物,喜欢美的事物,因此一个良好的交互,是非常重要的,在浏览器中,页面是主要的,控制台可能主要是用来吸引程序猿同类,提升程序猿同类对该公司的认同感(哎哟,不错哟,是我的菜)。但是在node环境中,没有页面,控制台就是交互唯一的入口,因此一个优美的控制台环境也是很重要的。

浏览器的样式设计

浏览器端比较简单,根据文档 console.log有一个格式化输出的选项(学过c语言的童鞋对格式化输出应该不陌生),其中有个选项%c就是设置输出样式(css样式,这样可定制化程度应该够用了吧)

占位符 含义
%s 字符串输出
%d or %i 整数输出
%f 浮点数输出
%o 打印javascript对象,可以是整数、字符串以及JSON数据
%c 样式
console.log("%cMy stylish message", "color: red; font-style: italic");

console.log("%c3D Text", `text-shadow: 0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);font-size:5em`);

console.log('%cRainbow Text ', `background-image:-webkit-gradient( linear, left top, right top, color-stop(0, #f22),color-stop(0.15, #f2f), color-stop(0.3, #22f), color-stop(0.45, #2ff), color-stop(0.6, #2f2),color-stop(0.75, #2f2), color-stop(0.9, #ff2), color-stop(1, #f22) );color:transparent;-webkit-background-clip: text;font-size:5em;`);

console.log("%c\n       ", `font-size:140px;background:url('http://hksite.cn/20180829153550853783124.png?imageMogr2/thumbnail/750x')no-repeat`);    

20180829153550863278904.png?imageMogr2/thumbnail/750x

当然初了样式,控制台还有很多实用的小技巧,例如追踪堆栈信息分组输出,输出表格,计时计次……可以参考 这个文章

20180906153619872081965.png?imageMogr2/thumbnail/750x

Node 控制台样式设计

Node由于是运行在后台,它使用的是用户系统的控制台,无法利用浏览器便捷的渲染引擎,因此,它无法实现类似显示图(字符图如果算的话),阴影,边框这么复杂的样式,但是,小改改颜色什么的还是可以的。

毕竟清一色的黑白界面看久了还是会视觉疲劳的,所以现在的一些比较耗时的工具(npm,webpack,glup……)都会用颜色和简单的加载动画去优化用户体验,不让这个等待过程过于枯燥。想想,这和我们在浏览器端优化用户体验的思路不一样的吗?

20180904153606606414264.png?imageMogr2/thumbnail/750x

控制台颜色

原理

不想看原理,想快速的使用的童鞋可以直接往下翻

其实node端的console是可以设置颜色的,这就涉及到linux的颜色转义序列了,最初接触这个东西是PS1中修改字体颜色,其实就是用它来控制linux下控制台输出颜色的,熟悉的人可能还记得:

\e[F;Bm 输入字符串\e[0m

\e 转义字符开始,ESC 的 ASCII 码用十进制表示就是 27,等于用八进制表示的 033。

[ 开始定义颜色。

F‘ 为字体颜色,编号30~37;

B为背景色,编号40~47。

O 为特殊意义代码

m 是标记,后面不用跟空格

| 前景 | 后景 | 颜色 |
| | -|
|30| 40|黑色|
|31| 41| 红色|
|32| 42| 绿色|
|33 |43| 黄色|
|34 |44|蓝色|
|35| 45 |洋红|
|36 |46| 青色|
|37 |47| 白色 |

举例,现在你可以直接在控制台输入:

echo -e "\e[37;41m 网易云音乐 \e[0m"

20180906153619883748207.png?imageMogr2/thumbnail/750x

那么接下来,用console来输出颜色就很简单了(注意\x1B就是十六进制的27),借用网上的一个样式表:

console.log('\x1B[31m%s\x1B[0m', '错误');  
console.log('\x1B[33m%s\x1b[0m:', '警告');  
var styles = {
    'bold'          : ['\x1B[1m',  '\x1B[22m'],
    'italic'        : ['\x1B[3m',  '\x1B[23m'],
    'underline'     : ['\x1B[4m',  '\x1B[24m'],
    'inverse'       : ['\x1B[7m',  '\x1B[27m'],
    'strikethrough' : ['\x1B[9m',  '\x1B[29m'],
    'white'         : ['\x1B[37m', '\x1B[39m'],
    'grey'          : ['\x1B[90m', '\x1B[39m'],
    'black'         : ['\x1B[30m', '\x1B[39m'],
    'blue'          : ['\x1B[34m', '\x1B[39m'],
    'cyan'          : ['\x1B[36m', '\x1B[39m'],
    'green'         : ['\x1B[32m', '\x1B[39m'],
    'magenta'       : ['\x1B[35m', '\x1B[39m'],
    'red'           : ['\x1B[31m', '\x1B[39m'],
    'yellow'        : ['\x1B[33m', '\x1B[39m'],
    'whiteBG'       : ['\x1B[47m', '\x1B[49m'],
    'greyBG'        : ['\x1B[49;5;8m', '\x1B[49m'],
    'blackBG'       : ['\x1B[40m', '\x1B[49m'],
    'blueBG'        : ['\x1B[44m', '\x1B[49m'],
    'cyanBG'        : ['\x1B[46m', '\x1B[49m'],
    'greenBG'       : ['\x1B[42m', '\x1B[49m'],
    'magentaBG'     : ['\x1B[45m', '\x1B[49m'],
    'redBG'         : ['\x1B[41m', '\x1B[49m'],
    'yellowBG'      : ['\x1B[43m', '\x1B[49m']

成熟工具包

当然,为了实现更加丰富多彩的颜色,还是建议使用现成的包(根据自己的喜欢选择,我选择chalk

  • colors :可以实现很复杂的颜色样式

    `javascript
    var colors = require(‘colors’);

console.log(‘hello’.green); // outputs green text
console.log(‘i like cake and pies’.underline.red) // outputs red underlined text
console.log(‘inverse the color’.inverse); // inverses the color
console.log(‘OMG Rainbows!’.rainbow); // rainbow
console.log(‘Run the trap’.trap); // Drops the bass


![20180904153606790789538.png?imageMogr2/thumbnail/750x](http://hksite.cn/20180904153606790789538.png?imageMogr2/thumbnail/750x)



- [chalk](https://github.com/chalk/chalk) 支持rgb256真彩色,并且写法我更喜欢。


 ```javascript
const chalk = require('chalk');
const log = console.log;

// Combine styled and normal strings
log(chalk.blue('Hello') + ' World' + chalk.red('!'));

// ES2015 template literal
log(`
CPU: ${chalk.red('90%')}
RAM: ${chalk.green('40%')}
DISK: ${chalk.yellow('70%')}
`);

// ES2015 tagged template literal
log(chalk`
CPU: {red ${cpu.totalPercent}%}
RAM: {green ${ram.used / ram.total * 100}%}
DISK: {rgb(255,131,0) ${disk.used / disk.total * 100}%}
`);   

20180904153606802735664.png?imageMogr2/thumbnail/750x

加载动画

介绍

我记得大学学C语言的时候,就有一个作业是做控制台动画(正弦余弦波型),还有做控制台游戏“弹球”,就通过利用命令清屏,然后一帧帧重绘出来。

system ('cls')

其实控制台动画,早在1997年就出现了,不知道有没有人看过这个,控制台版的星球大战:

 # telnet towel.blinkenlights.nl

img

img

还有这个小sl命令的小汽车:

# apt-get install sl         (In Debian like OS)
# yum -y install sl         (In Red Hat like OS)
# brew install sl  (Max Os)

20180906153620035810005.gif?imageMogr2/thumbnail/750x

(如果你想尝试更多,可以参考这篇文章:《20 Funny Commands of Linux or Linux is Fun in Terminal》)

原理

回到我们这边来,node后台处理经常会需要长时间运行的业务(下载远程数据,打包……)这时候,如果这时候控制台直接卡死,用户体验会很糟糕,用户也不知道现在到底在干嘛,所以给一个加载动画是很有必要的。

加载动画的原理也很简单,让我们的数据实在在同一行输出,通过一帧帧图案的替换,实现动画。下面我写了一个简单的实现加载动画和进度条的demo,可以体验一下:

const readline = require("readline");
const char = ["◐", "◓", "◑", "◒"];
let cur = 0;
let info = "loading...";
let bar = "[----]";
let done = false;
// setInterval(() => {
//   //删除光标所在行
//   readline.clearLine(process.stdout);
//   //移动光标到行首
//   readline.cursorTo(process.stdout, 0);
//   cur = (cur + 1) % char.length;
//   process.stdout.write(char[cur] + " loading...", "utf-8");
// }, 200);

let timer = setInterval(() => {
  //删除光标所在行;
  readline.clearLine(process.stdout);
  //移动光标到行首
  readline.cursorTo(process.stdout, 0);

  if (done) {
    info = "done!";
    // clearInterval(timer);
  }
  process.stdout.write(`${bar} ${info}`, "utf-8");
  bar = bar.replace("-", "="); //利用每次只替换一个的原理
  if (bar.indexOf("-") < 0) {
    done = true;
  }
}, 200);

20180906153620027078712.gif?imageMogr2/thumbnail/750x

20180906153620125032482.gif?imageMogr2/thumbnail/750x

当然,你也可以用single-line-log 去处理。不过现在现成的加载动画的包也很多,就没必要自己手动写了:

成熟的工具包

  • ora:halk的作者,不愧是控制台艺术的完美饯行者,刚说完他的chalk,又要提他的ora ,这是一个控制台加载动画的包。用法也非常简单(通过start()控制开始,然后在需要结束的时候触发succeed/fail/warn/info函数即可。
const ora = require('ora');

const spinner = ora('Loading unicorns').start();
……
spinner.succeed([text])
……

20180906153621326687462.gif

  • Node.CLI-Progress 这是一个处理进度条的组件,原理和我上面写的都大同小异,不过包装的十分完善了,感兴趣可以去看看。

20180905153615825615771.png?imageMogr2/thumbnail/750x

字符画(ASCII Art)

介绍

字符画,英文名:zi fu hua~ 开玩笑,字符画专业词汇叫:ASCII Art,最早于1982年(早我出生10年)诞生于卡内基梅隆大学,根据WIkiPedia的解释:

ASCII艺术,又名“文字图”、“字符画”、“文字画”,这种主要依靠计算机表现的艺术形式是指使用计算机字符(主要是ASCII)

来表达图片,最早于1982年美国卡内基梅隆大学出现,互联网刚出现时在英语世界的社交网(Usenet、BITNET、网络论坛、

FidoNet、电子布告栏系统BBS)上时常利用到的表情符号。它可以由文本编辑器生成。很多ASCII艺术要求使用定宽字体(固

定宽度的字体,例如在传统打字机上使用的字体)来显示。

:-) 到 下面这些例子,都是字符画的表现形式:

    HHHHHH    HHHHHH     IIIIII     
     HHHH      HHHH       IIII      
     HHHH      HHHH       IIII      
     HHHHHHHHHHHHHH       IIII      
     HHHHHHHHHHHHHH       IIII     
     HHHHHHHHHHHHHH       IIII       
     HHHH      HHHH       IIII      
     HHHH      HHHH       IIII     
     HHHH      HHHH       IIII     
    HHHHHH    HHHHHH     IIIIII 

20180906153620220693453.png?imageMogr2/thumbnail/750x

成熟工具

这种艺术,如果只凭我们手敲控制,可谓难于上青天,所以需要借助一些现成的生成工具:

  • Text to ASCII Art Generator 这是一个文字转ASCII码图案的工具,有很多工具的图案就是用这个生成的

  • Ascii Art Generator 这网站可以把图片转换成ASCII码图案,可以生成纯字符的,也可以生成带颜色字符的,并且可以生成一个

    html给你。

    ……(这类网站实在太多,功能都大同小异)

交互操作

除了显示外,我们还可以加入一些交互式的操作,这个就更复杂了,还好有inquirer 。它提供了很多交互式的操作,关键是它提供了很多插件:单选,时间选择,自动不全,建议,它还有和chalk配合使用的动态字体换色……

反正,这一款足以强大到编写你想要的交互式操作,建立属于自己的CLI!

20180906153621331477876.gif

20180906153621334693593.gif

最后

不管做什么,当你不是把它当作一个机械产物,而是用美的眼光去看待,这件物件便有了温度。

前端作为一个富有创造性和艺术性的职业,虽然不一定能像画家一样做一个美好视觉体验的创造者,但是至少可以当一个美好视觉体验的传递者。

配合颜色和加载字符动画,或者字符画,你的控制台将不再那么单调,至少,让使用者觉得舒服,以下是我现在做的项目的大概输出:

20180906153620178013728.png?imageMogr2/thumbnail/750x

20180906153620182284354.png?imageMogr2/thumbnail/750x