使用Hugo Shortcode和svg标签构建自定义图形!

2020-03-16

介绍

我们会在这篇文章中简略地解释Hugo ShortCode, 并讲解Hugo ShortCode的一种用法,最后我们会介绍HTML中的svg标签,比较canvas和svg两种作图方式.

什么是Hugo ShortCode?

概念

我们知道Hugo是一款高性能的静态网站生成器,尤其是它能够将Markdown文档转换成HTML网页,并自动完成网站目录的组织和网页超链接的设置,之前我已有一篇文章介绍过用Hugo搭建个人博客的一个简单的过程,今天我们来介绍Hugo的一个功能:ShortCode.

正如我刚才所说的,Hugo用户习惯于以Markdown的格式通过通用的文本编辑器(VS Code, Sublime Text, Atom等等)撰写博客文章,然后交由Hugo将Markdown文件「渲染」成最终的HTML网页,然而我们知道,Markdown只能支持有限的功能,例如,不能直接在Markdown文档中添加一段视频,一些Markdown渲染器不能将图片中的Caption显示出来,也不能直接插入音频等.

首先想到的一个办法是在Markdown转化成HTML之后,再去HTML文件里手动编辑,这是方法之一,但显然不是一个办法;联想到Hugo是一个其实也是一个模板引擎,能不能通过某种方式,通知模板引擎在工作的时候,对Markdown文件中的一部分带有特殊标记的内容,做特殊的处理呢?譬如说,如果模板引擎将Markdown文件中的

{{< myShortcode >}}
[内容]
{{< /myShortcode >}}

看出是特殊标记,而转而去寻找myShortcode这个符号所对应的具体方法,来对[内容]做单独地渲染,不就可以让用户留在Markdown的环境下写作,而不必去手动地编辑HTML文件的同时,也能实现Markdown在Hugo环境下的功能拓展吗?这个功能,这个将Markdown文本中一段特殊标记的内容按照标记符号所对应的模板单独渲染的功能,就叫做ShortCode.

实例

当Hugo在Markdown文档中遇到

{{< myShortcode >}}
abcxyz
{{< /myShortcode >}}

这样的标记时,会首先去寻找Hugo项目目录下或者主题目录下的layouts/shortcodes/这个文件夹寻找myShortcode.html模板文件,然后根据模板文件中定义的对内容的转换和渲染方法,转换内容(这里是)abcxyz,并且将转换后的HTML内容替换Shortcode在目标HTML文档中的出现.

假如说layouts/shortcodes/pquote.html文件是这样

<p><q>{{ .Inner }}</q></p>

那么

{{< pquote >}}
abcxyz
{{< /pquote >}}

将被模板引擎渲染成

<p><q>abcxyz</q></p>

相当于给原内容里面加了一个q标签(q就是quote的意思).

通过ShortCode和svg标签在Markdown文件中添加自定义图形

raw ShortCode与自定义HTML内容

最简单也是最灵活地,我们可以使用{{< raw >}} ShortCode,顾名思义,它允许写作者在Markdown文件中指定Hugo模板引擎将部分内容视为纯HTML内容,原样转换和渲染.在layouts/shortcodes/raw.html中,{{< raw >}}的定义是

<!-- raw html -->
{{ .Inner }}

即明白这是允许用户在文章中插入自定义HTML内容.

svg标签

而不仅仅是在XML格式的文件中,在HTML格式的文件中,我们也可以用叫做svg的实体标签

<svg ..attributes...>
...svg elements...
</svg>

来定义图形和图形元素.例如

<svg width="800" height="400">
</svg>

就声明了一块800像素乘400像素的区域,用于画图,接下来,可以在svg实体中添加svg元素(SVG Elements),例如

<svg width="800" height="400">

    <rect 
        x="200"
        y="200"
        width="50" 
        height="50" 
        fill="none" 
        stroke="gray" 
        stroke-width="2" 
    />

    <circle 
        cx="100" 
        cy="100" 
        r="60" 
        fill="none" 
        stroke="gray" 
        stroke-width="2" 
    />

</svg>

那么在网页上显示出来,就是下面这样子的

在上面的例子中,我们先定义了一个rect对象,然后是一个circle对象,正如你所看到的,XML中「实体」的概念,实际上对应着编程语言中「对象」的概念,图形在这里是一个一个的实体,你只需要把它的属性描述处理,然后底层图形渲染引擎就会自动为你new出这个图形对象,在这里,不禁又一次地体会到了面向对象编程思想的优美和简洁.

然后,在rect实体和circle实体中,我们通过XML语言的字段(attribute)来描述对象的属性,也正如你所看到的,x="200" y="200"表示矩形的左上角的坐标,width="50" height="50"正是矩形的长宽(单位是像素),fill="none"表示图形内部不填充,stroke="gray"规定图形的边界是灰色的,stroke-width="2"设定了图形的边界的宽度是2像素,这些其实都是很好理解的,也很容易阅读,而且可以看到,fillstrokestroke-widthrect实体和circle实体中都是通用的,事实上,在svg命名空间中,像这样在多个svg元素都通用的字段属性还有很多,感兴趣的读者不妨访问文末的参考链接,去一探究竟.

可以看到,想的是什么,画出来的就是什么,图像对象的参数可以精确控制,却不用我们操心具体的底层图形问题,我们不用关心这一个像素一个像素是怎么画的,也不用关心如何更新图形,只要我们确定了图形的几何参数,图形的在屏幕上的显示也就确定了,这正是由数学方式描述的绘图系统的优越性.

svg的标记语言绘图方式和canvas绘图方式的比较

通过canvas绘图方式绘图实际上是利用一套叫做Canvas的API,调用这套API进行画图呢,我们要写JavaScript代码,要理解图形上下文的概念,并且实际上的画图操作也只不过是规定在哪一个区域填充哪些像素,类似于纸和笔和颜料这样的涂画、点画,画起来非常灵活,但是实际上很低效,因为要关心的细节非常多,基本上是一个像素一个像素的画.

设想在canvas中要更改一个图形对象的几何参数怎么做?由于canvas没有图形对象这样的概念,你要自己定义一个图形类来记录图形的集合参数,图形对象和画布上的像素是互相独立的,你要先把那个图形在画布上的像素恢复为背景色,等于说在画布上抹除这个图形,然后再画一个新的上去.

而在svg的画图方式中,由于图形对象和图形的表现是直接对应的,我们只需更改svg元素的属性,例如把circle实体的r="60"更改为r="100",这个被更改的circle对象或者circle实体在显示器上显示的半径就自动由60像素变为100像素.这期间我们根本没关心计算机是怎么画出来这个图形的,我们只不过是重新声明了一遍这个图形对象,由此看来svg这种绘图方式是非常方便的.

如果是canvas绘图方式类似于纸和笔,那么svg绘图方式其实就是尺和规,是基于简洁而精确的数学方式的作图,而不是一个像素一个像素的涂改式的作图,是真正的所想即所得,大家可以好好体会一下.

参考文献

[1] 入门 - SVG | MDN

[2] - SVG: Scalable Vector Graphics | MDN

[3] Document Structure — SVG 2

[4] Extensible Markup Language (XML) 1.1 (Second Edition)

[5] Canvas API - Web APIs | MDN

技术交流hugosvg

Linux中的crontab命令的简单介绍及其用法

证明任意$n$个连续的正整数的乘积都能被$n!$整除