js打印到控制台_如何实现可复用的控制台“艺术字”打印功能
之前在使用一些开源项目时,经常会看到在控制台输出项目大大的 LOGO。例如:
- hexo minos 主题启动时在控制台里会显示「MINOS」文案
- fis3 启动时也会有显示「FIS」
添加这种大号「艺术字」可以达到「品牌露出」的效果,当然,也是程序员特有「情趣」的体现。
但它们的实现方式无外乎把编排好的 Logo 通过 console.log
输出。这种方式问题在于它几乎没有任何复用能力,而且一些需要转义的情况还会导致字符串的可维护性极差。因此,我花了一个周末的时候,实现了一个易用的、可复用的控制台「艺术字」lib。这样,下次有新的需求,只需要把正常的文本传给它,它就可以帮你自动编排与打印。
1. 目标
正如上节所说,目前一般项目的做法都是自定写一串特定的文本,例如 minos:
还有 fis3 这种由于需要添加转义所以显得凌乱不好维护的
这种些方式都是通过「硬编码」来实现的,如果有了新项目或需求变动还得重新编排调整。
因此,准备实现一种能够根据输入的字符串进行自动排版展示的控制台「艺术字」打印库,例如通过 yo('yoo-hoo')
就会输出:
下次如果文案改了,直接换下字符串参数就行 —— yo('new-one')
:
总结来说,就是实现一个通用的、可复用的控制台「艺术字」打印功能。基于这个目标开发了 yoo-hoo这个库。
下面来说说大致怎么实现。
2. 如何实现
和其他字体显示的需求类似,我们可以将功能抽象为三个部分:
- 字体库的生成
- 字体的排版
- 字体的渲染
这里我们先说一下字体的渲染。
2.1. 字体渲染
之所以先说这部分,是因为它会影响排版信息的输出格式。
其实字体渲染这部分并没有什么特别的,我们在控制台这个环境,受限于 API,基本就是使用 console.log
来将内容「渲染」到屏幕上。不过,正是这里的「渲染」形式的限制,会倒推我们的排版方式。
我们知道,控制台基本都是单行顺序渲染的,大致就是「Z」字型。同时,由于我们的「艺术字」会占据多行,所以最终的渲染不是按单个字顺序渲染的,需要先排好版,然后按行来逐步渲染到屏幕上。
这有点像是咱们常见的打印机。如果你要打印一个苹果,它会从上往下逐步打印出这个苹果,而不是直接像盖章那样直接印刷一个苹果。
下面我们会先介绍字体库的生成,而不是紧接挨着的字体排版。因为排版是一个承上启下的过程,当我们确定了上下游环节,这块的逻辑自然也就确定了。
2.2. 字体库生成
当我们想要实现可复用能力时,因此我们需要找到或者抽象出系统内逻辑上的最小可复用单元 —— 在这里显然就是字符。简单来说,对于输入字符串 JS
时,如果我们能找到对应的 J 和 S 的字符表示形式,辅以排版,理论上就有能力实现我们的目标。这有点像是咱们老祖宗的活字印刷术。
所以在字体库这里,我们会有一个字义与字型的映射。这个其实和咱们前端常见的字体文件内格式的思想一样,都需要有这么一个映射关系。
字型哪里来呢?好吧,我也是用了一个笨办法 —— 自己「手绘」 。举个例子,下面就是我「手绘」的 1:
绘制的过程是枯燥的,好再很多字型的局部是有一定复用的,简化了这项繁琐的工作。当然,这只是一次性的工作,一旦创建好一类「字体」,以后就不需要再重复这项工作了。
我把上面这个内容存在一个单独的文件中,目前直接以 .txt 为后缀,这就是我们的字体原始格式。之所以不放在 .js 中,是因为 JavaScript 中 是想要转义的,这样文本的视觉和最后的呈现效果就不一致了,不利于调试和维护。
原始字体文件分为两部分:
- 上面第一行是字义,支持一个多个字义对应一个图形。例如
·
和*
我使用了同一个图形。多个字义间空格分割,不换行。 - 除去第一行,剩下的内容就是字型。
理论上,我们可以以这个原始字体文件来作为字体库了,通过 NodeJS 中的 fs
模块读取并解析文件内容即可得到映射关系。
但我希望它也能在非 NodeJS 环境(例如浏览器)中使用,所以不能依赖 fs
模块。这里做了一个原始文件的解析脚本,生成对应的 JS 模块。由于我们并不直接维护这些生成的 JS 模块,所以它的可读性不重要,可以设计数据格式的时候可以完全面向后续的排版流程。
首先实现一个简单的解析器来解析第一行的字义。这也类似一个词法解析器,但由于语法规则极其弱智(简单),所以也就不用多说了,大致如下:
下面就是处理字型部分。之所以需要处理字型,是因为上面提到的转义问题。由于我们在原始格式中使用了 来进行字型展示,而将其直接放入生成的 JS 文件中这个 就变为了转义符,要想正常展示需要变为 。一种方式是正则匹配,将所有源文本中的 替换为 再写入。但我选择了另一种方式。
将字符通过 .charCodeAt
方法转为 char code 存储,读取字体信息时再通过 String.fromCharCode
转回来。原来的字符串变成了数字类型的数组,这样就没有特殊字符的问题了。最后,通过拼接文本并生成 JS 文件来将原始的、利于人维护的字体文件,转成了编译 JS 工作的模块。
其中 defs 就是这个字型对应的字义列表,codes 则是字型的 char code 数组,所有的字体都被放在一个 JS 文件中。
这里提一下,第 3 行的 parsedFonts
就是遍历所有原始字体文件解析到的内容,因此得到这部分也是需要通过 NodeJS 的 fs
模块来递归读取源文件目录下的字体文件的。算是基操,就不用展开了。
由于这部分是可以提前解析编译的,一旦生成了 JS 模块后就不会对 NodeJS 运行时有依赖,所以保证了其依然可以运行在浏览器中。
2.3. 字体的排版
我们的字体格式确定了,目标的渲染方式也确定了。最后就可以填充这部分的逻辑实现了。
具体排版上会遇到一些细节点,例如不等高字体的空行填充、最大行宽的换行判断(需要用户执行行宽),不过这些都是小点,处理也不太复杂。这里可能介绍一下稍有特殊的一块 —— 字间距调整。
我们知道,一些艺术字的倾斜程度可能很大,例如这个字符「1」:
如果按简单的矩形型包围盒来分配空间,大概会是下面这样:
前后两个字体,即使设置为最小间距(0),仍然会距离很远,这样就破坏了一定的显示效果。例如上图中我两个包围盒间距其实只有 1,但看起来就很大。我们实际希望的可能是下面这样:
间距为 1 时,两个字符「1」调整为在最近的地方间距为 1。如果要更宽的效果可以设置更多间距。这个处理起来主要就是需要算出最大的「挤压空间」(即两个盒子最大支持的交叉空间)。最开始渲染的时候说了,我们是按 console 出的行来存储的与打印的,举个例子,这个「1」高度为 8 ,所以渲染的时候就是一个 8 个元素的字符串数组:
渲染的时候直接 lines.forEach(l => console.log(l))
即可。
注意,为了便于读者阅读,上面的 lines 数组内的字符串我没有加上转义,它是不合法的!只是为了展示起来更便于阅读理解,实际中不能这么写。
最大缩进(缩进这个词不准确,但希望大家能够理解那个意思)的计算只需要知道之前的每个 line 尾部对应有多少空格,同时需要再其后新添加字符每个 line 前面又分别有多少空格,综合两者,再遍历所有的 line 取一个最小值即可:
最后 calcIndent
方法返回的就是新字符需要向前缩进(或者说缩紧)的值。最后渲染的时候根据这个值来调整每行连接时添加的空格数即可。
捎带一提,之前的字体格式 load 进来会被转换为类似字典的格式 —— 字义作为 key,字型等一系列属性作为 value:
这样遍于 split
完用户传入的字符串后,更简单的索引到对应的字型和字体信息。
2.4. 其他
当然,其他还会有一些工作,包括
- 支持颜色
- 支持返回排版完的 lines 让用户自己渲染
- 支持用户自定义调整字间距
这些目前实现上遇到的问题不大,篇幅原因也就不说了。具体的代码可以在 Github 上看到。
3. 总结
实现可复用的控制台“艺术字”功能,总的来说并没有太多复杂的点,整体的流程模型就是
生成字体库 --> 字体排版 --> 渲染文本
这对于前端来说应该是非常好理解的。
做这个项目也确实是自己在工作中希望给一些库加上这种 logo 或者 banner 展示,但每次重复枯燥的工作确实令人反感。所以想了下可行性之后就搞了 yoo-hoo 这么个小玩意儿,如果大家也遇到类似的问题,希望能有所帮助。
4. 最后
目前 yoo-hoo@1.0.x 内置了一套 26 个字母(A-Z)、10 个数字(0-9)、·
*
-
|
这些字符的字体库。
考虑到单一的字型和有限的字体量肯定不能满足所有需求,所以开发时代码结构就留下了支持外部扩展的模式。
后续可以把 2.2 节中的字体源文件解析工具独立出来,支持用户「手绘」自己的字型,用工具生成对应格式后,将字体的 JS 模块传入 yo
方法中作为扩展字体加载。
字体源文件的「手绘」虽有成本,但所见即所得,编写难度不大 同时也算是一劳永逸。
原作者姓名:alienzhou
原出处:segmentfault
原文链接:如何实现可复用的控制台“艺术字”打印功能_精益前端 - SegmentFault 思否
js打印到控制台_如何实现可复用的控制台“艺术字”打印功能相关推荐
- java打印星型_初识java java入门知识 基础知识 打印各种星型图形 源代码
今天给大家带来的是初级Java基础部分的知识:包括初识Java.变量.常量.数据类型.运算符.各种选择结构.循环结构.数组等Java的基础语法部分!最后还有****循环结构的进阶****,步骤超详细, ...
- python 调用控制台_如何使用Python的交互控制台
简介 Python的交互控制台(也叫做Python解释器,或是Python Shell)为程序员提供了"运行指令"和"不创建文件测试测试代码"的快速途径. 交互 ...
- python日志模块为什么打印到界面_如何将外部模块的日志消息打印到主Python模块的终端窗口?...
我正在写一个Python命令行程序.在 有一个主Python脚本文件,用作入口点.当用户运行这个脚本时,它将执行一些外部Python脚本文件.外部Python脚本文件也可以执行其他外部Python脚本 ...
- qt 隐藏控制台_带可选GUI的Qt控制台应用程序
简单地说这行到你的亲文件: CONFIG += console 在Qt5.x也从Win7到Win10你可以做这样的事情: //includes #include #include #include # ...
- java调用打印预览_急求一个用Java实现的打印及打印预览功能的Demo
展开全部 package com.szallcom.tools; import java.awt.BorderLayout; import java.awt.Color; import java.aw ...
- 打印表单_超市生鲜日常作业表单,打印出来就能用!
零售商要在日趋激烈的市场竞争中生存.发展,必须要树立低价格形象.加强吸引客流的能力并不断增强顾客的忠诚度.低价格形象是一种市场营销策略,是零售商吸引顾客的主要手段. 显然蔬菜.水果作为顾客的目标性购买 ...
- python如何打印txt文件_在Python中的.txt文件中打印特定行?
I have got a .txt file that contains a lot of lines. I would like my program to ask me what line I w ...
- jq控制div是否展示_选择控制台_调度台之前,这几点你应该要看!
随着现 代智能化技术的不断发展,各个领域都在打造与时俱进的智能办公环境.而提升智能办公环境怎么能少得了控制台和调度台这些智能化设备? 控制台_调度台效果展示 针对如何选择控制台.调度台.操作台等设备, ...
- JS数据结构与算法_链表
上一篇:JS数据结构与算法_栈&队列 下一篇:JS数据结构与算法_集合&字典 写在前面 说明:JS数据结构与算法 系列文章的代码和示例均可在此找到 上一篇博客发布以后,仅几天的时间竟然 ...
最新文章
- 对于量子计算来说,99%的准确度足够吗?
- gradle 的 依赖管理(八)
- nyoj164——卡特兰数(待填坑)
- JavaFX之TableView的TableRow
- stk在计算机仿真中的应用_学习电路仿真:proteus电路仿真软件在ARM中的应用解析...
- python打包exe
- SQL Cookbook(读书笔记)No.2
- C#的rdlc报表分组汇总学习
- python求小于n的最大素数_枚举1--求小于n的最大素数
- 新乡医学院三全学院赴范县历史成就观察团
- 高德地图API:如何根据经纬度获取位置信息
- Python新手接了第一个副业单子,2小时完成:Python修正excel表格数据
- 《Python编程从入门到实践 第二版》第十六章练习
- STM32F4内的FLASH和RAM
- Debian Bullseye 更新源备份
- java实验报告(实验三)
- NDN网络学习笔记(一)——NDN基础
- SLIC图像超像素分割算法解析
- Java利用Set集合去重复
- java中内边距跟外边距,padding和margin——内边距和外边距