@liggi/figkit 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/GUIDE.md +34 -4
- package/README.md +2 -2
- package/bin/fig.mjs +3 -3
- package/dist/viz.iife.js +10 -10
- package/examples/charts/entities.json +17 -0
- package/examples/consolidate.html +10 -6
- package/package.json +1 -1
- package/runtime/fig.css +7 -1
- package/runtime/fig.js +164 -33
- package/viz/draw.js +88 -0
- package/viz/spec.js +48 -3
package/GUIDE.md
CHANGED
|
@@ -28,6 +28,11 @@ the images and look, then embed the PNG: ``.
|
|
|
28
28
|
A question about structure ("what are the entities?", "where does X live?", "how do these relate?", "what loads
|
|
29
29
|
what?", "walk me through it") is answered with a picture first, not with numbered steps.
|
|
30
30
|
|
|
31
|
+
- "What are the entities and how do they relate?" is an `entities` spec (below), not boxes and arrows in HTML. It
|
|
32
|
+
draws references: which record holds a pointer to which. The order work happens in (approve, then label, then
|
|
33
|
+
train) is not a reference; it goes in prose, a list or a separate flow. A record that creates others still points
|
|
34
|
+
at them: draw the pointers it holds, not the steps it runs. Draw every pointer a record holds, even when another
|
|
35
|
+
line reaches the same record by a longer way; leaving one out says the column is not there.
|
|
31
36
|
- Each figure is a plain `fig` with at most 5 boxes and no `group`. More than that is two or three figures in a row,
|
|
32
37
|
not one map: what exists, then one case through it, then what changes. A process or machine the code runs in is a
|
|
33
38
|
`tag` on the box, not a box around it. Use `fig detail` only when the reader asked for the whole map.
|
|
@@ -39,9 +44,9 @@ what?", "walk me through it") is answered with a picture first, not with numbere
|
|
|
39
44
|
three arrows; one shared copy is one box fanning out to the three. "How many" must be visible without reading.
|
|
40
45
|
- Name each thing once, and use that name in the title, the boxes and your prose.
|
|
41
46
|
|
|
42
|
-
## Charts from a spec
|
|
47
|
+
## Charts and entities from a spec
|
|
43
48
|
|
|
44
|
-
When the whole figure is one chart of a type below, write a JSON spec instead of HTML. You give the data; figkit
|
|
49
|
+
When the whole figure is one chart or one entities picture of a type below, write a JSON spec instead of HTML. You give the data; figkit
|
|
45
50
|
does the layout, colours and labels. Use HTML (the rest of this guide) for anything else, including a chart that sits
|
|
46
51
|
beside boxes or arrows.
|
|
47
52
|
|
|
@@ -100,6 +105,30 @@ mark's `x` must be one of them. The y axis starts at zero unless `"zero": false`
|
|
|
100
105
|
"mark": { "x": "2026-10-14", "label": "212, launch day" } }
|
|
101
106
|
```
|
|
102
107
|
|
|
108
|
+
`entities`: what the things are and which points at which. 2 to 5 `records`, each with an `id` you use in `refs`,
|
|
109
|
+
a `name` in the reader's words, and up to 4 `fields` that say what it holds (put a table name here only if the reader
|
|
110
|
+
needs it). Each of up to 8 `refs` is a pointer the `from` record holds to the `to` record: `count` is how many `from`
|
|
111
|
+
records can point at one `to` (`"many"`, the default, or `"one"`), and `"optional": true` when the pointer may be
|
|
112
|
+
empty. figkit places the records (what is pointed at sits above what points at it) and draws each reference as a line
|
|
113
|
+
joined at the records' names: a dot on the record named, and on the holder a crow's foot when many can point at one or
|
|
114
|
+
a short bar when only one can; dashed when it may be empty; never an arrow, never a key. It draws a two-column layout
|
|
115
|
+
for a phone. Every record must be in a reference. Accent at most one record: the one the title is about. The title
|
|
116
|
+
claims only what the lines show; if it says "everything names X", every record has a line to X. Names and fields are
|
|
117
|
+
in plain words, not in-house terms or button labels.
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{ "type": "entities", "title": "Every order line names one product and one order",
|
|
121
|
+
"records": [ { "id": "order", "name": "Order", "fields": ["placed at"] },
|
|
122
|
+
{ "id": "line", "name": "Order line", "fields": ["quantity"], "tone": "accent" },
|
|
123
|
+
{ "id": "product", "name": "Product", "fields": ["sku"] },
|
|
124
|
+
{ "id": "payment", "name": "Payment" } ],
|
|
125
|
+
"refs": [ { "from": "line", "to": "order" },
|
|
126
|
+
{ "from": "line", "to": "product" },
|
|
127
|
+
{ "from": "payment", "to": "order", "count": "one", "optional": true } ] }
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
More than 5 records is two figures: the core records, then one corner of it with the core record it hangs off.
|
|
131
|
+
|
|
103
132
|
Flows (boxes and arrows) have no spec: write them in HTML, below.
|
|
104
133
|
|
|
105
134
|
- `title` (required) is the point, 14 words at most. `note` is the reading line under it; `source` a footer.
|
|
@@ -123,7 +152,7 @@ Flows (boxes and arrows) have no spec: write them in HTML, below.
|
|
|
123
152
|
```
|
|
124
153
|
|
|
125
154
|
- In the `<h1>`, `<em>` turns the words accent-coloured italic and `<br>` sets a line break.
|
|
126
|
-
- `fig` is a glance figure, 960 wide: one point, big type, reads inline on a phone. At most
|
|
155
|
+
- `fig` is a glance figure, 960 wide: one point, big type, reads inline on a phone. At most 5 boxes, 8 arrows and 70 words.
|
|
127
156
|
- `fig detail` is 1360 wide, for a flow or map the reader asked for and opens full screen; to explain a system, use
|
|
128
157
|
several `fig` figures instead (see Explaining a system). At most 18 boxes, 18 arrows and 190 words.
|
|
129
158
|
Widen it with `style="--w: 1560px"` only when a row will not fit.
|
|
@@ -196,7 +225,8 @@ never nudge with margins.
|
|
|
196
225
|
|
|
197
226
|
Put them anywhere inside the figure; `from` and `to` are element ids. Any element can be an end: a node, a group, a
|
|
198
227
|
`mark` on a screenshot, a `<span>` of text. Arrows keep clear of boxes and loose text, and arrows sharing an end and
|
|
199
|
-
a colour share a trunk.
|
|
228
|
+
a colour share a trunk. When a label has no free place, figkit opens the gap between the two boxes (or widens the
|
|
229
|
+
figure a little) and draws again; keep labels to a few words so it rarely has to.
|
|
200
230
|
|
|
201
231
|
- colour: `accent`, `second`, `good`, `bad`; `dashed`; `weight="3"`; `both` for two heads; `head="none"`
|
|
202
232
|
- `blocked`: a route that does not exist. The line stops short of the target at a cross, with no arrowhead
|
package/README.md
CHANGED
|
@@ -46,8 +46,8 @@ npx figkit order.html --out order.png
|
|
|
46
46
|
|
|
47
47
|
## A chart from a spec
|
|
48
48
|
|
|
49
|
-
For one chart of a known type (`split`, `bars`, `before-after`, `dumbbell`, `series`)
|
|
50
|
-
the rest. Save this as `checkout.json`:
|
|
49
|
+
For one chart of a known type (`split`, `bars`, `before-after`, `dumbbell`, `series`), or an `entities` picture of
|
|
50
|
+
records and the references between them, give the data and figkit does the rest, including the layout. Save this as `checkout.json`:
|
|
51
51
|
|
|
52
52
|
```json
|
|
53
53
|
{ "type": "bars", "title": "The new checkout halves the time to pay",
|
package/bin/fig.mjs
CHANGED
|
@@ -39,7 +39,7 @@ if (/\.json$/i.test(src)) {
|
|
|
39
39
|
console.log(`This chart spec has ${spec.problems.length} problem${spec.problems.length === 1 ? '' : 's'}:\n${spec.problems.map((p) => ` - ${p}`).join('\n')}`);
|
|
40
40
|
process.exit(1);
|
|
41
41
|
}
|
|
42
|
-
body = `<main class="fig chart"><script type="application/json" id="figkit-spec">${JSON.stringify(spec.spec).replace(/</g, '\\u003c')}</script></main>`;
|
|
42
|
+
body = `<main class="fig ${spec.spec.type === 'entities' ? 'entities-fig' : 'chart'}"><script type="application/json" id="figkit-spec">${JSON.stringify(spec.spec).replace(/</g, '\\u003c')}</script></main>`;
|
|
43
43
|
} else if (!/class="[^"]*\bfig\b/.test(body)) body = `<main class="fig">\n${body}\n</main>`;
|
|
44
44
|
await ensureBuilt();
|
|
45
45
|
|
|
@@ -93,7 +93,7 @@ try {
|
|
|
93
93
|
if (phone) await page.addInitScript(() => { window.__figPhone = true; });
|
|
94
94
|
await page.goto(pathToFileURL(wrapped).href);
|
|
95
95
|
await page.waitForFunction('window.__figDone === true', null, { timeout: 30000 });
|
|
96
|
-
const r = await page.evaluate(() => ({ problems: window.fig.problems, info: window.fig.info, sides: !!document.querySelector('.fig .sides') }));
|
|
96
|
+
const r = await page.evaluate(() => ({ problems: window.fig.problems, info: window.fig.info, sides: !!document.querySelector('.fig .sides, .fig .entities'), entities: !!document.querySelector('.fig .entities') }));
|
|
97
97
|
await page.locator('.fig').first().screenshot({ path: shot });
|
|
98
98
|
await page.close();
|
|
99
99
|
return { ...r, problems: [...errors.map((e) => `Script error: ${e}`), ...r.problems] };
|
|
@@ -108,7 +108,7 @@ try {
|
|
|
108
108
|
|
|
109
109
|
const { info } = desk;
|
|
110
110
|
const lines = [`Figure: ${png} (${info.width * 2}×${info.height * 2})`];
|
|
111
|
-
if (mob) lines.push(`Phone layout: ${phonePng} (${mob.info.width * 2}×${mob.info.height * 2}), the sides stacked, for a viewer to show on a phone`);
|
|
111
|
+
if (mob) lines.push(`Phone layout: ${phonePng} (${mob.info.width * 2}×${mob.info.height * 2}), ${desk.entities ? 'the records in two columns' : 'the sides stacked'}, for a viewer to show on a phone`);
|
|
112
112
|
lines.push(`Phone inline: ${inline} (preview only)`);
|
|
113
113
|
const ph = (mob ?? desk).info.phone;
|
|
114
114
|
const sizes = [['the title', ph?.title], ['headings', ph?.heading], ['body', ph?.body]].filter(([, v]) => v != null).map(([k, v]) => `${k} ${v}px`);
|