Skip to content

Render a year overview and color every day that matches your search criteria

Render a year overview for your data

Basic

Track activities in your dailies, i.e. if you have prayed.

const values = dv.pages('"10 Example Data/dailys"').where(p => p.praying === "yes");
const year = 2022;
const color = "green";
const emptyColor = "rgba(255,255,255,0.1)";

// == Create calendar data ==
let date = dv.luxon.DateTime.utc(year)
const calendar = [];
for(let i = 1; i <= 12; i++) {
    calendar[i] = []
}

// == Fill calendar ==
while (date.year == year) {
    const col = !!values.find(p => p.day.equals(date.startOf('day'))) ? color : emptyColor;
    calendar[date.month].push(getDayEl(date, col))

    date = addOneDay(date);
}

// == Render calendar ==
calendar.forEach((month, i) => {
    const monthEl = `<span style='display:inline-block;min-width:30px;font-size:small'>${dv.luxon.DateTime.utc(year, i).toFormat('MMM')}</span>`

    dv.el("div", monthEl + month.reduce((acc, curr) => `${acc} ${curr}`, ""))
})

function addOneDay(date) {
    return dv.luxon.DateTime.fromMillis(date + dv.duration("1d"))
}

function getDayEl(date, color) {
    const sizeOfDays = "12px";
    return `<span style="width:${sizeOfDays};height:${sizeOfDays};border-radius:2px;background-color:${color};display:inline-block;font-size:4pt;" title="${date.toFormat('yyyy-MM-dd')}"></span>`
}

Variants

Use a meta data field with a date instead of file.day

See on one glimpse the start and finish dates of your projects.

const values = dv.pages('"10 Example Data/projects"').where(p => p.started);
const year = 2022;
const emptyColor = "rgba(255,255,255,0.1)";

// == Fill data ==
let date = dv.luxon.DateTime.utc(year)
const calendar = [];
for(let i = 1; i <= 12; i++) {
    calendar[i] = []
}

while (date.year == year) {
    calendar[date.month].push(getDayEl(date, determineColor(date)))

    date = addOneDay(date);
}

// == Render calendar ==
calendar.forEach((month, i) => {
    const monthEl = `<span style='display:inline-block;min-width:30px;font-size:small'>${dv.luxon.DateTime.utc(year, i).toFormat('MMM')}</span>`

    dv.el("div", monthEl + month.reduce((acc, curr) => `${acc} ${curr}`, ""))
})

function addOneDay(date) {
    return dv.luxon.DateTime.fromMillis(date + dv.duration("1d"))
}
function getDayEl(date, color) {
    const sizeOfDays = "12px";
    return `<span style="width:${sizeOfDays};height:${sizeOfDays};border-radius:2px;background-color:${color};display:inline-block;font-size:4pt;" title="${date.toFormat('yyyy-MM-dd')}"></span>`
}

function determineColor(date) {
    const started = values.find(p => p.started?.startOf('day').equals(date.startOf('day')));
    const finished = values.find(p => p.finished?.startOf('day').equals(date.startOf('day')));
    let color = emptyColor;

    if (started && finished) {
        color = '#9959ff';  
    } else if (started) {
        color = '#ff5976'
    } else if (finished) {
        color = 'green'
    }

    return color;
}

Add information on hover

Hover over a dot and wait a moment to see which project started or finished.

const values = dv.pages('"10 Example Data/projects"').where(p => p.started);
const year = 2022;
const emptyColor = "rgba(255,255,255,0.1)";

// == Fill data ==
let date = dv.luxon.DateTime.utc(year)
const calendar = [];
for(let i = 1; i <= 12; i++) {
    calendar[i] = []
}

while (date.year == year) {
    calendar[date.month].push(getDayEl(date, determineColor(date), createTooltip()))

    date = addOneDay(date);

    function createTooltip() {
        let tooltip = "";
        const vals = values.filter(p => checkDateEq(p.started, date) || checkDateEq(p.finished, date))
        for (let val of vals) {
            tooltip += `${val.file.name} `
        }
        return tooltip;
    }
}

// == Render calendar ==
calendar.forEach((month, i) => {
    const monthEl = `<span style='display:inline-block;min-width:30px;font-size:small'>${dv.luxon.DateTime.utc(year, i).toFormat('MMM')}</span>`

    dv.el("div", monthEl + month.reduce((acc, curr) => `${acc} ${curr}`, ""))
})

function addOneDay(date) {
    return dv.luxon.DateTime.fromMillis(date + dv.duration("1d"))
}
function getDayEl(date, color, hoverInfo) {
    const sizeOfDays = "12px";
    return `<span style="width:${sizeOfDays};height:${sizeOfDays};border-radius:2px;background-color:${color};display:inline-block;font-size:4pt;" title="${hoverInfo}"></span>`
}

function checkDateEq(date1, date2) {
    if (!date1 || !date2) return false
    return date1.startOf('day').equals(date2.startOf('day'))
}

function determineColor(date) {
    const started = values.find(p => p.started?.startOf('day').equals(date.startOf('day')));
    const finished = values.find(p => p.finished?.startOf('day').equals(date.startOf('day')));
    let color = emptyColor;

    if (started && finished) {
        color = '#9959ff';  
    } else if (started) {
        color = '#ff5976'
    } else if (finished) {
        color = 'green'
    }

    return color;
}

