可在预览模式直接调节的可视化进度条

在b站收藏了许多视频,这些视频都有挺多p的,想在ob记录记录每个视频大概学到多少了,提醒自己去学学,又不想为这点东西单独列一堆笔记,于是就用dataviewjs实现了这么个功能,主要是试验一下预览模式下的修改功能

20220509_154200

这里要感谢宏沉一笑大佬提供的按钮方案

实现代码如下:

```dataviewjs
const file = dv.current()
//const file = dv.page(`DateBase`) 本来想把数据放另一个文件来着
const af = app.vault.getMarkdownFiles().filter(p=>p.path==file.file.path)[0]

let content = await app.vault.readRaw(file.file.path)
const rawText = /(?<=\%\%)[\s\S]*?(?=\%\%)/.exec(content)[0].split('\n').filter(p=>p.length!=0)
let Data = rawText.map(p=>p.split('|')).map(p=>[p[0],Number(p[1]),p[2]=Number(p[2])])

const button = (data,i)=>{
    const title = this.container.createEl('span',{'text':Data[i][0]})
    const plan = this.container.createEl('span',{'text':Data[i][1]+'/'+Data[i][2]})
    const progress = this.container.createEl('progress')
    progress.value = Data[i][1]
    progress.max = Data[i][2]

    const button = this.container.createEl('div',)
    const btn_p = button.createEl('button',{'text':'+'})
    const btn_s = button.createEl('button',{'text':'-'})
    //本来想加个可以直接写数字修改的按钮,但是我做不出来弹窗😭,所以大幅度改变只能手动修改下面的数字了
    //const btn_set = this.container.createEl('button',{'text':'set'})
    btn_p.addEventListener('click',async (evt)=> {
        evt.preventDefault()
        midifyData(i,'p')
        progress.value = Data[i][1]
        plan.innerHTML = Data[i][1]+'/'+Data[i][2]
    })
    btn_s.addEventListener('click',async (evt)=> {
        evt.preventDefault()
        midifyData(i,'s')
        progress.value = Data[i][1]
        plan.innerHTML = Data[i][1]+'/'+Data[i][2]
    })
    return [title,plan,progress,button]
}

// 表格本体
dv.table(
    ['标题','进度','进度条','修改'],
    Data.map((p,i)=>button(p,i))
    )

// 保存按钮
const btn_save = this.container.createEl('button',{'text':'save'})
btn_save.addEventListener('click',async (evt)=> {
        evt.preventDefault()
        save()
    })

// 修改函数,直接加减可以大于max或变负数
function midifyData(i,m) {
    if(Data[i][1]<Data[i][2] && m=='p') Data[i][1] += 1
    if(Data[i][1]>0 && m=='s') Data[i][1] -= 1
}

// 保存函数
function save() {
    for(let i in Data)
        content = content.replace(rawText[i],`${Data[i][0]}|${Data[i][1]}|${Data[i][2]}`)
    app.vault.modify(af,content)
}
```

%%
高数 - 曲线曲面积分|8|8
电路原理|188|259
%%

:smiling_face_with_tear:,可惜没能实现自动保存到文件里,要是把保存方法写到加减按钮里就会太慢了,每次加1或减1都要等一下,毕竟刷新原理是库api修改文件->dataview检测到文件修改->刷新

不过,这表格展示还是不太好看,希望大家提提建议,看看这几个元素怎么摆才好看,改天再写点样式来

10 个赞

太强了!!!有一个功能我一直想知道怎么实现,就是关于进度条的颜色。不知道能不能让进度条自动改变颜色。比如低于30%是红色,30-60黄色60-99绿色。100自动变成:white_check_mark:

嗯,修改颜色是个好主意,顺手还实现了排序功能

