@formicoidea/labre-framework-edgy 0.23.0 → 0.23.2

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@formicoidea/labre-framework-edgy",
3
3
  "description": "Labre edgy framework for @formicoidea/labre-core.",
4
- "version": "0.23.0",
4
+ "version": "0.23.2",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "author": "lajola",
@@ -18,7 +18,7 @@
18
18
  "src"
19
19
  ],
20
20
  "dependencies": {
21
- "@formicoidea/labre-core": "0.23.0",
21
+ "@formicoidea/labre-core": "0.23.2",
22
22
  "lit": "^3.2.0"
23
23
  }
24
24
  }
@@ -1,208 +1,208 @@
1
- import {
2
- type ElementRenderer,
3
- ElementRendererExtension,
4
- } from '@formicoidea/labre-core/blocks/surface';
5
- import type { EdgyFacetsElementModel } from '@formicoidea/labre-core/model';
6
-
7
- import {
8
- COLORS,
9
- FONT_FAMILY,
10
- LABEL_FONT_SIZE,
11
- PICTO_STROKE,
12
- REF_H,
13
- REF_W,
14
- refScale,
15
- VENN,
16
- } from './consts';
17
- import { CIRCLE_A, CIRCLE_B, CIRCLE_C, facetLabelAnchors } from './label-layout';
18
-
19
- type Pt = { x: number; y: number };
20
-
21
- /**
22
- * Canvas renderer for the EDGY Enterprise Design Facets diagram — reproduces the
23
- * validated mockup: three overlapping circles (Identity / Architecture /
24
- * Experience), the three pairwise intersection regions (Organisation / Brand /
25
- * Product) painted by clip-intersection, the white centre, the six white
26
- * pictograms and the three facet labels placed outside the circles.
27
- *
28
- * The whole diagram is drawn in the fixed reference space and scaled uniformly
29
- * to the element bounds so the circles never distort.
30
- */
31
- export const edgy: ElementRenderer<EdgyFacetsElementModel> = (
32
- model,
33
- ctx,
34
- matrix
35
- ) => {
36
- const [, , w, h] = model.deserializedXYWH;
37
- const cx = w / 2;
38
- const cy = h / 2;
39
- ctx.setTransform(
40
- matrix.translateSelf(cx, cy).rotateSelf(model.rotate).translateSelf(-cx, -cy)
41
- );
42
-
43
- // Uniform fit of the reference design, centered (letterboxed).
44
- const { s, ox, oy } = refScale(w, h);
45
- ctx.translate(ox, oy);
46
- ctx.scale(s, s);
47
-
48
- const A = CIRCLE_A;
49
- const B = CIRCLE_B;
50
- const C = CIRCLE_C;
51
- const R = VENN.R;
52
-
53
- const disc = (c: Pt, color: string) => {
54
- ctx.beginPath();
55
- ctx.arc(c.x, c.y, R, 0, Math.PI * 2);
56
- ctx.fillStyle = color;
57
- ctx.fill();
58
- };
59
- // Paint the region common to every circle in `cs` (clip-intersection).
60
- const inter = (cs: Pt[], color: string) => {
61
- ctx.save();
62
- for (const c of cs) {
63
- ctx.beginPath();
64
- ctx.arc(c.x, c.y, R, 0, Math.PI * 2);
65
- ctx.clip();
66
- }
67
- ctx.fillStyle = color;
68
- ctx.fillRect(0, 0, REF_W, REF_H);
69
- ctx.restore();
70
- };
71
-
72
- // ── Facets + intersections ──────────────────────────────────────────
73
- disc(A, COLORS.identity);
74
- disc(B, COLORS.architecture);
75
- disc(C, COLORS.experience);
76
- inter([A, B], COLORS.organisation);
77
- inter([A, C], COLORS.brand);
78
- inter([B, C], COLORS.product);
79
- inter([A, B, C], COLORS.center);
80
-
81
- // White separating outlines.
82
- ctx.strokeStyle = COLORS.separator;
83
- ctx.lineWidth = 2.5;
84
- for (const c of [A, B, C]) {
85
- ctx.beginPath();
86
- ctx.arc(c.x, c.y, R, 0, Math.PI * 2);
87
- ctx.stroke();
88
- }
89
-
90
- // ── White pictos ────────────────────────────────────────────────────
91
- const pictoSetup = () => {
92
- ctx.strokeStyle = COLORS.picto;
93
- ctx.fillStyle = COLORS.picto;
94
- ctx.lineWidth = PICTO_STROKE;
95
- ctx.lineJoin = 'round';
96
- ctx.lineCap = 'round';
97
- };
98
- const lens = (x: number, y: number) => {
99
- pictoSetup();
100
- ctx.beginPath();
101
- ctx.arc(x, y, 10, 0, Math.PI * 2);
102
- ctx.stroke();
103
- ctx.beginPath();
104
- ctx.moveTo(x + 7, y + 7);
105
- ctx.lineTo(x + 15, y + 15);
106
- ctx.stroke();
107
- };
108
- const house = (x: number, y: number) => {
109
- pictoSetup();
110
- ctx.beginPath();
111
- ctx.moveTo(x - 11, y + 9);
112
- ctx.lineTo(x - 11, y - 2);
113
- ctx.lineTo(x, y - 11);
114
- ctx.lineTo(x + 11, y - 2);
115
- ctx.lineTo(x + 11, y + 9);
116
- ctx.closePath();
117
- ctx.stroke();
118
- };
119
- const heart = (x: number, y: number) => {
120
- pictoSetup();
121
- ctx.beginPath();
122
- ctx.moveTo(x, y + 11);
123
- ctx.bezierCurveTo(x - 14, y - 1, x - 9, y - 12, x, y - 4);
124
- ctx.bezierCurveTo(x + 9, y - 12, x + 14, y - 1, x, y + 11);
125
- ctx.closePath();
126
- ctx.stroke();
127
- };
128
- const network = (x: number, y: number) => {
129
- pictoSetup();
130
- ctx.beginPath();
131
- ctx.moveTo(x, y - 9);
132
- ctx.lineTo(x - 9, y + 7);
133
- ctx.lineTo(x + 9, y + 7);
134
- ctx.closePath();
135
- ctx.stroke();
136
- for (const [px, py] of [
137
- [x, y - 9],
138
- [x - 9, y + 7],
139
- [x + 9, y + 7],
140
- ]) {
141
- ctx.beginPath();
142
- ctx.arc(px, py, 2.6, 0, Math.PI * 2);
143
- ctx.fill();
144
- }
145
- };
146
- const sun = (x: number, y: number) => {
147
- pictoSetup();
148
- ctx.beginPath();
149
- ctx.arc(x, y, 6, 0, Math.PI * 2);
150
- ctx.stroke();
151
- for (let i = 0; i < 8; i++) {
152
- const a = (i * Math.PI) / 4;
153
- ctx.beginPath();
154
- ctx.moveTo(x + Math.cos(a) * 9, y + Math.sin(a) * 9);
155
- ctx.lineTo(x + Math.cos(a) * 12, y + Math.sin(a) * 12);
156
- ctx.stroke();
157
- }
158
- };
159
- const cube = (x: number, y: number) => {
160
- pictoSetup();
161
- const p = [
162
- [x, y - 11],
163
- [x + 10, y - 5],
164
- [x + 10, y + 6],
165
- [x, y + 12],
166
- [x - 10, y + 6],
167
- [x - 10, y - 5],
168
- ];
169
- ctx.beginPath();
170
- p.forEach(([qx, qy], i) => (i ? ctx.lineTo(qx, qy) : ctx.moveTo(qx, qy)));
171
- ctx.closePath();
172
- ctx.stroke();
173
- ctx.beginPath();
174
- ctx.moveTo(x - 10, y - 5);
175
- ctx.lineTo(x, y + 1);
176
- ctx.lineTo(x + 10, y - 5);
177
- ctx.moveTo(x, y + 1);
178
- ctx.lineTo(x, y + 12);
179
- ctx.stroke();
180
- };
181
-
182
- // Single-facet zone pictos.
183
- lens(A.x - 30, A.y - 22);
184
- house(B.x + 30, B.y - 22);
185
- heart(C.x, C.y + 36);
186
- // Intersection pictos at the validated sweet spots.
187
- network(VENN.cx, 114);
188
- sun(VENN.cx - 58, 206);
189
- cube(VENN.cx + 58, 206);
190
-
191
- // ── Labels (outside the circles) ────────────────────────────────────
192
- if (model.showLabels) {
193
- ctx.font = `500 ${LABEL_FONT_SIZE}px ${FONT_FAMILY}`;
194
- ctx.textBaseline = 'middle';
195
- const colorByField: Record<string, string> = {
196
- identityLabel: COLORS.identity,
197
- architectureLabel: COLORS.architecture,
198
- experienceLabel: COLORS.experience,
199
- };
200
- for (const { field, text, x, y, align } of facetLabelAnchors(model)) {
201
- ctx.fillStyle = colorByField[field];
202
- ctx.textAlign = align;
203
- ctx.fillText(text, x, y);
204
- }
205
- }
206
- };
207
-
208
- export const EdgyFacetsRendererExtension = ElementRendererExtension('edgy', edgy);
1
+ import {
2
+ type ElementRenderer,
3
+ ElementRendererExtension,
4
+ } from '@formicoidea/labre-core/blocks/surface';
5
+ import type { EdgyFacetsElementModel } from '@formicoidea/labre-core/model';
6
+
7
+ import {
8
+ COLORS,
9
+ FONT_FAMILY,
10
+ LABEL_FONT_SIZE,
11
+ PICTO_STROKE,
12
+ REF_H,
13
+ REF_W,
14
+ refScale,
15
+ VENN,
16
+ } from './consts';
17
+ import { CIRCLE_A, CIRCLE_B, CIRCLE_C, facetLabelAnchors } from './label-layout';
18
+
19
+ type Pt = { x: number; y: number };
20
+
21
+ /**
22
+ * Canvas renderer for the EDGY Enterprise Design Facets diagram — reproduces the
23
+ * validated mockup: three overlapping circles (Identity / Architecture /
24
+ * Experience), the three pairwise intersection regions (Organisation / Brand /
25
+ * Product) painted by clip-intersection, the white centre, the six white
26
+ * pictograms and the three facet labels placed outside the circles.
27
+ *
28
+ * The whole diagram is drawn in the fixed reference space and scaled uniformly
29
+ * to the element bounds so the circles never distort.
30
+ */
31
+ export const edgy: ElementRenderer<EdgyFacetsElementModel> = (
32
+ model,
33
+ ctx,
34
+ matrix
35
+ ) => {
36
+ const [, , w, h] = model.deserializedXYWH;
37
+ const cx = w / 2;
38
+ const cy = h / 2;
39
+ ctx.setTransform(
40
+ matrix.translateSelf(cx, cy).rotateSelf(model.rotate).translateSelf(-cx, -cy)
41
+ );
42
+
43
+ // Uniform fit of the reference design, centered (letterboxed).
44
+ const { s, ox, oy } = refScale(w, h);
45
+ ctx.translate(ox, oy);
46
+ ctx.scale(s, s);
47
+
48
+ const A = CIRCLE_A;
49
+ const B = CIRCLE_B;
50
+ const C = CIRCLE_C;
51
+ const R = VENN.R;
52
+
53
+ const disc = (c: Pt, color: string) => {
54
+ ctx.beginPath();
55
+ ctx.arc(c.x, c.y, R, 0, Math.PI * 2);
56
+ ctx.fillStyle = color;
57
+ ctx.fill();
58
+ };
59
+ // Paint the region common to every circle in `cs` (clip-intersection).
60
+ const inter = (cs: Pt[], color: string) => {
61
+ ctx.save();
62
+ for (const c of cs) {
63
+ ctx.beginPath();
64
+ ctx.arc(c.x, c.y, R, 0, Math.PI * 2);
65
+ ctx.clip();
66
+ }
67
+ ctx.fillStyle = color;
68
+ ctx.fillRect(0, 0, REF_W, REF_H);
69
+ ctx.restore();
70
+ };
71
+
72
+ // ── Facets + intersections ──────────────────────────────────────────
73
+ disc(A, COLORS.identity);
74
+ disc(B, COLORS.architecture);
75
+ disc(C, COLORS.experience);
76
+ inter([A, B], COLORS.organisation);
77
+ inter([A, C], COLORS.brand);
78
+ inter([B, C], COLORS.product);
79
+ inter([A, B, C], COLORS.center);
80
+
81
+ // White separating outlines.
82
+ ctx.strokeStyle = COLORS.separator;
83
+ ctx.lineWidth = 2.5;
84
+ for (const c of [A, B, C]) {
85
+ ctx.beginPath();
86
+ ctx.arc(c.x, c.y, R, 0, Math.PI * 2);
87
+ ctx.stroke();
88
+ }
89
+
90
+ // ── White pictos ────────────────────────────────────────────────────
91
+ const pictoSetup = () => {
92
+ ctx.strokeStyle = COLORS.picto;
93
+ ctx.fillStyle = COLORS.picto;
94
+ ctx.lineWidth = PICTO_STROKE;
95
+ ctx.lineJoin = 'round';
96
+ ctx.lineCap = 'round';
97
+ };
98
+ const lens = (x: number, y: number) => {
99
+ pictoSetup();
100
+ ctx.beginPath();
101
+ ctx.arc(x, y, 10, 0, Math.PI * 2);
102
+ ctx.stroke();
103
+ ctx.beginPath();
104
+ ctx.moveTo(x + 7, y + 7);
105
+ ctx.lineTo(x + 15, y + 15);
106
+ ctx.stroke();
107
+ };
108
+ const house = (x: number, y: number) => {
109
+ pictoSetup();
110
+ ctx.beginPath();
111
+ ctx.moveTo(x - 11, y + 9);
112
+ ctx.lineTo(x - 11, y - 2);
113
+ ctx.lineTo(x, y - 11);
114
+ ctx.lineTo(x + 11, y - 2);
115
+ ctx.lineTo(x + 11, y + 9);
116
+ ctx.closePath();
117
+ ctx.stroke();
118
+ };
119
+ const heart = (x: number, y: number) => {
120
+ pictoSetup();
121
+ ctx.beginPath();
122
+ ctx.moveTo(x, y + 11);
123
+ ctx.bezierCurveTo(x - 14, y - 1, x - 9, y - 12, x, y - 4);
124
+ ctx.bezierCurveTo(x + 9, y - 12, x + 14, y - 1, x, y + 11);
125
+ ctx.closePath();
126
+ ctx.stroke();
127
+ };
128
+ const network = (x: number, y: number) => {
129
+ pictoSetup();
130
+ ctx.beginPath();
131
+ ctx.moveTo(x, y - 9);
132
+ ctx.lineTo(x - 9, y + 7);
133
+ ctx.lineTo(x + 9, y + 7);
134
+ ctx.closePath();
135
+ ctx.stroke();
136
+ for (const [px, py] of [
137
+ [x, y - 9],
138
+ [x - 9, y + 7],
139
+ [x + 9, y + 7],
140
+ ]) {
141
+ ctx.beginPath();
142
+ ctx.arc(px, py, 2.6, 0, Math.PI * 2);
143
+ ctx.fill();
144
+ }
145
+ };
146
+ const sun = (x: number, y: number) => {
147
+ pictoSetup();
148
+ ctx.beginPath();
149
+ ctx.arc(x, y, 6, 0, Math.PI * 2);
150
+ ctx.stroke();
151
+ for (let i = 0; i < 8; i++) {
152
+ const a = (i * Math.PI) / 4;
153
+ ctx.beginPath();
154
+ ctx.moveTo(x + Math.cos(a) * 9, y + Math.sin(a) * 9);
155
+ ctx.lineTo(x + Math.cos(a) * 12, y + Math.sin(a) * 12);
156
+ ctx.stroke();
157
+ }
158
+ };
159
+ const cube = (x: number, y: number) => {
160
+ pictoSetup();
161
+ const p = [
162
+ [x, y - 11],
163
+ [x + 10, y - 5],
164
+ [x + 10, y + 6],
165
+ [x, y + 12],
166
+ [x - 10, y + 6],
167
+ [x - 10, y - 5],
168
+ ];
169
+ ctx.beginPath();
170
+ p.forEach(([qx, qy], i) => (i ? ctx.lineTo(qx, qy) : ctx.moveTo(qx, qy)));
171
+ ctx.closePath();
172
+ ctx.stroke();
173
+ ctx.beginPath();
174
+ ctx.moveTo(x - 10, y - 5);
175
+ ctx.lineTo(x, y + 1);
176
+ ctx.lineTo(x + 10, y - 5);
177
+ ctx.moveTo(x, y + 1);
178
+ ctx.lineTo(x, y + 12);
179
+ ctx.stroke();
180
+ };
181
+
182
+ // Single-facet zone pictos.
183
+ lens(A.x - 30, A.y - 22);
184
+ house(B.x + 30, B.y - 22);
185
+ heart(C.x, C.y + 36);
186
+ // Intersection pictos at the validated sweet spots.
187
+ network(VENN.cx, 114);
188
+ sun(VENN.cx - 58, 206);
189
+ cube(VENN.cx + 58, 206);
190
+
191
+ // ── Labels (outside the circles) ────────────────────────────────────
192
+ if (model.showLabels) {
193
+ ctx.font = `500 ${LABEL_FONT_SIZE}px ${FONT_FAMILY}`;
194
+ ctx.textBaseline = 'middle';
195
+ const colorByField: Record<string, string> = {
196
+ identityLabel: COLORS.identity,
197
+ architectureLabel: COLORS.architecture,
198
+ experienceLabel: COLORS.experience,
199
+ };
200
+ for (const { field, text, x, y, align } of facetLabelAnchors(model)) {
201
+ ctx.fillStyle = colorByField[field];
202
+ ctx.textAlign = align;
203
+ ctx.fillText(text, x, y);
204
+ }
205
+ }
206
+ };
207
+
208
+ export const EdgyFacetsRendererExtension = ElementRendererExtension('edgy', edgy);