mirror of
https://gitlab.com/arnekeller/trilium-timeline.git
synced 2024-11-09 19:00:46 +00:00
3f5a562c5d
Update !!!meta.json, Timeline Widget Import.zip, and 4 more files...
177 lines
8.4 KiB
JavaScript
177 lines
8.4 KiB
JavaScript
/** Version 1.0 **/
|
|
renderTimeline();
|
|
|
|
async function renderTimeline() {
|
|
// Initialize libraries and context
|
|
var vis = require('vis.min.js');
|
|
//var moment = require('moment.min.js');
|
|
var container = document.getElementById("timeline");
|
|
var menu = document.getElementById("menu");
|
|
|
|
// Get widget attribute values and fetch notes from defined tags
|
|
const events = await api.runOnServer(() => {
|
|
const parentNote = api.startNote.getParentNotes()[0];
|
|
// fetch what labels to look for from widget attributes
|
|
// event notes (start/end)
|
|
const event_note_label_start = parentNote.getLabelValue('event_label_start').toString();
|
|
const event_note_label_end = parentNote.getLabelValue('event_label_end').toString();
|
|
// agent notes (birth/death)
|
|
const person_note_label_start = parentNote.getLabelValue('person_label_start').toString();
|
|
const person_note_label_end = parentNote.getLabelValue('person_label_end').toString();
|
|
// date types (categories)
|
|
const event_label_type = parentNote.getLabelValue('event_label_type').toString();
|
|
|
|
// fetch notes with those labels
|
|
const event_notes = api.getNotesWithLabel(event_note_label_start);
|
|
const person_notes_birth = api.getNotesWithLabel(person_note_label_start);
|
|
const person_notes_death = api.getNotesWithLabel(person_note_label_end);
|
|
const events = [];
|
|
for (const note of event_notes) {
|
|
const id = note.noteId;
|
|
const content = note.title;
|
|
const start = note.getLabelValue(event_note_label_start);
|
|
const end = note.getLabelValue(event_note_label_end);
|
|
const group = note.getLabelValue(event_label_type) ? note.getLabelValue(event_label_type) : (
|
|
parentNote.getLabelValue('event_type_default') ? parentNote.getLabelValue('event_type_default') : 'default');
|
|
if (content && start) {
|
|
events.push({ id, content, start, end, group });
|
|
}
|
|
}
|
|
// make a 'birth' event for each person note with start date
|
|
for (const note of person_notes_birth) {
|
|
const id = note.noteId;
|
|
const start = note.getLabelValue(person_note_label_start);
|
|
const group = note.getLabelValue(event_label_type) ? note.getLabelValue(event_label_type) : (
|
|
parentNote.getLabelValue('event_type_default') ? parentNote.getLabelValue('event_type_default') : 'default');
|
|
if (start) {
|
|
const content = note.title + ' (Birth)';
|
|
events.push({ id, content, start, group });
|
|
}
|
|
}
|
|
// make a 'death' event for each person note with end date
|
|
for (const note of person_notes_death) {
|
|
const id = note.noteId;
|
|
const start = note.getLabelValue(person_note_label_end);
|
|
const group = note.getLabelValue(event_label_type) ? note.getLabelValue(event_label_type) : (
|
|
parentNote.getLabelValue('event_type_default') ? parentNote.getLabelValue('event_type_default') : 'default');
|
|
if (start) {
|
|
const content = note.title + ' (Death)';
|
|
events.push({ id, content, start, group });
|
|
}
|
|
}
|
|
return events;
|
|
});
|
|
|
|
// Get event types, make groups
|
|
const types = await api.runOnServer(() => {
|
|
const parentNote = api.startNote.getParentNotes()[0];
|
|
const event_type_list = parentNote.getLabelValue('event_type_list').toString().split(';');
|
|
const types = [];
|
|
var i = 1;
|
|
for (const type of event_type_list) {
|
|
// type format each type seperated by ;
|
|
// id(string), order(int), label(string), color(string), visible(bool), type(string), forceGroup(int)
|
|
types.push({
|
|
id: type.split(',')[0].toString(),
|
|
order: type.split(',')[1] ? (parseInt(type.split(',')[1],10)) : i,
|
|
content: type.split(',')[2] ? (type.split(',')[2].toString()) : type.split(',')[0].toString(),
|
|
color: type.split(',')[3] ? (type.split(',')[3].toString()) : null,
|
|
visible: type.split(',')[4] ? (type.split(',')[4] === 'true') : true,
|
|
type: type.split(',')[5] ? type.split(',')[5].toString() : null,
|
|
forceGroup: type.split(',')[6] ? (type.split(',')[6].toString()) : null
|
|
});
|
|
i++;
|
|
}
|
|
return types
|
|
});
|
|
|
|
// merge the default group with attribute-added groups
|
|
var groups = new vis.DataSet([
|
|
{id:'default', order: 100, content:'', color:'white', visible:true, type:null, forceGroup:null},
|
|
...types
|
|
]);
|
|
|
|
// Create a DataSet for all event items
|
|
var items = new vis.DataSet();
|
|
for (var i = 0; i < events.length; i++) {
|
|
// get date values and note link
|
|
var note_id = events[i].id;
|
|
var note_link = await api.createNoteLink(note_id);
|
|
var event_content = events[i].content;
|
|
note_link[0].firstChild.innerText = event_content;
|
|
var event_start = vis.moment(events[i].start, 'YYYY-MM-DD-hh:mm:ss');
|
|
var event_end = events[i].end ? vis.moment(events[i].end, 'YYYY-MM-DD-hh:mm:ss') : null;
|
|
// set event group
|
|
var event_group = events[i].group
|
|
? (groups.get({filter: function (item) { return (item.id === events[i].group) }})[0]
|
|
? groups.get({filter: function (item) { return (item.id === events[i].group) }})[0]
|
|
: groups.get({filter: function (item) { return (item.id === 'default') }})[0])
|
|
: groups.get({filter: function (item) { return (item.id === 'default') }})[0];
|
|
// fill event data
|
|
items.add({
|
|
id: i,
|
|
content: note_link[0].firstChild,
|
|
start: event_start,
|
|
end: event_end,
|
|
group: event_group.forceGroup ? event_group.forceGroup : event_group.id,
|
|
type: (event_group.type=='box' || event_group.type=='point' || event_group.type=='range' || event_group.type=='background') ? event_group.type : null,
|
|
className: event_group.id,
|
|
style: `background-color:${event_group.color};border-color:${event_group.color};`
|
|
});
|
|
}
|
|
|
|
// Timeline options
|
|
const timeline_options = await api.runOnServer(() => {
|
|
const parentNote = api.startNote.getParentNotes()[0];
|
|
const timeline_start = parentNote.getLabelValue('timeline_start');
|
|
const timeline_end = parentNote.getLabelValue('timeline_end');
|
|
const timeline_present = parentNote.getLabelValue('timeline_present');
|
|
return {timeline_start, timeline_end, timeline_present};
|
|
});
|
|
var options = {
|
|
clickToUse: false,
|
|
showCurrentTime: true,
|
|
height: '95%',
|
|
start: timeline_options.timeline_start,
|
|
end: timeline_options.timeline_end
|
|
};
|
|
|
|
// Set timeline wrapper height
|
|
container.parentNode.style.height = '100%';
|
|
// Fix timeline display
|
|
container.parentNode.parentNode.parentNode.parentNode.style.display = 'initial';
|
|
// Create Timeline
|
|
var timeline = new vis.Timeline(container, items, groups, options);
|
|
// Add present time marker based on "timeline_present" label
|
|
timeline.setCurrentTime(timeline_options.timeline_present);
|
|
|
|
// Create UI menu buttons from added groups (that are not forced into another group)
|
|
menu.innerHTML = '';
|
|
const toggle_groups = groups.get({filter:function(item){return(item.forceGroup===null && item.id!=='default')}});
|
|
for (const group of toggle_groups) {
|
|
var button = document.createElement('input');
|
|
button.type = 'button';
|
|
button.id = `toggle-${group.id}`;
|
|
button.value = group.content;
|
|
button.className = (group.visible===true) ? 'toggled' : '';
|
|
menu.appendChild(button);
|
|
}
|
|
|
|
// Bind toggle buttons
|
|
for (const group of toggle_groups) {
|
|
document.getElementById(`toggle-${group.id}`).onclick = function(){
|
|
toggleGroupVisibility(group.id);
|
|
}
|
|
}
|
|
|
|
// Function to toggle group visibility
|
|
function toggleGroupVisibility(group_id){
|
|
var visibility = groups.get({filter:function(item){return(item.id==group_id)}})[0].visible;
|
|
groups.update({id: group_id, visible: !visibility});
|
|
console.log(document.getElementById(`toggle-${group_id}`));
|
|
document.getElementById(`toggle-${group_id}`).className = (!visibility===true) ? 'toggled' : '';
|
|
timeline.setGroups(groups);
|
|
timeline.redraw();
|
|
}
|
|
}
|