Timeline view, and feature requests to make it further do what it was not meant for

As ever, I’d like to request some features that were never implemented for perfectly good reasons, as a punishment for @eastgate’s provision of useful features that I inevitably end up using in ways never intended.

I also am acutely aware that there may be a happy event coming in terms of Tinderbox updates, so these features are unlikely to be high on the demand list.

With those disclaimers and apologies out of the way: I’m spending time in the Timeline view, using it in a way that I know I shouldn’t, but nothing else would give me the flexibility to get up and running to the point I can ask for further features!

These would be:

  1. In a timeline view, keeping the name of the band associated with the band when it is scrolled out of view; I realise this may require a change to the tinderbox Planck constant, but it’s worth an ask.

  2. Would it be possible - somehow - to map the positions of notes in a timeline back to their map view manifestations? Timeline view is great for moving things around and making sense of linear time, but being able to pull their positions to a view where I can add adornments and work with the visual elements of the notes would be a godsend. Again, I appreciated Timeline does some things that Map view doesn’t handle the same way (eg, items in sub-groups show at the top level of a timeline, but not in a map) that may confound what seems a simple data mapping exercise, from an overwhelmingly naïf perspective. (and now I think about it a little deeper and feel the crunky edges, maybe injecting adornments into the map to replace the timeline bands, and I’m starting to feel apologetic about the scale of this and understanding why it’s never happened before)


Would you have some screenshots of what the timeline view you’re talking about could be?

1 Like

You can do this with actions. In fact, I demo’d just this a while ago, in my Meetup talk about the visual language of map view. (@satikusala : can you locate the date and link?)

The basic idea is to use the date to set $Xpos, and use the timeline band (or some other attribute) set set $Ypos.

1 Like

#1. I concur. If band labels are defined, the are drawn at the left margin of the main timeline within their band. If the timeline scale is such that is it necessary to have to scroll the main part of the view horizontally, going right (later in time) the band labels scroll off-screen. Conversely, one doesn’t want the labels to stay on screen for a vertical scroll. The fact that the requirements differ in the X and Y axis of scrolling suggests a fix might be less simple than the description!

#2. Before the timeline people made complex map grids with $Xpos representing date/time, $Width duration and $Pos for differing bands of info. But that then crimps more general map use. Timelines, as you note do allow adornments. I think this topic would benefit from a clear view of specific features you want in a different view. A thing most overlook with timelines is the data is usually unhelpfully lumpy (not evenly spaced in time) but we aesthetically want a ‘nice’ view. I’d say, pick one of the two: more features or better packing. The busier a map, the less customisation each item can clearly display, or there can be fewer items visible at the same time. So a busier timeline might, for different reasons, also be less useful putting us back at square one. Background tabs don’t compute, so having extra tabs doesn’t mean more load on Tinderbox. The tab taking focus draws/refreshes itself, the tab losing focus or closing stops updating. Views are based on the same data but showing different things. Taking more view A features and putting them in view B essentially fuses A and B that originally differed for a reason. I recognise the underlying sense of the seeming tyranny of being ‘forced’ to do some things if a different view, but as some point I realised that was more a sense of ennui than real impediment. The upside? I started using/swapping view types more than I used to because I know why and in changes made in view type B don’t affect my understanding on return to view type A (unless I intended it so).

A further thought on the latter is that if a note that makes sense in view A doesn’t in view B, you’ve over-optimised for view A. No error/criticism in that, but the scope for realisation that you’'re in a dead-end (habit!) and to consider some incremental re-formalisation.


Having the ability to split the main window into two separate view types might help?

Perhaps that would go against a fundamental principle I’ve missed, but the larger my monitor gets and the more power tinderbox has, the more I’d like a second perspective.

Why not open 2 windows and tile them. You can even set both to show view only, and those can be different view types.

A limitation (which I think devolves for the Apple frameworks used by Tinderbox’s design) is that all open windows for the same document share the same focus. IOW, selecting a new note in windows #1 shifts focus in window #2. In this case that’s likely what you’d want.

If you want 3 views, open 3 windows! If you want to run in view-only mode, select a note and use View menu or ⌘+⌥+X to open the selected note as a standalone window. In deed you can have multiples of the latter.

