Custom widget for Grist to embed and edit draw.io diagrams.
-
To use this, ensure you have a column to put diagram data into. Call it what you want - you can select it later.
-
Add a new custom widget, and use this URL:
https://lgdan.github.io/grist-widget-drawio/
-
Give the widget full document access, and pick your column to store the diagram data.
-
Make sure you have a record selected (not a blank one).
-
Double click the placeholder image, and use the draw.io editor as you would normally. Hit save to sync back a PNG export to the column you chose earlier of the selected row.
The code behind this is not robust. Whilst it does read and save back to the selected cell, it does not handle the following situations:
- 🔒 Someone else edits the cell you're editing (no locking).
- 🗑️ You click on a different cell (no autosave, no warning) and your work is lost.
Because the drawing XML is embedded in the PNG metadata, you can extract it. I've included a sample (see extract_xml.py) to use. You can then read the shapes and lines (vertecies and edges) from the diagram data.
This leads to all sorts of fun, like linking rows to entities in the diagram, or having other rows do lookups to see if they are 'mentioned' in the diagrams.
If you create a new column called XML
and put the contents of extract_xml.py
in there, you can then:
[element.get("value",default=element.get("id")) for element in $XML.findall("diagram/mxGraphModel/root/mxCell") if element.get("vertex",default=None)]
[element.get("value",default=element.get("id")) for element in $XML.findall("diagram/mxGraphModel/root/mxCell") if element.get("edge",default=None)]
vertecies = [element for element in $XML.findall("diagram/mxGraphModel/root/mxCell") if element.get("vertex",default=None)]
edges = [element for element in $XML.findall("diagram/mxGraphModel/root/mxCell") if element.get("edge",default=None)]
relationships = []
for edge in edges:
edgeText = edge.get("value",default=edge.get("id"))
sourceVertexId = edge.get("source",default="?")
targetVertexId = edge.get("target",default="?")
if ("?" not in [sourceVertexId, targetVertexId]):
sourceVertex = [x for x in vertecies if x.get("id") == sourceVertexId]
targetVertex = [x for x in vertecies if x.get("id") == targetVertexId]
sourceVertexValue = sourceVertex[0].get("value")
targetVertexValue = targetVertex[0].get("value")
relationships.append(f"[{sourceVertexValue}] --[{edgeText}]--> [{targetVertexValue}]")
# return (sourceVertex + " --> " + targetVertex)
return "\n".join(sorted(relationships))
vertecies = [element for element in $XML.findall("diagram/mxGraphModel/root/mxCell") if element.get("vertex",default=None)]
edges = [element for element in $XML.findall("diagram/mxGraphModel/root/mxCell") if element.get("edge",default=None)]
issues = []
# Labels
[issues.append("[WARN] Edge '" + edge.get("id") + "' should have a value.") for edge in edges if not edge.get("value")]
[issues.append("[WARN] Vertex '" + vertex.get("id") + "' should have a value.") for vertex in vertecies if not vertex.get("value")]
# Edges should be connected
[issues.append("[WARN] Edge '" + edge.get("value",default=edge.get("id")) + "' should be connected at both ends.") for edge in edges if not (edge.get("source") and edge.get("target"))]
if (issues):
return "\n".join(issues)
else:
return "Passed."
(This assumes you have a Relationships
column in your diagram table following example 3.)
as_is_state = $As_Is.Relationships.split("\n")
to_be_state = $To_Be.Relationships.split("\n")
diff = sorted(set(as_is_state) ^ set(to_be_state))
return "\n".join(diff)
-
This code is released under MIT license. I am not affiliated with Grist, Grist Labs, Draw.IO, or JGraph Ltd in any way.
-
Grist is (c) Grist Labs 2025 (https://www.getgrist.com)
-
Draw.io and Diagrams.net is (c) 2005-2023 JGraph Ltd, Artisans' House, 7 Queensbridge, NN4 7BF, Northampton, England. Company #04051179. (https://www.drawio.com)