在Obsidian中记录习惯-Habit Calendar

分享一个用于展示习惯的插件Habit Calendar,以及我是如何使用Obsidian记录习惯的。

Habit Calendar

Habit Calendar插件基于@duoaniHabit Tracker修改而来,可以让你使用DataviewJS方便地渲染出一个月视图。

使用方法

只需要准备好日历数据,然后在dataviewjs代码块中调用 renderHabitCalendar即可。例如下面的代码将会渲染出这样的日历:

```dataviewjs
renderHabitCalendar(this.container, {
  year: 2023,
  month: 1,
  entries: [{
    date: '2023-01-01',
    content: '⭐'
  }, {
    date: '2023-01-03',
    content: '⭐'
  }]
})
```

插件支持预览和跳转功能,可以跳转到对应的日记当中,或者跳转到指定的链接

hover

同时支持自定义日历中填写的内容,可以是纯文本、markdown或者html,所以你可以自由地在里面放图片、链接等多种内容。因为支持用markdown填充,所以也支持[[类似这种obsidian链接]]

我记录习惯的方式

在日记中记录习惯的执行情况

每一个习惯使用一个checkbox表示,并且带上#habit标签,同时添加一个dataview的属性,记录习惯的强度。例如每天读书30分钟我会像下面这样记录:

- [ ] #habit 阅读(reading:: 30)分钟

这样在阅读模式以及预览模式下就会显示成下图这样,不失可读性。同时,这样的格式可以记录习惯的执行强度(30分钟),是否完成(勾选与否),习惯名称(reading),方便后续进行数据处理。

image

如何提取出习惯的执行信息

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)
```

7 个赞

请问这个是说明heatmap calendar 中链接的笔记文件名称必须是‘YYYY-MM-DD’格式吗

let pages = dv.pages(`"600-日记/DailyNote/2024年/02月"`)
let data = []

for (let page of pages) {
		if (page.mood) { 
			data.push({date: moment(page.file.name,'YYYY年MM月DD日').format("YYYY-MM-DD"), content: page.mood})
	} 
}
renderHeatmapCalendar(this.container, {year: 2024, month:2, entries: data, filepath: dv.current().file.path, width: "100%"}) 

我试用了这个插件,但是预览效果却不是月视图。请问这是什么原因呢?