You can do all this now without any changes to the app. HTH. :slight_smile:

That does help, thanks.

1 Like

A neat part of this approach (e.g. if you’ve lots of screen space) is you can have more than one stand-alone text window open so you’ve not dependent on selecting a given item to read the Text ( and Displayed Attributes: these windows can’t show the Links pane). I’d not go overboard: there isn’t a fixed limit but perhaps 3 or 4 rather than 30 to 40! If the TBX is closed from a main window, the standalone text windows are remembered and re-opened on next use.

Any downsides to stand-alone windows? Depending on what feature of the text pane you use, they don’t:

  • show the links pane.
  • the link parks cannot be used to drag links., so text links cannot be made (except via the zip method). Using the link widget on the view pane selected item it is possible to drag-create Basic links.

(all you people with big enough screens to open multiple windows! (jealous rage emoji) )

I’ve managed to butcher a rudimentary bit of code to map(verb) dates and timeline bands back into map(noun) layouts.

What I’m trying to do is build not just a timeline of events, but show interconnections between them and overarching durations (documenting an enormously protracted piece of academic due process, and the events that have impacted it and my research areas). This is why I need to be able to use adornments, add non-timeline items (to explain and annotate events and impact), and have cause and effect arrows flying asunder.

I’ll stick the code at the end - it’s absolutely a rough first draft - because what I need to think about now is how to handle the situation of notes occupying the same space or overlapping.

I’m using this as a stamp - I pick a note that is set up as a timeline container, with items within it with start, optional end times, and possibly timelinebands. It then butchers their XPos, YPos and Widths, based on the dates it extracts. Though you can nest groups in a timeline (which is great for setting them up in an outline view), this makes zero sense in a map view. I’d have loved to be able to alias the notes into a new container (particularly to handle this nesting scenatio), but realised that aliases cannot be programmatically constructed. I also thought about cloning notes into a new flattened container, but nothing of the language dictionary (as documented extensively in ATbRef) suggested that this was something that should be attempted with code - as I understood it, I’d have to create new notes, then hunt through attribute lists, separate which were intrinsic, prototype, user-changed, or added arbitrarily, which seemed so fussy that I took it as a cue that I should be considering the data modelling issue differently.

// customise the following for layout control

var:number mappingXScale = 6;
var:number mappingYScale = 2;

//var:string destinationName = "Timeline Map";
//var:string destinationContainer = "";

// set up logging

// variables we will reuse

var:string toEpoch=".format('U').toNumber()";

// get notes we're mapping

var notes = collect(descendants,$IDString);

// get timeline bounds

var timeStartAtt = "$"+$TimelineStartAttribute;
var timeEndAtt   = "$"+$TimelineEndAttribute;
var timeStart    = $TimelineStart;
var timeEnd      = $TimelineEnd;
var timeStartE   = timeStart.format("U").toNumber();
var timeEndE		= timeEnd.format("U").toNumber();