```dataviewjs
let file = dv.current()
let af = app.vault.getMarkdownFiles().filter(p=>p.path==file.file.path)[0]
let container = this.container

let content = await app.vault.readRaw(file.file.path)
let regexp = /(?<=\%\%)[\s\S]*?(?=\%\%)/
let rawText = regexp.exec(content)[0].split('\n').filter(p=>p.length!=0)
let Data = rawText.map(p=>p.split('+|+')).map(p=>[p[0],Number(p[1]),p[2]=Number(p[2])])

// 表格元素
let rank = (data,i)=>{
	let com = table.createEl('div')
    let title = Data[i][0]
    let plan = com.createEl('span',{'text':Data[i][1]+'/'+Data[i][2]})
    let progress = com.createEl('progress')
    changePro(progress,Data[i][1]/Data[i][2],com)
    progress.value = Data[i][1]
    progress.max = Data[i][2]

    let button = com.createEl('div',)
    let btn_p = button.createEl('button',{'text':'+'})
    let btn_s = button.createEl('button',{'text':'-'})
    btn_p.addEventListener('click',async (evt)=> {
        midifyData(i,'p')
        progress.value = Data[i][1]
        changePro(progress,Data[i][1]/Data[i][2],com)
        plan.innerHTML = Data[i][1]+'/'+Data[i][2]
    })
    btn_s.addEventListener('click',async (evt)=> {
        midifyData(i,'s')
        progress.value = Data[i][1]
        changePro(progress,Data[i][1]/Data[i][2],com)
        plan.innerHTML = Data[i][1]+'/'+Data[i][2]
    })
    return [title,plan,progress,button]
}

// 表格本体
let table = container.createEl("div");
let headers = ['标题','进度','进度条','修改']
let values = Data.map((p,i)=>rank(p,i))
createTable(headers,values,table)

// 保存按钮
let button_ = container.createEl('div',{'id':'con'})
let btn_save = button_.createEl('button',{'text':'save'})
btn_save.addEventListener('click',async (evt)=> {
    evt.preventDefault()
    let data = '\n'+Data.map(p=>p.join('+|+')).join('\n')+'\n'
    content = content.replace(regexp,data)
    app.vault.modify(af,content)
})

// 排序
let sortOptions = ['名称 A-Z','名称 Z-A','百分比-正序','百分比-倒序']
let sortFun = [
	(a,b)=>dv.compare(a[0],b[0]),
	(a,b)=>dv.compare(b[0],a[0]),
	(a,b)=>dv.compare(b[1]/b[2],a[1]/a[2]),
	(a,b)=>dv.compare(a[1]/a[2],b[1]/b[2]),
]
let se = button_.createEl('select')
let op = sortOptions.map(p=>se.createEl('option',{'text':p}))
se.onchange = function() {
	let index = se.selectedIndex
	table.empty()
	Data = Data.sort(sortFun[index])
    createTable(
	    headers, 
	    Data.map((p,i)=>rank(p,i)),
	    table)
}

// 其他函数
function createTable(headers,values,t) {
	dv.table(headers,values)
	t.appendChild(container.getElementsByTagName('table')[0])
}
function changePro(progress, p, com) {
	if(p>=0 && p<0.3) progress.className = 'red'
	else if(p>=0.3 && p<0.6) progress.className = 'yellow'
	else if(p>=0.6 && p<1) progress.className = 'green'
	else if(p==1) progress.className = 'ok'

}
// 修改函数
function midifyData(i,m) {
    if(Data[i][1]<Data[i][2] && m=='p') Data[i][1] += 1
    if(Data[i][1]>0 && m=='s') Data[i][1] -= 1
}
```

%%
高数 - 曲线曲面积分+|+8+|+8
电路原理+|+188+|+259
%%

css文件

progress {
  border-radius: 10px;
  height: 0.4em;
  width: 10em;
}
progress::-webkit-progress-bar {
  border-radius: 10px;
  background: white!important;
}
progress.red::-webkit-progress-value {
  border-radius: 10px;
  background: red;
}
progress.yellow::-webkit-progress-value {
  border-radius: 10px;
  background: yellow;
}
progress.green::-webkit-progress-value {
  border-radius: 10px;
  background: green;
}
progress.ok {
  height: 0;
  width: 0;
}
progress.ok:after {
  content: "✅";
}
1 个赞

