@liggi/figkit 0.4.0 → 0.6.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 +154 -12
- package/THIRD_PARTY_NOTICES.md +48 -1
- package/bin/fig.mjs +5 -3
- package/dist/viz.iife.js +86 -18
- package/examples/charts/bars-ref.json +6 -0
- package/examples/charts/estimates.json +7 -0
- package/examples/charts/heatmap-signed.json +5 -0
- package/examples/charts/map.json +269 -0
- package/examples/charts/states.json +71 -0
- package/package.json +2 -1
- package/runtime/fig.css +56 -0
- package/runtime/fig.js +218 -20
- package/viz/draw.js +168 -14
- package/viz/map-spec.js +121 -0
- package/viz/map.js +513 -0
- package/viz/spec.js +64 -6
- package/viz/states-spec.js +161 -0
- package/viz/states.js +203 -0
package/GUIDE.md
CHANGED
|
@@ -30,14 +30,20 @@ what?", "walk me through it") is answered with a picture first, not with numbere
|
|
|
30
30
|
|
|
31
31
|
- "What happens when…?", "walk me through a run" and "who calls whom?" are a `sequence` spec (below): the steps in
|
|
32
32
|
order between the parts, not a numbered list or a table of steps.
|
|
33
|
+
- "What's the lifecycle of X?" and "what states can it be in?" are a `states` spec (below): the states one thing
|
|
34
|
+
moves through and what moves it on, not boxes and arrows in HTML.
|
|
33
35
|
- "What are the entities and how do they relate?" is an `entities` spec (below), not boxes and arrows in HTML. It
|
|
34
36
|
draws references: which record holds a pointer to which. The order work happens in (approve, then label, then
|
|
35
37
|
train) is not a reference; it goes in prose, a list or a separate flow. A record that creates others still points
|
|
36
38
|
at them: draw the pointers it holds, not the steps it runs. Draw every pointer a record holds, even when another
|
|
37
39
|
line reaches the same record by a longer way; leaving one out says the column is not there.
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
- "How does X fit together?", "what are all the parts of X?", "give me the map of X": when the question really is
|
|
41
|
+
about the whole system and it has more than 5 parts worth naming, draw a `map` spec (below): every part in its
|
|
42
|
+
subsystem and every link, laid out by figkit. Follow it with a plain `fig` of the part the question is about,
|
|
43
|
+
so the reader knows where to look; a map alone answers "what exists", not "what matters here".
|
|
44
|
+
- Otherwise each figure is a plain `fig` with at most 5 boxes and no `group`. More than that is two or three figures
|
|
45
|
+
in a row: what exists, then one case through it, then what changes. A process or machine the code runs in is a
|
|
46
|
+
`tag` on the box, not a box around it. A system of more than 5 parts is a `map`, not a hand-placed `fig detail`.
|
|
41
47
|
- Under each figure, write only what it cannot show: why, the exceptions, what to do. Never retell it as steps.
|
|
42
48
|
- Put a real instance in each box, with its kind as the smaller line: "Refunds over £500" over "Approval rule",
|
|
43
49
|
not a box that says only "Rule".
|
|
@@ -48,7 +54,7 @@ what?", "walk me through it") is answered with a picture first, not with numbere
|
|
|
48
54
|
|
|
49
55
|
## Charts and entities from a spec
|
|
50
56
|
|
|
51
|
-
When the whole figure is one chart, one entities picture or one
|
|
57
|
+
When the whole figure is one chart, one entities picture, one sequence, one lifecycle or one system map of a type below, write a JSON spec instead of HTML. You give the data; figkit
|
|
52
58
|
does the layout, colours and labels. Use HTML (the rest of this guide) for anything else, including a chart that sits
|
|
53
59
|
beside boxes or arrows.
|
|
54
60
|
|
|
@@ -76,6 +82,21 @@ and embed the PNG, as for any figure.
|
|
|
76
82
|
"bars": [ { "label": "Current checkout", "value": 86 }, { "label": "New checkout", "value": 41, "tone": "good" } ] }
|
|
77
83
|
```
|
|
78
84
|
|
|
85
|
+
A bar chart that compares every bar with one level, such as production or the current version, takes `ref`: the
|
|
86
|
+
level's `value` and a `label` naming it in words ("Production (ash-prod-27b)", never a bare number). figkit draws it as
|
|
87
|
+
its own first row in the second colour, with a dashed line from its end down through every bar; bars above it are
|
|
88
|
+
accented and the rest are grey, and the key says what the colour means. The colours are figkit's, so a `tone` on a bar
|
|
89
|
+
is refused, and `note` is required so the reader knows what the level's number counts. With ranges, a bar counts as
|
|
90
|
+
above only when its whole range is above. `show` on the ref replaces its printed value, e.g. `"50%, a tie"`.
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{ "type": "bars", "title": "Two of the four new layouts beat the current page",
|
|
94
|
+
"note": "Share of visitors who finished checkout", "unit": "%",
|
|
95
|
+
"ref": { "label": "Current page", "value": 61 },
|
|
96
|
+
"bars": [ { "label": "One-page form", "value": 68 }, { "label": "Saved cards first", "value": 64 },
|
|
97
|
+
{ "label": "Address lookup", "value": 60 }, { "label": "Guest by default", "value": 57 } ] }
|
|
98
|
+
```
|
|
99
|
+
|
|
79
100
|
`before-after`: one measure that changed, the two values side by side on one scale; `note` (required) says what
|
|
80
101
|
the number counts. For several things changing,
|
|
81
102
|
use `bars` or `dumbbell`.
|
|
@@ -148,7 +169,9 @@ different things on the same scale.
|
|
|
148
169
|
```
|
|
149
170
|
|
|
150
171
|
`heatmap`: a grid of values over two dimensions (day by hour, team by week), coloured from pale to dark blue: darker
|
|
151
|
-
is always more.
|
|
172
|
+
is always more. When any value is below zero (a change, a gap, a correlation), the grid is signed and the colour runs
|
|
173
|
+
from orange below zero through pale at zero to blue above, equally strong at equal distances from zero, with the
|
|
174
|
+
numbers printed with their sign; the scale shows 0 between the two halves. Numbers keep the decimal places you give. Up to 12 `rows` and 31 `columns`; `values` is one array per row. `note` (required) says what the
|
|
152
175
|
colour counts, and the scale is drawn above the grid. Here the colour is the measure, so the one-accent rule moves:
|
|
153
176
|
`mark` outlines the one cell to notice in the accent colour and names it beside the scale. Cells show their numbers
|
|
154
177
|
when there is room. Columns label themselves at even steps, so give hours as "12am", "1am", … and they read 12am,
|
|
@@ -185,6 +208,28 @@ the things counted (`"each": "runs"`), else "n = 14"; give every bar one or none
|
|
|
185
208
|
|
|
186
209
|
The title claims only what the ranges allow: when they overlap, "catches more" needs a "but".
|
|
187
210
|
|
|
211
|
+
`estimates`: signed results with their ranges, one row each around a zero line (a forest plot): a gap between two
|
|
212
|
+
groups, a change against control, a correlation. Use it when the sign is the point and each number has a range: "+7.4
|
|
213
|
+
(+2.7 to +12.4)". For numbers counted up from zero, use `bars`; for a move from one value to another, `dumbbell`. Every
|
|
214
|
+
row needs `low` and `high`, and `range` says once what they are. `note` (required) says what the number is and which
|
|
215
|
+
way round ("matched minus not matched"). `sides` names what each side of zero means, printed under the axis and meeting at zero; keep each to two or three words, or figkit reports it. figkit
|
|
216
|
+
chooses the colours: a row whose range clears zero is filled in the accent colour, one whose range includes zero is a
|
|
217
|
+
hollow grey dot, and the key says so; a `tone` is refused. With `"better": "higher"` or `"lower"`, a row clear of zero
|
|
218
|
+
is `good` or `bad` instead. Up to 12 rows; `n` and `each` as on `bars`. Numbers keep the decimal places you give, with
|
|
219
|
+
their sign. A range that does not contain its value, or a range of no width, is refused.
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{ "type": "estimates", "title": "Free delivery lifts orders in two regions; the north's range includes zero",
|
|
223
|
+
"note": "Change in orders per 100 visitors, free delivery minus paid", "range": "95% interval",
|
|
224
|
+
"sides": { "below": "Paid better", "above": "Free better" },
|
|
225
|
+
"rows": [ { "label": "South", "value": 2.4, "low": 1.1, "high": 3.7 },
|
|
226
|
+
{ "label": "Midlands", "value": 1.8, "low": 0.6, "high": 3.0 },
|
|
227
|
+
{ "label": "North", "value": 0.7, "low": -0.9, "high": 2.3 } ] }
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
The title says a result only for rows whose range clears zero; a row whose range includes zero is "no clear change",
|
|
231
|
+
not a small gain.
|
|
232
|
+
|
|
188
233
|
`dots`: every value as a dot, for a sample small enough to look at one by one (up to 300 a group, 600 in all), in 1
|
|
189
234
|
to 6 groups on one axis. Use it instead of a bar of the average when the spread or a few odd values are the point.
|
|
190
235
|
Dots that would overlap stack upward and downward, so none hides another, and each group's count is printed. `note`
|
|
@@ -280,12 +325,108 @@ steps show.
|
|
|
280
325
|
More than 5 participants or 12 steps is two figures: the whole run with minor parts merged into one participant, then
|
|
281
326
|
the stage that needs detail. Leave out steps that only log or record what happened unless the question is about them.
|
|
282
327
|
|
|
328
|
+
`states`: the states one thing moves through and what moves it on: a pull request, an order, a ticket, a person
|
|
329
|
+
in a study. Use it for "what's the lifecycle of X?", "what states can it be in?", "what happens after it's
|
|
330
|
+
approved?": the question is about one thing and where it can go next. A `sequence` is about several parts taking turns;
|
|
331
|
+
a flow is about what connects to what. 2 to 7 `states`, each an `id`, a `name` and an optional one-line `note` (a rule
|
|
332
|
+
that holds there: "A restart needs a new review"). Mark the one state things begin in `"start": true`, and the states
|
|
333
|
+
they stop in `"end": true`: nothing ever leaves an end, so a mark that comes and goes on a state (the current
|
|
334
|
+
default, a pin) is that state's `note`, not an end. `entry` labels the way in ("Card created"). 1 to 10 `moves`, each `from` one state `to`
|
|
335
|
+
another with a `label` saying what makes the move happen. figkit draws the longest run from the start down one
|
|
336
|
+
column, the other states beside it, and a move back to an earlier state as a loop up the left side. `from` can be a
|
|
337
|
+
list of states for one move any of them can make (retire, cancel), drawn as one bracket beside them and one arrow; `back` names the same
|
|
338
|
+
move the other way (`"back": "Restore"`), drawn with a head at both ends.
|
|
339
|
+
|
|
340
|
+
Counts: `count` on every move is how many of the things made that move at least once, `each` names them
|
|
341
|
+
(`"people"`), and the start's `count` is how many entered. `stayed` on a state that is not an end is how many went no further
|
|
342
|
+
than it. `"shares": true` adds each move's share of those who
|
|
343
|
+
reached the state it leaves; a loop back brings nothing new into that base. figkit says what the counts mean under
|
|
344
|
+
the reading line, and refuses counts on only some moves, a move counted higher than reached the state it leaves,
|
|
345
|
+
moves out of a state passed through once adding up to more than reached it, and a share of fewer than 10.
|
|
346
|
+
|
|
347
|
+
It also refuses a lifecycle with no start or two, an end with a way out, a state nothing leaves that is not marked
|
|
348
|
+
end, a state the start cannot reach, a move to its own state (put that in the state's `note`), and two moves between
|
|
349
|
+
the same states the same way. Accent one state or the moves the title is about. The title claims only what the moves
|
|
350
|
+
show.
|
|
351
|
+
|
|
352
|
+
```json
|
|
353
|
+
{ "type": "states", "title": "An order waits after a declined card until a new card is added",
|
|
354
|
+
"entry": "Shopper checks out",
|
|
355
|
+
"states": [ {"id": "waiting", "name": "Awaiting payment", "start": true},
|
|
356
|
+
{"id": "declined", "name": "Card declined", "note": "Shopper emailed", "tone": "accent"},
|
|
357
|
+
{"id": "paid", "name": "Paid"},
|
|
358
|
+
{"id": "packed", "name": "Packed"},
|
|
359
|
+
{"id": "shipped", "name": "Shipped", "end": true},
|
|
360
|
+
{"id": "cancelled", "name": "Cancelled", "end": true} ],
|
|
361
|
+
"moves": [ {"from": "waiting", "to": "paid", "label": "Charge succeeds"},
|
|
362
|
+
{"from": "waiting", "to": "declined", "label": "Charge fails"},
|
|
363
|
+
{"from": "declined", "to": "waiting", "label": "New card added"},
|
|
364
|
+
{"from": "paid", "to": "packed", "label": "Warehouse picks"},
|
|
365
|
+
{"from": "packed", "to": "shipped", "label": "Carrier collects"},
|
|
366
|
+
{"from": ["paid", "packed"], "to": "cancelled", "label": "Shopper cancels"} ] }
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
A states picture holds 7 states, not the 5 boxes of other figures: each state is a short name read in order down one
|
|
370
|
+
path, and an ordinary lifecycle is four or five steps plus one or two ways off it. More than 7 is two figures: the
|
|
371
|
+
main path with the side branches merged into one state, then the branch that needs detail.
|
|
372
|
+
|
|
373
|
+
`map`: a whole system, its parts grouped by subsystem and the links between them, laid out by figkit. Use it when
|
|
374
|
+
the question is about the whole system ("how does X fit together?", "what are all the parts?"); for one path through
|
|
375
|
+
it use `sequence`, and for one corner of it a plain `fig`. 2 to 6 `subsystems`, each an `id`, a `name` and an optional
|
|
376
|
+
`kind` (the folder or team it belongs to). 6 to 24 `parts`, each an `id`, a `name` in the reader's words, a `kind` as
|
|
377
|
+
the smaller line (the file, the service, what it is: "lib/detectors/gate.ts", "Postgres") and `in`, the subsystem it
|
|
378
|
+
belongs to; something outside the system, such as GitHub or a database another team runs, still goes in a subsystem,
|
|
379
|
+
"Outside". At most 8 parts in one subsystem. Up to 30 `links`, each `from` the part that calls, reads or sends `to`
|
|
380
|
+
the part called, read or written, with an optional `label` of a few words ("writes scores", "pick lists"). Label the
|
|
381
|
+
links the question is about and leave the obvious ones bare: every label is one more thing to place in a crowded
|
|
382
|
+
picture. A label sits on its own line, never beside it, because between subsystems lines run side by side and a word
|
|
383
|
+
beside one reads as naming its neighbour; figkit moves it along the line to a clear spot and refuses the figure when
|
|
384
|
+
there is none, naming the label to drop. A real map of 23 parts kept 18 of its 21 labels. Draw a link one way only, from the part that starts the exchange; the reply is implied. `"tone": "accent"` on the parts and links the question
|
|
385
|
+
is about, the same ones the title names.
|
|
386
|
+
|
|
387
|
+
figkit lays the parts out in layers inside each subsystem, packs the subsystems into rows that read largest on a full
|
|
388
|
+
screen, and routes every link around the boxes. With links accented, it places the accented path first: the subsystems
|
|
389
|
+
it passes through go one after another, lined up so the path runs as one straight line, or steps aside where a part is
|
|
390
|
+
in the way, and the other subsystems go beside it, routed around it. It refuses a map whose accented path still turns
|
|
391
|
+
back on itself, and names any grey link that crosses it. Accent links that follow one another in one direction.
|
|
392
|
+
A map with an accented path holds 28 links, and at most 3 grey links on any part of the path: the path takes a part's
|
|
393
|
+
top and bottom, so grey links come in from the sides. Measured on a real map of 24 parts, its path stayed one straight
|
|
394
|
+
run with no grey link crossing it at 15 to 26 links, and failed at 27 (4 grey links on one part of the path), 29 and
|
|
395
|
+
30 (lines on top of each other, or 17 to 21 crossings); a second real map held at 28 links. The phone layout draws each subsystem as one box listing its parts,
|
|
396
|
+
with the number of links between subsystems on the arrows. It refuses an id that names no part or subsystem, a part in
|
|
397
|
+
no subsystem, a part or subsystem with no link or no parts, two links between the same parts, either way, a link from
|
|
398
|
+
a part to itself, and two parts with the same name. After drawing it reports labels that collide and links that run on
|
|
399
|
+
top of each other; up to one crossing per 2 links is allowed and named in a note.
|
|
400
|
+
|
|
401
|
+
```json
|
|
402
|
+
{ "type": "map", "title": "Every order passes through the order service before stores see it",
|
|
403
|
+
"subsystems": [ { "id": "shop", "name": "Storefront" }, { "id": "orders", "name": "Orders" },
|
|
404
|
+
{ "id": "stores", "name": "Store fulfilment" } ],
|
|
405
|
+
"parts": [ { "id": "web", "name": "Shop website", "kind": "Next.js app", "in": "shop" },
|
|
406
|
+
{ "id": "basket", "name": "Basket service", "kind": "Go service", "in": "shop" },
|
|
407
|
+
{ "id": "order", "name": "Order service", "kind": "Go service", "in": "orders", "tone": "accent" },
|
|
408
|
+
{ "id": "events", "name": "Order events", "kind": "Kafka topic", "in": "orders" },
|
|
409
|
+
{ "id": "planner", "name": "Picking planner", "kind": "nightly batch", "in": "stores" },
|
|
410
|
+
{ "id": "picker", "name": "Picker app", "kind": "handheld scanner", "in": "stores" } ],
|
|
411
|
+
"links": [ { "from": "web", "to": "basket" },
|
|
412
|
+
{ "from": "basket", "to": "order", "label": "checkout", "tone": "accent" },
|
|
413
|
+
{ "from": "order", "to": "events", "label": "publishes" },
|
|
414
|
+
{ "from": "events", "to": "planner" }, { "from": "planner", "to": "picker", "label": "pick lists" } ] }
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
A map holds 24 parts, not the 5 boxes of other figures, because it is opened full screen and read region by region,
|
|
418
|
+
not taken in at a glance. 24 parts and 30 links is where real systems stop reading: drawn from their code, two systems
|
|
419
|
+
of 23 and 24 parts with 28 and 30 links crossed 9 and 11 times and could be followed full screen; at 32 links one of
|
|
420
|
+
them crossed anywhere from 12 to 20 times as small changes moved its regions, and at 31 to 34 parts and 45 to 48 links
|
|
421
|
+
they crossed 28 to 49 times and could not be followed. More than 24 is two maps: the subsystems with the busiest one merged to a few parts, then
|
|
422
|
+
that subsystem as its own map. The title still claims one thing the map shows.
|
|
423
|
+
|
|
283
424
|
Flows (boxes and arrows) have no spec: write them in HTML, below. A flow says what connects to what; when the order
|
|
284
|
-
things happen in is the point, use `sequence`.
|
|
425
|
+
things happen in is the point, use `sequence`; when one thing's states are the point, use `states`.
|
|
285
426
|
|
|
286
427
|
- `title` (required) is the point, 14 words at most. `note` is the reading line under it; `source` a footer.
|
|
287
428
|
- `"style": "report"` draws a light chart in one sans font, for a chart that sits in a page: a research report, a doc.
|
|
288
|
-
It also draws a phone layout, `chart.phone.png
|
|
429
|
+
It also draws a phone layout, `chart.phone.png`, as do `estimates`, `heatmap` and `bars` with a `ref` in either style. Leave it out for the default dark figure for a dark chat.
|
|
289
430
|
- Keep `note` to what is measured, and "lower is better" where it applies; dates and method go in `source`.
|
|
290
431
|
- `unit` is printed straight after each number. `show` on an item replaces its printed value, e.g. `"11 of 29"`.
|
|
291
432
|
- `tone` is `accent` for what to notice, `good` or `bad` when it is a result; at most two tones in a chart. Leave the rest grey.
|
|
@@ -308,8 +449,8 @@ things happen in is the point, use `sequence`.
|
|
|
308
449
|
|
|
309
450
|
- In the `<h1>`, `<em>` turns the words accent-coloured italic and `<br>` sets a line break.
|
|
310
451
|
- `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.
|
|
311
|
-
- `fig detail` is 1360 wide, for a flow
|
|
312
|
-
several `fig` figures instead (see Explaining a system). At most 18 boxes, 18 arrows and 190 words.
|
|
452
|
+
- `fig detail` is 1360 wide, for a flow the reader asked for and opens full screen; to explain a system, use
|
|
453
|
+
several `fig` figures or a `map` spec instead (see Explaining a system). At most 18 boxes, 18 arrows and 190 words.
|
|
313
454
|
Widen it with `style="--w: 1560px"` only when a row will not fit.
|
|
314
455
|
- Height follows the content. There is no fixed canvas to fill.
|
|
315
456
|
- Text must be at least 15px; the theme's sizes all pass. The phone line the command prints is information, and only the problems list needs fixing.
|
|
@@ -418,8 +559,8 @@ A few numbers compared:
|
|
|
418
559
|
```
|
|
419
560
|
|
|
420
561
|
Grouped bars, several lines, small multiples and heat maps have specs (`groups`, `lines`, `panels`, `heatmap`); use
|
|
421
|
-
them when the chart is the whole figure. Dots, ranges, scatters and small counts have specs too
|
|
422
|
-
(`dots`, `scatter`, ranges on `bars` and `series`, `units`). Anything else (a distribution of thousands, a chart beside boxes) is
|
|
562
|
+
them when the chart is the whole figure. Dots, ranges, signed estimates, scatters and small counts have specs too
|
|
563
|
+
(`dots`, `estimates`, `scatter`, ranges on `bars` and `series`, `units`). Anything else (a distribution of thousands, a chart beside boxes) is
|
|
423
564
|
Observable Plot, already loaded with d3:
|
|
424
565
|
|
|
425
566
|
```html
|
|
@@ -452,7 +593,8 @@ notice in `accent`, and label it directly on the chart; no legends. Start bar ax
|
|
|
452
593
|
|
|
453
594
|
## What the checks catch, and what they cannot
|
|
454
595
|
|
|
455
|
-
Measured in the rendered page: text past its box or the frame, text too small,
|
|
596
|
+
Measured in the rendered page: text past its box or the frame, text too small, text too faint against what is drawn
|
|
597
|
+
behind it (a contrast under 3 to 1), boxes and labels that overlap, arrows
|
|
456
598
|
through boxes, arrows crossing, edges that almost line up, too many words, boxes, arrows or colours, facts strung
|
|
457
599
|
together with separators, a missing or long title.
|
|
458
600
|
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Third-party notices
|
|
2
2
|
|
|
3
|
-
`dist/viz.iife.js` bundles Observable Plot and the d3 modules it uses. Their licences follow. The fonts (Newsreader, Geist Sans, Geist Mono, under the SIL Open Font License 1.1), Playwright (Apache-2.0), d3 (ISC) and Zod (MIT) are installed as ordinary dependencies and are not copied into this package.
|
|
3
|
+
`dist/viz.iife.js` bundles Observable Plot and the d3 modules it uses, and dagre with its graphlib for laying out maps. Their licences follow. The fonts (Newsreader, Geist Sans, Geist Mono, under the SIL Open Font License 1.1), Playwright (Apache-2.0), d3 (ISC) and Zod (MIT) are installed as ordinary dependencies and are not copied into this package.
|
|
4
4
|
|
|
5
5
|
## @observablehq/plot
|
|
6
6
|
|
|
@@ -630,3 +630,50 @@ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
|
630
630
|
THIS SOFTWARE.
|
|
631
631
|
```
|
|
632
632
|
|
|
633
|
+
## @dagrejs/dagre
|
|
634
|
+
|
|
635
|
+
```
|
|
636
|
+
Copyright (c) 2012-2014 Chris Pettitt
|
|
637
|
+
|
|
638
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
639
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
640
|
+
in the Software without restriction, including without limitation the rights
|
|
641
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
642
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
643
|
+
furnished to do so, subject to the following conditions:
|
|
644
|
+
|
|
645
|
+
The above copyright notice and this permission notice shall be included in
|
|
646
|
+
all copies or substantial portions of the Software.
|
|
647
|
+
|
|
648
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
649
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
650
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
651
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
652
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
653
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
654
|
+
THE SOFTWARE.
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
## @dagrejs/graphlib
|
|
658
|
+
|
|
659
|
+
```
|
|
660
|
+
Copyright (c) 2012-2014 Chris Pettitt
|
|
661
|
+
|
|
662
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
663
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
664
|
+
in the Software without restriction, including without limitation the rights
|
|
665
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
666
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
667
|
+
furnished to do so, subject to the following conditions:
|
|
668
|
+
|
|
669
|
+
The above copyright notice and this permission notice shall be included in
|
|
670
|
+
all copies or substantial portions of the Software.
|
|
671
|
+
|
|
672
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
673
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
674
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
675
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
676
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
677
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
678
|
+
THE SOFTWARE.
|
|
679
|
+
```
|
package/bin/fig.mjs
CHANGED
|
@@ -46,7 +46,7 @@ if (/\.json$/i.test(src)) {
|
|
|
46
46
|
console.log(`This chart spec has ${spec.problems.length} problem${spec.problems.length === 1 ? '' : 's'}:\n${spec.problems.map((p) => ` - ${p}`).join('\n')}`);
|
|
47
47
|
process.exit(1);
|
|
48
48
|
}
|
|
49
|
-
const cls = [spec.spec.type === 'entities' ? 'entities-fig' : spec.spec.type === 'sequence' ? 'sequence-fig' : 'chart', spec.spec.type === 'panels' ? 'panels-fig' : '', spec.spec.style ?? ''].filter(Boolean).join(' ');
|
|
49
|
+
const cls = [spec.spec.type === 'entities' ? 'entities-fig' : spec.spec.type === 'sequence' ? 'sequence-fig' : spec.spec.type === 'states' ? 'states-fig' : spec.spec.type === 'map' ? 'detail map-fig' : 'chart', spec.spec.type === 'panels' ? 'panels-fig' : '', spec.spec.style ?? ''].filter(Boolean).join(' ');
|
|
50
50
|
body = `<main class="fig ${cls}"><script type="application/json" id="figkit-spec">${JSON.stringify(spec.spec).replace(/</g, '\\u003c')}</script></main>`;
|
|
51
51
|
} else if (!/class="[^"]*\bfig\b/.test(body)) body = `<main class="fig">\n${body}\n</main>`;
|
|
52
52
|
await ensureBuilt();
|
|
@@ -101,7 +101,7 @@ try {
|
|
|
101
101
|
if (phone) await page.addInitScript(() => { window.__figPhone = true; });
|
|
102
102
|
await page.goto(pathToFileURL(wrapped).href);
|
|
103
103
|
await page.waitForFunction('window.__figDone === true', null, { timeout: 30000 });
|
|
104
|
-
const r = await page.evaluate(() => ({ problems: window.fig.problems, info: window.fig.info, sides: !!document.querySelector('.fig .sides, .fig .entities, .fig .sequence, .fig .panels, .fig.report'), entities: !!document.querySelector('.fig .entities'), sequence: !!document.querySelector('.fig .sequence'), panels: !!document.querySelector('.fig .panels'), stack: !!document.querySelector('.fig .sides') }));
|
|
104
|
+
const r = await page.evaluate(() => ({ problems: window.fig.problems, notes: window.fig.notes ?? [], info: window.fig.info, sides: !!document.querySelector('.fig .sides, .fig .map, .fig .entities, .fig .sequence, .fig .states, .fig .panels, .fig .estimates, .fig .heatmap, .fig fig-bars.has-ref, .fig.report'), states: !!document.querySelector('.fig .states'), entities: !!document.querySelector('.fig .entities'), sequence: !!document.querySelector('.fig .sequence'), panels: !!document.querySelector('.fig .panels'), map: !!document.querySelector('.fig .map'), stack: !!document.querySelector('.fig .sides') }));
|
|
105
105
|
await page.locator('.fig').first().screenshot({ path: shot });
|
|
106
106
|
await page.close();
|
|
107
107
|
return { ...r, problems: [...errors.map((e) => `Script error: ${e}`), ...r.problems] };
|
|
@@ -116,12 +116,14 @@ try {
|
|
|
116
116
|
|
|
117
117
|
const { info } = desk;
|
|
118
118
|
const lines = [`Figure: ${png} (${info.width * 2}×${info.height * 2})`];
|
|
119
|
-
if (mob) lines.push(`Phone layout: ${phonePng} (${mob.info.width * 2}×${mob.info.height * 2}), ${desk.entities ? 'the records in two columns' : desk.sequence ? 'the participants narrower' : desk.panels ? 'the panels stacked' : desk.stack ? 'the sides stacked' : 'at phone width'}, for a viewer to show on a phone`);
|
|
119
|
+
if (mob) lines.push(`Phone layout: ${phonePng} (${mob.info.width * 2}×${mob.info.height * 2}), ${desk.map ? 'each subsystem as one box' : desk.entities ? 'the records in two columns' : desk.sequence ? 'the participants narrower' : desk.states ? 'the states narrower' : desk.panels ? 'the panels stacked' : desk.stack ? 'the sides stacked' : 'at phone width'}, for a viewer to show on a phone`);
|
|
120
120
|
lines.push(`Phone inline: ${inline} (preview only)`);
|
|
121
121
|
const ph = (mob ?? desk).info.phone;
|
|
122
122
|
const sizes = [['the title', ph?.title], ['headings', ph?.heading], ['body', ph?.body]].filter(([, v]) => v != null).map(([k, v]) => `${k} ${v}px`);
|
|
123
123
|
if (sizes.length) lines.push(`Inline on a phone: ${sizes.join(', ')}; under about 6px only reads after a tap to zoom.`);
|
|
124
124
|
if (!mob && info.unmarked) lines.push('Its columns sit side by side and will shrink on a phone. If they are two sides to compare, add class "sides" to the row or grid that holds them, and a stacked phone layout is drawn too.');
|
|
125
|
+
for (const n of desk.notes) lines.push(`Note: ${n}`);
|
|
126
|
+
for (const n of mob?.notes ?? []) lines.push(`Phone layout note: ${n}`);
|
|
125
127
|
const all = [...desk.problems, ...(mob?.problems ?? []).map((p) => `Phone layout: ${p}`)];
|
|
126
128
|
lines.push(all.length ? `\n${all.length} problem${all.length === 1 ? '' : 's'}:` : '\nNo problems found by the checks.');
|
|
127
129
|
for (const p of all) lines.push(` - ${p}`);
|