分享一个用于展示习惯的插件Habit Calendar,以及我是如何使用Obsidian记录习惯的。
Habit Calendar
Habit Calendar插件基于@duoani的Habit Tracker修改而来,可以让你使用DataviewJS方便地渲染出一个月视图。
使用方法
只需要准备好日历数据,然后在dataviewjs代码块中调用 renderHabitCalendar
即可。例如下面的代码将会渲染出这样的日历:
```dataviewjs
renderHabitCalendar(this.container, {
year: 2023,
month: 1,
entries: [{
date: '2023-01-01',
content: '⭐'
}, {
date: '2023-01-03',
content: '⭐'
}]
})
```
插件支持预览和跳转功能,可以跳转到对应的日记当中,或者跳转到指定的链接
同时支持自定义日历中填写的内容,可以是纯文本、markdown或者html,所以你可以自由地在里面放图片、链接等多种内容。因为支持用markdown填充,所以也支持[[类似这种obsidian链接]]
。
我记录习惯的方式
在日记中记录习惯的执行情况
每一个习惯使用一个checkbox表示,并且带上#habit
标签,同时添加一个dataview的属性,记录习惯的强度。例如每天读书30分钟我会像下面这样记录:
- [ ] #habit 阅读(reading:: 30)分钟
这样在阅读模式以及预览模式下就会显示成下图这样,不失可读性。同时,这样的格式可以记录习惯的执行强度(30分钟),是否完成(勾选与否),习惯名称(reading),方便后续进行数据处理。
如何提取出习惯的执行信息
dataviewjs把每个checkbox当成一个task,所以通过dataviewjs可以方便地访问每个task内的属性,包括该task是否完成、task包含什么标签、task包含什么dataview属性,具体的代码见下文。
习惯月视图
使用Habit Calendar插件,获取习惯数据之后传入renderHabitCalendar
:
```dataviewjs
let files = dv.pages(`"日记/2023/02"`)
let data = []
for (let file of files) {
for (let task of file.file.tasks) {
if (task.tags.contains('#habit') && task.checked && task.reading) { // 包含#habit并且已完成的task,并且reading值不为空
data.push({date: file.file.name, content: `📖 ${task.reading} min`})
}
}
}
renderHabitCalendar(this.container, {year: 2023, month: 2, entries: data, filepath: dv.current().file.path, width: "100%"})
```
效果如下:
习惯年视图
可以使用Heatmap Calendar这个插件。
同样先获取所有数据,然后传入Heatmap Calendar的接口中。
```dataviewjs
// 这一大段是从Heatmap Calendar中复制下来的。
dv.span("** 📖 阅读 **")
const calendarData = {
year: 2023, // (optional) defaults to current year
colors: { // (optional) defaults to green
blue: ["#8cb9ff", "#69a3ff", "#428bff", "#1872ff", "#0058e2"], // first entry is considered default if supplied
green: ["#c6e48b", "#7bc96f", "#49af5d", "#2e8840", "#196127"],
red: ["#ff9e82", "#ff7b55", "#ff4d1a", "#e73400", "#bd2a00"],
orange: ["#ffa244", "#fd7f00", "#dd6f00", "#bf6000", "#9b4e00"],
pink: ["#ff96cb", "#ff70b8", "#ff3a9d", "#ee0077", "#c30062"],
orangeToRed: ["#ffdf04", "#ffbe04", "#ff9a03", "#ff6d02", "#ff2c01"]
},
showCurrentDayBorder: true, // (optional) defaults to true
defaultEntryIntensity: 4, // (optional) defaults to 4
intensityScaleStart: 10, // (optional) defaults to lowest value passed to entries.intensity
intensityScaleEnd: 100, // (optional) defaults to highest value passed to entries.intensity
entries: [], // (required) populated in the DataviewJS loop below
}
function getHabitInPage(page, habit) {
for (let task of page.file.tasks) {
if (task.tags.contains('#habit') && task.checked && task[habit]) {
return task[habit]
}
}
return undefined
}
//DataviewJS loop
for (let page of dv.pages('"日记/2023"')) {
const habitIntensity = getHabitInPage(page, 'reading')
if (!habitIntensity) {
continue
}
//dv.span("<br>" + page.file.name) // uncomment for troubleshooting
calendarData.entries.push({
date: page.file.name, // (required) Format YYYY-MM-DD
intensity: habitIntensity, // (required) the data you want to track, will map color intensities automatically
content: await dv.span(`[](${page.file.name})`),
color: "orange", // (optional) Reference from *calendarData.colors*. If no color is supplied; colors[0] is used
})
}
renderHeatmapCalendar(this.container, calendarData)
```