很强!!!爱了哈哈哈。

还有想问一下,想入门dataviewjs有什么推荐的教学么。起码能看懂代码语法之类的,现在只能做到拿来就用,但是有时候也想知道原理。

1 个赞

大佬,这个css文件放在哪里啊,不知道怎么使用后面这个版本的

就和别的css文件一样放在.obsidian/snippets下,然后在设置-外观下面刷新打开

我还是有报错哎,可能我太小白了

额,看一下整个文件的内容,我不明白为什么会有non-finite的值:rofl:

然后就是复制了你的第二段代码,没有其他内容

%%
高数 - 曲线曲面积分|8|8
电路原理|188|259
%%

:scream::scream:我的锅,为了能用 [[a|b]] 来显示双链,把分隔符改为 +|+ 了,改了却忘了说,现在已经改了

哈哈,原来是这样,我说怎么就是不行呢,主要我也读不懂代码,谢谢大佬!


大佬大佬,我突然有一个想法不知道能不能实现,就是通过按扭直接去修改这个status,状态。在表格模式点击按扭可以出现三个选项“计划中”“进行中”“已完成”。方便直接修改。

直接修改的话可以参考宏沉一笑大佬的文章,我也没仔细看,只看到了可以写按钮的方法就兴奋的跑去实验了,才发现弹窗方法大佬也展示了

于是,进度条3.0版本就出现了 :partying_face:

摘要

先安装 Metaedit 插件,打开 Auto Properties ,点它右下角的齿轮,左边的框框填个 new,右边不用填,进度条里的东西都是可以点的!

```dataviewjs
let dv_=app.plugins.plugins["dataview"].api
let {update,autoprop} = app.plugins.plugins["metaedit"].api

let file = dv.current()
let af = app.vault.getMarkdownFiles().filter(p=>p.path==file.file.path)[0]
let container = this.container

let content = await app.vault.readRaw(file.file.path)
let regexp = /(?<=\%\%)[\s\S]*?(?=\%\%)/
let rawText = regexp.exec(content)[0].split('\n').filter(p=>p.length!=0)
let Data = rawText.map(p=>p.split('+|+')).map(p=>[p[0],Number(p[1]),p[2]=Number(p[2])])

// 表格元素
let rank = (data,i)=>{
	let com = table.createEl('div',{'cls':'com'})
    let progress = com.createEl('div',{cls:'progress'})
    let title = dv_.renderValue(Data[i][0],com)
    let bar = progress.createEl('div',{cls:'p-bar'})
    progressColor(bar,Data[i][1]/Data[i][2])
    bar.style.width = Data[i][1]/Data[i][2]*100+'%'
    let button = bar.createEl('div',{cls:'btn'})
    let btn_p = button.createEl('div',{'text':'+'})
    let btn_s = button.createEl('div',{'text':'-'})
    let ratio1 = bar.createEl('div',{'cls':'per','text':String(Data[i][1])})
    let ratio2 = bar.createEl('div',{'cls':'per','text':'/'})
    let ratio3 = bar.createEl('div',{'cls':'per','text':String(Data[i][2])})
    btn_p.onclick = function() {
	    Data[i][1]+=1
        m(i,ratio1,ratio3,bar)
    }
    btn_s.onclick = function() {
	    Data[i][1]-=1
        m(i,ratio1,ratio3,bar)
    }
    ratio1.onclick = async function() {
		let text = await autoprop('new')
		Data[i][1] = Number(text)
		m(i,ratio1,ratio3,bar)
	}
    ratio3.onclick = async function() {
		let text = await autoprop('new')
		Data[i][2] = Number(text)
		m(i,ratio1,ratio3,bar)
	}
}

// 表格本体
let table = container.createEl("div",{'cls':'table'});
Data.map((p,i)=>rank(p,i))

// 保存按钮
let button_ = container.createEl('div',{'id':'con'})
let btn_save = button_.createEl('button',{'text':'save'})
btn_save.addEventListener('click',async (evt)=> {
    evt.preventDefault()
    let data = '\n'+Data.map(p=>p.join('+|+')).join('\n')+'\n'
    content = content.replace(regexp,data)
    app.vault.modify(af,content)
})

// 排序
let sortOptions = ['名称 A-Z','名称 Z-A','百分比-正序','百分比-倒序']
let sortFun = [
	(a,b)=>dv.compare(a[0],b[0]),
	(a,b)=>dv.compare(b[0],a[0]),
	(a,b)=>dv.compare(b[1]/b[2],a[1]/a[2]),
	(a,b)=>dv.compare(a[1]/a[2],b[1]/b[2]),
]
let se = button_.createEl('select')
let op = sortOptions.map(p=>se.createEl('option',{'text':p}))
se.onchange = function() {
	let index = se.selectedIndex
	table.empty()
	Data = Data.sort(sortFun[index])
    values = Data.map((p,i)=>rank(p,i))
}

// 其他函数
function progressColor(bar, p) {
	if(p>=0 && p<0.3) bar.className = 'p-bar p-red'
	else if(p>=0.3 && p<0.6) bar.className = 'p-bar p-yellow'
	else if(p>=0.6 && p<=1) bar.className = 'p-bar p-green'

}
function midifyData(i) {
    if(Data[i][1]>Data[i][2]) Data[i][1] = Data[i][2]
    if(Data[i][1]<0) Data[i][1] = 0
}
function m(i,ratio1,ratio3,bar) {
    midifyData(i)
    ratio1.innerHTML = Data[i][1]
    ratio3.innerHTML = Data[i][2]
    bar.style.width = Data[i][1]/Data[i][2]*100+'%'
    progressColor(bar,Data[i][1]/Data[i][2])
}
```

