复刻了那个交互式旅行博文
之前看到 有一篇交互式的旅行博文 做得很精美,作者本人也发了 codrops 教程,但是只写了思路没给源代码(教程最后说 GitHub link coming soon,但这一等就是十年),在其他人的站也看到过一次。都没有源代码但是我们可以从 codrops 的 demo 页面 直接查看 minify 后的结果逆向出来,github 搜得到很多这样的项目。
总之就是本站也实现了一份,可以看这一篇或这一篇,现为互动式地图博文(为获得最好的体验,推荐使用最新版桌面端 chrome 进行浏览)。
思路
目标效果很清晰,没有太多奇技淫巧可以讲,主要的实现与特效就只有:
- 监听页面滚动,对 SVG 修改 stroke 信息以同步路径进度
- 标记原文,在特定内容被展示时同步路径进度、位置、缩放
- 路径打点,同步绘制三角形
- 色差效果
- CRT 滤镜
- 渐近模糊
文章间不同的数据就需要在写文章的时候录入,而相同的部分就抽取为 js 和 css 放到 ejs 当中(本博用的 hexo)了。
综上考虑特效,文章里需要录入的数据也只有:
- 地图数据
- 路径数据
- 原文关联路径,打点位置和放大倍率
所以 md 的格式(hexo 主题用)也就大致能约定出来长这样:1
2
3
4
5
6
7layout: storytellingmap
path: 'xxx.SVG'
map: 'xxx.png'
---
<p data-percent='40' data-scale='1.4'>
需要在路径40%处放大1.4倍的内容
</p>
比原始实现的版本简单了不止一点点,剩下的就是单纯的编码实现了。
难点
地图和路线的获取
特定区域的地图图片倒是挺容易获取的:snazzymaps、openstreetmap 都可以免费下载。但路线 SVG 却很难得到(考虑过在 figma 里沿着地图慢慢描)。最后是在谷歌地图里创建个人地图,导出为 KML 文件(以获得SVG)和打印地图(以获得地图图片)。谷歌地图的好处是可以一站获取两份数据,还支持导航:输入起止点就可以获得线路。
匹配地图和路线
从上面得到的 KML 可以通过命令行工具(mapshaper)或者在线工具(mygeodata)转换成 SVG。但需要注意,因为投影转换规则不同,路线最终与地图可能匹配不上。这是因为……你知道图片是平的但地球是圆的,对吧?
这里需要使用 EPSG:3857 进行转换,不然你会发现不管如何拉伸平移旋转,路线就是不在道路上。
谷歌地图的坑
这一篇里遇到有一段线路走了两遍,但 KML 导出 SVG 后可以看到只剩连续的点,丢失了「重复」这个重要信息。解决方案是在重复点前后截断,导出两份 KML,转换为两个 SVG 后再合并 SVG,以获得重复路线。
SVG 转坐标
SVG 是通过 M-移动,L-画线,H-水平,V-垂直,C-贝塞尔等 token 描述矢量的,我们需要把这个 path 信息转换为一系列绝对的坐标供 canvas 画线用。当然这个也有实现了,不用自己造轮子。
色差效果
模拟真实镜头的色差,内容边界(尤其是亮色与暗色的边界)有彩色的描边条纹。这其实可以通过简单的 svg filter 实现:使用红绿两个 feColorMatrix 分离图像的红色与非红色通道,然后使用 screen blend 错位投影即可。
CRT 滤镜
模拟显像管显示器,你可以看到很多黑色细竖线,放大后可以观察到红绿蓝的偏色。这其实是使用了一块 4x3 的 png 转 base64,然后作为页面的 background-image。这一节的难度其实是找到合适的 png,我制作了一张圆形的半透明三原色的图片,然后将它缩小到 4x3。
渐近模糊
模拟近摄时的微距效果,靠近 canvas 上下边缘的位置有模糊效果。
稍微有些遗憾是没有找到可以下载 SVG 地图的地方,如果可以的话那原数据能更小一点,加载速度会快一些(渲染卡不卡还真难说)。优势就挺明显了,在已有博文的基础上修改一篇不用新开编辑器绘制路线,全程浏览器内就能完成所有编辑工作,标记语法也非常精简,美滋滋。
说了这么多,源代码可以直接在上面两篇HTML里看到,没有混淆压缩甚至还保留了注释,有兴趣的同学自己拿回去改改原数据(估计)就能用。