Obsidian Vault 状态大盘工具
5 min read

Obsidian Vault 状态大盘工具

借助 Dataview、Obsidian Chart 对 Better Word Count 插件中的 Obsidian Vault 状态统计数据进行可视化展示,实现的关键是一段 dataviewjs 脚本,参考文中的 gist 链接。
Obsidian Vault 状态大盘工具
Photo by Chris

对于 Obsidian 记录的状态一直有一个不痛不痒的需求:看看最近一段时间记录的统计数据。之所以不是强诉求是因为原生的状态栏(status bar)有相关统计展示,之前折腾过一个 Python 写的工具只实现了核心功能,显示部分没有做,最近在浏览 Obsidian 社区的时候发现了一个叫做 Better Word Count 的插件,这个插件对 Vault 有详细的数字统计,我打算利用目前已有的能力完成这个 Vault 状态显示的需求。

解决方案

解决思路

Alfred Usage Statistics

受到 Alfred Usage 的启发我打算用 Obsidian Chart 来完成图表的渲染,同时利用 Obsidian Dataview 数据处理能力来处理图表渲染需要的数据。

前置准备

根据上面的思路,在完成工具开发之前 Obsidian 需要有几个前置依赖

1. better word count 插件

better word count 插件安装完成之后打开统计数据收集开关。

Config of Better Word Count

2. obsidian chart 插件

安装并使能 obsidian chart 插件,同时准备好 chartjs 文档以备后续使用。

3. dataview 插件

安装并使能 dataview 插件,同时在配置中打开 dataviewjs。

Config of Dataview

Vault 状态工具

在完成准备工作之后就可以进行 Vault 状态展示工具的开发了,欢迎动手能力强的同学直接拿着 gist code 去自定义修改,最后欢迎在评论区附上自己的效果图。

dataviewjs 工具

1. 新建 dataviewjs

在 Obsidian 中新建(或直接嵌入到已有 note 的合适位置)note,在 note 中插入 dataviewjs(dataviewjs 的使用可以参考 dataview 文档),如下图所示:

dataviewjs syntax

2. 获取 better word count 统计数据

根据 better word count 插件的描述,统计数据会以 JSON 的格式保存在文件 .obsidian/vault-stats.json  中。因此我们只需要读取和解析出需要渲染的数据即可,具体操作如下所示:

const staticsDataDir = this.app.vault.configDir + "/vault-stats.json";
const data = await this.app.vault.adapter.read(staticsDataDir);

const statics = JSON.parse(data);
let wordsData = [];
let filesData = [];
let pagesData = [];
const history = Object.keys(statics.history);
for (const date of history) {
    wordsData.push({ x: date, y: statics.history[date].words });
    filesData.push({ x: date, y: statics.history[date].files });
    pagesData.push({ x: date, y: statics.history[date].totalPages });
}

3. 配置 chart

根据 obsidian chart 文档来配置需要展示的图表,obsidian chart 底层使用的是 chartjs 所以很多图表配置项需要去 chartjs 文档中查找,如果你选者的是折线图显示可以直接参考下面这段代码:

const chartData = {
    type: "line",
    data: {
        datasets: [
            {
                label: "Daily Words",
                data: wordsData,
                backgroundColor: ['rgba(255, 99, 132, 0.2)'],
                borderColor: ['rgba(255, 99, 132, 1)'],
                borderWidth: 1.2,
            },
            {
                label: "Total Files",
                data: filesData,
                backgroundColor: ['rgba(75, 192, 192, 0.2)'],
                borderColor: ['rgba(75, 192, 192, 1)'],
                borderWidth: 1.2,
            },
            {
                label: "Total Pages",
                data: pagesData,
                backgroundColor: ['rgba(54, 162, 235, 0.2)'],
                borderColor: ['rgba(54, 162, 235, 1)'],
                borderWidth: 1.2,
            }
        ],
    },
    options: {
        pointHoverBorderWidth: 6,
        interaction: {
            mode: 'index',
            axis: 'y',
        },
        plugins: {
            title: {
                display: true,
                text: 'Statistics of Obsidian Vault',
                font: { weight: 'bold italic', size: '16px', family: 'Barlow' },
            },
            subtitle: {
                display: true,
                text: this.app.vault.getName(),
                font: { size: '14px', style: 'italic', family: 'sans-serif' }
            }
        },
        animations: {
            tension: {
                duration: 1000,
                easing: 'easeInOutSine',
                from: 0.5,
                to: 0,
                loop: true
            }
        },
        scales: {
            y: {
                stacked: true,
                border: {
                    display: true,
                    width: 0.8,
                },
                grid: {
                    display: true,
                    drawOnChartArea: true,
                    drawTicks: true,
                    color: 'rgba(239, 239, 239, 0.2)',
                },
            },
            x: {
                border: {
                    display: false,
                    width: 0.8,
                },
                grid: {
                    color: 'rgba(239, 239, 239, 0.2)',
                },
            },
        },
    },
};

图表渲染和调试

在 dataviewjs 的最后加上如下的绘制代码即可:

// 调用 obsidian chart API
window.renderChart(chartData, this.container);

// P.S.
// renderChart 可以多次调用即绘制多张图表

tips

chartjs 自定义

chartjs 有很多进阶的配置可以去文档按图索骥,我的做法是直接搜索关键字,例如我想设置图表网格线的颜色,我在 chartjs 文档中搜索了一下  “grid” 就会发现对应的内容:

chartjs grid config document

图表动画

为了让图表看上去美观一点,我加了一点动画主要配置是这一段:

        animations: {
            tension: {
                duration: 1000,
                easing: 'easeInOutSine',
                from: 0.5,
                to: 0,
                loop: true
            }
        },

看一下效果图:

0:00
/
preview of vault statistics

图表交互

图表支持悬停效果,我主要配置了数据展示:

        pointHoverBorderWidth: 6,
        interaction: {
            mode: 'index',
            axis: 'y',
        },
interaction of chart

后续

chartjs 自定义能力非常强,后续我打算在交互做点文章,主要是很多配置支持 javascript 编程,如下图 dataset 参数所示,backgroundColor 是 scriptable 的就意味着可以通过编程实现 hover 改变背景颜色,深浅主题自动切换等等。这里有非常多的想象空间,欢迎愿意折腾的同学在评论区分享你的案例。

chartjs scriptable parameters

References

  1. lukeleppan/better-word-count: Counts the words of selected text in the editor.
  2. Line Chart | Chart.js

Public discussion