SVG Year timeline in your daily note (now a plugin)

Doing this seems like the date is wrong, it should be the template’s "Need escaping?

Change one of the double-quote pairs to single-quotes.

Thanks, I have another question, if I put this in the diary template, when I create the diary, I still can’t find the date in this place, but the above will work

Sorry for the delay in replying. Yes, that’s the Templater part that I updated. It took the day of the year and multiplied by ten by tagging a trailing zero. If you replace that with my update it does the same in math with the “* 10” but then adds ten more for each preceding gap (+ Month-1 * 10).

And no need to apologise. Not knowing something is not a crime. :grin:

2 Likes

I know that the Daily Notes plugin will create a note with the title set to the date in “YYYY-MM-DD” format, so I use the tp.file.title function to get the date by referencing the note’s title, but you could use the tp.date.now() without that to get today’s date.

I use this:

# 📆Daily Notes for <% tp.date.now("ddd", 0, tp.file.title, "YYYY-MM-DD") %> [[<% tp.file.title %>]]

to get this:

# 📆Daily Notes for Tue [[2022-08-16]] 

(Using the note title I can create a daily note in advance or retrospectively, title it for the required date, and the Templater code will correctly slot in the title/links etc. ) - Although I just realised that the timeline dot I carefully fixed doesn’t use the reference, so would be set for the date I created the note, not the date of the note title. I should make a note to fix that. :man_facepalming:

1 Like

It seems that when Calendar created the diary, the template was called, but when the diary was not created successfully, the template could not find the file name (tp.file.title), which caused this place to fail.

That would make sense. I tried it here with the Calendar creating a random date’s Daily Note and it worked okay. Do you know why the initial note creation failed in your case?

If the journal 2022-08-19 is created first, it is normal to manually load the template. But if I load the template while creating the journal 2022-08-19, the template fails

I found the reason, it is a problem with the Templater plugin, just go back to 1.13.0 :smiley:

Sorry again, I really can’t figure this out - I’ve been headscratching for a while now. What happens to the tp.file.title bit of the original code? That bit makes sure the correct date for my ‘daily note’ - without it the template aborts.
This is what I have…
<g> <circle cx="<% tp.date.now("DDD", 0, tp.file.title) %>0" cy="14" r="16" stroke="black" fill="white" /> </g>
and this is what I have tried )most recently)…
<g> <circle cx="<% (tp.date.now("DDD") * 10) + ((tp.date.now("M") - 1) * 10) %>0" cy="14" r="16" stroke="black" fill="white" /> </g>
Ahh, one moment – curly quotes might be the issue… Nope, the white marker disappears entirely!

The problem is the zero following the Templater code (i.e. %>0"). It’s making your cx value an order of magnitude larger than it should be. Just remove it and the calculation should work (i.e. %>").

Is there a way to show this on a note without dates or template plugin. I was thinking how to pass the date value to the circle tag in the code.

Ok i fixed this. I created a react component called timelinebar and then passed the days dynamically as props in the cx tag. Now the timeline is shown on any note and no need of only having daily note or templater installed. Just include the component on any note md file.

1Q. Doesnt the circle shows wrong position as we move towards the later part of the year? because the width of the sections are the months days*10 but the next month starts with addition of 10 in it. So that creates a lag on the circle marker when we see towards the later part of the year. Eg below 1st sep is showing in August.

1 Like

take a look at SVG Year timeline in your daily note - #40 by TanelTM above… it has code to counter the drift

1 Like

I just found this and am super excited :grinning: I thought I’d include how I’m using it, in case anybody’s interested :grinning:

I want to be able to use this timeline both on my weekly pages and my daily pages, so I created a separate snippet template for the timeline, which I can include in other templates. My timeline snippet has logic to check whether the file title matches my daily note pattern (YYYYMMDD) or my weekly note pattern (YYYY-MM-DD – Week). If the title doesn’t match either of those patterns, it just uses the current date. Then it generates the svg dynamically, so that the months will all be the right sizes, even in a leap year :tada:

Timeline Snippet:

<%* 
let title = tp.file.title;
let startDate = "";
if (title.match(/^[12][019]\d{2}[01]\d[0123]\d$/)) {
    startDate = tp.date.now("MM-DD-YYYY", 0, title);
} else if (title.match(/^[12][019]\d{2}-[01]\d-[0123]\d -- Week$/)) { 
    startDate = tp.date.now("MM-DD-YYYY", 0, title, "YYYY-MM-DD [-- Week]");
} else {
	startDate = moment().format("MM-DD-YYYY");
}
var year = moment(startDate).format("YYYY");
  var monthStart = 0;
  var monthBlocks = "";
  var monthLabels = "";
  var marker = "";
  for(let i = 1; i <= 12; i++) {
	  let daysInMonth = moment(year + "-" + i).daysInMonth();
	  let monthName = moment(year + "-" + i).format("MMMM");
	  monthBlocks += `<rect class="month-block month-block--${monthName}" x="${monthStart * 10}" width="${daysInMonth * 10}" height="25"></rect>`;
	  monthLabels += `<text class="month-label month-label--${monthName}" fill="#747474" x="${monthStart * 10}" y="120">${monthName}</text>`;
	  if (moment(startDate).format("M") == i) {
		  marker = monthStart + parseInt(moment(startDate).format("D"));
	  }
	  monthStart += daysInMonth + 1;
  } %>