// timeEnd may be the string "never" - in this case,
//  we should pull the highest date from start/end
//  of all child nodes
if(timeEnd == "never") {
	timeEnd = timeStart;
	timeEndU = timeStartU;

		var noteRef   = "("+n+")";
		var testDate  = eval(timeStartAtt+noteRef);
		var testDateE = eval(timeStartAtt+noteRef+toEpoch);
		if(testDate!="never") {
			if(testDateE>timeEndE) {
				timeEnd = testDate;
				timeEndE = testDateE;
		} else {
			testDate  = eval(timeEndtAtt+noteRef);
			testDateE = eval(timeEndAtt+noteRef+toEpoch);
			if(testDate!="never") {
				if(testDate>timeEndU) {
					timeEnd = testDate;
					timeEndE = testDateE;

//dolog("start = "+timeStart+", end = "+timeEnd);

var:number timelineTemporalWidth = timeEndE - timeStartE;

//dolog("timeline start = " + timeStart + ", end = " + timeEnd);
//dolog("seconds = " + timelineTemporalWidth);

// rewrite X, Y, Width of notes
notes = collect(descendants,$IDString);
	var noteRef			= "("+n+")";
	var startDateS		= eval(timeStartAtt+noteRef);
	if(startDateS!	="never") {
		// only touch notes with a start date!
		var startDateE = eval(timeStartAtt+noteRef+toEpoch);
		$Xpos(n) 		= (startDateE-timeStartE) / timelineTemporalWidth * mappingXScale;
		var endDateS	= eval(timeEndAtt+noteRef);
		if(endDateS!="never") {
			var endDateE	= eval(timeEndAtt+noteRef+toEpoch);
			// only set widths for notes with end dates
			$Width(n) = endDateE / timelineTemporalWidth * mappingXScale;
		// set a vertical position
		$Ypos(n)		= $TimelineBand(n) * mappingYScale;

function dolog(msg) {
	$Text('/log') = $Text('/log') + msg + "\n\n";


Not directly, but there is a way around that. you may have noticed that if you make an agent and drag an alias inside it out of the alias, the agent makes a new one. You could leverage the same trick in code by having an agent matching all the notes you might want to alias. Now, find() the note—or rather alias—in the agent (note_ the parent of the alias will be the agent) and move it (by setting its $Container) to where you want the agent. You now have your auto-generated alias. A bit of a faff, but do-able today—rather than needing features not in the app.

Not really. To be clear, whilst there are action code operators to create new notes, adornments, agents, there is no operator to make aliases. But, the workaround I give above can route around that limitation.

Your descriptions imply a confusion as the the difference between action code operators—action code’s built-in functions—and Tinderbox attributes. The latter can be used with action code but aren’t part of it per se. If you think of a Tinderbox note as a database record, its attributes are all the fields defined for that record.

Intrinsic attributes are not as arcane as it might seem. Although Tinderbox had ‘manually’ created aliases from the outset, aliases were primarily used with agents. At simplest intrinsic attributes reflect the fact that if, for example, I alias a note in a map both note and alias—being on the same map—need discrete positioning data ($XPos, $Ypos, $Width, $Height). If you look at the list of intrinsic attributes it should thus be evident why they need this special status. The key point when using intrinsic attributes is to ensure you consider whether you are acting upon an alias (e.g. in an agent action) or the original (e.g. stamping an actual note): more a case of attention to context than one of complexity.

You might wish to contact Support and make a formal feature request an operator to make aliases. Given that most Tinderbox users aren’t programmers, the developer has had a natural caution about adding features to create/delete/alias objects as it’s easy for a novice to do something they might regret. Of that triad the first two are now possible, the latter isn’t (yet!)

Some more follows in a new post…

Note that aliases and notes don’t necessarily always share all their links. Text links and web links are always present for both the original note and its alias(es). But, Basic links can differ: see more. That may seem inconvenient in this context but the design is intentional and necessary to support export (and internal-preview).

Note also that adornments do not support links. Adornments only show up in both Map and Timeline if the adornment has a start date time set for the attribute used to plot the timeline (default: $StartDate).

Aliases always—deliberately—have their titles drawn in an italic face (see more)—in all views. So noted lest “how to I make aliases on use italics?” creeps into the mix.

In timeline view, the user only controls x-axis movement. But the latter does not alter $Xpos. Instead x-axis movement alters $StartDate—or the Date-type attribute that timeline view is using to plot the view. Moving x-axis right moves date/time forward (future), left x-axis moves that date backwards (past). The notes position in map view is unaltered by the timeline view movement.

I note all this as it is unclear why the aliases are needed on the map, unless:

  • The map is a deliberate abstraction of notes that live in different parts of the outline (the outline being the underlying XML structure in which the notes are stored in the TBX, as well as being one of the views)
  • You need the same notes on multiple map, e.g. to show different narrative paths.

However, where something is on the timeline is discrete from where it is on a map of the same. Moving in either view does not move it in the other.

If using multiple maps (alternate map arrangements of the same subject) then take care that all basic links are original to original so they are consistent across all maps. Otherwise, if different maps need different link patterns you probably do want aliases to have discrete links but if doing so you must recreate all the still-wanted original basic links: you can’t mix the two behaviours.

Lastly, if looking at pathways, don’t overlook use of Hyperbolic view—even if only to validate your link pathways. Hyperbolic view can (from v9.6.0) filter its network (graph) by link type.