#10270 closed enhancement (fixed)
[PATCH] Workflow graph visualization macro
Reported by: | Owned by: | Peter Suter | |
---|---|---|---|
Priority: | normal | Milestone: | 1.0 |
Component: | ticket system | Version: | |
Severity: | normal | Keywords: | workflow macro |
Cc: | Branch: | ||
Release Notes: |
ticket: Added |
||
API Changes: | |||
Internal Changes: |
Description
I propose adding a macro to render workflow graphs, similar to the two illustrations on the TracWorkflow page (which could be replaced by this macro).
For example [[Workflow(fix = open -> closed; reopen = closed -> open)]]
would expand to this figure:
Most often this would be used in MacroProcessor mode, e.g. to paste the definition from Trac's basic-workflow.ini
:
{{{ #!Workflow leave = * -> * leave.operations = leave_status leave.default = 1 accept = new,assigned,accepted,reopened -> accepted accept.permissions = TICKET_MODIFY accept.operations = set_owner_to_self resolve = new,assigned,accepted,reopened -> closed resolve.permissions = TICKET_MODIFY resolve.operations = set_resolution reassign = new,assigned,accepted,reopened -> assigned reassign.permissions = TICKET_MODIFY reassign.operations = set_owner reopen = closed -> reopened reopen.permissions = TICKET_CREATE reopen.operations = del_resolution }}}
Attachments (5)
Change History (27)
by , 13 years ago
Attachment: | basic-example-workflow.png added |
---|
by , 13 years ago
Attachment: | example-open-closed.png added |
---|
Example rendering of [[Workflow(fix = open -> closed; reopen = closed -> open)]]
by , 13 years ago
Attachment: | workflowmacro-jscanvas.patch added |
---|
WorkflowMacro implementation using client-side javascript / canvas rendering
by , 13 years ago
Attachment: | example-basic-workflow.png added |
---|
Trac basic-workflow.ini example rendering
comment:1 by , 13 years ago
(Sorry, I messed up the filename on the first attachment:basic-example-workflow.png, it is the same file as attachment:example-basic-workflow.png and can be deleted.)
follow-up: 16 comment:2 by , 13 years ago
BTW, I know this could be done in a plugin and e.g. the th:GraphvizPlugin is similar and probably more versatile. There's also the showworkflow contrib script to convert workflow files to .dot
syntax and images.
But TracWorkflow is an important core part of Trac. Visualization is required to understand the implications and subtleties of a workflow, especially for new users implementing their own. I would consider it quite important that this native syntax is supported natively in Trac itself. Also, external dependencies (graphviz, dot) are not required for this comparably simple scenario (only small directed graphs with one kind of nodes and edges).
One could even take this further and integrate it into an admin panel to edit the workflow and see live visualizations or allow interactive graphical editing somehow.
comment:3 by , 13 years ago
The attached patch is an implementation of this proposed plugin, using client-side JavaScript rendering using the canvas
element (inspired by htdocs/js/log_graph.js and Dracula Graph Library).
I'm sure there are a lot of things that could be improved (both in terms of features and implementation), but it already works quite nicely. For example the attached figures were created using it.
follow-up: 5 comment:4 by , 13 years ago
Milestone: | → 0.13 |
---|---|
Owner: | set to |
This looks very nice. I will review the patch, but one question already: when the macro is called without arguments, does it show the current ticket workflow? That would be nice to have, and could be used in the TracGuide.
follow-up: 6 comment:5 by , 13 years ago
Replying to rblank:
when the macro is called without arguments, does it show the current ticket workflow?
Not yet, but that would be trivial to add.
comment:6 by , 13 years ago
Replying to psuter <petsuter@…>:
Replying to rblank:
when the macro is called without arguments, does it show the current ticket workflow?
Not yet, but that would be trivial to add.
follow-ups: 8 9 comment:7 by , 13 years ago
Ok, I have tested the macro, and it works nicely. I see the following issues:
- States containing "≠&" show them as HTML entities.
- In the template, you need to strip the outer
<html>
, otherwise it appears in the output. - Passing the graph data as an HTML table makes for difficult parsing. It could be passed as JSON data instead.
- The macro should show a message saying that JavaScript is required to display the graph.
- In JavaScript, try to keep as much as possible private, by defining private functions in an inner scope. Then, attach the functions you want to export to the
$
symbol. - We try to use a "
trac-
" prefix for all our id and class names. Unfortunately, we can't just change them everyhwere, as it would break all customizations, but we try to stick to it when introducing new ids and classes.
I have fixed these issues, and refactored the code so that the graph data can be passed with add_script_data()
and no additional template is necessary. The result is in rblank@ticket-10270-workflow-macro.
The following additional issues remain, but I'm unsure how to fix them:
- The layout has some randomness, so it is different every time you refresh. This is quite annoying.
- The text in nodes could be raised a bit so that it is centered in its frame.
- Firefox 3.6 seems to have a bug when displaying rotated text. The letters are kept straight, but the text follows the line corresponding to the rotation.
- IE8 doesn't seem to support the canvas method
measureText()
. It works fine with IE9.
follow-up: 11 comment:8 by , 13 years ago
Replying to rblank:
- IE8 doesn't seem to support the canvas method
measureText()
. It works fine with IE9.
excanvas.js Release 3 doesn't support measureText()
and fillText()
, however excanvas.js/trunk supports these methods. See http://explorercanvas.blogspot.com/2009/04/text-support-on-trunk.html.
Update excanvas.js/trunk or use flashcanvas instead of. flashcanvas supports measureText()
and fillText()
.
excanvas.js/trunk and flashcanvas works fine for me.
follow-up: 10 comment:9 by , 13 years ago
Replying to rblank:
Ok, I have tested the macro, and it works nicely. I see the following issues: […] I have fixed these issues
Very nice, thanks!
The following additional issues remain, but I'm unsure how to fix them:
- The layout has some randomness, so it is different every time you refresh. This is quite annoying.
The layout algorithm starts with all nodes at the same position, then pushes them away from each other. While nodes are at the same position, the push direction is chosen randomly. A simple trick would be to initialize them slightly offset, or push them in predetermined directions.
Maybe an entirely different layout algorithm should be tried.
- The text in nodes could be raised a bit so that it is centered in its frame.
Unfortunately measureText()
does not measure the height of text for some reason. Instead I assume 13px Arial
is centered by drawing a h = 14
pixel height (plus border size r
) box at the same coordinates as the text. Setting ctx.textBaseline = 'top'
seems to help. Alternatively, in drawNode()
one could change fillText(... y+h)
to e.g. fillText(... y+h-2)
to tweak this manually.
comment:10 by , 13 years ago
Replying to psuter <petsuter@…>:
Replying to rblank:
- The text in nodes could be raised a bit so that it is centered in its frame.
Setting
ctx.textBaseline = 'top'
seems to help.
Or 'middle'
, combined with much better edge label positioning here.
follow-up: 12 comment:11 by , 13 years ago
Replying to jomae:
excanvas.js Release 3 doesn't support
measureText()
andfillText()
, however excanvas.js/trunk supports these methods. See http://explorercanvas.blogspot.com/2009/04/text-support-on-trunk.html.
And we have a winner! I have updated excanvas.js
to current trunk (r73), compiled with the Closure Compiler, in [10760]. The graph now works on IE8, and node centering is great. The issue with Firefox 3.6 is probably not worth addressing (unless you have an idea how to fix it). I have pushed the update to my clone.
That leaves the randomness in the positioning and the colors. Would it be possible to just position the nodes in a circle, or will this lead to bad results? And instead of generating colors randomly, generate them with a deterministic algorithm?
follow-up: 13 comment:12 by , 13 years ago
Replying to rblank:
The graph now works on IE8
Sweet.
The issue with Firefox 3.6 is probably not worth addressing (unless you have an idea how to fix it).
No clue, probably not.
That leaves the randomness in the positioning and the colors. Would it be possible to just position the nodes in a circle, or will this lead to bad results? And instead of generating colors randomly, generate them with a deterministic algorithm?
It would be quite boring. :) No, I guess for such graphs with typically less than ten nodes it could work alright. See for yourself, it's now implemented in my branch. (Feel free to get rid of layoutForceDirected
if you like layoutCircular
.) Both the color generator (slightly tweaked to generate more saturated colors) and layoutForceDirected
are also deterministic now, using a primitive custom random number generator.
I also added MacroProcessor arguments width
and height
. Hm, maybe a layout
/ randomseed
arguments would be nice, too. Or would that just be feature creep?
follow-up: 14 comment:13 by , 13 years ago
Replying to psuter <petsuter@…>:
The issue with Firefox 3.6 is probably not worth addressing (unless you have an idea how to fix it).
No clue, probably not.
Funnily enough, this issue only appears on Linux. The text is fine on Firefox 3.6 on Windows. So yes, let's drop that.
It would be quite boring. :) No, I guess for such graphs with typically less than ten nodes it could work alright. See for yourself, it's now implemented in my branch.
That looks very nice indeed. There's still a small issue with the centering of the graph, it's located in the top-left corner of the available space. This is probably due to the way you fix node.x
and node.y
just before drawing, in particular the division by (graph.maxx - graph.minx + 1)
feels wrong (maxx
is 1 and minx
is -1, so the result is 3). You probably want to drop the +1
.
I also added MacroProcessor arguments
width
andheight
. Hm, maybe alayout
/randomseed
arguments would be nice, too. Or would that just be feature creep?
Definitely feature creep, I would say. Let's have a single algorithm and tune it until it's fine for most cases. The width
and height
arguments make sense, though.
by , 13 years ago
Attachment: | example-enterprise-opensource.png added |
---|
enterprise-workflow.ini
and opensorce-workflow.ini
rendered using force-directed (left) and circular (right) layout
follow-up: 15 comment:14 by , 13 years ago
Replying to rblank:
That looks very nice indeed. There's still a small issue with the centering of the graph, it's located in the top-left corner of the available space. This is probably due to the way you fix
node.x
andnode.y
just before drawing, in particular the division by(graph.maxx - graph.minx + 1)
feels wrong (maxx
is 1 andminx
is -1, so the result is 3). You probably want to drop the+1
.
Oops, right. That was in case maxx == minx
for some reason. Which reminds me to handle corner cases with one or even zero nodes. Both fixed in my branch.
I tried the other workflows from the contrib directory. The enterprise-workflow.ini
and opensorce-workflow.ini
have a few more nodes and edges, so they are a bit more challenging as you can see in the attached image.
The force-directed layout algorithm still ends up arranging the nodes more or less in a circle, so the circular layout in a way actually looks a bit cleaner.
The larger node names cause some clipping. Maybe the border size should be adjusted by the text measuring somehow. I'm also still not too happy that the edge labels are sometimes covered / overlapping.
Are there any other popular workflows publicly available? (I found one more: th:TestingWorkflow) Do you know if people typically create much larger workflows?
I'm not sure how I missed the WorkFlow/Examples before now. It contains figures where the edge labels include permissions and operations. Maybe that would be another useful parameter. Something like edgelabels=action,operations,permissions
?
follow-up: 17 comment:15 by , 13 years ago
Replying to psuter <petsuter@…>:
The force-directed layout algorithm still ends up arranging the nodes more or less in a circle, so the circular layout in a way actually looks a bit cleaner.
Good job! The current state is good enough to land on trunk. Done in [10764]. I have removed the force-directed layout altogether. The halo effect on edge labels is a nice touch, it really improves readability when the label overlaps an edge.
The larger node names cause some clipping. Maybe the border size should be adjusted by the text measuring somehow.
Yes, that would indeed be nice to have.
I'm not sure how I missed the WorkFlow/Examples before now. It contains figures where the edge labels include permissions and operations. Maybe that would be another useful parameter. Something like
edgelabels=action,operations,permissions
?
I wouldn't do that, no. It's lots of duplicated information, as the same actions and permissions are shown below each instance of an edge. That data is more suited for textual display in a table, not in a graph.
I'm leaving this ticket open for the clipping issue.
comment:16 by , 13 years ago
Replying to psuter <petsuter@…>:
One could even take this further and integrate it into an admin panel to edit the workflow and see live visualizations or allow interactive graphical editing somehow.
Just for reference, th:TracWorkflowAdminPlugin (which I somehow managed not to notice until now) does something like that, using graphviz. (There's also th:WorkflowEditorPlugin, but that one doesn't seem to have any graph visualization.)
follow-up: 18 comment:17 by , 13 years ago
Replying to rblank:
The larger node names cause some clipping. Maybe the border size should be adjusted by the text measuring somehow.
Yes, that would indeed be nice to have.
I'm leaving this ticket open for the clipping issue.
Here is an improvement to this. It's not quite perfect, as it ignores edge label size and conservatively uses the maximum node label width as if all node labels were that long, but to get these right seems not worth it.
comment:18 by , 13 years ago
Release Notes: | modified (diff) |
---|---|
Resolution: | → fixed |
Status: | new → closed |
Replying to psuter <petsuter@…>:
Here is an improvement to this. It's not quite perfect, as it ignores edge label size and conservatively uses the maximum node label width as if all node labels were that long, but to get these right seems not worth it.
Perfect, applied in [10768]. Thanks a lot for your excellent work!
comment:19 by , 13 years ago
Owner: | changed from | to
---|
comment:20 by , 13 years ago
Owner: | changed from | to
---|
comment:21 by , 8 years ago
@psuter - have you thought about factoring out your state machine drawing in a separate project? This could be useful for other client side projects that still have to rely on server side GraphViz to render graphs. Like https://github.com/jakesgordon/javascript-state-machine/pull/51
Trac basic-workflow.ini example rendering