Use a intensity to display different values

const values = dv.pages('"10 Example Data/dailys"').where(p => p.wellbeing?.mood);
const year = 2022;
const emptyColor = "rgba(255,255,255,0.1)";

// == Fill data ==
let date = dv.luxon.DateTime.utc(year)
const calendar = [];
for(let i = 1; i <= 12; i++) {
    calendar[i] = []
}

while (date.year == year) {
    calendar[date.month].push(
    getDayEl(
        date, 
        determineColor(date)))

    date = addOneDay(date);
}

// == Render calendar ==
calendar.forEach((month, i) => {
    const monthEl = `<span style='display:inline-block;min-width:30px;font-size:small'>${dv.luxon.DateTime.utc(year, i).toFormat('MMM')}</span>`

    dv.el("div", monthEl + month.reduce((acc, curr) => `${acc} ${curr}`, ""))
})

function addOneDay(date) {
    return dv.luxon.DateTime.fromMillis(date + dv.duration("1d"))
}

function getDayEl(date, color) {
    const sizeOfDays = "12px";
    return `<span style="width:${sizeOfDays};height:${sizeOfDays};border-radius:2px;background-color:${color};display:inline-block;font-size:4pt;" title="${date.toFormat('yyyy-MM-dd')}"></span>`
}

function determineColor(date) {
    console.log(values.find(p => !p.day))
    const page = values.find(p => p.file.day.startOf('day').equals(date.startOf('day')));
    if (!page) return emptyColor;


    let opacity = (page.wellbeing.mood / 4) ;
    return `rgba(177, 200, 51, ${opacity})`;

}

Use as a view file for reusability

What is#^dv-view

Simple case - input pages to display, the year to render and an "active" color

await dv.view("00 Meta/dataview_views/year_overview", 
    {
        pages: dv.pages('"10 Example Data/dailys"').where(p => p.praying === "yes"),
        year: 2022,
        color: "green"
    })

Complex case - Provide functions to determine color and tooltip. Both function will be called with the date to fill as argument and need to give back a string.

const pages = dv.pages('"10 Example Data/dailys"').where(p => p.wellbeing?.mood);

await dv.view("00 Meta/dataview_views/year_overview", 
    {
        pages: pages,
        year: 2022,
        color: determineColor,
        tooltipFn: generateTooltip
    })

function determineColor(date) {
    const page = pages.find(p => p.day.startOf('day').equals(date.startOf('day')));
    if (!page) return "rgba(9, 99, 199, 0.15)";

    let opacity = (page.wellbeing.mood / 4) ;
    return `rgba(177, 200, 51, ${opacity})`;

}

function generateTooltip(date) {
    const page = pages.find(p => p.day.startOf('day').equals(date.startOf('day')));
    if (!page) return date.toFormat('yyyy-MM-dd');

    return `${page.file.name}: ${page.wellbeing?.mood ?? ''}`
}

Render more than one meta data per day

Rendering multiple values

The amount of color blocks is determined by the number of colors given back, so all you need to tweak is what determineColor is giving back - and maybe increase the size of the day elements. 😉
If you want to use intensity too, determineColor needs to return something like [`rgba(177, 200, 51, ${(page.wellbeing.mood / 4)})`, `rgba(50, 90, 220, ${(page.wellbeing.health / 4)})`]

const values = dv.pages('"10 Example Data/dailys"').where(p => p.wellbeing?.mood);
const year = 2022;
const emptyColor = "rgba(255,255,255,0.1)";

// == Fill data ==
let date = dv.luxon.DateTime.utc(year)
const calendar = [];
for(let i = 1; i <= 12; i++) {
    calendar[i] = []
}

while (date.year === year) {
    calendar[date.month].push(
    getDayEl(
        date, 
        determineColor(date)))

    date = addOneDay(date);
}

// == Render calendar ==
calendar.forEach((month, i) => {
    const monthEl = `<span style='display:inline-block;min-width:30px;font-size:small'>${dv.luxon.DateTime.utc(year, i).toFormat('MMM')}</span>`

    dv.el("div", monthEl + month.reduce((acc, curr) => `${acc} ${curr}`, ""))
})

function addOneDay(date) {
    return dv.luxon.DateTime.fromMillis(date + dv.duration("1d"))
}

function getDayEl(date, colors) {
    const sizeOfDays = 14;
    const sizeOfColors = Math.round(sizeOfDays / colors.length)
    let dayEl = `<span style="width:${sizeOfDays}px;height:${sizeOfDays}px;display:inline-flex;flex-direction:column" title="${date.toFormat('yyyy-MM-dd')}">`
    for (let color of colors) {
        dayEl += `<span style="width:${sizeOfDays}px;height:${sizeOfColors}px;background-color:${color};display:inline-flex;"></span>`
    }
    dayEl += "</span>"
    return dayEl;
}

function determineColor(date) {
    const page = values.find(p => p.file.day.startOf('day').equals(date.startOf('day')));
    if (!page) return [emptyColor, emptyColor];

    return [
        page.beingthankful ? "#be83eb" : emptyColor,
        page.praying ? "#6c79b5" : emptyColor
    ]
}