@liggi/figkit 0.2.0 → 0.3.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 +62 -3
- package/README.md +3 -2
- package/bin/fig.mjs +14 -6
- package/dist/viz.iife.js +12 -12
- package/examples/charts/groups.json +40 -0
- package/examples/charts/heatmap.json +231 -0
- package/examples/charts/lines.json +234 -0
- package/examples/charts/panels.json +62 -0
- package/package.json +1 -1
- package/runtime/fig.css +36 -4
- package/runtime/fig.js +10 -2
- package/viz/draw.js +165 -4
- package/viz/spec.js +121 -2
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "groups",
|
|
3
|
+
"style": "report",
|
|
4
|
+
"title": "Only the new carrier got slower in December",
|
|
5
|
+
"note": "Median days from dispatch to doorstep",
|
|
6
|
+
"unit": " days",
|
|
7
|
+
"series": [
|
|
8
|
+
"Old carrier",
|
|
9
|
+
"New carrier"
|
|
10
|
+
],
|
|
11
|
+
"groups": [
|
|
12
|
+
{
|
|
13
|
+
"label": "October",
|
|
14
|
+
"values": [
|
|
15
|
+
2.1,
|
|
16
|
+
2.0
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"label": "November",
|
|
21
|
+
"values": [
|
|
22
|
+
2.2,
|
|
23
|
+
2.1
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"label": "December",
|
|
28
|
+
"values": [
|
|
29
|
+
2.4,
|
|
30
|
+
3.6
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"accent": {
|
|
35
|
+
"series": "New carrier",
|
|
36
|
+
"group": "December",
|
|
37
|
+
"tone": "bad"
|
|
38
|
+
},
|
|
39
|
+
"source": "Invented example data"
|
|
40
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "heatmap",
|
|
3
|
+
"style": "report",
|
|
4
|
+
"title": "The help desk is busiest midweek mornings",
|
|
5
|
+
"note": "Tickets opened per hour",
|
|
6
|
+
"rows": [
|
|
7
|
+
"Mon",
|
|
8
|
+
"Tue",
|
|
9
|
+
"Wed",
|
|
10
|
+
"Thu",
|
|
11
|
+
"Fri",
|
|
12
|
+
"Sat",
|
|
13
|
+
"Sun"
|
|
14
|
+
],
|
|
15
|
+
"columns": [
|
|
16
|
+
"12am",
|
|
17
|
+
"1am",
|
|
18
|
+
"2am",
|
|
19
|
+
"3am",
|
|
20
|
+
"4am",
|
|
21
|
+
"5am",
|
|
22
|
+
"6am",
|
|
23
|
+
"7am",
|
|
24
|
+
"8am",
|
|
25
|
+
"9am",
|
|
26
|
+
"10am",
|
|
27
|
+
"11am",
|
|
28
|
+
"12pm",
|
|
29
|
+
"1pm",
|
|
30
|
+
"2pm",
|
|
31
|
+
"3pm",
|
|
32
|
+
"4pm",
|
|
33
|
+
"5pm",
|
|
34
|
+
"6pm",
|
|
35
|
+
"7pm",
|
|
36
|
+
"8pm",
|
|
37
|
+
"9pm",
|
|
38
|
+
"10pm",
|
|
39
|
+
"11pm"
|
|
40
|
+
],
|
|
41
|
+
"values": [
|
|
42
|
+
[
|
|
43
|
+
3,
|
|
44
|
+
2,
|
|
45
|
+
1,
|
|
46
|
+
1,
|
|
47
|
+
1,
|
|
48
|
+
2,
|
|
49
|
+
6,
|
|
50
|
+
14,
|
|
51
|
+
22,
|
|
52
|
+
25,
|
|
53
|
+
27,
|
|
54
|
+
28,
|
|
55
|
+
30,
|
|
56
|
+
29,
|
|
57
|
+
28,
|
|
58
|
+
27,
|
|
59
|
+
26,
|
|
60
|
+
24,
|
|
61
|
+
20,
|
|
62
|
+
16,
|
|
63
|
+
12,
|
|
64
|
+
9,
|
|
65
|
+
6,
|
|
66
|
+
4
|
|
67
|
+
],
|
|
68
|
+
[
|
|
69
|
+
3,
|
|
70
|
+
2,
|
|
71
|
+
1,
|
|
72
|
+
1,
|
|
73
|
+
1,
|
|
74
|
+
2,
|
|
75
|
+
6,
|
|
76
|
+
15,
|
|
77
|
+
23,
|
|
78
|
+
26,
|
|
79
|
+
28,
|
|
80
|
+
29,
|
|
81
|
+
32,
|
|
82
|
+
30,
|
|
83
|
+
29,
|
|
84
|
+
28,
|
|
85
|
+
27,
|
|
86
|
+
25,
|
|
87
|
+
21,
|
|
88
|
+
17,
|
|
89
|
+
13,
|
|
90
|
+
9,
|
|
91
|
+
6,
|
|
92
|
+
4
|
|
93
|
+
],
|
|
94
|
+
[
|
|
95
|
+
3,
|
|
96
|
+
2,
|
|
97
|
+
1,
|
|
98
|
+
1,
|
|
99
|
+
1,
|
|
100
|
+
2,
|
|
101
|
+
6,
|
|
102
|
+
15,
|
|
103
|
+
24,
|
|
104
|
+
27,
|
|
105
|
+
29,
|
|
106
|
+
30,
|
|
107
|
+
32,
|
|
108
|
+
31,
|
|
109
|
+
30,
|
|
110
|
+
29,
|
|
111
|
+
28,
|
|
112
|
+
26,
|
|
113
|
+
22,
|
|
114
|
+
17,
|
|
115
|
+
13,
|
|
116
|
+
10,
|
|
117
|
+
6,
|
|
118
|
+
4
|
|
119
|
+
],
|
|
120
|
+
[
|
|
121
|
+
3,
|
|
122
|
+
2,
|
|
123
|
+
1,
|
|
124
|
+
1,
|
|
125
|
+
1,
|
|
126
|
+
2,
|
|
127
|
+
6,
|
|
128
|
+
14,
|
|
129
|
+
22,
|
|
130
|
+
26,
|
|
131
|
+
28,
|
|
132
|
+
29,
|
|
133
|
+
31,
|
|
134
|
+
30,
|
|
135
|
+
29,
|
|
136
|
+
28,
|
|
137
|
+
27,
|
|
138
|
+
24,
|
|
139
|
+
20,
|
|
140
|
+
16,
|
|
141
|
+
12,
|
|
142
|
+
9,
|
|
143
|
+
6,
|
|
144
|
+
4
|
|
145
|
+
],
|
|
146
|
+
[
|
|
147
|
+
3,
|
|
148
|
+
2,
|
|
149
|
+
1,
|
|
150
|
+
1,
|
|
151
|
+
1,
|
|
152
|
+
2,
|
|
153
|
+
5,
|
|
154
|
+
13,
|
|
155
|
+
20,
|
|
156
|
+
22,
|
|
157
|
+
24,
|
|
158
|
+
25,
|
|
159
|
+
27,
|
|
160
|
+
26,
|
|
161
|
+
25,
|
|
162
|
+
24,
|
|
163
|
+
23,
|
|
164
|
+
22,
|
|
165
|
+
18,
|
|
166
|
+
14,
|
|
167
|
+
11,
|
|
168
|
+
8,
|
|
169
|
+
5,
|
|
170
|
+
4
|
|
171
|
+
],
|
|
172
|
+
[
|
|
173
|
+
2,
|
|
174
|
+
1,
|
|
175
|
+
1,
|
|
176
|
+
1,
|
|
177
|
+
1,
|
|
178
|
+
1,
|
|
179
|
+
4,
|
|
180
|
+
8,
|
|
181
|
+
13,
|
|
182
|
+
15,
|
|
183
|
+
16,
|
|
184
|
+
17,
|
|
185
|
+
18,
|
|
186
|
+
17,
|
|
187
|
+
17,
|
|
188
|
+
16,
|
|
189
|
+
16,
|
|
190
|
+
14,
|
|
191
|
+
12,
|
|
192
|
+
10,
|
|
193
|
+
7,
|
|
194
|
+
5,
|
|
195
|
+
4,
|
|
196
|
+
2
|
|
197
|
+
],
|
|
198
|
+
[
|
|
199
|
+
2,
|
|
200
|
+
1,
|
|
201
|
+
1,
|
|
202
|
+
1,
|
|
203
|
+
1,
|
|
204
|
+
1,
|
|
205
|
+
3,
|
|
206
|
+
8,
|
|
207
|
+
12,
|
|
208
|
+
14,
|
|
209
|
+
15,
|
|
210
|
+
15,
|
|
211
|
+
16,
|
|
212
|
+
16,
|
|
213
|
+
15,
|
|
214
|
+
15,
|
|
215
|
+
14,
|
|
216
|
+
13,
|
|
217
|
+
11,
|
|
218
|
+
9,
|
|
219
|
+
7,
|
|
220
|
+
5,
|
|
221
|
+
3,
|
|
222
|
+
2
|
|
223
|
+
]
|
|
224
|
+
],
|
|
225
|
+
"mark": {
|
|
226
|
+
"row": "Wed",
|
|
227
|
+
"column": "12pm",
|
|
228
|
+
"label": "Busiest: Wed noon"
|
|
229
|
+
},
|
|
230
|
+
"source": "Invented example data"
|
|
231
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "lines",
|
|
3
|
+
"style": "report",
|
|
4
|
+
"title": "Weekday orders peak at noon",
|
|
5
|
+
"note": "Orders per hour",
|
|
6
|
+
"series": [
|
|
7
|
+
{
|
|
8
|
+
"label": "Weekdays",
|
|
9
|
+
"points": [
|
|
10
|
+
{
|
|
11
|
+
"x": 0,
|
|
12
|
+
"y": 3
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"x": 1,
|
|
16
|
+
"y": 2
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"x": 2,
|
|
20
|
+
"y": 1
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"x": 3,
|
|
24
|
+
"y": 1
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"x": 4,
|
|
28
|
+
"y": 1
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"x": 5,
|
|
32
|
+
"y": 2
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"x": 6,
|
|
36
|
+
"y": 6
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"x": 7,
|
|
40
|
+
"y": 14
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"x": 8,
|
|
44
|
+
"y": 22
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"x": 9,
|
|
48
|
+
"y": 25
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"x": 10,
|
|
52
|
+
"y": 27
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"x": 11,
|
|
56
|
+
"y": 28
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"x": 12,
|
|
60
|
+
"y": 30
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"x": 13,
|
|
64
|
+
"y": 29
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"x": 14,
|
|
68
|
+
"y": 28
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"x": 15,
|
|
72
|
+
"y": 27
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"x": 16,
|
|
76
|
+
"y": 26
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"x": 17,
|
|
80
|
+
"y": 24
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"x": 18,
|
|
84
|
+
"y": 20
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"x": 19,
|
|
88
|
+
"y": 16
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"x": 20,
|
|
92
|
+
"y": 12
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"x": 21,
|
|
96
|
+
"y": 9
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"x": 22,
|
|
100
|
+
"y": 6
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"x": 23,
|
|
104
|
+
"y": 4
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"label": "Weekends",
|
|
110
|
+
"points": [
|
|
111
|
+
{
|
|
112
|
+
"x": 0,
|
|
113
|
+
"y": 4
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"x": 1,
|
|
117
|
+
"y": 3
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"x": 2,
|
|
121
|
+
"y": 2
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"x": 3,
|
|
125
|
+
"y": 1
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"x": 4,
|
|
129
|
+
"y": 1
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"x": 5,
|
|
133
|
+
"y": 1
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"x": 6,
|
|
137
|
+
"y": 2
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"x": 7,
|
|
141
|
+
"y": 4
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"x": 8,
|
|
145
|
+
"y": 8
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"x": 9,
|
|
149
|
+
"y": 13
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"x": 10,
|
|
153
|
+
"y": 17
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"x": 11,
|
|
157
|
+
"y": 20
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"x": 12,
|
|
161
|
+
"y": 22
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"x": 13,
|
|
165
|
+
"y": 22
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"x": 14,
|
|
169
|
+
"y": 21
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"x": 15,
|
|
173
|
+
"y": 20
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"x": 16,
|
|
177
|
+
"y": 19
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"x": 17,
|
|
181
|
+
"y": 18
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"x": 18,
|
|
185
|
+
"y": 17
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"x": 19,
|
|
189
|
+
"y": 15
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"x": 20,
|
|
193
|
+
"y": 13
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"x": 21,
|
|
197
|
+
"y": 10
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"x": 22,
|
|
201
|
+
"y": 8
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"x": 23,
|
|
205
|
+
"y": 6
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
],
|
|
210
|
+
"accent": "Weekdays",
|
|
211
|
+
"mark": {
|
|
212
|
+
"x": 12,
|
|
213
|
+
"label": "30 at noon"
|
|
214
|
+
},
|
|
215
|
+
"xTicks": [
|
|
216
|
+
{
|
|
217
|
+
"x": 0,
|
|
218
|
+
"label": "12am"
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"x": 6,
|
|
222
|
+
"label": "6am"
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"x": 12,
|
|
226
|
+
"label": "12pm"
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"x": 18,
|
|
230
|
+
"label": "6pm"
|
|
231
|
+
}
|
|
232
|
+
],
|
|
233
|
+
"source": "Invented example data"
|
|
234
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "panels",
|
|
3
|
+
"style": "report",
|
|
4
|
+
"chart": "groups",
|
|
5
|
+
"title": "The cheaper plan answers almost as fast as the premium one",
|
|
6
|
+
"note": "Share of tickets answered within an hour",
|
|
7
|
+
"unit": "%",
|
|
8
|
+
"max": 100,
|
|
9
|
+
"series": [
|
|
10
|
+
"Basic",
|
|
11
|
+
"Standard",
|
|
12
|
+
"Premium"
|
|
13
|
+
],
|
|
14
|
+
"accent": {
|
|
15
|
+
"series": "Standard"
|
|
16
|
+
},
|
|
17
|
+
"panels": [
|
|
18
|
+
{
|
|
19
|
+
"label": "Email",
|
|
20
|
+
"groups": [
|
|
21
|
+
{
|
|
22
|
+
"label": "Weekdays",
|
|
23
|
+
"values": [
|
|
24
|
+
61,
|
|
25
|
+
84,
|
|
26
|
+
89
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"label": "Weekends",
|
|
31
|
+
"values": [
|
|
32
|
+
38,
|
|
33
|
+
70,
|
|
34
|
+
74
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"label": "Chat",
|
|
41
|
+
"groups": [
|
|
42
|
+
{
|
|
43
|
+
"label": "Weekdays",
|
|
44
|
+
"values": [
|
|
45
|
+
72,
|
|
46
|
+
91,
|
|
47
|
+
94
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"label": "Weekends",
|
|
52
|
+
"values": [
|
|
53
|
+
55,
|
|
54
|
+
83,
|
|
55
|
+
86
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"source": "Invented example data"
|
|
62
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liggi/figkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Explanatory figures for agents and people: write a little HTML or a chart spec, get a laid-out PNG and a list of what is wrong with it.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/runtime/fig.css
CHANGED
|
@@ -8,6 +8,8 @@ html, body { margin: 0; padding: 0; background: transparent; }
|
|
|
8
8
|
--paper: #2d3142; --panel: #252938; --ink: #f5f5f5; --muted: #c3c6cf; --soft: #949eb2; --line: #8d95ad; --hair: rgba(245,245,245,.16);
|
|
9
9
|
--accent: #f08a59; --second: #739fdf; --good: #6fc392; --bad: #ef6b73;
|
|
10
10
|
--on-fill: #1d2030;
|
|
11
|
+
/* grey marks: the ones not to notice; fill2 a darker grey for a second series */
|
|
12
|
+
--fill: var(--soft); --fill2: var(--line);
|
|
11
13
|
--sans: 'Geist Sans', 'Geist', system-ui, sans-serif;
|
|
12
14
|
--serif: 'Newsreader', Georgia, serif;
|
|
13
15
|
--mono: 'Geist Mono', ui-monospace, monospace;
|
|
@@ -135,7 +137,7 @@ fig-arrow { display: none; }
|
|
|
135
137
|
/* ---------- split bar: parts of a whole ---------- */
|
|
136
138
|
fig-split { display: flex; flex-direction: column; gap: 10px; }
|
|
137
139
|
fig-split .fs-bar { display: flex; gap: 3px; height: 58px; }
|
|
138
|
-
fig-split .fs-seg { --tone: var(--
|
|
140
|
+
fig-split .fs-seg { --tone: var(--fill); background: var(--tone); color: var(--on-fill); min-width: 4px; display: flex; align-items: center; gap: 10px; padding: 0 14px; overflow: hidden; white-space: nowrap; }
|
|
139
141
|
fig-split .fs-seg:first-child { border-radius: 8px 0 0 8px; } fig-split .fs-seg:last-child { border-radius: 0 8px 8px 0; }
|
|
140
142
|
fig-split .fs-seg.fs-out { padding: 0; }
|
|
141
143
|
fig-split .fs-seg.fs-out > * { display: none; }
|
|
@@ -151,7 +153,7 @@ fig-change { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0,
|
|
|
151
153
|
fig-change .fc-side { display: flex; flex-direction: column; gap: 10px; }
|
|
152
154
|
fig-change .fc-when { font-size: var(--small); font-weight: 600; color: var(--muted); }
|
|
153
155
|
fig-change .fc-num { font-family: var(--serif); font-weight: 400; font-size: calc(var(--num) * 1.5); line-height: 1; letter-spacing: -.01em; color: var(--ink); }
|
|
154
|
-
fig-change .fc-bar { height: 14px; min-width: 3px; background: var(--
|
|
156
|
+
fig-change .fc-bar { height: 14px; min-width: 3px; background: var(--fill); border-radius: 3px; }
|
|
155
157
|
fig-change .before .fc-num { color: var(--muted); }
|
|
156
158
|
fig-change .after .fc-num { color: var(--tone); }
|
|
157
159
|
fig-change .after .fc-bar { background: var(--tone); }
|
|
@@ -161,7 +163,7 @@ fig-change .fc-arrow { color: var(--soft); display: flex; }
|
|
|
161
163
|
fig-bars { display: grid; grid-template-columns: max-content minmax(0, 1fr); column-gap: 16px; row-gap: 10px; align-items: center; }
|
|
162
164
|
fig-bars .fb-label { font-size: var(--body); }
|
|
163
165
|
fig-bars .fb-track { display: flex; align-items: center; gap: 10px; min-width: 0; }
|
|
164
|
-
fig-bars .fb-bar { --tone: var(--
|
|
166
|
+
fig-bars .fb-bar { --tone: var(--fill); height: 26px; background: var(--tone); border-radius: 3px; min-width: 3px; flex: 0 0 auto; }
|
|
165
167
|
fig-bars .fb-val { font-family: var(--serif); font-size: 1.3em; font-weight: 400; font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
166
168
|
fig-bars .fb-val.lead { color: var(--tone); }
|
|
167
169
|
fig-bars .fb-sub { font-weight: 400; color: var(--soft); font-size: var(--small); margin-left: 6px; }
|
|
@@ -170,7 +172,7 @@ fig-bars .fb-sub { font-weight: 400; color: var(--soft); font-size: var(--small)
|
|
|
170
172
|
.fig .chart { min-width: 0; }
|
|
171
173
|
.fig .fd-key { display: flex; gap: 28px; margin: 0 0 18px; font-size: var(--small); font-weight: 600; color: var(--soft); }
|
|
172
174
|
.fig .fd-key span { display: inline-flex; align-items: center; gap: 8px; }
|
|
173
|
-
.fig .fd-key i { display: inline-block; width: 13px; height: 13px; border-radius: 50%; background: var(--
|
|
175
|
+
.fig .fd-key i { display: inline-block; width: 13px; height: 13px; border-radius: 50%; background: var(--fill); }
|
|
174
176
|
.fig .fd-key .fd-to i { width: 0; height: 0; border-radius: 0; background: none; border-left: 13px solid currentColor; border-top: 7.5px solid transparent; border-bottom: 7.5px solid transparent; }
|
|
175
177
|
.fig .fd-key .fd-to.back i { transform: scaleX(-1); }
|
|
176
178
|
.fig.chart > footer { border-top: 0; padding-top: 0; }
|
|
@@ -186,3 +188,33 @@ fig-bars .fb-sub { font-weight: 400; color: var(--soft); font-size: var(--small)
|
|
|
186
188
|
.fig .t-second.t-second { color: var(--second); }
|
|
187
189
|
.fig .t-good.t-good { color: var(--good); } .fig .t-bad.t-bad { color: var(--bad); }
|
|
188
190
|
.fig .decision:not(.accent):not(.second):not(.good):not(.bad) { --tone: var(--line); }
|
|
191
|
+
|
|
192
|
+
/* ---------- report: a light chart that sits in a page (a research report, a doc), set in one sans ---------- */
|
|
193
|
+
.fig.report {
|
|
194
|
+
--paper: #ffffff; --panel: #ffffff; --ink: #1d2130; --muted: #5b6170; --soft: #7a8092; --line: #9aa0ad; --hair: rgba(29,33,48,.12);
|
|
195
|
+
--fill: #b4b8c2; --fill2: #7d8391;
|
|
196
|
+
--accent: #cf5a23; --second: #2f6bc4; --good: #2f8f5b; --bad: #c9414a; --on-fill: #ffffff;
|
|
197
|
+
--serif: var(--sans);
|
|
198
|
+
--w: 720px; --pad: 32px; --gap: 14px;
|
|
199
|
+
--title: 26px; --read: 18px; --h: 18px; --body: 17px; --small: 16px; --num: 30px;
|
|
200
|
+
border: 1px solid #e6e2d8; border-radius: 10px; gap: 20px;
|
|
201
|
+
}
|
|
202
|
+
.fig.panels-fig { --w: 1000px; }
|
|
203
|
+
.fig.panels-fig.phone { --w: 560px; }
|
|
204
|
+
.fig.report h1 { font-weight: 600; letter-spacing: -.01em; line-height: 1.2; }
|
|
205
|
+
.fig.report > header { gap: 6px; }
|
|
206
|
+
.fig.report > footer { border-top: 0; padding-top: 0; }
|
|
207
|
+
.fig.report.phone { --w: 400px; --pad: 20px; --title: 22px; --read: 16px; --body: 16px; --small: 15px; }
|
|
208
|
+
.fig.report fig-bars .fb-val, .fig.report fig-split .fs-seg b, .fig.report fig-change .fc-num { font-weight: 500; letter-spacing: 0; }
|
|
209
|
+
.fig.report fig-bars .fb-val { font-size: 1.05em; }
|
|
210
|
+
.fig.report fig-bars .fb-val.lead { font-weight: 600; }
|
|
211
|
+
|
|
212
|
+
/* panels: the same chart drawn for each part, side by side, one above the other on a phone */
|
|
213
|
+
.fig .panels { display: grid; grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr)); column-gap: 36px; row-gap: 28px; }
|
|
214
|
+
.fig.phone .panels { grid-template-columns: minmax(0, 1fr); }
|
|
215
|
+
.fig .panel > h2 { font-size: calc(var(--h) * 1.15); margin: 0 0 4px; }
|
|
216
|
+
|
|
217
|
+
/* heat map scale: what the colour means, at readable size */
|
|
218
|
+
.fig .hm-key { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; font-size: var(--small); color: var(--muted); margin: 0 0 12px; }
|
|
219
|
+
.fig .hm-key i { display: inline-block; width: 160px; height: 14px; border-radius: 3px; }
|
|
220
|
+
.fig.phone .hm-key i { width: 84px; }
|
package/runtime/fig.js
CHANGED
|
@@ -544,7 +544,7 @@
|
|
|
544
544
|
if (!el) { fig.problems.push(`fig.plot: nothing matches ${target}.`); return; }
|
|
545
545
|
el.classList.add('chart');
|
|
546
546
|
const width = Math.floor(el.clientWidth) || 640;
|
|
547
|
-
const t = { ink: css('--ink'), muted: css('--muted'), soft: css('--soft'), line: css('--line'), hair: css('--hair'), accent: css('--accent'), second: css('--second'), good: css('--good'), bad: css('--bad'), paper: css('--paper'), panel: css('--panel') };
|
|
547
|
+
const t = { ink: css('--ink'), muted: css('--muted'), soft: css('--soft'), fill: css('--fill'), fill2: css('--fill2'), line: css('--line'), hair: css('--hair'), accent: css('--accent'), second: css('--second'), good: css('--good'), bad: css('--bad'), paper: css('--paper'), panel: css('--panel') };
|
|
548
548
|
try {
|
|
549
549
|
const opts = build({ Plot: window.Plot, d3: window.d3, width, theme: t });
|
|
550
550
|
const size = parseFloat(css('--small')) || 15;
|
|
@@ -635,7 +635,10 @@
|
|
|
635
635
|
if (near.length) P.push(`Almost aligned but not quite: ${near.slice(0, 6).join('; ')}${near.length > 6 ? `; and ${near.length - 6} more` : ''}. Put them in one row, column or grid so they share the edge.`);
|
|
636
636
|
|
|
637
637
|
// Too much on the page.
|
|
638
|
-
|
|
638
|
+
// Panels repeat the same labels in each panel; a label read once counts once.
|
|
639
|
+
const panelText = R.querySelector('.panels') ? [...new Set([...R.querySelectorAll('.panels text, .panels h2')].map((e) => e.textContent.trim()))].join(' ') : null;
|
|
640
|
+
const outside = R.querySelector('.panels') ? [...R.children].filter((c) => !c.matches('script, style') && !c.querySelector('.panels') && !c.matches('.panels')).map((c) => c.innerText).join(' ') : null;
|
|
641
|
+
const words = (panelText !== null ? outside + ' ' + panelText : R.innerText).split(/\s+/).filter(Boolean).length;
|
|
639
642
|
const nodes = R.querySelectorAll('.node:not(.bare), .decision').length, arrows = (fig.wires ?? []).length;
|
|
640
643
|
const budget = detail ? { words: 190, nodes: 18, arrows: 18 } : { words: 70, nodes: 5, arrows: 8 };
|
|
641
644
|
if (words > budget.words) P.push(`${words} words; a ${detail ? 'detail' : 'glance'} figure holds about ${budget.words}. Cut sentences that explain, and keep labels.`);
|
|
@@ -644,6 +647,11 @@
|
|
|
644
647
|
const tones = TONES.filter((t) => R.querySelector(`.${t}, [${t}], .t-${t}`));
|
|
645
648
|
if (tones.length > 2) P.push(`${tones.length} colours carry meaning (${tones.join(', ')}); use one for what the reader must notice and at most one more.`);
|
|
646
649
|
for (const o of obs) if (o.text || o.el.matches('.node')) { const t = o.el.innerText ?? ''; if ((t.match(/ [·|•] /g) ?? []).length >= 1 && !o.el.querySelector('*')) P.push(`${name(o.el)} strings facts together with separators; give each fact its own line or cut one.`); }
|
|
650
|
+
// A face that never loaded draws in whatever the machine has, and every measurement above is of that fallback.
|
|
651
|
+
const faces = [...document.fonts];
|
|
652
|
+
const families = [...new Set(['--sans', '--serif'].map((v) => css(v).split(',')[0].replace(/["']/g, '').trim()))];
|
|
653
|
+
const missing = families.filter((f) => !faces.some((x) => x.family.replace(/["']/g, '') === f && x.status === 'loaded'));
|
|
654
|
+
if (missing.length) P.push(`figkit's fonts did not load (${missing.join(', ')}); the figure is drawn in fallback fonts. Reinstall figkit with its dependencies.`);
|
|
647
655
|
const h1 = R.querySelector('h1');
|
|
648
656
|
if (!h1) P.push('No <h1>: give the figure a title that states its point.');
|
|
649
657
|
else if (h1.innerText.split(/\s+/).length > 14) P.push('The title is over 14 words; state the point more shortly.');
|