<svg class="year-timeline year-timeline--<%year%>" viewBox="0 -20 3760 150">
	<title>Timeline <%year%></title>
	<g class='bars'>
		<% monthBlocks %>	
	</g>
	<g class='labels' style="font-size:50px;" text-anchor="start">
		<% monthLabels %>	
	</g>
	<g class='markers'>
		<circle class="day-marker" cx="<%`${marker * 10}`%>" cy="14" r="15" stroke="black" fill="white" /> 
		<rect class="week-marker"  x="<%`${marker * 10}`%>" width="70" height="25" /> 
	</g>
</svg>

In my daily and weekly templates I wrap the timeline in an extra div, so I can use the classes for styling:

Partial Daily Template:

# Daily Log -- <% tp.date.now("dddd, MMMM D, YYYY", 0, tp.file.title) %>

[[<% tp.date.now("YYYY[ -- Year]", 0, tp.file.title) %> |<% tp.date.now("YYYY", 0, tp.file.title) %>]] » [[<% tp.date.now("YYYY-MM", 0, tp.file.title) %> -- Month#<% tp.date.now("YYYYMMDD dddd, MMM D, YYYY", 0, tp.file.title) %> | <% tp.date.now("MMMM", 0, tp.file.title) %>]]  » [[<% tp.date.weekday("YYYY-MM-DD", 0, tp.file.title) %> -- Week#<% tp.date.now("YYYYMMDD dddd, MMM D, YYYY", 0, tp.file.title) %> | Week <% tp.date.now("ww", 0, tp.file.title) %>]]
[[<% tp.date.now("YYYYMMDD", -1, tp.file.title) %> | ⇦ Previous Day]] | [[<% tp.date.now("YYYYMMDD", +1, tp.file.title) %> | Next Day ⇨]] 
<div class="timeline timeline--day"><% tp.file.include("[[Timeline]]") %></div>

Partial Weekly Template:

# <% tp.date.weekday("[Week] ww", 0, tp.file.title, "YYYY-MM-DD [-- Week]") %>:  <% tp.date.weekday("MMM D, YYYY", 0, tp.file.title, "YYYY-MM-DD [-- Week]") %> - <% tp.date.weekday("MMM D, YYYY", 6, tp.file.title, "YYYY-MM-DD [-- Week]") %>
[[<% tp.date.now("YYYY[ -- Year]", 0, tp.file.title, "YYYY-MM-DD [-- Week]") %> |<% tp.date.now("YYYY", 0, tp.file.title, "YYYY-MM-DD [-- Week]") %>]] » [[<% tp.date.now("YYYY-MM[ -- Month]", 0, tp.file.title, "YYYY-MM-DD [-- Week]") %> |<% tp.date.now("MMMM", 0, tp.file.title, "YYYY-MM-DD [-- Week]") %>]]
[[<% tp.date.weekday("YYYY-MM-DD [-- Week]", -7, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>| ⇦ Previous Week ]] | [[<% tp.date.weekday("YYYY-MM-DD [-- Week]", 7, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>| Next Week ⇨]] 
[[<% tp.date.weekday("YYYYMMDD", 0, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>|<% tp.date.weekday("ddd DD", 0, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>]] · [[<% tp.date.weekday("YYYYMMDD", 1, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>|<% tp.date.weekday("ddd DD", 1, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>]] · [[<% tp.date.weekday("YYYYMMDD", 2, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>|<% tp.date.weekday("ddd DD", 2, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>]] · [[<% tp.date.weekday("YYYYMMDD", 3, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>|<% tp.date.weekday("ddd DD", 3, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>]] · [[<% tp.date.weekday("YYYYMMDD", 4, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>|<% tp.date.weekday("ddd DD", 4, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>]] · [[<% tp.date.weekday("YYYYMMDD", 5, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>|<% tp.date.weekday("ddd DD", 5, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>]] · [[<% tp.date.weekday("YYYYMMDD", 6, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>|<% tp.date.weekday("ddd DD", 6, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>]]^<% tp.date.weekday("[W]ww", 0, tp.file.title, "YYYY-MM-DD [-- Week]" ) %>
<div class="timeline timeline--week"><% tp.file.include("[[Timeline]]") %></div>

Then I adjust it using CSS to color the months and hide the extra marker, depending on whether I’m looking at a week or a day.

Styles

.year-timeline .bars {
  padding-bottom: 50px;
}

.year-timeline .month-block {
  height: 50px;
}

.year-timeline .month-block--January {
  fill: #cfe2f3;
}

.year-timeline .month-block--February {
  fill: #a2c4c9;
}

.year-timeline .month-block--March {
  fill: #76a5af;
}

.year-timeline .month-block--April {
  fill: #93c47d;
}

.year-timeline .month-block--May {
  fill: #6aa84f;
}

.year-timeline .month-block--June {
  fill: #8fce00;
}

.year-timeline .month-block--July {
  fill: #ffd966;
}

.year-timeline .month-block--August {
  fill: #f1c232;
}

.year-timeline .month-block--September {
  fill: #ce7e00;
}

.year-timeline .month-block--October {
  fill: #e06666;
}

.year-timeline .month-block--November {
  fill: #f4cccc;
}

.year-timeline .month-block--December {
  fill: #eeeeee;
}

.year-timeline .month-label {
  font-size: 56px;
}

.year-timeline .day-marker {
  box-shadow: 0 0 5px 20px black;
  cy: 25;
  fill: rgba(52, 88, 235, 1);
  r: 20px;
  stroke-width: 5px;
  stroke: white;
}

.year-timeline .week-marker {
  fill: rgba(52, 88, 235, 1);
  height: 50px;
  outline: 5px solid black;
  stroke-width: 5px;
  stroke: white;
  /* x: 800px; */
  y: -3px;
}

.timeline--day .year-timeline .week-marker {
  display: none;
}

.timeline--week .year-timeline .day-marker {
  display: none;
}

Results:

Screenshot 2022-11-26 at 21.23.45

Screenshot 2022-11-26 at 21.24.36

Credit:

5 Likes

Obsidian now uses Electron 21, which uses Chrome 106, which means we can now use the new element:has(element) selector!
This allows for the timeline tag (<i data-timeline="{{date:DDD}}0"></i>) to be checked in the content, but the timeline itself can be rendered outside the content area.

Code example: Obsidian timeline CSS snippet alternative version · GitHub

We could also get rid of the data-timeline tag entirely, because we can check if the active tab has a date area label and then render the timeline accordingly. To generate all the CSS code would take some time, which I don’t have right now, but the selector for it would essentially be:

.workspace-tab-header-container:has(.workspace-tab-header.is-active[aria-label="2023-01-04"]) +
.workspace-tab-container .workspace-leaf::before {
	color: red;
	content: "This is a note for 2023-01-04!";
}

Happy hacking and happy new year!

3 Likes

Hi…
I LOVE this CSS snippet but I don’t use “Daily Notes” like you all do. Instead I want to use this timeline on a dashboard-like home page. I can’t figure out how to update the date portion so that it keeps moving the marker to the current date every time I open the home page on different days. All the examples in this thread use template {{}} syntax for the date. Obviously this won’t work for a home page as it’s not a template but a dynamic document. I was thinking dataview would be a great option but I just can’t get anything to work. How would I modify this CSS/SVG and the code embeding it into my home page to adapt this timeline to a home page rather than a Daily Note template?

  • Thanks

I love your timeline and use it daily. But I had a problem that it didn’t render when I created the note on iOS.
Modifying the timeline snippet helped:

<%*
let title = tp.file.title;
let startDate;

if (title.match(/\d{4}-\d{2}-\d{2}/)) {
  startDate = tp.date.now("YYYY-MM-DD", 0, title);
} else if (title.match(/\d{4}-W\d{2}/)) {
  startDate = tp.date.now("YYYY-MM-DD", 0, title, "gggg-[W]ww [-- Week]");
} else {
  startDate = moment().format("YYYY-MM-DD");
}

const year = moment(startDate).format("YYYY");
let monthStart = 0;
let monthBlocks = "";
let monthLabels = "";
let marker = "";

for (let i = 1; i <= 12; i++) {
  const daysInMonth = moment().year(year).month(i).daysInMonth();
  const monthName = moment().year(year).month(i).format("MMMM");
  monthBlocks += `<rect class="month-block month-block--${monthName}" x="${monthStart * 10}" width="${daysInMonth * 10}" height="25"></rect>`;
  monthLabels += `<text class="month-label month-label--${monthName}" fill="#747474" x="${monthStart * 10}" y="120">${monthName}</text>`;

  if (moment(startDate).format("M") == i) {
    marker = monthStart + parseInt(moment(startDate).format("D"));
  }

  monthStart += daysInMonth + 1;
};


tR += `<svg class="year-timeline year-timeline--${year}" viewBox="0 -20 3760 150">
    <title>Timeline ${year}</title>
    <g class='bars'>
      ${monthBlocks}
    </g>
    <g class='labels' style="font-size:50px;" text-anchor="start">
      ${monthLabels}
    </g>
    <g class='markers'>
      <circle class="day-marker" cx="${marker * 10}" cy="14" r="15" stroke="black" fill="white" /> 
      <rect class="week-marker"  x="${marker * 10}" width="70" height="25" /> 
    </g>
  </svg>`
%>

Cheers!

1 Like

Should be i-1 apologies

1 Like