Presenting: Gantt ~ for basic gantt charts

Yup, the R&D team at TWaddle Global Inc. gives the world yet another good-to-have-thingy-when-you-need-it!

Gantt


While it fulfills my current needs (i.e I’m not very likely to modify the functionality of it much) I’d welcome feedback from experienced Gantt chartists.

13 Likes

I may use this for project stuff, my first thought was actually “oh yes! this is what I want for chronology chart making, especially geneological stuff!”

This is great - I was thinking of making something for timelines in my wiki. I’m happy to have your instead!

A few ideas:

  • Can your macro take a filter, rather than a tag? For example [has[some_custom_field]].
  • Does this support indeterminate end dates for “now” / ongoing? This would help for some of the charts I want to make.

Thanks again for making this!

1 Like

I opened this on a smartphone and wondered what happens when there are many items spread across a long time interval. Given the geometry of a smartphone screen, will the captions get cramped and become visually hard to read, or is there horizontal scrolling of the chart planned?

Thanks for the kind words, guys.

The thought occurred to me but I settled for a simple tag. I realize this is not optimal for everyone but I don’t think it should be overly difficult to hack it if needed. I’ve commented the code pretty clearly, I think.

  • Does this support indeterminate end dates for “now” / ongoing? This would help for some of the charts I want to make.

That makes sense. I guess the “last specified end date” i.e as specified in some other segment, would be used then, right? Or else, where would the chart right end be?

Well, one aspect with featuring captions is exactly so they can be shorter versions of a tiddler title if needed. Could you show me a screenshot of what happens?

There are a number of Gantt charts available but a simple one is very useful. To me it would be further simplifield if I could use tiddlerwiki, utc timestamps as an imput date format.

I’m still thinking in geneological terms, where anything in the future is nonsensical - an entry with a start and no end would dynamically end at “now”. In a purely geneological graph, it would make no sense to have any end dates in the future, so this would be the entire chart cutoff. For mixed charts (projects with some future end values defined, some end-undefined entries) I imagine a visual fade out or dashed line to indicate ongoing would look about right (to me anyway), but may not be easy to implement.

Still thinking on this for geneology, it would be good to have the option to specify what fields hold the start and end dates, and for those values to be in different formats. My specific use is that all my <<tag people>> have birthdate fields and some have deathdate, with format of DDth MMM YYYY (though I tend to switch to mmm for longer months), and then parse them with parsedate from TiddlyTools for TW v5.3.8 — Small Tools for Big Ideas!™. This gives me a string I can treat as literal for trivial transclusion in text via {{Nemo||birthdate}}, but parseable for more complex calculations (eg I have a table showing all birthdays)

Makes sense. I think a filter would avoid “tag pollution” in a wiki, but I understand it complicates a plugin like this.

Maybe a modification - support now as a string in the start / end fields. Then it could be specified without needing to support the “missing” start / end date.

I wrote a Python script to generate a bunch of tiddlers (copypasting the code because the forum won’t let me upload a .py file :man_facepalming: )

#!/usr/bin/env python3

"""generate a JSON file containing tiddlers to import
for testing the Gantt TiddlyWiki plugin"""

from datetime import date, datetime, timedelta
import json


N = 100
OUTPUT_FILE = "tiddlers.json"
TODAY = date.today().strftime('%Y-%m-%d')

def add_days_to_date(date_str, x):
    """
    Bump a date in YYYY-MM-DD format by x days

    Args:

        date_str: initial date

        x: days

    Return: str
    """
    initial_date = datetime.strptime(date_str, "%Y-%m-%d")
    new_date = initial_date + timedelta(days=x)
    return new_date.strftime("%Y-%m-%d")


def get_tiddler_txt(title, start, end):
    """
    Tiddler text in JSON format

    Args:

        title: tiddler title

        start: start date in YYYY-MM-DD format

        end: end date in YYYY-MM-DD format

    Return: str
    """
    txt = ""
    return txt


def main():
    """main"""
    tiddlers = []
    for i in range(N):
        title = f"Task {i + 1}"
        start = add_days_to_date(TODAY, i)
        end = add_days_to_date(TODAY, i + 1)
        tiddler = {}
        tiddler["title"] = f"Task {i + 1}"
        tiddler["start"] = start
        tiddler["end"] = end
        tiddler["text"] = f"Task {i + 1} text field"
        tiddler["caption"] = f"Caption for Task {i + 1}"
        tiddler["note"] = f"Note for Task {i + 1}"
        tiddler["tags"] = "mytask"
        tiddler_str = json.dumps(tiddler)
        tiddlers.append(tiddler_str)
    text = ", ".join(tiddlers)
    text = f"[{text}]"
    with open(OUTPUT_FILE, "w") as f:
        f.write(text)


if __name__ == "__main__":
    main()

It creates a tiddlers.json file in the current directory

tiddlers.json (17.2 KB)

Here are the top and the bottom of the result after I create a tiddler with <<gantt mytask>> in it:

Gantt updated

Other than some minor bugs fixes it now features open ended tasks that only hold a start date (and the tag).

I’m guessing this should solve some of your needs, @Peter and @nemo

@vuk - oy’ vey - I’ll have to look into that.

2 Likes

This is beautiful! Makes me wish I had a need for Gantt charts.


… almost.

@vuk - about your chart with 100 tasks:

OK, so the result does display as expected but here are a few notes - plus a pragmatic solution:

Everything in the gantt chart is relative to the tiddler width. There is no innate width to the segments, so if one wants a wider chart, there could be a css class to the wrapping div and then the user would manually have to set a desired chart width (e.g 200%)… but I’m not sure how to present that with a decent UI. If it were to be done I’d not want this width setting to be visible in the main UI so it’d have to be some controlpanel setting or in the plugins readme tid. But including it there, even if trying to be fancy with some RangeWidget slider, I think it would be particularly fiddly on a small screen so the solution would work against itself. If you have any good idea for a UI, I’d love to hear it.

A more pragmatic workaround: Use multiple tags! The reason I created this plugin to begin with was because I’m just about to start studying for (another) university degree and the courses are logistically messy, so I need an overview. While all courses are tagged “course”, I can get them chunked by also tagging them with the year, so there are only a few courses seen at a time.

…i.e maybe the full 100 task project doesn’t have to be seen on the mobile screen? There could, indeed, be such a chart but there can also be tiddlers with charts showing sub-sets that are mobile friendly.

For an UI idea to be good, it would have to be based on UI design principles and decent understanding of the HTML + CSS wizardry that happens under the hood. I’m afraid these are areas of knowledge that are alien to me, hence my feedback is rather based on general analogies with other visual plugins (might be not very useful) and end user expectations (might be totally detached from the technical reality).

The general problem is how to show something that doesn’t fit on screen, without visually altering it to the point that it starts looking messy, like in the screenshots above.

Perhaps it’s technically possible to wrap it inside a horizontably scrollable canvas? Similar to how mindmap plugins do it? For example see TW5-Graph - there I can press on the screen and slide the finger horizontally. Of course if this is only achievable by dragging in a heavy JavaScript library, it would be overkill, and your suggestion to partition the whole timeline by using multiple tags is indeed a reasonable workaround.

I have just asked Gemini about a “CSS example of scrollable <div>” (see the disclaimer above about my CSS illiteracy) and, surprisingly for me, it produced a decent example.

First tiddler is the HTML code:

<div class="scroll-container">
  <div class="scroll-content">
    <div class="card">Card 1</div>
    <div class="card">Card 2</div>
    <div class="card">Card 3</div>
    <div class="card">Card 4</div>
    <div class="card">Card 5</div>
    <div class="card">Card 6</div>
  </div>
</div>

Here the scroll-content div would be the rendered <<gantt>> macro.

And this is the stylesheet:

.scroll-container {
  /* This defines the visible area for the content. */
  width: 100%; /* Or set a fixed width like 400px */
  max-width: 600px;
  border: 1px solid #ccc;
  padding: 10px;
  overflow-x: auto; /* This is the key property for horizontal scrolling. */
  white-space: nowrap; /* Prevents content from wrapping to the next line. */
}

.scroll-content {
  /* This is the inner container for the scrollable items. */
  display: flex; /* Arranges the child items in a row. */
  gap: 10px; /* Adds space between each item. */
}

/* Optional styling for the items inside the container. */
.card {
  width: 200px;
  height: 150px;
  flex-shrink: 0; /* Prevents the items from shrinking. This is crucial. */
  background-color: #f0f0f0;
  border: 1px solid #999;
  display: flex;
  justify-content: center;
  align-items: center;
  font-family: sans-serif;
}

This looks ok-ish on mobile: while it’s too big to fit on screen, it stays inside the tiddler and I can scroll it horizontally.

( @vuk - hmm, I initially, in this message, replied by basically dismissing what you write because it relies on setting a fixed width to the elements which must not be done in our case here but I’m fiddling and just may be on to something. We’ll see.)

Updated
(tiddlyhost seems to load slowly at the moment though-?)

The chart is now horizontally expandable (via the little corner handle) - @vuk

Frankly, I’m not sure it was worth it - please test it on a phone and see if you discover the same issues I find. (A clue; the chart width intentionally adapts to the tiddler so it doesn’t intrinsically have any width - so the window says “nothing to scroll here!”)

I can’t notice what problem exactly does this solve.

On a widescreen desktop, this is how the tiddler corner looks:

Screenshot

Yes I can drag by the corner and extend it, even past the tiddler visual border, but that keeps the tail of the text in the last tiddlers still invisible, because it does not fit anyway.

On Android (Vivaldi browser) I don’t even see the little triangle marker in the tiddler corner, nothing changed visually compared to the second screenshot in a previous post.

Right. I assumed the (main) problem in your initial post was that if you show very many items, they get cammed. Expanding the chart does air things up. But, OK, maybe the issue was that the last title(s) get cropped. You’re right, but I’m afraid I don’t know a good solution to that. I think it is somewhat of an edge case; it happens if the (obviously customizable) caption expands 42px beyond the colored part. I might do some more fiddling around but I don’t expect to find a good solution to this.

Found another itch, not related to the discussion above.

With the 100 tiddlers example, Task 3 and Task 4 are identically alligned, despite start of Task 4 being the same as end of Task 3. Looks like this happens at the transition between months, since the same can be observed for Task 64 and Task 65. Is there an off-by-one error in the math somewhere?

Yes, and somewhat intentionally so; To calculate the distance from the left for all items, I have simplified 1month=30days (and 1year=365days). The reasoning is that for real use cases this discrepancy is very unlikely to be noticed (we are talking a pixel or two). But when adding 100 items with the exact same time distance between them… well :slight_smile:

1 Like