markdown: tables

This commit is contained in:
Alexander Wang 2024-11-18 16:23:35 -08:00
parent fed65bcb51
commit b87100b672
No known key found for this signature in database
GPG key ID: D89FA31966BDBECE
7 changed files with 4496 additions and 2 deletions

View file

@ -1,6 +1,7 @@
#### Features 🚀
- Vars: vars in markdown blocks are substituted [#2218](https://github.com/terrastruct/d2/pull/2218)
- Markdown: Github-flavored tables work in `md` blocks [#2221](https://github.com/terrastruct/d2/pull/2221)
#### Improvements 🧹

954
e2etests/testdata/txtar/md-tables/dagre/board.exp.json generated vendored Normal file
View file

@ -0,0 +1,954 @@
{
"name": "",
"isFolderOnly": false,
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "savings",
"type": "text",
"pos": {
"x": 169,
"y": 50
},
"width": 343,
"height": 150,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#e8f4f8",
"stroke": "#4a90e2",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Month | Savings | Expenses | Balance |\n| -------- | ------- | -------- | ------- |\n| January | $250 | $150 | $100 |\n| February | $80 | $200 | -$120 |\n| March | $420 | $180 | $240 |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 343,
"labelHeight": 150,
"zIndex": 0,
"level": 1
},
{
"id": "status",
"type": "text",
"pos": {
"x": 270,
"y": 321
},
"width": 142,
"height": 113,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#f8e8e8",
"stroke": "#e24a4a",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Status | Count |\n| ------ | ----- |\n| Done | 42 |\n| Todo | 17 |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 142,
"labelHeight": 113,
"zIndex": 0,
"level": 1
},
{
"id": "metrics",
"type": "text",
"pos": {
"x": 254,
"y": 655
},
"width": 173,
"height": 335,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#f0f8e8",
"stroke": "#82e24a",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Metric | Value |\n| --------- | ------- |\n| Uptime | 99.9% |\n| Latency | 150ms |\n| Errors | 0.01% |\n| Requests | 15k/min |\n| CPU | 45% |\n| Memory | 68% |\n| Disk | 72% |\n| Network | 33% |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 173,
"labelHeight": 335,
"zIndex": 0,
"level": 1
},
{
"id": "financial",
"type": "rectangle",
"pos": {
"x": 562,
"y": 20
},
"width": 389,
"height": 444,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#e8f4f8",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "Financial Overview",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 220,
"labelHeight": 36,
"labelPosition": "OUTSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "financial.monthly",
"type": "text",
"pos": {
"x": 592,
"y": 50
},
"width": 329,
"height": 150,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Month | Revenue | Costs | Margin |\n| --------- | -------- | -------- | ------ |\n| January | $25,000 | $18,000 | 28% |\n| February | $28,500 | $19,200 | 33% |\n| March | $31,200 | $21,500 | 31% |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 329,
"labelHeight": 150,
"zIndex": 0,
"level": 2
},
{
"id": "financial.quarterly",
"type": "text",
"pos": {
"x": 599,
"y": 321
},
"width": 315,
"height": 113,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Quarter | Target | Actual | Variance |\n|:--------|-------:|:------:|:---------|\n| Q1 2024 | $75K | $84.7K | +12.9% |\n| Q2 2024 | $82K | - | - |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 315,
"labelHeight": 113,
"zIndex": 0,
"level": 2
},
{
"id": "monitoring",
"type": "rectangle",
"pos": {
"x": 548,
"y": 718
},
"width": 417,
"height": 573,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#f8e8e8",
"stroke": "B1",
"shadow": false,
"3d": true,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "System Health",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 168,
"labelHeight": 36,
"labelPosition": "OUTSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "monitoring.availability",
"type": "text",
"pos": {
"x": 578,
"y": 748
},
"width": 357,
"height": 150,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Service | Status | Uptime | Last Incident |\n|:-----------|:------:|:------:|:--------------|\n| API | ✅ | 99.9% | 15 days ago |\n| Database | ✅ | 99.8% | 3 days ago |\n| Cache | ⚠️ | 98.5% | 1 hour ago |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 357,
"labelHeight": 150,
"zIndex": 0,
"level": 2
},
{
"id": "monitoring.performance",
"type": "text",
"pos": {
"x": 585,
"y": 1111
},
"width": 344,
"height": 150,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Metric | P50 | P90 | P99 |\n|:----------------|:-----:|:-----:|:-----:|\n| Response Time | 120ms | 350ms | 750ms |\n| DB Query Time | 45ms | 180ms | 450ms |\n| Cache Latency | 5ms | 12ms | 30ms |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 344,
"labelHeight": 150,
"zIndex": 0,
"level": 2
},
{
"id": "projects",
"type": "rectangle",
"pos": {
"x": 10,
"y": 1452
},
"width": 1008,
"height": 210,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#e8f8e8",
"stroke": "#4a90e2",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": true,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "Project Tracking",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 190,
"labelHeight": 36,
"labelPosition": "OUTSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "projects.status",
"type": "text",
"pos": {
"x": 40,
"y": 1482
},
"width": 425,
"height": 150,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Project | Priority | Progress | Due Date | Owner |\n|---------|:--------:|:--------:|:---------|:------|\n| Alpha | HIGH | ![p](https://progress.com/80) 80% | 2024-04-01 | Alice |\n| Beta | MEDIUM | ![p](https://progress.com/45) 45% | 2024-05-15 | Bob |\n| Gamma | LOW | ![p](https://progress.com/20) 20% | 2024-06-30 | Carol |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 425,
"labelHeight": 150,
"zIndex": 0,
"level": 2
},
{
"id": "projects.risks",
"type": "text",
"pos": {
"x": 525,
"y": 1482
},
"width": 463,
"height": 150,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Risk ID | Description | Impact | Mitigation |\n|:-------:|:------------|:------:|:-----------|\n| R1 | Resource shortage | 🔴 High | Hire contractors |\n| R2 | Technical debt | 🟡 Med | Code review |\n| R3 | Scope creep | 🟢 Low | Clear requirements |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 463,
"labelHeight": 150,
"zIndex": 0,
"level": 2
},
{
"id": "team",
"type": "rectangle",
"pos": {
"x": 551,
"y": 1823
},
"width": 411,
"height": 247,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#f8f0e8",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "Team Analytics",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 177,
"labelHeight": 36,
"labelPosition": "OUTSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "team.velocity",
"type": "text",
"pos": {
"x": 581,
"y": 1853
},
"width": 351,
"height": 187,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Sprint | Points | Completed | Carryover |\n|:-------|:------:|:---------:|:---------:|\n| SP-1 | 34 | 30 | 4 |\n| SP-2 | 38 | 35 | 3 |\n| SP-3 | 42 | 40 | 2 |\n| Average| 38 | 35 | 3 |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 351,
"labelHeight": 187,
"zIndex": 0,
"level": 2
}
],
"connections": [
{
"id": "(savings -> status)[0]",
"src": "savings",
"srcArrow": "none",
"dst": "status",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 5,
"strokeWidth": 2,
"stroke": "B2",
"borderRadius": 10,
"label": "Triggers",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 54,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 340.5,
"y": 199.5
},
{
"x": 340.5,
"y": 248.3000030517578
},
{
"x": 340.5,
"y": 272.70001220703125
},
{
"x": 340.5,
"y": 321.5
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(status -> metrics)[0]",
"src": "status",
"srcArrow": "none",
"dst": "metrics",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "Monitors",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 58,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 340.5,
"y": 434
},
{
"x": 340.5,
"y": 474
},
{
"x": 340.5,
"y": 496.1000061035156
},
{
"x": 340.5,
"y": 514.25
},
{
"x": 340.5,
"y": 532.4000244140625
},
{
"x": 340.5,
"y": 615
},
{
"x": 340.5,
"y": 655
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "financial.(monthly -> quarterly)[0]",
"src": "financial.monthly",
"srcArrow": "none",
"dst": "financial.quarterly",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "Aggregates",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 77,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 756.5,
"y": 199.5
},
{
"x": 756.5,
"y": 248.3000030517578
},
{
"x": 756.5,
"y": 272.70001220703125
},
{
"x": 756.5,
"y": 321.5
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "monitoring.(availability -> performance)[0]",
"src": "monitoring.availability",
"srcArrow": "none",
"dst": "monitoring.performance",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "Affects",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 46,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 756.5,
"y": 898.5
},
{
"x": 756.5,
"y": 1020.0999755859375
},
{
"x": 756.5,
"y": 1062.699951171875
},
{
"x": 756.5,
"y": 1111.5
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(financial -> monitoring)[0]",
"src": "financial",
"srcArrow": "none",
"dst": "monitoring",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "Impacts",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 54,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 756.5,
"y": 463.5
},
{
"x": 756.5,
"y": 528.2999877929688
},
{
"x": 756.5,
"y": 568.0999755859375
},
{
"x": 756.5,
"y": 662.5
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(monitoring -> projects)[0]",
"src": "monitoring",
"srcArrow": "none",
"dst": "projects",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 5,
"strokeWidth": 2,
"stroke": "B2",
"borderRadius": 10,
"label": "Informs",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 51,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 756.5,
"y": 1290.5
},
{
"x": 756.5,
"y": 1355.300048828125
},
{
"x": 756.5,
"y": 1387.699951171875
},
{
"x": 756.5,
"y": 1452.5
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(projects -> team)[0]",
"src": "projects",
"srcArrow": "none",
"dst": "team",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "Assigns",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 50,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 756.5,
"y": 1661.5
},
{
"x": 756.5,
"y": 1726.300048828125
},
{
"x": 756.5,
"y": 1750.5
},
{
"x": 756.5,
"y": 1782.5
}
],
"isCurve": true,
"animated": true,
"tooltip": "",
"icon": null,
"zIndex": 0
}
],
"root": {
"id": "",
"type": "",
"pos": {
"x": 0,
"y": 0
},
"width": 0,
"height": 0,
"opacity": 0,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "N7",
"stroke": "",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "",
"fontSize": 0,
"fontFamily": "",
"language": "",
"color": "",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"zIndex": 0,
"level": 0
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 59 KiB

879
e2etests/testdata/txtar/md-tables/elk/board.exp.json generated vendored Normal file
View file

@ -0,0 +1,879 @@
{
"name": "",
"isFolderOnly": false,
"fontFamily": "SourceSansPro",
"shapes": [
{
"id": "savings",
"type": "text",
"pos": {
"x": 12,
"y": 386
},
"width": 343,
"height": 150,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#e8f4f8",
"stroke": "#4a90e2",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Month | Savings | Expenses | Balance |\n| -------- | ------- | -------- | ------- |\n| January | $250 | $150 | $100 |\n| February | $80 | $200 | -$120 |\n| March | $420 | $180 | $240 |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 343,
"labelHeight": 150,
"zIndex": 0,
"level": 1
},
{
"id": "status",
"type": "text",
"pos": {
"x": 112,
"y": 921
},
"width": 142,
"height": 113,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#f8e8e8",
"stroke": "#e24a4a",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Status | Count |\n| ------ | ----- |\n| Done | 42 |\n| Todo | 17 |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 142,
"labelHeight": 113,
"zIndex": 0,
"level": 1
},
{
"id": "metrics",
"type": "text",
"pos": {
"x": 97,
"y": 1419
},
"width": 173,
"height": 335,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#f0f8e8",
"stroke": "#82e24a",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Metric | Value |\n| --------- | ------- |\n| Uptime | 99.9% |\n| Latency | 150ms |\n| Errors | 0.01% |\n| Requests | 15k/min |\n| CPU | 45% |\n| Memory | 68% |\n| Disk | 72% |\n| Network | 33% |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 173,
"labelHeight": 335,
"zIndex": 0,
"level": 1
},
{
"id": "financial",
"type": "rectangle",
"pos": {
"x": 579,
"y": 12
},
"width": 429,
"height": 524,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#e8f4f8",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "Financial Overview",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 220,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "financial.monthly",
"type": "text",
"pos": {
"x": 629,
"y": 62
},
"width": 329,
"height": 150,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Month | Revenue | Costs | Margin |\n| --------- | -------- | -------- | ------ |\n| January | $25,000 | $18,000 | 28% |\n| February | $28,500 | $19,200 | 33% |\n| March | $31,200 | $21,500 | 31% |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 329,
"labelHeight": 150,
"zIndex": 0,
"level": 2
},
{
"id": "financial.quarterly",
"type": "text",
"pos": {
"x": 636,
"y": 373
},
"width": 315,
"height": 113,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Quarter | Target | Actual | Variance |\n|:--------|-------:|:------:|:---------|\n| Q1 2024 | $75K | $84.7K | +12.9% |\n| Q2 2024 | $82K | - | - |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 315,
"labelHeight": 113,
"zIndex": 0,
"level": 2
},
{
"id": "monitoring",
"type": "rectangle",
"pos": {
"x": 565,
"y": 712
},
"width": 442,
"height": 546,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#f8e8e8",
"stroke": "B1",
"shadow": false,
"3d": true,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "System Health",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 168,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "monitoring.availability",
"type": "text",
"pos": {
"x": 608,
"y": 754
},
"width": 357,
"height": 150,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Service | Status | Uptime | Last Incident |\n|:-----------|:------:|:------:|:--------------|\n| API | ✅ | 99.9% | 15 days ago |\n| Database | ✅ | 99.8% | 3 days ago |\n| Cache | ⚠️ | 98.5% | 1 hour ago |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 357,
"labelHeight": 150,
"zIndex": 0,
"level": 2
},
{
"id": "monitoring.performance",
"type": "text",
"pos": {
"x": 614,
"y": 1065
},
"width": 344,
"height": 150,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Metric | P50 | P90 | P99 |\n|:----------------|:-----:|:-----:|:-----:|\n| Response Time | 120ms | 350ms | 750ms |\n| DB Query Time | 45ms | 180ms | 450ms |\n| Cache Latency | 5ms | 12ms | 30ms |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 344,
"labelHeight": 150,
"zIndex": 0,
"level": 2
},
{
"id": "projects",
"type": "rectangle",
"pos": {
"x": 290,
"y": 1461
},
"width": 1008,
"height": 250,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#e8f8e8",
"stroke": "#4a90e2",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": true,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "Project Tracking",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 190,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "projects.status",
"type": "text",
"pos": {
"x": 340,
"y": 1511
},
"width": 425,
"height": 150,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Project | Priority | Progress | Due Date | Owner |\n|---------|:--------:|:--------:|:---------|:------|\n| Alpha | HIGH | ![p](https://progress.com/80) 80% | 2024-04-01 | Alice |\n| Beta | MEDIUM | ![p](https://progress.com/45) 45% | 2024-05-15 | Bob |\n| Gamma | LOW | ![p](https://progress.com/20) 20% | 2024-06-30 | Carol |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 425,
"labelHeight": 150,
"zIndex": 0,
"level": 2
},
{
"id": "projects.risks",
"type": "text",
"pos": {
"x": 785,
"y": 1511
},
"width": 463,
"height": 150,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Risk ID | Description | Impact | Mitigation |\n|:-------:|:------------|:------:|:-----------|\n| R1 | Resource shortage | 🔴 High | Hire contractors |\n| R2 | Technical debt | 🟡 Med | Code review |\n| R3 | Scope creep | 🟢 Low | Clear requirements |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 463,
"labelHeight": 150,
"zIndex": 0,
"level": 2
},
{
"id": "team",
"type": "rectangle",
"pos": {
"x": 568,
"y": 1915
},
"width": 451,
"height": 287,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#f8f0e8",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "Team Analytics",
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 177,
"labelHeight": 36,
"labelPosition": "INSIDE_TOP_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "team.velocity",
"type": "text",
"pos": {
"x": 618,
"y": 1965
},
"width": 351,
"height": 187,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "transparent",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "| Sprint | Points | Completed | Carryover |\n|:-------|:------:|:---------:|:---------:|\n| SP-1 | 34 | 30 | 4 |\n| SP-2 | 38 | 35 | 3 |\n| SP-3 | 42 | 40 | 2 |\n| Average| 38 | 35 | 3 |",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "markdown",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 351,
"labelHeight": 187,
"zIndex": 0,
"level": 2
}
],
"connections": [
{
"id": "(savings -> status)[0]",
"src": "savings",
"srcArrow": "none",
"dst": "status",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 5,
"strokeWidth": 2,
"stroke": "B2",
"borderRadius": 10,
"label": "Triggers",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 54,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 183.5,
"y": 536
},
{
"x": 183.5,
"y": 921
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(status -> metrics)[0]",
"src": "status",
"srcArrow": "none",
"dst": "metrics",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "Monitors",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 58,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 183.5,
"y": 1034
},
{
"x": 183.5,
"y": 1419
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "financial.(monthly -> quarterly)[0]",
"src": "financial.monthly",
"srcArrow": "none",
"dst": "financial.quarterly",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "Aggregates",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 77,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 794,
"y": 212
},
{
"x": 794,
"y": 373
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "monitoring.(availability -> performance)[0]",
"src": "monitoring.availability",
"srcArrow": "none",
"dst": "monitoring.performance",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "Affects",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 46,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 786.5,
"y": 904.5
},
{
"x": 786.5,
"y": 1065.5
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(financial -> monitoring)[0]",
"src": "financial",
"srcArrow": "none",
"dst": "monitoring",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "Impacts",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 54,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 794,
"y": 536
},
{
"x": 794,
"y": 697
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(monitoring -> projects)[0]",
"src": "monitoring",
"srcArrow": "none",
"dst": "projects",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 5,
"strokeWidth": 2,
"stroke": "B2",
"borderRadius": 10,
"label": "Informs",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 51,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 794,
"y": 1257.5
},
{
"x": 794,
"y": 1461.5
}
],
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
},
{
"id": "(projects -> team)[0]",
"src": "projects",
"srcArrow": "none",
"dst": "team",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "B1",
"borderRadius": 10,
"label": "Assigns",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 50,
"labelHeight": 21,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 794,
"y": 1711
},
{
"x": 794,
"y": 1915
}
],
"animated": true,
"tooltip": "",
"icon": null,
"zIndex": 0
}
],
"root": {
"id": "",
"type": "",
"pos": {
"x": 0,
"y": 0
},
"width": 0,
"height": 0,
"opacity": 0,
"strokeDash": 0,
"strokeWidth": 0,
"borderRadius": 0,
"fill": "N7",
"stroke": "",
"shadow": false,
"3d": false,
"multiple": false,
"double-border": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "",
"fontSize": 0,
"fontFamily": "",
"language": "",
"color": "",
"italic": false,
"bold": false,
"underline": false,
"labelWidth": 0,
"labelHeight": 0,
"zIndex": 0,
"level": 0
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 59 KiB

View file

@ -483,3 +483,163 @@ description: |md
```
|
b -> description -> a
-- md-tables --
# Financial table
savings: ||md
| Month | Savings | Expenses | Balance |
| -------- | ------- | -------- | ------- |
| January | $250 | $150 | $100 |
| February | $80 | $200 | -$120 |
| March | $420 | $180 | $240 |
||
# Simple 2x2 table
status: ||md
| Status | Count |
| ------ | ----- |
| Done | 42 |
| Todo | 17 |
||
# Long table with many rows
metrics: ||md
| Metric | Value |
| --------- | ------- |
| Uptime | 99.9% |
| Latency | 150ms |
| Errors | 0.01% |
| Requests | 15k/min |
| CPU | 45% |
| Memory | 68% |
| Disk | 72% |
| Network | 33% |
||
# Connect tables with labeled edges
savings -> status: Triggers {
style: {
stroke-dash: 5
}
}
status -> metrics: Monitors {
style: {
stroke-width: 2
}
}
# Add some styling
savings.style: {
fill: "#e8f4f8"
stroke: "#4a90e2"
}
status.style: {
fill: "#f8e8e8"
stroke: "#e24a4a"
}
metrics.style: {
fill: "#f0f8e8"
stroke: "#82e24a"
}
# Container for financial data
financial: {
label: "Financial Overview"
style.stroke-width: 2
monthly: ||md
| Month | Revenue | Costs | Margin |
| --------- | -------- | -------- | ------ |
| January | $25,000 | $18,000 | 28% |
| February | $28,500 | $19,200 | 33% |
| March | $31,200 | $21,500 | 31% |
||
quarterly: ||md
| Quarter | Target | Actual | Variance |
|:--------|-------:|:------:|:---------|
| Q1 2024 | $75K | $84.7K | +12.9% |
| Q2 2024 | $82K | - | - |
||
monthly -> quarterly: "Aggregates"
}
# Container for system metrics
monitoring: {
label: "System Health"
style.3d: true
availability: ||md
| Service | Status | Uptime | Last Incident |
|:-----------|:------:|:------:|:--------------|
| API | ✅ | 99.9% | 15 days ago |
| Database | ✅ | 99.8% | 3 days ago |
| Cache | ⚠️ | 98.5% | 1 hour ago |
||
performance: ||md
| Metric | P50 | P90 | P99 |
|:----------------|:-----:|:-----:|:-----:|
| Response Time | 120ms | 350ms | 750ms |
| DB Query Time | 45ms | 180ms | 450ms |
| Cache Latency | 5ms | 12ms | 30ms |
||
availability -> performance: "Affects"
}
# Container for project status
projects: {
label: "Project Tracking"
style.stroke: "#4a90e2"
style.double-border: true
status: ||md
| Project | Priority | Progress | Due Date | Owner |
|---------|:--------:|:--------:|:---------|:------|
| Alpha | HIGH | ![p](https://progress.com/80) 80% | 2024-04-01 | Alice |
| Beta | MEDIUM | ![p](https://progress.com/45) 45% | 2024-05-15 | Bob |
| Gamma | LOW | ![p](https://progress.com/20) 20% | 2024-06-30 | Carol |
||
risks: ||md
| Risk ID | Description | Impact | Mitigation |
|:-------:|:------------|:------:|:-----------|
| R1 | Resource shortage | 🔴 High | Hire contractors |
| R2 | Technical debt | 🟡 Med | Code review |
| R3 | Scope creep | 🟢 Low | Clear requirements |
||
}
# Container for team stats
team: {
label: "Team Analytics"
style.fill: "#f5f5f5"
velocity: ||md
| Sprint | Points | Completed | Carryover |
|:-------|:------:|:---------:|:---------:|
| SP-1 | 34 | 30 | 4 |
| SP-2 | 38 | 35 | 3 |
| SP-3 | 42 | 40 | 2 |
| Average| 38 | 35 | 3 |
||
}
# Connect containers
financial -> monitoring: "Impacts"
monitoring -> projects: "Informs" {
style.stroke-dash: 5
}
projects -> team: "Assigns" {
style.animated: true
}
# Styling
financial.style.fill: "#e8f4f8"
monitoring.style.fill: "#f8e8e8"
projects.style.fill: "#e8f8e8"
team.style.fill: "#f8f0e8"

View file

@ -98,6 +98,7 @@ func init() {
),
goldmark.WithExtensions(
extension.Strikethrough,
extension.Table,
),
)
}
@ -185,7 +186,8 @@ func isBlockElement(elType string) bool {
"ol",
"p",
"pre",
"ul":
"ul",
"table", "thead", "tbody", "tr", "td", "th": // Added table elements here
return true
default:
return false
@ -204,6 +206,7 @@ func hasAncestorElement(n *html.Node, elType string) bool {
type blockAttrs struct {
width, height, marginTop, marginBottom float64
extraData interface{}
}
func (b *blockAttrs) isNotEmpty() bool {
@ -280,7 +283,7 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, fontFamily *d2fonts.Fon
if debugMeasure {
fmt.Printf("%stext(%v,%v)\n", depthStr, w, h)
}
return blockAttrs{w + spaceWidths, h, 0, 0}
return blockAttrs{w + spaceWidths, h, 0, 0, 0}
case html.ElementNode:
isCode := false
switch n.Data {
@ -429,6 +432,142 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, fontFamily *d2fonts.Fon
block.height += Height_hr_em * float64(fontSize)
block.marginTop = go2.Max(block.marginTop, MarginTopBottom_hr)
block.marginBottom = go2.Max(block.marginBottom, MarginTopBottom_hr)
case "table":
var columnWidths []float64
var tableHeight float64
// Border width for table (outer border)
tableBorder := 1.0
// Iterate over child nodes (tbody, thead, tr)
for child := n.FirstChild; child != nil; child = child.NextSibling {
if child.Type == html.ElementNode && (child.Data == "tbody" || child.Data == "thead" || child.Data == "tfoot") {
childAttrs := ruler.measureNode(depth+1, child, fontFamily, fontSize, fontStyle)
tableHeight += childAttrs.height
if childColumnWidths, ok := childAttrs.extraData.([][]float64); ok {
columnWidths = mergeColumnWidths(columnWidths, childColumnWidths)
}
} else if child.Type == html.ElementNode && child.Data == "tr" {
rowAttrs := ruler.measureNode(depth+1, child, fontFamily, fontSize, fontStyle)
tableHeight += rowAttrs.height
if rowCellWidths, ok := rowAttrs.extraData.([]float64); ok {
columnWidths = mergeColumnWidths(columnWidths, [][]float64{rowCellWidths})
}
}
}
// Calculate total table width including ALL borders
tableWidth := 0.0
if len(columnWidths) > 0 {
// Add widths of all columns
for _, colWidth := range columnWidths {
tableWidth += colWidth
}
// Add border for every column division (including outer borders)
tableWidth += float64(len(columnWidths)+1) * tableBorder
}
// Add outer borders to height
tableHeight += 2 * tableBorder
block.width = tableWidth
block.height = tableHeight
case "thead", "tbody", "tfoot":
var sectionWidth, sectionHeight float64
var sectionColumnWidths [][]float64
// Iterate over tr elements
for child := n.FirstChild; child != nil; child = child.NextSibling {
if child.Type == html.ElementNode && child.Data == "tr" {
childAttrs := ruler.measureNode(depth+1, child, fontFamily, fontSize, fontStyle)
sectionHeight += childAttrs.height
sectionWidth = go2.Max(sectionWidth, childAttrs.width)
if rowCellWidths, ok := childAttrs.extraData.([]float64); ok {
sectionColumnWidths = append(sectionColumnWidths, rowCellWidths)
}
}
}
block.width = sectionWidth
block.height = sectionHeight
block.extraData = sectionColumnWidths // Pass column widths back to table
case "td", "th":
// Apply semibold style to header cells
cellFontStyle := fontStyle
if n.Data == "th" {
cellFontStyle = d2fonts.FONT_STYLE_SEMIBOLD
}
// Measure cell content with appropriate font style
var cellContentWidth, cellContentHeight float64
for child := n.FirstChild; child != nil; child = child.NextSibling {
// Pass the header-specific font style to child measurements
childAttrs := ruler.measureNode(depth+1, child, fontFamily, fontSize, cellFontStyle)
cellContentWidth = go2.Max(cellContentWidth, childAttrs.width)
cellContentHeight += childAttrs.height
}
block.width = cellContentWidth
block.height = cellContentHeight
case "tr":
var rowWidth, rowHeight float64
var cellWidths []float64
cellBorder := 1.0
rowBorder := 1.0
maxCellHeight := 0.0
cellCount := 0
// Check if this row is in a thead to determine default font style for cells
inHeader := hasAncestorElement(n, "thead")
rowFontStyle := fontStyle
if inHeader {
rowFontStyle = d2fonts.FONT_STYLE_SEMIBOLD
}
for child := n.FirstChild; child != nil; child = child.NextSibling {
if child.Type == html.ElementNode && (child.Data == "td" || child.Data == "th") {
cellCount++
// Use semibold for th elements regardless of location
childFontStyle := rowFontStyle
if child.Data == "th" {
childFontStyle = d2fonts.FONT_STYLE_SEMIBOLD
}
childAttrs := ruler.measureNode(depth+1, child, fontFamily, fontSize, childFontStyle)
cellPaddingH := 13.0 * 2
cellPaddingV := 6.0 * 2
cellWidth := childAttrs.width + cellPaddingH
cellHeight := childAttrs.height + cellPaddingV
cellWidths = append(cellWidths, cellWidth)
maxCellHeight = go2.Max(maxCellHeight, cellHeight)
}
}
if cellCount > 0 {
for _, w := range cellWidths {
rowWidth += w
}
rowWidth += float64(cellCount+1) * cellBorder
}
rowHeight = maxCellHeight + rowBorder
block.width = rowWidth
block.height = rowHeight
block.extraData = cellWidths
}
if block.height > 0 && block.height < lineHeightPx {
block.height = lineHeightPx
@ -440,3 +579,16 @@ func (ruler *Ruler) measureNode(depth int, n *html.Node, fontFamily *d2fonts.Fon
}
return blockAttrs{}
}
func mergeColumnWidths(existing []float64, new [][]float64) []float64 {
for _, rowWidths := range new {
for i, width := range rowWidths {
if i >= len(existing) {
existing = append(existing, width)
} else {
existing[i] = go2.Max(existing[i], width)
}
}
}
return existing
}