%%
高数 - 曲线曲面积分+|+8+|+8
电路原理+|+188+|+259
%%

css

.table {
  overflow-x: auto;
  overflow-y: hidden;
}
.com {
  margin: 0.3em;
}
.com div {
  float: left;
}
.btn {
  margin-left: 1px;
  display: flex;
  background: rgba(0,0,0,0)!important;
  -webkit-user-select: none;
  height: 1em;
}
.btn div {
  background: rgba(0,0,0,0)!important;
  line-height: 8px;
  height: 1em;
  width: 1em;
}
.btn div:hover {
  opacity: 0.3;
}
.per {
  -webkit-user-select: none;
  line-height: 14px;
  font-size: 0.8em;
}
.progress {
  background: transparent;
  margin-right: 0.3em;
  padding: 0.15em;
  border-style: solid;
  border-width: 0.15em;
  border-radius: 0.25em;
  width: calc(var(--line-width-readable)*0.5);
}
.p-bar.p-red {
  background: #c70000;
}
.p-bar.p-yellow {
  background: #948600;
}
.p-bar.p-green {
  background: #008a20;
}
.p-bar {
  display: flex;
  height: 0.75em;
  border-radius: 0.1rem;
  transition: width .2s linear;
}
1 个赞

感谢大佬回复,果然我这种小菜鸟好难啊哈哈哈。


请问这是为什么呢?

嗯,好像没添加css吧

另外可能是没表达清楚,数据的格式是

%%
高数 - 曲线曲面积分+|+8+|+8
电路原理+|+188+|+259
%%


是我没有更新最新的css。现在搞好了,感谢大佬 :smiling_face_with_three_hearts:

感谢大佬拯救我这种只会control c的小白 :laughing:

请问大佬,新版OB1.0里面按照这个设置了但是报错。。。
CSS 已经设置好了,在snippet里面也已经打开了。。。

贴入DS代码就显示。。。


:sob: 这个带按钮的进度条好好看啊。。。求大佬有空看看