@formicoidea/labre-framework-cynefin 0.42.0 → 0.43.1
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/dist/cynefin/crop.d.ts +6 -0
- package/dist/cynefin/crop.js +45 -0
- package/dist/cynefin/element-view.d.ts +30 -2
- package/dist/cynefin/element-view.js +42 -3
- package/dist/estuarine/consts.d.ts +95 -20
- package/dist/estuarine/consts.js +84 -28
- package/dist/estuarine/element-renderer.d.ts +7 -0
- package/dist/estuarine/element-renderer.js +45 -17
- package/dist/estuarine/labels.d.ts +3 -2
- package/dist/estuarine/labels.js +5 -4
- package/dist/presets.d.ts +13 -2
- package/dist/presets.js +13 -2
- package/dist/templates/index.js +16 -9
- package/dist/utils.d.ts +6 -8
- package/dist/utils.js +6 -7
- package/package.json +2 -2
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SerializedXYWH } from '@formicoidea/labre-core/global/gfx';
|
|
2
|
+
/**
|
|
3
|
+
* The frame of `xywh` brought back onto the drawing it letterboxes, or `null`
|
|
4
|
+
* when it is already on it.
|
|
5
|
+
*/
|
|
6
|
+
export declare function cynefinCroppedXYWH(xywh: SerializedXYWH): SerializedXYWH | null;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Bound } from '@formicoidea/labre-core/global/gfx';
|
|
2
|
+
import { refScale } from '../utils.js';
|
|
3
|
+
import { REF_H, REF_W } from './consts.js';
|
|
4
|
+
/**
|
|
5
|
+
* Cropping a Cynefin frame back onto its drawing, at the end of a resize.
|
|
6
|
+
*
|
|
7
|
+
* The diagram is a figurative reproduction of the official SVG, so it cannot be
|
|
8
|
+
* stretched: `element-renderer.ts` fits it uniformly and centres what is left
|
|
9
|
+
* over (`refScale`). Dragged off its 1080 × 777 proportion, the element
|
|
10
|
+
* therefore letterboxes — at 1600 × 600 there are FOUR HUNDRED model units of
|
|
11
|
+
* nothing either side of the picture. And a framework background is caught by
|
|
12
|
+
* its border and by nothing else
|
|
13
|
+
* (`model/src/elements/framework-background/hit-test.ts`, a band of `10 / zoom`
|
|
14
|
+
* around the `xywh`), so the frame the user has to aim at ends up hundreds of
|
|
15
|
+
* units away from anything drawn.
|
|
16
|
+
*
|
|
17
|
+
* The answer the PO chose (23/09/2026) is not to stretch the drawing and not to
|
|
18
|
+
* widen the hit test, but to bring the FRAME back to the picture when the user
|
|
19
|
+
* lets go of a resize handle. Nothing is deformed and nothing is truncated: the
|
|
20
|
+
* element simply stops claiming room it does not paint.
|
|
21
|
+
*
|
|
22
|
+
* Why it is safe under rotation: a uniform fit centres what it fits, so
|
|
23
|
+
* `ox + REF_W * s / 2 === w / 2`. The cropped box has the SAME CENTRE as the one
|
|
24
|
+
* it replaces, and a surface element rotates about its centre — so the drawing
|
|
25
|
+
* does not move, at any angle.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Below half a model unit there is nothing to see, and writing anyway would
|
|
29
|
+
* cost an undo entry for a gesture that changed nothing. It is also what makes
|
|
30
|
+
* the crop idempotent: a frame already cropped is left alone.
|
|
31
|
+
*/
|
|
32
|
+
const CROP_EPSILON = 0.5;
|
|
33
|
+
/**
|
|
34
|
+
* The frame of `xywh` brought back onto the drawing it letterboxes, or `null`
|
|
35
|
+
* when it is already on it.
|
|
36
|
+
*/
|
|
37
|
+
export function cynefinCroppedXYWH(xywh) {
|
|
38
|
+
const bound = Bound.deserialize(xywh);
|
|
39
|
+
if (!(bound.w > 0) || !(bound.h > 0))
|
|
40
|
+
return null;
|
|
41
|
+
const { s, ox, oy } = refScale(bound.w, bound.h, REF_W, REF_H);
|
|
42
|
+
if (ox < CROP_EPSILON && oy < CROP_EPSILON)
|
|
43
|
+
return null;
|
|
44
|
+
return new Bound(bound.x + ox, bound.y + oy, REF_W * s, REF_H * s).serialize();
|
|
45
|
+
}
|
|
@@ -17,7 +17,35 @@ export declare class CynefinView extends FrameworkBackgroundView<CynefinElementM
|
|
|
17
17
|
protected labelAt(lx: number, ly: number, w: number, h: number): EditableBackgroundLabel | null;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
* Resize gating
|
|
21
|
-
*
|
|
20
|
+
* Resize gating and, when the handle is let go, the crop.
|
|
21
|
+
*
|
|
22
|
+
* ## Gating
|
|
23
|
+
*
|
|
24
|
+
* The resize handles are hidden unless `model.resizeEnabled` is true (toggled
|
|
25
|
+
* from the toolbar). Moving / selecting stays available.
|
|
26
|
+
*
|
|
27
|
+
* ## The crop
|
|
28
|
+
*
|
|
29
|
+
* The diagram is a fixed drawing fitted uniformly into the element, so dragged
|
|
30
|
+
* off its proportion the element letterboxes: 400 model units of nothing either
|
|
31
|
+
* side at 1600 × 600. `onResizeEnd` brings the frame back onto the picture (see
|
|
32
|
+
* `./crop.ts`) — the drawing is neither deformed nor truncated, the element
|
|
33
|
+
* simply stops claiming room it does not paint.
|
|
34
|
+
*
|
|
35
|
+
* ## Why here, and why one undo step
|
|
36
|
+
*
|
|
37
|
+
* A resize STASHES `xywh` on the way in, writes the model on every move, and
|
|
38
|
+
* commits the stash in `onResizeEnd`, inside the manager's own
|
|
39
|
+
* `store.transact` (`std/gfx/interactivity/manager.ts`). Writing the cropped
|
|
40
|
+
* box BEFORE calling `default` therefore changes what is committed rather than
|
|
41
|
+
* adding a second write: the whole gesture stays one Yjs write, and one undo
|
|
42
|
+
* step. `captureSync` would do the opposite here — it would close the step and
|
|
43
|
+
* make the crop a second one.
|
|
44
|
+
*
|
|
45
|
+
* This seam is also what keeps the crop a GESTURE. A cascade watching `xywh`
|
|
46
|
+
* would fire on a peer's resize too and re-crop, on every screen, a frame
|
|
47
|
+
* nobody on that screen touched; and it would fire on a document being loaded.
|
|
48
|
+
* The readonly guard is belt and braces — `handleElementResize` already refuses
|
|
49
|
+
* to start in a readonly store — but it is the invariant, so it is stated.
|
|
22
50
|
*/
|
|
23
51
|
export declare const CynefinInteraction: import("@formicoidea/labre-core/store").ExtensionType;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FrameworkBackgroundView, hitTestBackgroundLabel, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import { translateKey, } from '@formicoidea/labre-core/shared/services';
|
|
3
3
|
import { GfxViewInteractionExtension } from '@formicoidea/labre-core/std/gfx';
|
|
4
|
+
import { cynefinCroppedXYWH } from './crop.js';
|
|
4
5
|
import { cynefinLabelHits } from './labels.js';
|
|
5
6
|
/**
|
|
6
7
|
* View for the Cynefin background. Registering it ensures `gfx.view.get(model)`
|
|
@@ -22,17 +23,55 @@ export class CynefinView extends FrameworkBackgroundView {
|
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
/**
|
|
25
|
-
* Resize gating
|
|
26
|
-
*
|
|
26
|
+
* Resize gating and, when the handle is let go, the crop.
|
|
27
|
+
*
|
|
28
|
+
* ## Gating
|
|
29
|
+
*
|
|
30
|
+
* The resize handles are hidden unless `model.resizeEnabled` is true (toggled
|
|
31
|
+
* from the toolbar). Moving / selecting stays available.
|
|
32
|
+
*
|
|
33
|
+
* ## The crop
|
|
34
|
+
*
|
|
35
|
+
* The diagram is a fixed drawing fitted uniformly into the element, so dragged
|
|
36
|
+
* off its proportion the element letterboxes: 400 model units of nothing either
|
|
37
|
+
* side at 1600 × 600. `onResizeEnd` brings the frame back onto the picture (see
|
|
38
|
+
* `./crop.ts`) — the drawing is neither deformed nor truncated, the element
|
|
39
|
+
* simply stops claiming room it does not paint.
|
|
40
|
+
*
|
|
41
|
+
* ## Why here, and why one undo step
|
|
42
|
+
*
|
|
43
|
+
* A resize STASHES `xywh` on the way in, writes the model on every move, and
|
|
44
|
+
* commits the stash in `onResizeEnd`, inside the manager's own
|
|
45
|
+
* `store.transact` (`std/gfx/interactivity/manager.ts`). Writing the cropped
|
|
46
|
+
* box BEFORE calling `default` therefore changes what is committed rather than
|
|
47
|
+
* adding a second write: the whole gesture stays one Yjs write, and one undo
|
|
48
|
+
* step. `captureSync` would do the opposite here — it would close the step and
|
|
49
|
+
* make the crop a second one.
|
|
50
|
+
*
|
|
51
|
+
* This seam is also what keeps the crop a GESTURE. A cascade watching `xywh`
|
|
52
|
+
* would fire on a peer's resize too and re-crop, on every screen, a frame
|
|
53
|
+
* nobody on that screen touched; and it would fire on a document being loaded.
|
|
54
|
+
* The readonly guard is belt and braces — `handleElementResize` already refuses
|
|
55
|
+
* to start in a readonly store — but it is the invariant, so it is stated.
|
|
27
56
|
*/
|
|
28
57
|
export const CynefinInteraction = GfxViewInteractionExtension(CynefinView.type, {
|
|
29
|
-
handleResize({ model }) {
|
|
58
|
+
handleResize({ std, model }) {
|
|
30
59
|
return {
|
|
31
60
|
beforeResize({ set }) {
|
|
32
61
|
if (!model.resizeEnabled) {
|
|
33
62
|
set({ allowedHandlers: [] });
|
|
34
63
|
}
|
|
35
64
|
},
|
|
65
|
+
onResizeEnd(context) {
|
|
66
|
+
if (!std.store.readonly) {
|
|
67
|
+
const cropped = cynefinCroppedXYWH(model.xywh);
|
|
68
|
+
// No write at all when the frame is already on the drawing: an
|
|
69
|
+
// undo entry for a gesture that changed nothing is a bug.
|
|
70
|
+
if (cropped)
|
|
71
|
+
model.xywh = cropped;
|
|
72
|
+
}
|
|
73
|
+
context.default(context);
|
|
74
|
+
},
|
|
36
75
|
};
|
|
37
76
|
},
|
|
38
77
|
});
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { ChromeWording } from '@formicoidea/labre-core/shared/services';
|
|
2
2
|
/**
|
|
3
3
|
* Visual constants for the Estuarine framework map, reproduced from the official
|
|
4
|
-
* SVG (viewBox 0 0 690 801). All geometry is authored in that fixed
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* gets a longer time axis and a
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* (
|
|
4
|
+
* SVG (viewBox 0 0 690 801). All geometry is authored in that fixed space; the
|
|
5
|
+
* renderer reads every coordinate below as a RATIO of the CROPPED window onto
|
|
6
|
+
* it ({@link REF_X} … {@link REF_H}) and maps it onto the element's real width
|
|
7
|
+
* and height independently, so a stretched map gets a longer time axis and a
|
|
8
|
+
* taller energy axis rather than the same drawing letterboxed (see
|
|
9
|
+
* `EstuarineFit` in `./element-renderer.ts`). The e axis is vertical &
|
|
10
|
+
* double-headed (energy), the t axis horizontal & single-headed (time only
|
|
11
|
+
* flows one way).
|
|
11
12
|
*
|
|
12
13
|
* The three curve legends below (`LABELS`) carry a `wording`, resolved by
|
|
13
14
|
* `element-renderer.ts` through the `CanvasRenderer` it is handed at paint
|
|
@@ -15,8 +16,40 @@ import type { ChromeWording } from '@formicoidea/labre-core/shared/services';
|
|
|
15
16
|
* italic `e` / `t` axis LETTERS (`AXIS_LABELS`) are notation, not words, and
|
|
16
17
|
* are deliberately NOT keyed (PO decision).
|
|
17
18
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* The CROPPED window onto the authored 690 × 801 SVG space — the rectangle the
|
|
21
|
+
* element's bounds are mapped onto.
|
|
22
|
+
*
|
|
23
|
+
* The SVG's own viewBox is loose around the drawing: the t axis stops at
|
|
24
|
+
* `x = 616 / 690` and the e axis at `y = 763 / 801`, so a board born on the raw
|
|
25
|
+
* viewBox carried dead space on every side (measured on the painted pixels at
|
|
26
|
+
* birth size: 16.6 left, 12.6 top, 35.5 right, 20.4 bottom, in model units).
|
|
27
|
+
* The board's own border is therefore nowhere near its drawing, which is both
|
|
28
|
+
* ugly and awkward — a background is grabbed BY that border
|
|
29
|
+
* (`framework-background/hit-test.ts`).
|
|
30
|
+
*
|
|
31
|
+
* So the reference box is the ink's bounding box grown by {@link REF_MARGIN},
|
|
32
|
+
* not the viewBox. `REF_X` / `REF_Y` is where that window starts in authored
|
|
33
|
+
* coordinates; every authored number in this file keeps its ORIGINAL value and
|
|
34
|
+
* the renderer subtracts the origin (`ax` / `ay`), so nothing about the drawing
|
|
35
|
+
* moves relative to anything else — only the frame around it tightens.
|
|
36
|
+
*
|
|
37
|
+
* `MAP_SCALE` (see `../presets.ts`) multiplies these, so a new board is born
|
|
38
|
+
* smaller while its drawing keeps exactly the size it had.
|
|
39
|
+
*/
|
|
40
|
+
export declare const REF_X = 8;
|
|
41
|
+
export declare const REF_Y = 4.5;
|
|
42
|
+
export declare const REF_W = 659;
|
|
43
|
+
export declare const REF_H = 786.5;
|
|
44
|
+
/**
|
|
45
|
+
* Space left between the ink and the edge of the board, in reference units.
|
|
46
|
+
*
|
|
47
|
+
* Small but not zero: a stroke is centred on its path, a glyph is measured
|
|
48
|
+
* generously, and a board whose ink touched its own border would look clipped.
|
|
49
|
+
* ~6 units is a little under one axis width (8) — enough to read as a margin,
|
|
50
|
+
* little enough that the border is visibly AROUND the drawing.
|
|
51
|
+
*/
|
|
52
|
+
export declare const REF_MARGIN = 6;
|
|
20
53
|
export declare const COLORS: {
|
|
21
54
|
readonly axis: "#941253";
|
|
22
55
|
/** Italic e / t axis letters. */
|
|
@@ -42,12 +75,38 @@ export declare const T_AXIS: {
|
|
|
42
75
|
readonly x2: 616;
|
|
43
76
|
};
|
|
44
77
|
export declare const AXIS_WIDTH = 8;
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
78
|
+
/**
|
|
79
|
+
* A filled arrowhead, welded to the END OF ITS AXIS.
|
|
80
|
+
*
|
|
81
|
+
* Declared the way the shared primitive declares one (`drawAxis`,
|
|
82
|
+
* `blocks/surface/src/framework-background/renderer.ts`): the head has ONE
|
|
83
|
+
* proportional anchor — {@link at}, the point where its axis stops, which
|
|
84
|
+
* travels with the stretch — and every other number below is an offset from
|
|
85
|
+
* that anchor in FIXED units, painted at the isotropic `strokeScale`.
|
|
86
|
+
*
|
|
87
|
+
* That split is the whole point. The vertices used to be three absolute
|
|
88
|
+
* authored points, so a stretch moved the tip by `sx` while the renderer
|
|
89
|
+
* rebuilt the base from the tip at the isotropic factor: as soon as
|
|
90
|
+
* `sx ≠ strokeScale` the triangle tore away from the line it belongs to
|
|
91
|
+
* (a 29-unit gap at 1600 × 400, the head drowning in the stroke at 400 × 1600).
|
|
92
|
+
* Anchoring the head to the axis end instead keeps it soldered at every ratio,
|
|
93
|
+
* and reproduces the authored SVG exactly when `sx === sy` — which is what the
|
|
94
|
+
* numbers below were read off.
|
|
95
|
+
*/
|
|
96
|
+
export interface EstuarineArrowhead {
|
|
97
|
+
/** Authored end of the axis this head is welded to — the ratio anchor. */
|
|
98
|
+
at: readonly [number, number];
|
|
99
|
+
/** Unit vector pointing OUT of the axis, towards the tip. */
|
|
100
|
+
dir: readonly [number, number];
|
|
101
|
+
/** How far past the axis end the tip sits, in fixed units. */
|
|
102
|
+
tip: number;
|
|
103
|
+
/** How far SHORT of the axis end the base sits: the weld's overlap. */
|
|
104
|
+
overlap: number;
|
|
105
|
+
/** Half the base's width, in fixed units. */
|
|
106
|
+
halfWidth: number;
|
|
107
|
+
}
|
|
108
|
+
/** The three heads: both ends of the e axis, the right end of the t axis. */
|
|
109
|
+
export declare const ARROWHEADS: readonly EstuarineArrowhead[];
|
|
51
110
|
/** Liminal: green boundary rising gently then dipping at the right end. */
|
|
52
111
|
export declare const LIMINAL_PATH = "M 63 193 C 67 192, 78 189, 85 188 C 92 187, 100 186, 107 185 C 114 184, 122 183, 129 183 C 136 183, 144 183, 151 183 C 158 183, 166 183, 173 183 C 180 183, 188 184, 195 185 C 202 186, 210 188, 217 189 C 224 190, 232 192, 239 194 C 246 196, 254 198, 261 201 C 268 204, 276 207, 283 210 C 290 213, 298 217, 305 220 C 312 223, 320 226, 327 230 C 334 234, 342 238, 349 242 C 356 246, 364 250, 371 255 C 378 260, 386 264, 393 269 C 400 274, 408 278, 415 283 C 422 288, 430 292, 437 297 C 444 302, 451 306, 458 310 C 465 314, 473 319, 480 323 C 487 327, 495 332, 502 335 C 509 338, 517 341, 524 343 C 531 345, 539 348, 546 349 C 553 350, 561 350, 568 350 C 575 350, 583 348, 590 346 C 597 344, 605 340, 612 336 C 619 332, 626 325, 633 319 C 640 313, 648 302, 651 298 C 654 294, 654 295, 654 294";
|
|
53
112
|
export declare const LIMINAL_WIDTH = 4.5;
|
|
@@ -99,17 +158,33 @@ export declare const LABELS: {
|
|
|
99
158
|
readonly color: "#e63322";
|
|
100
159
|
};
|
|
101
160
|
};
|
|
102
|
-
/**
|
|
161
|
+
/**
|
|
162
|
+
* Italic Georgia axis letters (left-anchored, alphabetic baseline).
|
|
163
|
+
*
|
|
164
|
+
* Each letter NAMES an axis, so it is declared against that axis the way a
|
|
165
|
+
* declared background declares a word (`backgroundPoint`,
|
|
166
|
+
* `blocks/surface/src/framework-background/def.ts`): a proportional anchor
|
|
167
|
+
* (`at`, the end of the axis it names) plus a FIXED `dx`/`dy` gap, painted at
|
|
168
|
+
* the isotropic `strokeScale` like the glyph itself.
|
|
169
|
+
*
|
|
170
|
+
* They used to be absolute authored positions projected by `sx`/`sy` while the
|
|
171
|
+
* glyph was typed isotropically, so the gap between letter and axis grew or
|
|
172
|
+
* collapsed with the ratio — the `t` climbing onto its own axis at 1600 × 400,
|
|
173
|
+
* falling far below it at 400 × 1600. `at + d·strokeScale` is exactly the
|
|
174
|
+
* authored position when `sx === sy`, and a constant gap everywhere else.
|
|
175
|
+
*/
|
|
103
176
|
export declare const AXIS_LABELS: {
|
|
104
177
|
readonly e: {
|
|
105
178
|
readonly text: "e";
|
|
106
|
-
readonly
|
|
107
|
-
readonly
|
|
179
|
+
readonly at: readonly [43.5, 97];
|
|
180
|
+
readonly dx: -29.5;
|
|
181
|
+
readonly dy: 41;
|
|
108
182
|
};
|
|
109
183
|
readonly t: {
|
|
110
184
|
readonly text: "t";
|
|
111
|
-
readonly
|
|
112
|
-
readonly
|
|
185
|
+
readonly at: readonly [616, 649];
|
|
186
|
+
readonly dx: -36;
|
|
187
|
+
readonly dy: 36;
|
|
113
188
|
};
|
|
114
189
|
readonly size: 34;
|
|
115
190
|
};
|
package/dist/estuarine/consts.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Visual constants for the Estuarine framework map, reproduced from the official
|
|
3
|
-
* SVG (viewBox 0 0 690 801). All geometry is authored in that fixed
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* gets a longer time axis and a
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* (
|
|
3
|
+
* SVG (viewBox 0 0 690 801). All geometry is authored in that fixed space; the
|
|
4
|
+
* renderer reads every coordinate below as a RATIO of the CROPPED window onto
|
|
5
|
+
* it ({@link REF_X} … {@link REF_H}) and maps it onto the element's real width
|
|
6
|
+
* and height independently, so a stretched map gets a longer time axis and a
|
|
7
|
+
* taller energy axis rather than the same drawing letterboxed (see
|
|
8
|
+
* `EstuarineFit` in `./element-renderer.ts`). The e axis is vertical &
|
|
9
|
+
* double-headed (energy), the t axis horizontal & single-headed (time only
|
|
10
|
+
* flows one way).
|
|
10
11
|
*
|
|
11
12
|
* The three curve legends below (`LABELS`) carry a `wording`, resolved by
|
|
12
13
|
* `element-renderer.ts` through the `CanvasRenderer` it is handed at paint
|
|
@@ -14,8 +15,40 @@
|
|
|
14
15
|
* italic `e` / `t` axis LETTERS (`AXIS_LABELS`) are notation, not words, and
|
|
15
16
|
* are deliberately NOT keyed (PO decision).
|
|
16
17
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* The CROPPED window onto the authored 690 × 801 SVG space — the rectangle the
|
|
20
|
+
* element's bounds are mapped onto.
|
|
21
|
+
*
|
|
22
|
+
* The SVG's own viewBox is loose around the drawing: the t axis stops at
|
|
23
|
+
* `x = 616 / 690` and the e axis at `y = 763 / 801`, so a board born on the raw
|
|
24
|
+
* viewBox carried dead space on every side (measured on the painted pixels at
|
|
25
|
+
* birth size: 16.6 left, 12.6 top, 35.5 right, 20.4 bottom, in model units).
|
|
26
|
+
* The board's own border is therefore nowhere near its drawing, which is both
|
|
27
|
+
* ugly and awkward — a background is grabbed BY that border
|
|
28
|
+
* (`framework-background/hit-test.ts`).
|
|
29
|
+
*
|
|
30
|
+
* So the reference box is the ink's bounding box grown by {@link REF_MARGIN},
|
|
31
|
+
* not the viewBox. `REF_X` / `REF_Y` is where that window starts in authored
|
|
32
|
+
* coordinates; every authored number in this file keeps its ORIGINAL value and
|
|
33
|
+
* the renderer subtracts the origin (`ax` / `ay`), so nothing about the drawing
|
|
34
|
+
* moves relative to anything else — only the frame around it tightens.
|
|
35
|
+
*
|
|
36
|
+
* `MAP_SCALE` (see `../presets.ts`) multiplies these, so a new board is born
|
|
37
|
+
* smaller while its drawing keeps exactly the size it had.
|
|
38
|
+
*/
|
|
39
|
+
export const REF_X = 8;
|
|
40
|
+
export const REF_Y = 4.5;
|
|
41
|
+
export const REF_W = 659;
|
|
42
|
+
export const REF_H = 786.5;
|
|
43
|
+
/**
|
|
44
|
+
* Space left between the ink and the edge of the board, in reference units.
|
|
45
|
+
*
|
|
46
|
+
* Small but not zero: a stroke is centred on its path, a glyph is measured
|
|
47
|
+
* generously, and a board whose ink touched its own border would look clipped.
|
|
48
|
+
* ~6 units is a little under one axis width (8) — enough to read as a margin,
|
|
49
|
+
* little enough that the border is visibly AROUND the drawing.
|
|
50
|
+
*/
|
|
51
|
+
export const REF_MARGIN = 6;
|
|
19
52
|
export const COLORS = {
|
|
20
53
|
axis: '#941253',
|
|
21
54
|
/** Italic e / t axis letters. */
|
|
@@ -33,23 +66,32 @@ export const E_AXIS = { x: 43.5, y1: 97, y2: 763 };
|
|
|
33
66
|
/** t axis (horizontal, single-headed → right): y, left x, right x. */
|
|
34
67
|
export const T_AXIS = { y: 649, x1: 28, x2: 616 };
|
|
35
68
|
export const AXIS_WIDTH = 8;
|
|
36
|
-
/**
|
|
69
|
+
/** The three heads: both ends of the e axis, the right end of the t axis. */
|
|
37
70
|
export const ARROWHEADS = [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
[
|
|
41
|
-
[
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
[
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
71
|
+
// e — top
|
|
72
|
+
{
|
|
73
|
+
at: [E_AXIS.x, E_AXIS.y1],
|
|
74
|
+
dir: [0, -1],
|
|
75
|
+
tip: 25,
|
|
76
|
+
overlap: 3,
|
|
77
|
+
halfWidth: 13.5,
|
|
78
|
+
},
|
|
79
|
+
// e — bottom
|
|
80
|
+
{
|
|
81
|
+
at: [E_AXIS.x, E_AXIS.y2],
|
|
82
|
+
dir: [0, 1],
|
|
83
|
+
tip: 22,
|
|
84
|
+
overlap: 5,
|
|
85
|
+
halfWidth: 13.5,
|
|
86
|
+
},
|
|
87
|
+
// t — right
|
|
88
|
+
{
|
|
89
|
+
at: [T_AXIS.x2, T_AXIS.y],
|
|
90
|
+
dir: [1, 0],
|
|
91
|
+
tip: 27,
|
|
92
|
+
overlap: 3,
|
|
93
|
+
halfWidth: 13,
|
|
94
|
+
},
|
|
53
95
|
];
|
|
54
96
|
/** Liminal: green boundary rising gently then dipping at the right end. */
|
|
55
97
|
export const LIMINAL_PATH = 'M 63 193 C 67 192, 78 189, 85 188 C 92 187, 100 186, 107 185 C 114 184, 122 183, 129 183 C 136 183, 144 183, 151 183 C 158 183, 166 183, 173 183 C 180 183, 188 184, 195 185 C 202 186, 210 188, 217 189 C 224 190, 232 192, 239 194 C 246 196, 254 198, 261 201 C 268 204, 276 207, 283 210 C 290 213, 298 217, 305 220 C 312 223, 320 226, 327 230 C 334 234, 342 238, 349 242 C 356 246, 364 250, 371 255 C 378 260, 386 264, 393 269 C 400 274, 408 278, 415 283 C 422 288, 430 292, 437 297 C 444 302, 451 306, 458 310 C 465 314, 473 319, 480 323 C 487 327, 495 332, 502 335 C 509 338, 517 341, 524 343 C 531 345, 539 348, 546 349 C 553 350, 561 350, 568 350 C 575 350, 583 348, 590 346 C 597 344, 605 340, 612 336 C 619 332, 626 325, 633 319 C 640 313, 648 302, 651 298 C 654 294, 654 295, 654 294';
|
|
@@ -118,10 +160,24 @@ export const LABELS = {
|
|
|
118
160
|
color: COLORS.volatile,
|
|
119
161
|
},
|
|
120
162
|
};
|
|
121
|
-
/**
|
|
163
|
+
/**
|
|
164
|
+
* Italic Georgia axis letters (left-anchored, alphabetic baseline).
|
|
165
|
+
*
|
|
166
|
+
* Each letter NAMES an axis, so it is declared against that axis the way a
|
|
167
|
+
* declared background declares a word (`backgroundPoint`,
|
|
168
|
+
* `blocks/surface/src/framework-background/def.ts`): a proportional anchor
|
|
169
|
+
* (`at`, the end of the axis it names) plus a FIXED `dx`/`dy` gap, painted at
|
|
170
|
+
* the isotropic `strokeScale` like the glyph itself.
|
|
171
|
+
*
|
|
172
|
+
* They used to be absolute authored positions projected by `sx`/`sy` while the
|
|
173
|
+
* glyph was typed isotropically, so the gap between letter and axis grew or
|
|
174
|
+
* collapsed with the ratio — the `t` climbing onto its own axis at 1600 × 400,
|
|
175
|
+
* falling far below it at 400 × 1600. `at + d·strokeScale` is exactly the
|
|
176
|
+
* authored position when `sx === sy`, and a constant gap everywhere else.
|
|
177
|
+
*/
|
|
122
178
|
export const AXIS_LABELS = {
|
|
123
|
-
e: { text: 'e', x:
|
|
124
|
-
t: { text: 't',
|
|
179
|
+
e: { text: 'e', at: [E_AXIS.x, E_AXIS.y1], dx: -29.5, dy: 41 },
|
|
180
|
+
t: { text: 't', at: [T_AXIS.x2, T_AXIS.y], dx: -36, dy: 36 },
|
|
125
181
|
size: 34,
|
|
126
182
|
};
|
|
127
183
|
export const LABEL_LETTER_SPACING = 4;
|
|
@@ -109,6 +109,13 @@ export declare function applyEstuarineTransform(ctx: CanvasRenderingContext2D, w
|
|
|
109
109
|
* arrowheads and every word. Their POSITION follows the stretch — an axis
|
|
110
110
|
* ends where the map now ends — while their SHAPE does not, because a
|
|
111
111
|
* stretched arrowhead or a squashed letter is a defect, never a feature.
|
|
112
|
+
*
|
|
113
|
+
* One rule keeps that split honest, and it is the shared primitive's own
|
|
114
|
+
* (`drawAxis` / `backgroundPoint`): **an anchor is a RATIO of the frame, and
|
|
115
|
+
* every offset from an anchor is in FIXED units.** A shape must never take
|
|
116
|
+
* its anchor from one and its offset from the other — that mix is exactly
|
|
117
|
+
* what tore the arrowheads off their axes and slid the `e` / `t` letters
|
|
118
|
+
* around on a stretched map.
|
|
112
119
|
* - **Stretched reference space**, entered by {@link applyEstuarineTransform}:
|
|
113
120
|
* the three curves, which are boundaries across the plane and must cover
|
|
114
121
|
* whatever plane the user has made.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ElementRendererExtension, taggedPath2D, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import { translateKey, } from '@formicoidea/labre-core/shared/services';
|
|
3
3
|
import { FONT_FAMILY } from '../utils.js';
|
|
4
|
-
import { ARROWHEADS, AXIS_LABELS, AXIS_WIDTH, COLORS, COUNTERFACTUAL_PATH, COUNTERFACTUAL_WIDTH, E_AXIS, LABEL_LETTER_SPACING, LABELS, LIMINAL_PATH, LIMINAL_WIDTH, REF_H, REF_W, T_AXIS, VOLATILE_PATH, VOLATILE_WIDTH, } from './consts.js';
|
|
4
|
+
import { ARROWHEADS, AXIS_LABELS, AXIS_WIDTH, COLORS, COUNTERFACTUAL_PATH, COUNTERFACTUAL_WIDTH, E_AXIS, LABEL_LETTER_SPACING, LABELS, LIMINAL_PATH, LIMINAL_WIDTH, REF_H, REF_W, REF_X, REF_Y, T_AXIS, VOLATILE_PATH, VOLATILE_WIDTH, } from './consts.js';
|
|
5
5
|
import { estuarineLegendText } from './labels.js';
|
|
6
6
|
/**
|
|
7
7
|
* The three reference curves are drawn as a permanent GHOST (PO arbitration,
|
|
@@ -82,6 +82,10 @@ export function estuarineFit(w, h) {
|
|
|
82
82
|
export function applyEstuarineTransform(ctx, w, h) {
|
|
83
83
|
const fit = estuarineFit(w, h);
|
|
84
84
|
ctx.scale(fit.sx, fit.sy);
|
|
85
|
+
// The crop: authored (REF_X, REF_Y) is the element's own origin. Applied
|
|
86
|
+
// INSIDE the scale so the translation is expressed in authored units, which
|
|
87
|
+
// is the space the `Path2D` this transform is meant for is written in.
|
|
88
|
+
ctx.translate(-REF_X, -REF_Y);
|
|
85
89
|
return fit;
|
|
86
90
|
}
|
|
87
91
|
/**
|
|
@@ -97,6 +101,13 @@ export function applyEstuarineTransform(ctx, w, h) {
|
|
|
97
101
|
* arrowheads and every word. Their POSITION follows the stretch — an axis
|
|
98
102
|
* ends where the map now ends — while their SHAPE does not, because a
|
|
99
103
|
* stretched arrowhead or a squashed letter is a defect, never a feature.
|
|
104
|
+
*
|
|
105
|
+
* One rule keeps that split honest, and it is the shared primitive's own
|
|
106
|
+
* (`drawAxis` / `backgroundPoint`): **an anchor is a RATIO of the frame, and
|
|
107
|
+
* every offset from an anchor is in FIXED units.** A shape must never take
|
|
108
|
+
* its anchor from one and its offset from the other — that mix is exactly
|
|
109
|
+
* what tore the arrowheads off their axes and slid the `e` / `t` letters
|
|
110
|
+
* around on a stretched map.
|
|
100
111
|
* - **Stretched reference space**, entered by {@link applyEstuarineTransform}:
|
|
101
112
|
* the three curves, which are boundaries across the plane and must cover
|
|
102
113
|
* whatever plane the user has made.
|
|
@@ -111,10 +122,10 @@ export const estuarine = (model, ctx, matrix, renderer) => {
|
|
|
111
122
|
.rotateSelf(model.rotate)
|
|
112
123
|
.translateSelf(-cx, -cy));
|
|
113
124
|
const fit = estuarineFit(w, h);
|
|
114
|
-
/** Authored x → element x
|
|
115
|
-
const ax = (x) => x * fit.sx;
|
|
125
|
+
/** Authored x → element x, through the cropped window (see `./consts.ts`). */
|
|
126
|
+
const ax = (x) => (x - REF_X) * fit.sx;
|
|
116
127
|
/** Authored y → element y. */
|
|
117
|
-
const ay = (y) => y * fit.sy;
|
|
128
|
+
const ay = (y) => (y - REF_Y) * fit.sy;
|
|
118
129
|
ctx.lineCap = 'round';
|
|
119
130
|
ctx.lineJoin = 'round';
|
|
120
131
|
// ── Axes ────────────────────────────────────────────────────────────
|
|
@@ -130,17 +141,29 @@ export const estuarine = (model, ctx, matrix, renderer) => {
|
|
|
130
141
|
ctx.moveTo(ax(T_AXIS.x1), ay(T_AXIS.y));
|
|
131
142
|
ctx.lineTo(ax(T_AXIS.x2), ay(T_AXIS.y));
|
|
132
143
|
ctx.stroke();
|
|
133
|
-
// Each head is
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
144
|
+
// Each head is welded to the END OF ITS AXIS — the one proportional anchor —
|
|
145
|
+
// and built entirely from fixed offsets around that point, exactly as the
|
|
146
|
+
// shared primitive's `drawAxis` builds one. Anchor by ratio, offset by fixed
|
|
147
|
+
// units, never a mix of the two on the two ends of one shape: that is the
|
|
148
|
+
// rule the old formula broke by pinning the tip proportionally and then
|
|
149
|
+
// rebuilding the base from it at the isotropic scale.
|
|
150
|
+
const k = fit.strokeScale;
|
|
151
|
+
for (const head of ARROWHEADS) {
|
|
152
|
+
const [dx, dy] = head.dir;
|
|
153
|
+
// Across the axis, same fixed units — the base's half-width.
|
|
154
|
+
const [px, py] = [-dy, dx];
|
|
155
|
+
const endX = ax(head.at[0]);
|
|
156
|
+
const endY = ay(head.at[1]);
|
|
157
|
+
// The base sits SHORT of the axis end, so the stroke dies inside the
|
|
158
|
+
// triangle and the two never come apart however the map is pulled.
|
|
159
|
+
const baseX = endX - dx * head.overlap * k;
|
|
160
|
+
const baseY = endY - dy * head.overlap * k;
|
|
161
|
+
const spreadX = px * head.halfWidth * k;
|
|
162
|
+
const spreadY = py * head.halfWidth * k;
|
|
140
163
|
ctx.beginPath();
|
|
141
|
-
ctx.moveTo(
|
|
142
|
-
ctx.lineTo(
|
|
143
|
-
ctx.lineTo(
|
|
164
|
+
ctx.moveTo(endX + dx * head.tip * k, endY + dy * head.tip * k);
|
|
165
|
+
ctx.lineTo(baseX - spreadX, baseY - spreadY);
|
|
166
|
+
ctx.lineTo(baseX + spreadX, baseY + spreadY);
|
|
144
167
|
ctx.closePath();
|
|
145
168
|
ctx.fill();
|
|
146
169
|
}
|
|
@@ -180,13 +203,18 @@ export const estuarine = (model, ctx, matrix, renderer) => {
|
|
|
180
203
|
legend(curve.key);
|
|
181
204
|
}
|
|
182
205
|
// ── Italic e / t axis letters ───────────────────────────────────────
|
|
206
|
+
// A letter names an axis, so it rides the END of that axis (proportional)
|
|
207
|
+
// at a FIXED gap from it — the same anchor-plus-offset a declared background
|
|
208
|
+
// writes as `backgroundPoint`. The glyph and the gap then scale together, so
|
|
209
|
+
// the letter sits the same distance from its axis at every ratio.
|
|
183
210
|
if (model.showAxisLabels) {
|
|
184
211
|
ctx.fillStyle = COLORS.axisLabel;
|
|
185
|
-
ctx.font = `italic 700 ${AXIS_LABELS.size *
|
|
212
|
+
ctx.font = `italic 700 ${AXIS_LABELS.size * k}px Georgia, serif`;
|
|
186
213
|
ctx.textAlign = 'left';
|
|
187
214
|
ctx.textBaseline = 'alphabetic';
|
|
188
|
-
|
|
189
|
-
|
|
215
|
+
for (const letter of [AXIS_LABELS.e, AXIS_LABELS.t]) {
|
|
216
|
+
ctx.fillText(letter.text, ax(letter.at[0]) + letter.dx * k, ay(letter.at[1]) + letter.dy * k);
|
|
217
|
+
}
|
|
190
218
|
}
|
|
191
219
|
};
|
|
192
220
|
export const EstuarineRendererExtension = ElementRendererExtension('estuarine', estuarine);
|
|
@@ -33,7 +33,8 @@ export declare function estuarineLegendText(model: EstuarineElementModel, key: E
|
|
|
33
33
|
* Clickable boxes of the visible legends, in ELEMENT-LOCAL coordinates.
|
|
34
34
|
*
|
|
35
35
|
* Anchored through the same fit the renderer anchors them with: proportionally
|
|
36
|
-
* in both directions
|
|
37
|
-
*
|
|
36
|
+
* in both directions — through the same cropped window (`REF_X` / `REF_Y`) —
|
|
37
|
+
* and typed isotropically. A legend whose curve is switched off is not painted
|
|
38
|
+
* and is therefore not aimable either.
|
|
38
39
|
*/
|
|
39
40
|
export declare function estuarineLabelHits(model: EstuarineElementModel, fit: EstuarineLegendFit, translate: EstuarineWordingResolver): BackgroundLabelHit[];
|
package/dist/estuarine/labels.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { backgroundTextHitBox } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
-
import { LABEL_LETTER_SPACING, LABELS } from './consts.js';
|
|
2
|
+
import { LABEL_LETTER_SPACING, LABELS, REF_X, REF_Y } from './consts.js';
|
|
3
3
|
/**
|
|
4
4
|
* What a legend SAYS: the user's own word, else the vocabulary.
|
|
5
5
|
*
|
|
@@ -20,8 +20,9 @@ export function estuarineLegendText(model, key, translate) {
|
|
|
20
20
|
* Clickable boxes of the visible legends, in ELEMENT-LOCAL coordinates.
|
|
21
21
|
*
|
|
22
22
|
* Anchored through the same fit the renderer anchors them with: proportionally
|
|
23
|
-
* in both directions
|
|
24
|
-
*
|
|
23
|
+
* in both directions — through the same cropped window (`REF_X` / `REF_Y`) —
|
|
24
|
+
* and typed isotropically. A legend whose curve is switched off is not painted
|
|
25
|
+
* and is therefore not aimable either.
|
|
25
26
|
*/
|
|
26
27
|
export function estuarineLabelHits(model, fit, translate) {
|
|
27
28
|
const props = model;
|
|
@@ -31,7 +32,7 @@ export function estuarineLabelHits(model, fit, translate) {
|
|
|
31
32
|
if (!props[label.visibleProp])
|
|
32
33
|
continue;
|
|
33
34
|
const text = estuarineLegendText(model, key, translate);
|
|
34
|
-
const box = backgroundTextHitBox(text, label.size * fit.strokeScale, label.x * fit.sx, label.y * fit.sy, 'center');
|
|
35
|
+
const box = backgroundTextHitBox(text, label.size * fit.strokeScale, (label.x - REF_X) * fit.sx, (label.y - REF_Y) * fit.sy, 'center');
|
|
35
36
|
// A legend is letter-spaced, so it is wider than the shared estimate: half
|
|
36
37
|
// of the extra width on each side, since the word is centred on its anchor.
|
|
37
38
|
const spread = (Math.max(text.length - 1, 0) * LABEL_LETTER_SPACING * fit.strokeScale) /
|
package/dist/presets.d.ts
CHANGED
|
@@ -8,9 +8,20 @@
|
|
|
8
8
|
* the estuarine background was drawn at scale 1 while the button drew it at
|
|
9
9
|
* 1.2. Derived from one table, neither can happen again.
|
|
10
10
|
*/
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Estuarine map default scale: how many canvas units one reference unit of the
|
|
13
|
+
* drawing is worth when the map is born. The DRAWING's size, in other words —
|
|
14
|
+
* which is why it is this number, and not the birth box, that is the constant.
|
|
15
|
+
*/
|
|
12
16
|
export declare const MAP_SCALE = 1.2;
|
|
13
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* The box an estuarine map is born in — the size the toolbox draws.
|
|
19
|
+
*
|
|
20
|
+
* Derived from the CROPPED reference box (`estuarine/consts.ts`), so the board
|
|
21
|
+
* is born just big enough to hold its drawing plus a thin margin. It shrank
|
|
22
|
+
* when the crop tightened (828 × 961.2 → 790.8 × 943.8) and the drawing inside
|
|
23
|
+
* it did not change size by a single unit — `MAP_SCALE` is still 1.2.
|
|
24
|
+
*/
|
|
14
25
|
export declare const ESTUARINE_MAP_W: number;
|
|
15
26
|
export declare const ESTUARINE_MAP_H: number;
|
|
16
27
|
/** The box a Cynefin frame is born in. */
|
package/dist/presets.js
CHANGED
|
@@ -12,9 +12,20 @@ import { ESTUARINE_ROLE } from './estuarine/roles.js';
|
|
|
12
12
|
* the estuarine background was drawn at scale 1 while the button drew it at
|
|
13
13
|
* 1.2. Derived from one table, neither can happen again.
|
|
14
14
|
*/
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Estuarine map default scale: how many canvas units one reference unit of the
|
|
17
|
+
* drawing is worth when the map is born. The DRAWING's size, in other words —
|
|
18
|
+
* which is why it is this number, and not the birth box, that is the constant.
|
|
19
|
+
*/
|
|
16
20
|
export const MAP_SCALE = 1.2;
|
|
17
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* The box an estuarine map is born in — the size the toolbox draws.
|
|
23
|
+
*
|
|
24
|
+
* Derived from the CROPPED reference box (`estuarine/consts.ts`), so the board
|
|
25
|
+
* is born just big enough to hold its drawing plus a thin margin. It shrank
|
|
26
|
+
* when the crop tightened (828 × 961.2 → 790.8 × 943.8) and the drawing inside
|
|
27
|
+
* it did not change size by a single unit — `MAP_SCALE` is still 1.2.
|
|
28
|
+
*/
|
|
18
29
|
export const ESTUARINE_MAP_W = EST_W * MAP_SCALE;
|
|
19
30
|
export const ESTUARINE_MAP_H = EST_H * MAP_SCALE;
|
|
20
31
|
/** The box a Cynefin frame is born in. */
|
package/dist/templates/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { FontFamily, ShapeStyle, TextAlign } from '@formicoidea/labre-core/model
|
|
|
3
3
|
import { NOTATION_NEUTRALS } from '@formicoidea/labre-core/shared/consts';
|
|
4
4
|
import { translateKey, } from '@formicoidea/labre-core/shared/services';
|
|
5
5
|
import { cynefinEstuarineCommands } from '../commands.js';
|
|
6
|
-
import { HEX_SIZE } from '../estuarine/consts.js';
|
|
6
|
+
import { HEX_SIZE, REF_X, REF_Y } from '../estuarine/consts.js';
|
|
7
7
|
import { CYNEFIN_H, CYNEFIN_W, cynefinBackgroundProps, ESTUARINE_MAP_H, ESTUARINE_MAP_W, estuarineHexagonBox, estuarineHexagonProps, estuarineMapProps, MAP_SCALE, } from '../presets.js';
|
|
8
8
|
/**
|
|
9
9
|
* The Cynefin / Estuarine palettes — DERIVED from the toolbox, one template per
|
|
@@ -12,8 +12,8 @@ import { CYNEFIN_H, CYNEFIN_W, cynefinBackgroundProps, ESTUARINE_MAP_H, ESTUARIN
|
|
|
12
12
|
* Every single-artefact entry below is what its command actually draws, run
|
|
13
13
|
* once against a recording surface. Hand-written, they had drifted exactly as
|
|
14
14
|
* far as a copy drifts: the hexagons had lost the `textFitMode` #52 gave them,
|
|
15
|
-
* and the estuarine background was drawn at scale 1
|
|
16
|
-
*
|
|
15
|
+
* and the estuarine background was drawn at scale 1 where the button draws it
|
|
16
|
+
* at `MAP_SCALE`. Derived, neither can happen again — and
|
|
17
17
|
* `templates-parity.unit.spec.ts` re-runs each command and compares.
|
|
18
18
|
*
|
|
19
19
|
* The two COMPOSITIONS stay hand-written: a sorting board and a constraint map
|
|
@@ -47,12 +47,19 @@ function sticky(x, y, text) {
|
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
|
-
* A constraint on the shipped map, placed by its CENTRE in the map's
|
|
51
|
-
* space (690×801
|
|
52
|
-
*
|
|
50
|
+
* A constraint on the shipped map, placed by its CENTRE in the map's AUTHORED
|
|
51
|
+
* space (the 690×801 the drawing was laid out in), carried onto the box the map
|
|
52
|
+
* is actually born at.
|
|
53
|
+
*
|
|
54
|
+
* `- REF_X` / `- REF_Y` is the map's crop: the board's own origin is authored
|
|
55
|
+
* `(REF_X, REF_Y)`, not `(0, 0)`, so a hexagon placed on a curve stays on that
|
|
56
|
+
* curve. Derived, never restated — tightening the crop moves the drawing and
|
|
57
|
+
* the constraints on it together.
|
|
53
58
|
*/
|
|
59
|
+
const mapX = (cx) => (cx - REF_X) * MAP_SCALE;
|
|
60
|
+
const mapY = (cy) => (cy - REF_Y) * MAP_SCALE;
|
|
54
61
|
const hexAt = (cx, cy) => estuarineHexagonProps({
|
|
55
|
-
xywh: estuarineHexagonBox(cx
|
|
62
|
+
xywh: estuarineHexagonBox(mapX(cx), mapY(cy)),
|
|
56
63
|
});
|
|
57
64
|
const CAPTION_W = 120;
|
|
58
65
|
const CAPTION_H = 24;
|
|
@@ -69,8 +76,8 @@ const CAPTION_GAP = 8;
|
|
|
69
76
|
* Neutral, and staying so: a name is nobody's artefact.
|
|
70
77
|
*/
|
|
71
78
|
function caption(cx, cy, str) {
|
|
72
|
-
const x = cx
|
|
73
|
-
const y = cy
|
|
79
|
+
const x = mapX(cx) - CAPTION_W / 2;
|
|
80
|
+
const y = mapY(cy) + HEX_SIZE / 2 + CAPTION_GAP;
|
|
74
81
|
return {
|
|
75
82
|
type: 'text',
|
|
76
83
|
text: surfaceText(str),
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Uniform fit of a fixed reference design
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Uniform fit of a fixed reference design into an element, THE one in the
|
|
3
|
+
* library: `@labre/affine-block-surface`'s `refScale`. Re-exported here because
|
|
4
|
+
* both diagrams of this package draw an authored artwork and have always called
|
|
5
|
+
* it by this name — the body used to be copied here, and in two other packages
|
|
6
|
+
* besides (R37, one source of truth).
|
|
5
7
|
*/
|
|
6
|
-
export
|
|
7
|
-
s: number;
|
|
8
|
-
ox: number;
|
|
9
|
-
oy: number;
|
|
10
|
-
};
|
|
8
|
+
export { refScale } from '@formicoidea/labre-core/blocks/surface';
|
|
11
9
|
export declare const FONT_FAMILY = "Inter, sans-serif";
|
package/dist/utils.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Uniform fit of a fixed reference design
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Uniform fit of a fixed reference design into an element, THE one in the
|
|
3
|
+
* library: `@labre/affine-block-surface`'s `refScale`. Re-exported here because
|
|
4
|
+
* both diagrams of this package draw an authored artwork and have always called
|
|
5
|
+
* it by this name — the body used to be copied here, and in two other packages
|
|
6
|
+
* besides (R37, one source of truth).
|
|
5
7
|
*/
|
|
6
|
-
export
|
|
7
|
-
const s = Math.min(w / refW, h / refH);
|
|
8
|
-
return { s, ox: (w - refW * s) / 2, oy: (h - refH * s) / 2 };
|
|
9
|
-
}
|
|
8
|
+
export { refScale } from '@formicoidea/labre-core/blocks/surface';
|
|
10
9
|
export const FONT_FAMILY = 'Inter, sans-serif';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formicoidea/labre-framework-cynefin",
|
|
3
3
|
"description": "Labre cynefin-estuarine framework for @formicoidea/labre-core.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.43.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"author": "lajola",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"dist"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@formicoidea/labre-core": "0.
|
|
34
|
+
"@formicoidea/labre-core": "0.43.1",
|
|
35
35
|
"@preact/signals-core": "^1.8.0",
|
|
36
36
|
"lit": "^3.2.0"
|
|
37
37
|
}
|