@formicoidea/labre-framework-cynefin 0.23.2 → 0.23.3
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/consts.d.ts +79 -0
- package/dist/cynefin/consts.js +141 -0
- package/dist/cynefin/element-renderer.d.ts +14 -0
- package/dist/cynefin/element-renderer.js +114 -0
- package/dist/cynefin/element-view.d.ts +14 -0
- package/dist/cynefin/element-view.js +23 -0
- package/dist/cynefin/toolbar/config.d.ts +31 -0
- package/dist/cynefin/toolbar/config.js +43 -0
- package/dist/descriptor.d.ts +7 -0
- package/{src/descriptor.ts → dist/descriptor.js} +4 -5
- package/dist/effects.d.ts +9 -0
- package/dist/effects.js +6 -0
- package/dist/estuarine/consts.d.ts +84 -0
- package/dist/estuarine/consts.js +54 -0
- package/dist/estuarine/element-renderer.d.ts +13 -0
- package/dist/estuarine/element-renderer.js +83 -0
- package/dist/estuarine/element-view.d.ts +14 -0
- package/dist/estuarine/element-view.js +23 -0
- package/dist/estuarine/toolbar/config.d.ts +37 -0
- package/dist/estuarine/toolbar/config.js +47 -0
- package/{src/index.ts → dist/index.d.ts} +1 -1
- package/dist/index.js +1 -0
- package/dist/templates/index.d.ts +3 -0
- package/dist/templates/index.js +94 -0
- package/dist/toolbar/icons.d.ts +8 -0
- package/{src/toolbar/icons.ts → dist/toolbar/icons.js} +13 -17
- package/dist/toolbar/menu.d.ts +17 -0
- package/{src/toolbar/menu.ts → dist/toolbar/menu.js} +88 -112
- package/dist/toolbar/senior-button.d.ts +12 -0
- package/{src/toolbar/senior-button.ts → dist/toolbar/senior-button.js} +42 -48
- package/dist/toolbar/senior-tool.d.ts +2 -0
- package/{src/toolbar/senior-tool.ts → dist/toolbar/senior-tool.js} +10 -14
- package/dist/utils.d.ts +11 -0
- package/{src/utils.ts → dist/utils.js} +10 -11
- package/dist/view.d.ts +6 -0
- package/dist/view.js +37 -0
- package/package.json +15 -6
- package/src/cynefin/consts.ts +0 -188
- package/src/cynefin/element-renderer.ts +0 -156
- package/src/cynefin/element-view.ts +0 -32
- package/src/cynefin/toolbar/config.ts +0 -60
- package/src/effects.ts +0 -20
- package/src/estuarine/consts.ts +0 -69
- package/src/estuarine/element-renderer.ts +0 -122
- package/src/estuarine/element-view.ts +0 -32
- package/src/estuarine/toolbar/config.ts +0 -65
- package/src/templates/index.ts +0 -130
- package/src/view.ts +0 -44
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { DefaultTool } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
-
import { EmptyTool } from '@formicoidea/labre-core/gfx/pointer';
|
|
3
|
-
import { EdgelessToolbarToolMixin } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
|
|
4
|
-
import { SignalWatcher } from '@formicoidea/labre-core/global/lit';
|
|
5
|
-
import { css, html, LitElement } from 'lit';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import { DefaultTool } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { EmptyTool } from '@formicoidea/labre-core/gfx/pointer';
|
|
3
|
+
import { EdgelessToolbarToolMixin } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
|
|
4
|
+
import { SignalWatcher } from '@formicoidea/labre-core/global/lit';
|
|
5
|
+
import { css, html, LitElement } from 'lit';
|
|
6
|
+
import { cynefinToolbarIcon } from './icons';
|
|
7
|
+
/** Main toolbar button that opens the combined Cynefin / Estuarine sub-menu. */
|
|
8
|
+
export class EdgelessCynefinEstuarineSeniorButton extends EdgelessToolbarToolMixin(SignalWatcher(LitElement)) {
|
|
9
|
+
constructor() {
|
|
10
|
+
super(...arguments);
|
|
11
|
+
this.enableActiveBackground = true;
|
|
12
|
+
this.type = EmptyTool;
|
|
13
|
+
}
|
|
14
|
+
static { this.styles = css `
|
|
14
15
|
:host,
|
|
15
16
|
.ce-button {
|
|
16
17
|
display: block;
|
|
@@ -49,38 +50,31 @@ export class EdgelessCynefinEstuarineSeniorButton extends EdgelessToolbarToolMix
|
|
|
49
50
|
--y: -10px;
|
|
50
51
|
--s: 1.07;
|
|
51
52
|
}
|
|
52
|
-
`;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
maxWidth: 'calc(100vw - 16px)',
|
|
78
|
-
marginLeft: '0',
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
override render() {
|
|
83
|
-
return html`<edgeless-toolbar-button
|
|
53
|
+
`; }
|
|
54
|
+
_toggleMenu() {
|
|
55
|
+
if (this.popper) {
|
|
56
|
+
this.popper.dispose();
|
|
57
|
+
this.popper = null;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this.setEdgelessTool(DefaultTool);
|
|
61
|
+
const menu = this.createPopper('edgeless-cynefin-estuarine-menu', this);
|
|
62
|
+
menu.element.edgeless = this.edgeless;
|
|
63
|
+
const el = menu.element;
|
|
64
|
+
const wrap = el.parentElement;
|
|
65
|
+
if (wrap) {
|
|
66
|
+
wrap.style.overflow = 'visible';
|
|
67
|
+
wrap.style.justifyContent = 'flex-end';
|
|
68
|
+
}
|
|
69
|
+
Object.assign(el.style, {
|
|
70
|
+
position: 'static',
|
|
71
|
+
width: 'max-content',
|
|
72
|
+
maxWidth: 'calc(100vw - 16px)',
|
|
73
|
+
marginLeft: '0',
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
render() {
|
|
77
|
+
return html `<edgeless-toolbar-button
|
|
84
78
|
class="ce-button"
|
|
85
79
|
.tooltip=${this.popper ? '' : 'Cynefin / Estuarine'}
|
|
86
80
|
.tooltipOffset=${4}
|
|
@@ -90,6 +84,6 @@ export class EdgelessCynefinEstuarineSeniorButton extends EdgelessToolbarToolMix
|
|
|
90
84
|
<div class="ce-root">
|
|
91
85
|
<div class="ce-card">${cynefinToolbarIcon}</div>
|
|
92
86
|
</div>
|
|
93
|
-
</edgeless-toolbar-button>`;
|
|
94
|
-
|
|
95
|
-
}
|
|
87
|
+
</edgeless-toolbar-button>`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import { SeniorToolExtension } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
|
|
2
|
-
import { html } from 'lit';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return {
|
|
9
|
-
name: 'Cynefin / Estuarine',
|
|
10
|
-
content: html`<edgeless-cynefin-estuarine-senior-button
|
|
1
|
+
import { SeniorToolExtension } from '@formicoidea/labre-core/widgets/edgeless-toolbar';
|
|
2
|
+
import { html } from 'lit';
|
|
3
|
+
/** A single senior tool hosting both the Cynefin and Estuarine frameworks. */
|
|
4
|
+
export const cynefinEstuarineSeniorTool = SeniorToolExtension('cynefin-estuarine', ({ block }) => {
|
|
5
|
+
return {
|
|
6
|
+
name: 'Cynefin / Estuarine',
|
|
7
|
+
content: html `<edgeless-cynefin-estuarine-senior-button
|
|
11
8
|
.edgeless=${block}
|
|
12
|
-
></edgeless-cynefin-estuarine-senior-button>`,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
);
|
|
9
|
+
></edgeless-cynefin-estuarine-senior-button>`,
|
|
10
|
+
};
|
|
11
|
+
});
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Uniform fit of a fixed reference design (`refW × refH`) into an element of
|
|
3
|
+
* size `w × h`: the scale factor plus the centering offsets (letterboxed).
|
|
4
|
+
* Keeps the artwork undistorted at any element size.
|
|
5
|
+
*/
|
|
6
|
+
export declare function refScale(w: number, h: number, refW: number, refH: number): {
|
|
7
|
+
s: number;
|
|
8
|
+
ox: number;
|
|
9
|
+
oy: number;
|
|
10
|
+
};
|
|
11
|
+
export declare const FONT_FAMILY = "Inter, sans-serif";
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Uniform fit of a fixed reference design (`refW × refH`) into an element of
|
|
3
|
-
* size `w × h`: the scale factor plus the centering offsets (letterboxed).
|
|
4
|
-
* Keeps the artwork undistorted at any element size.
|
|
5
|
-
*/
|
|
6
|
-
export function refScale(w
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const FONT_FAMILY = 'Inter, sans-serif';
|
|
1
|
+
/**
|
|
2
|
+
* Uniform fit of a fixed reference design (`refW × refH`) into an element of
|
|
3
|
+
* size `w × h`: the scale factor plus the centering offsets (letterboxed).
|
|
4
|
+
* Keeps the artwork undistorted at any element size.
|
|
5
|
+
*/
|
|
6
|
+
export function refScale(w, h, refW, refH) {
|
|
7
|
+
const s = Math.min(w / refW, h / refH);
|
|
8
|
+
return { s, ox: (w - refW * s) / 2, oy: (h - refH * s) / 2 };
|
|
9
|
+
}
|
|
10
|
+
export const FONT_FAMILY = 'Inter, sans-serif';
|
package/dist/view.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ViewExtensionContext, ViewExtensionProvider } from '@formicoidea/labre-core/ext-loader';
|
|
2
|
+
export declare class CynefinEstuarineViewExtension extends ViewExtensionProvider {
|
|
3
|
+
name: string;
|
|
4
|
+
effect(): void;
|
|
5
|
+
setup(context: ViewExtensionContext): void;
|
|
6
|
+
}
|
package/dist/view.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ViewExtensionProvider, } from '@formicoidea/labre-core/ext-loader';
|
|
2
|
+
import { extendTemplateCategory } from '@formicoidea/labre-core/gfx/template';
|
|
3
|
+
import { CynefinRendererExtension } from './cynefin/element-renderer';
|
|
4
|
+
import { CynefinInteraction, CynefinView } from './cynefin/element-view';
|
|
5
|
+
import { cynefinToolbarExtension } from './cynefin/toolbar/config';
|
|
6
|
+
import { effects } from './effects';
|
|
7
|
+
import { EstuarineRendererExtension } from './estuarine/element-renderer';
|
|
8
|
+
import { EstuarineInteraction, EstuarineView } from './estuarine/element-view';
|
|
9
|
+
import { estuarineToolbarExtension } from './estuarine/toolbar/config';
|
|
10
|
+
import { cynefinTemplateCategory, estuarineTemplateCategory, } from './templates';
|
|
11
|
+
import { cynefinEstuarineSeniorTool } from './toolbar/senior-tool';
|
|
12
|
+
export class CynefinEstuarineViewExtension extends ViewExtensionProvider {
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
this.name = 'affine-cynefin-estuarine-gfx';
|
|
16
|
+
}
|
|
17
|
+
effect() {
|
|
18
|
+
super.effect();
|
|
19
|
+
effects();
|
|
20
|
+
extendTemplateCategory(cynefinTemplateCategory);
|
|
21
|
+
extendTemplateCategory(estuarineTemplateCategory);
|
|
22
|
+
}
|
|
23
|
+
setup(context) {
|
|
24
|
+
super.setup(context);
|
|
25
|
+
context.register(CynefinView);
|
|
26
|
+
context.register(CynefinRendererExtension);
|
|
27
|
+
context.register(EstuarineView);
|
|
28
|
+
context.register(EstuarineRendererExtension);
|
|
29
|
+
if (this.isEdgeless(context.scope)) {
|
|
30
|
+
context.register(CynefinInteraction);
|
|
31
|
+
context.register(EstuarineInteraction);
|
|
32
|
+
context.register(cynefinEstuarineSeniorTool);
|
|
33
|
+
context.register(cynefinToolbarExtension);
|
|
34
|
+
context.register(estuarineToolbarExtension);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
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.23.
|
|
4
|
+
"version": "0.23.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"author": "lajola",
|
|
@@ -10,15 +10,24 @@
|
|
|
10
10
|
],
|
|
11
11
|
"license": "MPL-2.0",
|
|
12
12
|
"exports": {
|
|
13
|
-
".":
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./view": {
|
|
18
|
+
"types": "./dist/view.d.ts",
|
|
19
|
+
"import": "./dist/view.js"
|
|
20
|
+
},
|
|
21
|
+
"./descriptor": {
|
|
22
|
+
"types": "./dist/descriptor.d.ts",
|
|
23
|
+
"import": "./dist/descriptor.js"
|
|
24
|
+
}
|
|
16
25
|
},
|
|
17
26
|
"files": [
|
|
18
|
-
"
|
|
27
|
+
"dist"
|
|
19
28
|
],
|
|
20
29
|
"dependencies": {
|
|
21
|
-
"@formicoidea/labre-core": "0.23.
|
|
30
|
+
"@formicoidea/labre-core": "0.23.3",
|
|
22
31
|
"lit": "^3.2.0"
|
|
23
32
|
}
|
|
24
33
|
}
|
package/src/cynefin/consts.ts
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Visual constants for the Liminal Cynefin diagram, reproduced from the official
|
|
3
|
-
* SVG (viewBox 0 0 1080 777). All geometry is authored in that fixed reference
|
|
4
|
-
* space and scaled uniformly to the element bounds by the renderer.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export const REF_W = 1080;
|
|
8
|
-
export const REF_H = 777;
|
|
9
|
-
|
|
10
|
-
export const COLORS = {
|
|
11
|
-
boundary: '#333333',
|
|
12
|
-
teal: '#2a9d99',
|
|
13
|
-
/** Domain headings + subheadings (h1 / h2). */
|
|
14
|
-
heading: '#6d6e71',
|
|
15
|
-
/** Body, small annotations and the big A / C glyphs. */
|
|
16
|
-
body: '#231f20',
|
|
17
|
-
} as const;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Dark boundary strokes drawn *behind* the teal "iterate" curve:
|
|
21
|
-
* [svg path, lineWidth, miterJoin].
|
|
22
|
-
*/
|
|
23
|
-
export const DARK_BACK_PATHS: ReadonlyArray<readonly [string, number, boolean]> = [
|
|
24
|
-
// Main arc: top segment (Complex|Complicated) then left segment (Complex|Chaotic)
|
|
25
|
-
['M 550.1 17 A 296 296 0 0 1 338 328.5 A 448.7 448.7 0 0 1 26 331', 15.5, false],
|
|
26
|
-
// Thin "Confusion" arc sweeping down towards the cliff
|
|
27
|
-
['M 649 294 C 644 382, 588 462, 440 506', 5, false],
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
/** Teal "iterate" curve, drawn *over* the back arcs and the dashed paving. */
|
|
31
|
-
export const TEAL_PATH =
|
|
32
|
-
'M 475.1 9.1 C 477.5 13.3, 484.4 26.1, 489.3 34.6 C 494.2 43.1, 499.7 51.7, 504.4 60.2 C 509.1 68.7, 513.4 77.2, 517.6 85.7 C 521.8 94.2, 525.7 102.7, 529.7 111.2 C 533.7 119.7, 538.1 128.3, 541.8 136.8 C 545.5 145.3, 549.0 153.8, 551.9 162.3 C 554.8 170.8, 557.1 179.3, 559.0 187.8 C 560.9 196.3, 562.0 204.8, 563.0 213.3 C 564.0 221.8, 564.8 230.4, 565.0 238.9 C 565.2 247.4, 565.0 255.9, 564.0 264.4 C 563.0 272.9, 561.2 281.4, 559.0 289.9 C 556.8 298.4, 554.6 307.0, 550.9 315.5 C 547.2 324.0, 542.3 332.5, 536.8 341.0 C 531.2 349.5, 524.9 358.3, 517.6 366.5 C 510.4 374.7, 501.6 383.0, 493.3 390.0 C 485.0 397.0, 476.4 403.1, 468.0 408.4 C 459.6 413.7, 451.2 418.0, 442.8 421.7 C 434.4 425.4, 425.9 427.4, 417.5 430.8 C 409.1 434.2, 400.3 437.5, 392.2 442.1 C 384.1 446.7, 377.1 455.5, 369.0 458.4 C 360.9 461.3, 352.1 459.4, 343.7 459.4 C 335.3 459.4, 326.9 459.1, 318.5 458.4 C 310.1 457.7, 301.6 456.8, 293.2 455.4 C 284.8 454.0, 276.4 452.2, 268.0 450.3 C 259.6 448.4, 251.1 446.2, 242.7 444.1 C 234.3 442.1, 225.8 440.0, 217.4 438.0 C 209.0 436.0, 200.6 434.4, 192.2 431.9 C 183.8 429.3, 175.3 426.1, 166.9 422.7 C 158.5 419.3, 150.0 415.5, 141.6 411.4 C 133.2 407.3, 124.8 403.3, 116.4 398.2 C 108.0 393.1, 99.5 386.9, 91.1 380.8 C 82.7 374.7, 74.3 368.7, 65.9 361.4 C 57.5 354.1, 45.7 342.8, 40.6 336.9 C 35.5 330.9, 36.4 327.6, 35.5 325.7';
|
|
33
|
-
export const TEAL_WIDTH = 10.5;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Dark boundary strokes drawn *over* the teal curve:
|
|
37
|
-
* [svg path, lineWidth, miterJoin].
|
|
38
|
-
*/
|
|
39
|
-
export const DARK_FRONT_PATHS: ReadonlyArray<readonly [string, number, boolean]> = [
|
|
40
|
-
// Thick descending branch with the bottom elbow (right edge of the cliff)
|
|
41
|
-
['M 340 332 C 390 440, 437 525, 472 632 Q 479 658, 453 700', 15.5, true],
|
|
42
|
-
// Thin left line (left edge of the cliff)
|
|
43
|
-
['M 345 356 C 372 440, 408 540, 413 655 C 414 685, 412 710, 412 738', 4, false],
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
/** Cliff hatching: [x1,y1,x2,y2], lineWidth 3. */
|
|
47
|
-
export const HATCHES: ReadonlyArray<readonly [number, number, number, number]> = [
|
|
48
|
-
[375, 420, 371, 431],
|
|
49
|
-
[386, 443, 380, 461],
|
|
50
|
-
[395, 462, 386, 483],
|
|
51
|
-
[402, 477, 392, 506],
|
|
52
|
-
[412, 497, 400, 539],
|
|
53
|
-
[417, 511, 403, 558],
|
|
54
|
-
[427, 533, 409, 591],
|
|
55
|
-
[435, 551, 411, 612],
|
|
56
|
-
[444, 573, 415, 659],
|
|
57
|
-
[455, 603, 415, 700],
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
/** Dashed Complicated↔Clear boundary, as oriented square pavings: [x,y,size,rotateDeg]. */
|
|
61
|
-
export const DASH_RECTS: ReadonlyArray<readonly [number, number, number, number]> = [
|
|
62
|
-
[511, 245, 13.8, 206.8], [530, 255.5, 13.7, 205.2], [549.5, 265.5, 13.6, 203.5],
|
|
63
|
-
[569.5, 274.5, 13.5, 201.9], [590, 282.5, 13.5, 200.2], [610.5, 289.5, 13.4, 198.6],
|
|
64
|
-
[631, 296, 13.3, 196.9], [673.5, 307, 13.2, 193.6], [695, 311.5, 13.1, 192.0],
|
|
65
|
-
[716, 315.5, 13.0, 190.3], [738, 319, 12.9, 188.7], [759.5, 322, 12.8, 187.0],
|
|
66
|
-
[781, 324.5, 12.8, 185.4], [803, 325.5, 12.7, 183.7], [824.5, 326.5, 12.6, 182.1],
|
|
67
|
-
[846, 327.5, 12.5, 180.5], [868, 327.5, 12.4, 178.8], [889.5, 326.5, 12.3, 177.2],
|
|
68
|
-
[912, 325.5, 12.2, 175.5], [933, 323.5, 12.1, 173.9], [954.5, 321.5, 12.1, 172.2],
|
|
69
|
-
[976, 318, 12.0, 170.6], [998, 314, 11.9, 168.9], [1019, 310, 11.8, 167.3],
|
|
70
|
-
];
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* The four domain blocks. Each has a heading (h1) and, when descriptions are
|
|
74
|
-
* shown, a subheading (h2) and three decision lines whose lead word is bold.
|
|
75
|
-
* All three text levels share the block's left `x`.
|
|
76
|
-
*/
|
|
77
|
-
export interface DomainBlock {
|
|
78
|
-
heading: string;
|
|
79
|
-
/** Left edge shared by heading, subheading and body lines. */
|
|
80
|
-
x: number;
|
|
81
|
-
/** Heading (h1) baseline. */
|
|
82
|
-
hy: number;
|
|
83
|
-
subheading: string;
|
|
84
|
-
/** Subheading (h2) baseline. */
|
|
85
|
-
sy: number;
|
|
86
|
-
/** Decision lines: bold lead word + remainder, with their baseline. */
|
|
87
|
-
lines: ReadonlyArray<{ lead: string; rest: string; y: number }>;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export const DOMAINS: ReadonlyArray<DomainBlock> = [
|
|
91
|
-
{
|
|
92
|
-
heading: 'Complex',
|
|
93
|
-
x: 37,
|
|
94
|
-
hy: 31,
|
|
95
|
-
subheading: 'Adaptive system',
|
|
96
|
-
sy: 53,
|
|
97
|
-
lines: [
|
|
98
|
-
{ lead: 'Probe', rest: ' the context with parallel experiments', y: 71 },
|
|
99
|
-
{ lead: 'Sense', rest: ' how the context reacts', y: 90 },
|
|
100
|
-
{ lead: 'Respond', rest: ' by amplifying positive experiments', y: 109 },
|
|
101
|
-
],
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
heading: 'Complicated',
|
|
105
|
-
x: 779,
|
|
106
|
-
hy: 31,
|
|
107
|
-
subheading: 'Ordered system',
|
|
108
|
-
sy: 53,
|
|
109
|
-
lines: [
|
|
110
|
-
{ lead: 'Sense', rest: ' the context with analytical methods', y: 71 },
|
|
111
|
-
{ lead: 'Analyse', rest: ' observations', y: 90 },
|
|
112
|
-
{ lead: 'Respond', rest: ' by applying one of many good solutions', y: 109 },
|
|
113
|
-
],
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
heading: 'Chaotic',
|
|
117
|
-
x: 37,
|
|
118
|
-
hy: 587,
|
|
119
|
-
subheading: 'Un-ordered system',
|
|
120
|
-
sy: 609,
|
|
121
|
-
lines: [
|
|
122
|
-
{ lead: 'Act', rest: ' on the context to stabilize (it or yourself)', y: 627 },
|
|
123
|
-
{ lead: 'Sense', rest: ' how the context reacts', y: 646 },
|
|
124
|
-
{ lead: 'Respond', rest: ' by re-acting', y: 665 },
|
|
125
|
-
],
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
heading: 'Clear',
|
|
129
|
-
x: 779,
|
|
130
|
-
hy: 587,
|
|
131
|
-
subheading: 'Ordered system',
|
|
132
|
-
sy: 609,
|
|
133
|
-
lines: [
|
|
134
|
-
{ lead: 'Sense', rest: ' the context with analytical methods', y: 627 },
|
|
135
|
-
{ lead: 'Categorize', rest: ' observations', y: 646 },
|
|
136
|
-
{ lead: 'Respond', rest: ' by applying tried and true practices', y: 665 },
|
|
137
|
-
],
|
|
138
|
-
},
|
|
139
|
-
];
|
|
140
|
-
|
|
141
|
-
/** Teal annotation labels (centered): [text, x, y]. */
|
|
142
|
-
export const TEAL_LABELS: ReadonlyArray<readonly [string, number, number]> = [
|
|
143
|
-
['iterate', 510, 16],
|
|
144
|
-
['iterate', 533, 230],
|
|
145
|
-
['strategy by design', 257, 225],
|
|
146
|
-
['radical innovation', 268, 390],
|
|
147
|
-
['by design', 268, 406],
|
|
148
|
-
['extreme repurposing', 217, 496],
|
|
149
|
-
['good practice', 814, 196],
|
|
150
|
-
['best practice', 751, 459],
|
|
151
|
-
];
|
|
152
|
-
|
|
153
|
-
/** Small exaptation sub-labels (centered): [text, x, y]. */
|
|
154
|
-
export const SMALL_LABELS: ReadonlyArray<readonly [string, number, number]> = [
|
|
155
|
-
['dispositional exaptation', 257, 239],
|
|
156
|
-
['stimulated exaptation', 268, 419],
|
|
157
|
-
['stress-based exaptation', 217, 510],
|
|
158
|
-
];
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* The two central markers — Aporia (A) and Confusion (C) — each a big glyph and
|
|
162
|
-
* a name, with an optional teal note ("prepare to exit"). All centered.
|
|
163
|
-
*/
|
|
164
|
-
export interface Marker {
|
|
165
|
-
letter: string;
|
|
166
|
-
/** Big glyph position. */
|
|
167
|
-
lx: number;
|
|
168
|
-
ly: number;
|
|
169
|
-
name: string;
|
|
170
|
-
/** Name (body) position. */
|
|
171
|
-
nx: number;
|
|
172
|
-
ny: number;
|
|
173
|
-
/** Optional teal note position + text. */
|
|
174
|
-
note?: { text: string; x: number; y: number };
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export const MARKERS: ReadonlyArray<Marker> = [
|
|
178
|
-
{
|
|
179
|
-
letter: 'A',
|
|
180
|
-
lx: 444,
|
|
181
|
-
ly: 334,
|
|
182
|
-
name: 'Aporia',
|
|
183
|
-
nx: 447,
|
|
184
|
-
ny: 349,
|
|
185
|
-
note: { text: 'prepare to exit', x: 449, y: 366 },
|
|
186
|
-
},
|
|
187
|
-
{ letter: 'C', lx: 531, ly: 419, name: 'Confusion', nx: 529, ny: 436 },
|
|
188
|
-
];
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type ElementRenderer,
|
|
3
|
-
ElementRendererExtension,
|
|
4
|
-
} from '@formicoidea/labre-core/blocks/surface';
|
|
5
|
-
import type { CynefinElementModel } from '@formicoidea/labre-core/model';
|
|
6
|
-
|
|
7
|
-
import { FONT_FAMILY, refScale } from '../utils';
|
|
8
|
-
import {
|
|
9
|
-
COLORS,
|
|
10
|
-
DARK_BACK_PATHS,
|
|
11
|
-
DARK_FRONT_PATHS,
|
|
12
|
-
DASH_RECTS,
|
|
13
|
-
DOMAINS,
|
|
14
|
-
HATCHES,
|
|
15
|
-
MARKERS,
|
|
16
|
-
REF_H,
|
|
17
|
-
REF_W,
|
|
18
|
-
SMALL_LABELS,
|
|
19
|
-
TEAL_LABELS,
|
|
20
|
-
TEAL_PATH,
|
|
21
|
-
TEAL_WIDTH,
|
|
22
|
-
} from './consts';
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Canvas renderer for the Liminal Cynefin diagram — reproduces the official SVG:
|
|
26
|
-
* the dark hand-drawn boundary, the teal "iterate" curve, the dashed
|
|
27
|
-
* Complicated↔Clear paving and the hatched cliff, plus the four domain blocks
|
|
28
|
-
* (heading + Probe/Sense/Respond decisions), the teal annotation labels and the
|
|
29
|
-
* central Aporia (A) / Confusion (C) markers. Drawn in the fixed reference space
|
|
30
|
-
* and scaled uniformly to the element bounds.
|
|
31
|
-
*/
|
|
32
|
-
export const cynefin: ElementRenderer<CynefinElementModel> = (
|
|
33
|
-
model,
|
|
34
|
-
ctx,
|
|
35
|
-
matrix
|
|
36
|
-
) => {
|
|
37
|
-
const [, , w, h] = model.deserializedXYWH;
|
|
38
|
-
const cx = w / 2;
|
|
39
|
-
const cy = h / 2;
|
|
40
|
-
ctx.setTransform(
|
|
41
|
-
matrix.translateSelf(cx, cy).rotateSelf(model.rotate).translateSelf(-cx, -cy)
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
const { s, ox, oy } = refScale(w, h, REF_W, REF_H);
|
|
45
|
-
ctx.translate(ox, oy);
|
|
46
|
-
ctx.scale(s, s);
|
|
47
|
-
|
|
48
|
-
ctx.lineCap = 'butt';
|
|
49
|
-
|
|
50
|
-
// ── Dark boundary strokes (behind the teal curve) ───────────────────
|
|
51
|
-
ctx.strokeStyle = COLORS.boundary;
|
|
52
|
-
for (const [d, lw, miter] of DARK_BACK_PATHS) {
|
|
53
|
-
ctx.lineJoin = miter ? 'miter' : 'round';
|
|
54
|
-
ctx.lineWidth = lw;
|
|
55
|
-
ctx.stroke(new Path2D(d));
|
|
56
|
-
}
|
|
57
|
-
ctx.lineJoin = 'round';
|
|
58
|
-
|
|
59
|
-
// ── Dashed boundary (oriented square pavings) ───────────────────────
|
|
60
|
-
ctx.fillStyle = COLORS.boundary;
|
|
61
|
-
for (const [x, y, sz, rot] of DASH_RECTS) {
|
|
62
|
-
ctx.save();
|
|
63
|
-
ctx.translate(x, y);
|
|
64
|
-
ctx.rotate((rot * Math.PI) / 180);
|
|
65
|
-
ctx.fillRect(-sz / 2, -sz / 2, sz, sz);
|
|
66
|
-
ctx.restore();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// ── Teal "iterate" liminal curve ────────────────────────────────────
|
|
70
|
-
if (model.showLiminalLine) {
|
|
71
|
-
ctx.strokeStyle = COLORS.teal;
|
|
72
|
-
ctx.lineWidth = TEAL_WIDTH;
|
|
73
|
-
ctx.stroke(new Path2D(TEAL_PATH));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ── Dark boundary strokes (over the teal curve) ─────────────────────
|
|
77
|
-
ctx.strokeStyle = COLORS.boundary;
|
|
78
|
-
for (const [d, lw, miter] of DARK_FRONT_PATHS) {
|
|
79
|
-
ctx.lineJoin = miter ? 'miter' : 'round';
|
|
80
|
-
ctx.lineWidth = lw;
|
|
81
|
-
ctx.stroke(new Path2D(d));
|
|
82
|
-
}
|
|
83
|
-
ctx.lineJoin = 'round';
|
|
84
|
-
|
|
85
|
-
// ── Cliff hatching ──────────────────────────────────────────────────
|
|
86
|
-
ctx.lineWidth = 3;
|
|
87
|
-
for (const [x1, y1, x2, y2] of HATCHES) {
|
|
88
|
-
ctx.beginPath();
|
|
89
|
-
ctx.moveTo(x1, y1);
|
|
90
|
-
ctx.lineTo(x2, y2);
|
|
91
|
-
ctx.stroke();
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
ctx.textBaseline = 'alphabetic';
|
|
95
|
-
|
|
96
|
-
// ── Titles: domain headings + A / C marker glyphs and names ─────────
|
|
97
|
-
if (model.showTitles) {
|
|
98
|
-
ctx.textAlign = 'left';
|
|
99
|
-
ctx.fillStyle = COLORS.heading;
|
|
100
|
-
ctx.font = `700 30px ${FONT_FAMILY}`;
|
|
101
|
-
for (const d of DOMAINS) ctx.fillText(d.heading, d.x, d.hy);
|
|
102
|
-
|
|
103
|
-
ctx.textAlign = 'center';
|
|
104
|
-
for (const m of MARKERS) {
|
|
105
|
-
ctx.fillStyle = COLORS.body;
|
|
106
|
-
ctx.font = `700 38px ${FONT_FAMILY}`;
|
|
107
|
-
ctx.fillText(m.letter, m.lx, m.ly);
|
|
108
|
-
ctx.font = `13.5px ${FONT_FAMILY}`;
|
|
109
|
-
ctx.fillText(m.name, m.nx, m.ny);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// ── Explanatory text: subheadings, decisions, annotations, notes ────
|
|
114
|
-
if (model.showDescriptions) {
|
|
115
|
-
// Subheadings (h2) + bold-lead decision lines
|
|
116
|
-
ctx.textAlign = 'left';
|
|
117
|
-
for (const d of DOMAINS) {
|
|
118
|
-
ctx.fillStyle = COLORS.heading;
|
|
119
|
-
ctx.font = `700 15px ${FONT_FAMILY}`;
|
|
120
|
-
ctx.fillText(d.subheading, d.x, d.sy);
|
|
121
|
-
|
|
122
|
-
ctx.fillStyle = COLORS.body;
|
|
123
|
-
for (const { lead, rest, y } of d.lines) {
|
|
124
|
-
ctx.font = `700 13.5px ${FONT_FAMILY}`;
|
|
125
|
-
ctx.fillText(lead, d.x, y);
|
|
126
|
-
const leadW = ctx.measureText(lead).width;
|
|
127
|
-
ctx.font = `13.5px ${FONT_FAMILY}`;
|
|
128
|
-
ctx.fillText(rest, d.x + leadW, y);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
ctx.textAlign = 'center';
|
|
133
|
-
|
|
134
|
-
// Teal annotation labels
|
|
135
|
-
ctx.fillStyle = COLORS.teal;
|
|
136
|
-
ctx.font = `700 15px ${FONT_FAMILY}`;
|
|
137
|
-
for (const [t, x, y] of TEAL_LABELS) ctx.fillText(t, x, y);
|
|
138
|
-
|
|
139
|
-
// Small exaptation sub-labels
|
|
140
|
-
ctx.fillStyle = COLORS.body;
|
|
141
|
-
ctx.font = `10.5px ${FONT_FAMILY}`;
|
|
142
|
-
for (const [t, x, y] of SMALL_LABELS) ctx.fillText(t, x, y);
|
|
143
|
-
|
|
144
|
-
// Marker notes ("prepare to exit")
|
|
145
|
-
ctx.fillStyle = COLORS.teal;
|
|
146
|
-
ctx.font = `700 15px ${FONT_FAMILY}`;
|
|
147
|
-
for (const m of MARKERS) {
|
|
148
|
-
if (m.note) ctx.fillText(m.note.text, m.note.x, m.note.y);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
export const CynefinRendererExtension = ElementRendererExtension(
|
|
154
|
-
'cynefin',
|
|
155
|
-
cynefin
|
|
156
|
-
);
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { CynefinElementModel } from '@formicoidea/labre-core/model';
|
|
2
|
-
import {
|
|
3
|
-
GfxElementModelView,
|
|
4
|
-
GfxViewInteractionExtension,
|
|
5
|
-
} from '@formicoidea/labre-core/std/gfx';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* View for the Cynefin background. Registering it ensures `gfx.view.get(model)`
|
|
9
|
-
* returns a view (required so move / select interactions work).
|
|
10
|
-
*/
|
|
11
|
-
export class CynefinView extends GfxElementModelView<CynefinElementModel> {
|
|
12
|
-
static override type: string = 'cynefin';
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Resize gating: the resize handles are hidden unless `model.resizeEnabled` is
|
|
17
|
-
* true (toggled from the toolbar). Moving / selecting stays available.
|
|
18
|
-
*/
|
|
19
|
-
export const CynefinInteraction = GfxViewInteractionExtension<CynefinView>(
|
|
20
|
-
CynefinView.type,
|
|
21
|
-
{
|
|
22
|
-
handleResize({ model }) {
|
|
23
|
-
return {
|
|
24
|
-
beforeResize({ set }) {
|
|
25
|
-
if (!model.resizeEnabled) {
|
|
26
|
-
set({ allowedHandlers: [] });
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
},
|
|
31
|
-
}
|
|
32
|
-
);
|