@formicoidea/labre-framework-wardley 0.23.1 → 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 +6 -15
- package/{dist/consts.js → src/consts.ts} +72 -63
- package/{dist/descriptor.js → src/descriptor.ts} +1 -1
- package/src/effects.ts +17 -0
- package/src/element-renderer.ts +242 -0
- package/src/element-view.ts +143 -0
- package/src/gradient.ts +137 -0
- package/src/index.ts +1 -0
- package/src/label-layout.ts +126 -0
- package/src/legend.ts +438 -0
- package/{dist/node/consts.js → src/node/consts.ts} +109 -101
- package/src/node/node-renderer.ts +142 -0
- package/{dist/node/node-view.d.ts → src/node/node-view.ts} +11 -11
- package/src/templates/index.ts +236 -0
- package/src/templates/maps.ts +283 -0
- package/src/toolbar/config.ts +280 -0
- package/{dist/toolbar/icons.js → src/toolbar/icons.ts} +66 -51
- package/{dist/toolbar/node-config.js → src/toolbar/node-config.ts} +28 -21
- package/{dist/toolbar/senior-tool.js → src/toolbar/senior-tool.ts} +11 -11
- package/src/toolbar/wardley-menu.ts +552 -0
- package/src/toolbar/wardley-senior-button.ts +154 -0
- package/src/view.ts +39 -0
- package/dist/consts.d.ts +0 -72
- package/dist/descriptor.d.ts +0 -7
- package/dist/effects.d.ts +0 -10
- package/dist/effects.js +0 -7
- package/dist/element-renderer.d.ts +0 -15
- package/dist/element-renderer.js +0 -160
- package/dist/element-view.d.ts +0 -21
- package/dist/element-view.js +0 -122
- package/dist/gradient.d.ts +0 -18
- package/dist/gradient.js +0 -112
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -2
- package/dist/label-layout.d.ts +0 -21
- package/dist/label-layout.js +0 -73
- package/dist/legend.d.ts +0 -12
- package/dist/legend.js +0 -333
- package/dist/node/consts.d.ts +0 -107
- package/dist/node/label-editor.d.ts +0 -28
- package/dist/node/label-editor.js +0 -216
- package/dist/node/node-renderer.d.ts +0 -17
- package/dist/node/node-renderer.js +0 -106
- package/dist/node/node-view.js +0 -10
- package/dist/templates/index.d.ts +0 -3
- package/dist/templates/index.js +0 -172
- package/dist/templates/maps.d.ts +0 -3
- package/dist/templates/maps.js +0 -247
- package/dist/toolbar/config.d.ts +0 -75
- package/dist/toolbar/config.js +0 -206
- package/dist/toolbar/icons.d.ts +0 -31
- package/dist/toolbar/node-config.d.ts +0 -2
- package/dist/toolbar/senior-tool.d.ts +0 -2
- package/dist/toolbar/wardley-menu.d.ts +0 -53
- package/dist/toolbar/wardley-menu.js +0 -408
- package/dist/toolbar/wardley-senior-button.d.ts +0 -18
- package/dist/toolbar/wardley-senior-button.js +0 -146
- package/dist/toolbar/wardley-tool-button.d.ts +0 -10
- package/dist/toolbar/wardley-tool-button.js +0 -123
- package/dist/view.d.ts +0 -7
- package/dist/view.js +0 -36
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
-
function accept(f) {
|
|
3
|
-
if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected");
|
|
4
|
-
return f;
|
|
5
|
-
}
|
|
6
|
-
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
7
|
-
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
8
|
-
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
9
|
-
var _, done = false;
|
|
10
|
-
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
11
|
-
var context = {};
|
|
12
|
-
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
13
|
-
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
14
|
-
context.addInitializer = function(f) {
|
|
15
|
-
if (done) throw new TypeError("Cannot add initializers after decoration has completed");
|
|
16
|
-
extraInitializers.push(accept(f || null));
|
|
17
|
-
};
|
|
18
|
-
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
19
|
-
if (kind === "accessor") {
|
|
20
|
-
if (result === void 0) continue;
|
|
21
|
-
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
22
|
-
if (_ = accept(result.get)) descriptor.get = _;
|
|
23
|
-
if (_ = accept(result.set)) descriptor.set = _;
|
|
24
|
-
if (_ = accept(result.init)) initializers.unshift(_);
|
|
25
|
-
} else if (_ = accept(result)) {
|
|
26
|
-
if (kind === "field") initializers.unshift(_);
|
|
27
|
-
else descriptor[key] = _;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
31
|
-
done = true;
|
|
32
|
-
};
|
|
33
|
-
var __runInitializers = function(thisArg, initializers, value) {
|
|
34
|
-
var useValue = arguments.length > 2;
|
|
35
|
-
for (var i = 0; i < initializers.length; i++) {
|
|
36
|
-
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
37
|
-
}
|
|
38
|
-
return useValue ? value : void 0;
|
|
39
|
-
};
|
|
40
|
-
import { DefaultTool, EdgelessCRUDIdentifier, TextUtils } from "@blocksuite/affine-block-surface";
|
|
41
|
-
import { WardleyNodeElementModel } from "@blocksuite/affine-model";
|
|
42
|
-
import { BlockSuiteError, ErrorCode } from "@blocksuite/global/exceptions";
|
|
43
|
-
import { WithDisposable } from "@blocksuite/global/lit";
|
|
44
|
-
import { ShadowlessElement, stdContext } from "@blocksuite/std";
|
|
45
|
-
import { GfxControllerIdentifier } from "@blocksuite/std/gfx";
|
|
46
|
-
import { RANGE_SYNC_EXCLUDE_ATTR } from "@blocksuite/std/inline";
|
|
47
|
-
import { consume } from "@lit/context";
|
|
48
|
-
import { html, nothing } from "lit";
|
|
49
|
-
import { property, query } from "lit/decorators.js";
|
|
50
|
-
import { styleMap } from "lit/directives/style-map.js";
|
|
51
|
-
import * as Y from "yjs";
|
|
52
|
-
import { LABEL } from "./consts";
|
|
53
|
-
export function mountWardleyNodeLabelEditor(node, edgeless) {
|
|
54
|
-
const mountElm = edgeless.querySelector(".edgeless-mount-point");
|
|
55
|
-
if (!mountElm) {
|
|
56
|
-
throw new BlockSuiteError(ErrorCode.ValueNotExists, "edgeless block's mount point does not exist");
|
|
57
|
-
}
|
|
58
|
-
const gfx = edgeless.std.get(GfxControllerIdentifier);
|
|
59
|
-
const crud = edgeless.std.get(EdgelessCRUDIdentifier);
|
|
60
|
-
const updated = crud.getElementById(node.id);
|
|
61
|
-
if (!(updated instanceof WardleyNodeElementModel)) {
|
|
62
|
-
console.error("Cannot mount label editor on a non-wardley-node element");
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
gfx.tool.setTool(DefaultTool);
|
|
66
|
-
gfx.selection.set({ elements: [node.id], editing: true });
|
|
67
|
-
if (!node.text) {
|
|
68
|
-
crud.updateElement(node.id, { text: new Y.Text() });
|
|
69
|
-
}
|
|
70
|
-
const editor = new EdgelessWardleyNodeLabelEditor();
|
|
71
|
-
editor.element = crud.getElementById(node.id);
|
|
72
|
-
mountElm.append(editor);
|
|
73
|
-
}
|
|
74
|
-
let EdgelessWardleyNodeLabelEditor = (() => {
|
|
75
|
-
let _classSuper = WithDisposable(ShadowlessElement);
|
|
76
|
-
let _element_decorators;
|
|
77
|
-
let _element_initializers = [];
|
|
78
|
-
let _element_extraInitializers = [];
|
|
79
|
-
let _std_decorators;
|
|
80
|
-
let _std_initializers = [];
|
|
81
|
-
let _std_extraInitializers = [];
|
|
82
|
-
let _richText_decorators;
|
|
83
|
-
let _richText_initializers = [];
|
|
84
|
-
let _richText_extraInitializers = [];
|
|
85
|
-
return class EdgelessWardleyNodeLabelEditor extends _classSuper {
|
|
86
|
-
static {
|
|
87
|
-
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
88
|
-
_element_decorators = [property({ attribute: false })];
|
|
89
|
-
_std_decorators = [consume({ context: stdContext })];
|
|
90
|
-
_richText_decorators = [query("rich-text")];
|
|
91
|
-
__esDecorate(this, null, _element_decorators, { kind: "accessor", name: "element", static: false, private: false, access: { has: (obj) => "element" in obj, get: (obj) => obj.element, set: (obj, value) => {
|
|
92
|
-
obj.element = value;
|
|
93
|
-
} }, metadata: _metadata }, _element_initializers, _element_extraInitializers);
|
|
94
|
-
__esDecorate(this, null, _std_decorators, { kind: "accessor", name: "std", static: false, private: false, access: { has: (obj) => "std" in obj, get: (obj) => obj.std, set: (obj, value) => {
|
|
95
|
-
obj.std = value;
|
|
96
|
-
} }, metadata: _metadata }, _std_initializers, _std_extraInitializers);
|
|
97
|
-
__esDecorate(this, null, _richText_decorators, { kind: "accessor", name: "richText", static: false, private: false, access: { has: (obj) => "richText" in obj, get: (obj) => obj.richText, set: (obj, value) => {
|
|
98
|
-
obj.richText = value;
|
|
99
|
-
} }, metadata: _metadata }, _richText_initializers, _richText_extraInitializers);
|
|
100
|
-
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
101
|
-
}
|
|
102
|
-
get inlineEditor() {
|
|
103
|
-
return this.richText.inlineEditor;
|
|
104
|
-
}
|
|
105
|
-
get crud() {
|
|
106
|
-
return this.std.get(EdgelessCRUDIdentifier);
|
|
107
|
-
}
|
|
108
|
-
get gfx() {
|
|
109
|
-
return this.std.get(GfxControllerIdentifier);
|
|
110
|
-
}
|
|
111
|
-
get selection() {
|
|
112
|
-
return this.gfx.selection;
|
|
113
|
-
}
|
|
114
|
-
get inlineEditorContainer() {
|
|
115
|
-
return this.inlineEditor?.rootElement;
|
|
116
|
-
}
|
|
117
|
-
_unmount() {
|
|
118
|
-
if (this.element.text) {
|
|
119
|
-
const text = this.element.text.toString();
|
|
120
|
-
const trimmed = text.trim();
|
|
121
|
-
if (trimmed.length === 0) {
|
|
122
|
-
this.crud.updateElement(this.element.id, { text: void 0 });
|
|
123
|
-
} else if (trimmed.length < text.length) {
|
|
124
|
-
this.crud.updateElement(this.element.id, {
|
|
125
|
-
text: new Y.Text(trimmed)
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
this.remove();
|
|
130
|
-
this.selection.set({ elements: [], editing: false });
|
|
131
|
-
}
|
|
132
|
-
connectedCallback() {
|
|
133
|
-
super.connectedCallback();
|
|
134
|
-
this.setAttribute(RANGE_SYNC_EXCLUDE_ATTR, "true");
|
|
135
|
-
}
|
|
136
|
-
firstUpdated() {
|
|
137
|
-
this.disposables.add(this.gfx.viewport.viewportUpdated.subscribe(() => this.requestUpdate()));
|
|
138
|
-
this.updateComplete.then(() => {
|
|
139
|
-
if (!this.inlineEditor)
|
|
140
|
-
return;
|
|
141
|
-
this.inlineEditor.focusEnd();
|
|
142
|
-
if (!this.inlineEditorContainer)
|
|
143
|
-
return;
|
|
144
|
-
this.disposables.addFromEvent(this.inlineEditorContainer, "blur", () => this._unmount());
|
|
145
|
-
}).catch(console.error);
|
|
146
|
-
this.disposables.addFromEvent(this, "keydown", (evt) => {
|
|
147
|
-
if (evt.key === "Escape") {
|
|
148
|
-
this.ownerDocument.activeElement?.blur();
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
async getUpdateComplete() {
|
|
153
|
-
const result = await super.getUpdateComplete();
|
|
154
|
-
await this.richText?.updateComplete;
|
|
155
|
-
return result;
|
|
156
|
-
}
|
|
157
|
-
render() {
|
|
158
|
-
if (!this.element.text)
|
|
159
|
-
return nothing;
|
|
160
|
-
const [, , w, h] = this.element.deserializedXYWH;
|
|
161
|
-
const R = Math.min(w, h) / 2;
|
|
162
|
-
const [ox, oy] = this.element.labelOffset ?? [0, 0];
|
|
163
|
-
const modelX = this.element.x + w / 2 + R + LABEL.gap + ox;
|
|
164
|
-
const modelY = this.element.y + h / 2 + oy - LABEL.font / 2;
|
|
165
|
-
const [x, y] = this.gfx.viewport.toViewCoord(modelX, modelY);
|
|
166
|
-
const zoom = this.gfx.viewport.zoom;
|
|
167
|
-
const style = styleMap({
|
|
168
|
-
position: "absolute",
|
|
169
|
-
left: `${x}px`,
|
|
170
|
-
top: `${y}px`,
|
|
171
|
-
minWidth: "8px",
|
|
172
|
-
fontSize: `${LABEL.font}px`,
|
|
173
|
-
fontFamily: TextUtils.wrapFontFamily(LABEL.family),
|
|
174
|
-
lineHeight: "normal",
|
|
175
|
-
color: LABEL.color,
|
|
176
|
-
outline: "none",
|
|
177
|
-
whiteSpace: "nowrap",
|
|
178
|
-
transform: `scale(${zoom}, ${zoom})`,
|
|
179
|
-
transformOrigin: "top left",
|
|
180
|
-
zIndex: "1"
|
|
181
|
-
});
|
|
182
|
-
return html`<rich-text
|
|
183
|
-
.yText=${this.element.text}
|
|
184
|
-
.enableFormat=${false}
|
|
185
|
-
.enableAutoScrollHorizontally=${false}
|
|
186
|
-
style=${style}
|
|
187
|
-
></rich-text>`;
|
|
188
|
-
}
|
|
189
|
-
#element = __runInitializers(this, _element_initializers, void 0);
|
|
190
|
-
get element() {
|
|
191
|
-
return this.#element;
|
|
192
|
-
}
|
|
193
|
-
set element(_) {
|
|
194
|
-
this.#element = _;
|
|
195
|
-
}
|
|
196
|
-
#std = (__runInitializers(this, _element_extraInitializers), __runInitializers(this, _std_initializers, void 0));
|
|
197
|
-
get std() {
|
|
198
|
-
return this.#std;
|
|
199
|
-
}
|
|
200
|
-
set std(_) {
|
|
201
|
-
this.#std = _;
|
|
202
|
-
}
|
|
203
|
-
#richText = (__runInitializers(this, _std_extraInitializers), __runInitializers(this, _richText_initializers, void 0));
|
|
204
|
-
get richText() {
|
|
205
|
-
return this.#richText;
|
|
206
|
-
}
|
|
207
|
-
set richText(_) {
|
|
208
|
-
this.#richText = _;
|
|
209
|
-
}
|
|
210
|
-
constructor() {
|
|
211
|
-
super(...arguments);
|
|
212
|
-
__runInitializers(this, _richText_extraInitializers);
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
})();
|
|
216
|
-
export { EdgelessWardleyNodeLabelEditor };
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { type ElementRenderer } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
-
import { type WardleyNodeElementModel } from '@formicoidea/labre-core/model';
|
|
3
|
-
/**
|
|
4
|
-
* Renderer for a Wardley node. The circle is drawn by REUSING the native shape
|
|
5
|
-
* renderer (so stroke width, colors and theme behave exactly like a native
|
|
6
|
-
* ellipse). On top of it, a glyph is drawn for two kinds:
|
|
7
|
-
* - `anchor` → an inscribed person (head + shoulders), clipped to the circle.
|
|
8
|
-
* - `ecosystem` → a double border at the rim + diagonal hatching confined to the
|
|
9
|
-
* inner donut + a hollow central circle.
|
|
10
|
-
* All glyph strokes use the model's (editable) stroke color; the white band and
|
|
11
|
-
* the hollow center come from the base fill, so colors stay editable.
|
|
12
|
-
*/
|
|
13
|
-
export declare const wardleyNode: ElementRenderer<WardleyNodeElementModel>;
|
|
14
|
-
export declare const WardleyNodeRendererExtension: import("@formicoidea/labre-core/store").ExtensionType & {
|
|
15
|
-
identifier: import("@formicoidea/labre-core/global/di").ServiceIdentifier<ElementRenderer<WardleyNodeElementModel>>;
|
|
16
|
-
};
|
|
17
|
-
//# sourceMappingURL=node-renderer.d.ts.map
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { ElementRendererExtension, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
-
import { shape as shapeRenderer } from '@formicoidea/labre-core/gfx/shape';
|
|
3
|
-
import { DefaultTheme } from '@formicoidea/labre-core/model';
|
|
4
|
-
import { ANCHOR, ECOSYSTEM, METHOD, NODE_FILL } from './consts';
|
|
5
|
-
/**
|
|
6
|
-
* Renderer for a Wardley node. The circle is drawn by REUSING the native shape
|
|
7
|
-
* renderer (so stroke width, colors and theme behave exactly like a native
|
|
8
|
-
* ellipse). On top of it, a glyph is drawn for two kinds:
|
|
9
|
-
* - `anchor` → an inscribed person (head + shoulders), clipped to the circle.
|
|
10
|
-
* - `ecosystem` → a double border at the rim + diagonal hatching confined to the
|
|
11
|
-
* inner donut + a hollow central circle.
|
|
12
|
-
* All glyph strokes use the model's (editable) stroke color; the white band and
|
|
13
|
-
* the hollow center come from the base fill, so colors stay editable.
|
|
14
|
-
*/
|
|
15
|
-
export const wardleyNode = (model, ctx, matrix, renderer, rc, bound) => {
|
|
16
|
-
const [, , w, h] = model.deserializedXYWH;
|
|
17
|
-
const cx = w / 2;
|
|
18
|
-
const cy = h / 2;
|
|
19
|
-
// Capture the element-local transform BEFORE the shape renderer mutates the
|
|
20
|
-
// matrix, so the glyph can be drawn in the same space afterwards.
|
|
21
|
-
const glyphMatrix = DOMMatrix.fromMatrix(matrix)
|
|
22
|
-
.translateSelf(cx, cy)
|
|
23
|
-
.rotateSelf(model.rotate)
|
|
24
|
-
.translateSelf(-cx, -cy);
|
|
25
|
-
// Native ellipse (fill / stroke / theme handled natively).
|
|
26
|
-
shapeRenderer(model, ctx, matrix, renderer, rc, bound);
|
|
27
|
-
if (model.kind !== 'anchor' &&
|
|
28
|
-
model.kind !== 'ecosystem' &&
|
|
29
|
-
model.kind !== 'method')
|
|
30
|
-
return;
|
|
31
|
-
const strokeWidth = model.strokeWidth || 1;
|
|
32
|
-
const R = Math.min(w, h) / 2 - strokeWidth / 2;
|
|
33
|
-
const color = renderer.getColorValue(model.strokeColor, DefaultTheme.shapeStrokeColor, true);
|
|
34
|
-
ctx.setTransform(glyphMatrix);
|
|
35
|
-
// ── Anchor: person glyph (clipped to the circle) ────────────────────
|
|
36
|
-
if (model.kind === 'anchor') {
|
|
37
|
-
ctx.save();
|
|
38
|
-
ctx.beginPath();
|
|
39
|
-
ctx.arc(cx, cy, R - strokeWidth / 2, 0, Math.PI * 2);
|
|
40
|
-
ctx.clip();
|
|
41
|
-
ctx.lineWidth = strokeWidth;
|
|
42
|
-
ctx.strokeStyle = color;
|
|
43
|
-
ctx.lineCap = 'round';
|
|
44
|
-
ctx.lineJoin = 'round';
|
|
45
|
-
// head
|
|
46
|
-
ctx.beginPath();
|
|
47
|
-
ctx.arc(cx, cy + ANCHOR.headCY * R, ANCHOR.headR * R, 0, Math.PI * 2);
|
|
48
|
-
ctx.stroke();
|
|
49
|
-
// rounded shoulders (extremities sit on the circle border)
|
|
50
|
-
const sx = ANCHOR.shoulderEndX * R;
|
|
51
|
-
const sy = ANCHOR.shoulderEndY * R;
|
|
52
|
-
const kx = ANCHOR.shoulderCtrlX * R;
|
|
53
|
-
const ky = ANCHOR.shoulderCtrlY * R;
|
|
54
|
-
ctx.beginPath();
|
|
55
|
-
ctx.moveTo(cx - sx, cy + sy);
|
|
56
|
-
ctx.bezierCurveTo(cx - kx, cy + ky, cx + kx, cy + ky, cx + sx, cy + sy);
|
|
57
|
-
ctx.stroke();
|
|
58
|
-
ctx.restore();
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
// ── Method: a white component inscribed in the colored outer circle ──
|
|
62
|
-
if (model.kind === 'method') {
|
|
63
|
-
const rInner = R * METHOD.centerRatio;
|
|
64
|
-
ctx.fillStyle = NODE_FILL;
|
|
65
|
-
ctx.lineWidth = strokeWidth;
|
|
66
|
-
ctx.strokeStyle = color;
|
|
67
|
-
ctx.beginPath();
|
|
68
|
-
ctx.arc(cx, cy, rInner, 0, Math.PI * 2);
|
|
69
|
-
ctx.fill();
|
|
70
|
-
ctx.stroke();
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
// ── Ecosystem: double border + hatched inner donut + hollow center ──
|
|
74
|
-
const rBorder2 = R * ECOSYSTEM.secondBorderRatio;
|
|
75
|
-
const rCenter = R * ECOSYSTEM.centerRatio;
|
|
76
|
-
const rHatch = R * ECOSYSTEM.hatchOuterRatio;
|
|
77
|
-
// Hatch confined to the donut [rCenter, rHatch] (even-odd clip = annulus).
|
|
78
|
-
ctx.save();
|
|
79
|
-
ctx.beginPath();
|
|
80
|
-
ctx.arc(cx, cy, rHatch, 0, Math.PI * 2);
|
|
81
|
-
ctx.moveTo(cx + rCenter, cy);
|
|
82
|
-
ctx.arc(cx, cy, rCenter, 0, Math.PI * 2);
|
|
83
|
-
ctx.clip('evenodd');
|
|
84
|
-
ctx.lineWidth = Math.max(0.5, strokeWidth * 0.6);
|
|
85
|
-
ctx.strokeStyle = color;
|
|
86
|
-
const step = R * ECOSYSTEM.hatchSpacingRatio;
|
|
87
|
-
for (let d = -2 * R; d <= 2 * R; d += step) {
|
|
88
|
-
ctx.beginPath();
|
|
89
|
-
ctx.moveTo(cx - R, cy - R + d);
|
|
90
|
-
ctx.lineTo(cx + R, cy + R + d);
|
|
91
|
-
ctx.stroke();
|
|
92
|
-
}
|
|
93
|
-
ctx.restore();
|
|
94
|
-
// Double border (2nd inscribed circle) + central hole border. No fill: the
|
|
95
|
-
// white band and hollow center come from the base ellipse fill.
|
|
96
|
-
ctx.lineWidth = strokeWidth;
|
|
97
|
-
ctx.strokeStyle = color;
|
|
98
|
-
ctx.beginPath();
|
|
99
|
-
ctx.arc(cx, cy, rBorder2, 0, Math.PI * 2);
|
|
100
|
-
ctx.stroke();
|
|
101
|
-
ctx.beginPath();
|
|
102
|
-
ctx.arc(cx, cy, rCenter, 0, Math.PI * 2);
|
|
103
|
-
ctx.stroke();
|
|
104
|
-
};
|
|
105
|
-
export const WardleyNodeRendererExtension = ElementRendererExtension('wardleyNode', wardleyNode);
|
|
106
|
-
//# sourceMappingURL=node-renderer.js.map
|
package/dist/node/node-view.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
|
|
2
|
-
/**
|
|
3
|
-
* View for a Wardley node. Registering it ensures `gfx.view.get(model)` returns
|
|
4
|
-
* a view (required so move / select / connector interactions work). The label
|
|
5
|
-
* is a separate native text element, so no custom editing is needed here.
|
|
6
|
-
*/
|
|
7
|
-
export class WardleyNodeView extends GfxElementModelView {
|
|
8
|
-
static { this.type = 'wardleyNode'; }
|
|
9
|
-
}
|
|
10
|
-
//# sourceMappingURL=node-view.js.map
|
package/dist/templates/index.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import { makeTemplateSnapshot, surfaceText, } from '@formicoidea/labre-core/gfx/template';
|
|
2
|
-
import { ConnectorMode, FontFamily, PointStyle, ShapeStyle, StrokeStyle, TextAlign, } from '@formicoidea/labre-core/model';
|
|
3
|
-
import { REF_WIDTH } from '../consts';
|
|
4
|
-
import { wardleyMaps } from './maps';
|
|
5
|
-
import { ECOSYSTEM_SIZE, HANDLE_SIZE, INERTIA_COLOR, INERTIA_SIZE, LABEL_FONT_SIZE, LINK_GREY, LINK_STROKE_WIDTH, MARKET_DOT_RING, MARKET_DOT_SIZE, MARKET_DOT_STROKE_WIDTH, MARKET_LINK_COLOR, MARKET_LINK_WIDTH, MARKET_SIZE, METHOD_FILL, METHOD_SIZE, NODE_FILL, NODE_SIZE, NODE_STROKE, NODE_STROKE_WIDTH, PIPELINE_FILL, PIPELINE_HEIGHT, PIPELINE_WIDTH, WARDLEY_RED, } from '../node/consts';
|
|
6
|
-
const VARIANT_DEFAULTS = {
|
|
7
|
-
classic: {},
|
|
8
|
-
opportunity: {
|
|
9
|
-
yAxisTitle: 'Opportunity',
|
|
10
|
-
showVisibilityLabels: false,
|
|
11
|
-
showCornerLabels: false,
|
|
12
|
-
},
|
|
13
|
-
benefit: {
|
|
14
|
-
yAxisTitle: '',
|
|
15
|
-
visibilityHigh: 'Benefit',
|
|
16
|
-
visibilityLow: 'Investment',
|
|
17
|
-
showCornerLabels: false,
|
|
18
|
-
},
|
|
19
|
-
'evolution-gradient': {},
|
|
20
|
-
};
|
|
21
|
-
const bg = (variant, w = REF_WIDTH) => {
|
|
22
|
-
const h = Math.round((w * 9) / 16);
|
|
23
|
-
return { type: 'wardley', variant, ...VARIANT_DEFAULTS[variant], xywh: `[0,0,${w},${h}]` };
|
|
24
|
-
};
|
|
25
|
-
/** A wardley node ellipse positioned by top-left. */
|
|
26
|
-
function node(kind, x, y, d = NODE_SIZE, fill = NODE_FILL, strokeWidth = NODE_STROKE_WIDTH) {
|
|
27
|
-
return {
|
|
28
|
-
type: 'wardleyNode',
|
|
29
|
-
kind,
|
|
30
|
-
shapeType: 'ellipse',
|
|
31
|
-
filled: true,
|
|
32
|
-
fillColor: fill,
|
|
33
|
-
strokeColor: NODE_STROKE,
|
|
34
|
-
strokeWidth,
|
|
35
|
-
shapeStyle: ShapeStyle.General,
|
|
36
|
-
roughness: 0,
|
|
37
|
-
xywh: `[${x},${y},${d},${d}]`,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
function label(x, y, str, align = 'left') {
|
|
41
|
-
return {
|
|
42
|
-
type: 'text',
|
|
43
|
-
text: surfaceText(str),
|
|
44
|
-
color: NODE_STROKE,
|
|
45
|
-
fontFamily: FontFamily.Inter,
|
|
46
|
-
fontSize: LABEL_FONT_SIZE,
|
|
47
|
-
textAlign: align === 'center' ? TextAlign.Center : TextAlign.Left,
|
|
48
|
-
xywh: `[${x},${y},140,26]`,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
function connect(source, target, opts = {}) {
|
|
52
|
-
return {
|
|
53
|
-
type: 'connector',
|
|
54
|
-
mode: ConnectorMode.Straight,
|
|
55
|
-
stroke: opts.red ? WARDLEY_RED : LINK_GREY,
|
|
56
|
-
strokeStyle: opts.red ? StrokeStyle.Dash : StrokeStyle.Solid,
|
|
57
|
-
strokeWidth: LINK_STROKE_WIDTH,
|
|
58
|
-
frontEndpointStyle: PointStyle.None,
|
|
59
|
-
rearEndpointStyle: opts.red ? PointStyle.Triangle : PointStyle.None,
|
|
60
|
-
source,
|
|
61
|
-
target,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
const inertia = (x = 0, y = 0) => ({
|
|
65
|
-
type: 'shape',
|
|
66
|
-
shapeType: 'rect',
|
|
67
|
-
filled: true,
|
|
68
|
-
fillColor: INERTIA_COLOR,
|
|
69
|
-
strokeColor: INERTIA_COLOR,
|
|
70
|
-
strokeWidth: 0,
|
|
71
|
-
shapeStyle: ShapeStyle.General,
|
|
72
|
-
roughness: 0,
|
|
73
|
-
radius: 0,
|
|
74
|
-
xywh: `[${x},${y},${INERTIA_SIZE.w},${INERTIA_SIZE.h}]`,
|
|
75
|
-
});
|
|
76
|
-
/** Pipeline composite: body rect + handle square (straddling top) + label. */
|
|
77
|
-
function pipeline() {
|
|
78
|
-
return {
|
|
79
|
-
label: label(0, 0, 'Pipeline', 'center'),
|
|
80
|
-
body: {
|
|
81
|
-
type: 'wardleyNode',
|
|
82
|
-
kind: 'pipeline',
|
|
83
|
-
shapeType: 'rect',
|
|
84
|
-
filled: true,
|
|
85
|
-
fillColor: PIPELINE_FILL,
|
|
86
|
-
strokeColor: NODE_STROKE,
|
|
87
|
-
strokeWidth: NODE_STROKE_WIDTH,
|
|
88
|
-
shapeStyle: ShapeStyle.General,
|
|
89
|
-
roughness: 0,
|
|
90
|
-
radius: 0,
|
|
91
|
-
xywh: `[0,39,${PIPELINE_WIDTH},${PIPELINE_HEIGHT}]`,
|
|
92
|
-
},
|
|
93
|
-
handle: {
|
|
94
|
-
type: 'wardleyNode',
|
|
95
|
-
kind: 'handle',
|
|
96
|
-
shapeType: 'rect',
|
|
97
|
-
filled: true,
|
|
98
|
-
fillColor: NODE_FILL,
|
|
99
|
-
strokeColor: NODE_STROKE,
|
|
100
|
-
strokeWidth: NODE_STROKE_WIDTH,
|
|
101
|
-
shapeStyle: ShapeStyle.General,
|
|
102
|
-
roughness: 0,
|
|
103
|
-
radius: 0,
|
|
104
|
-
xywh: `[${PIPELINE_WIDTH / 2 - HANDLE_SIZE / 2},${39 - HANDLE_SIZE / 2},${HANDLE_SIZE},${HANDLE_SIZE}]`,
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
/** Market composite: outer circle + 3 inner dots wired in a triangle + label. */
|
|
109
|
-
function market() {
|
|
110
|
-
const R = MARKET_SIZE / 2;
|
|
111
|
-
const c = R; // center within the [0,0,MARKET_SIZE,MARKET_SIZE] box
|
|
112
|
-
const rho = MARKET_DOT_RING;
|
|
113
|
-
const sin60 = Math.sqrt(3) / 2;
|
|
114
|
-
const verts = [
|
|
115
|
-
[0, -rho],
|
|
116
|
-
[rho * sin60, rho / 2],
|
|
117
|
-
[-rho * sin60, rho / 2],
|
|
118
|
-
];
|
|
119
|
-
const dotAt = (vx, vy) => node('component', c + vx - MARKET_DOT_SIZE / 2, c + vy - MARKET_DOT_SIZE / 2, MARKET_DOT_SIZE, NODE_FILL, MARKET_DOT_STROKE_WIDTH);
|
|
120
|
-
const tri = (a, b) => ({
|
|
121
|
-
type: 'connector',
|
|
122
|
-
mode: ConnectorMode.Straight,
|
|
123
|
-
stroke: MARKET_LINK_COLOR,
|
|
124
|
-
strokeStyle: StrokeStyle.Solid,
|
|
125
|
-
strokeWidth: MARKET_LINK_WIDTH,
|
|
126
|
-
frontEndpointStyle: PointStyle.None,
|
|
127
|
-
rearEndpointStyle: PointStyle.None,
|
|
128
|
-
source: { id: a },
|
|
129
|
-
target: { id: b },
|
|
130
|
-
});
|
|
131
|
-
return {
|
|
132
|
-
circle: node('market', 0, 0, MARKET_SIZE, NODE_FILL),
|
|
133
|
-
d0: dotAt(verts[0][0], verts[0][1]),
|
|
134
|
-
d1: dotAt(verts[1][0], verts[1][1]),
|
|
135
|
-
d2: dotAt(verts[2][0], verts[2][1]),
|
|
136
|
-
t0: tri('d0', 'd1'),
|
|
137
|
-
t1: tri('d1', 'd2'),
|
|
138
|
-
t2: tri('d2', 'd0'),
|
|
139
|
-
label: label(MARKET_SIZE + 8, 2, 'Market'),
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
const single = (el) => ({ a: el });
|
|
143
|
-
const nodeWithLabel = (kind, d, fill, name) => ({
|
|
144
|
-
n: node(kind, 0, 0, d, fill),
|
|
145
|
-
l: label(d + 8, d / 2 - 13, name),
|
|
146
|
-
});
|
|
147
|
-
const ATTRS = 'width="100%" height="100%" viewBox="0 0 135 80" xmlns="http://www.w3.org/2000/svg"';
|
|
148
|
-
const bgPreview = (extra = '') => `<svg ${ATTRS} fill="none"><path d="M22 12 V64 H120" stroke="#3b3d42" stroke-width="2"/><path d="M44 12 V64 M68 12 V64 M94 12 V64" stroke="#9aa0a6" stroke-width="0.8"/>${extra}</svg>`;
|
|
149
|
-
const dotPreview = (fill, sw = 2) => `<svg ${ATTRS} fill="none"><circle cx="67" cy="40" r="13" fill="${fill}" stroke="#1f2328" stroke-width="${sw}"/></svg>`;
|
|
150
|
-
function tpl(name, preview, elements) {
|
|
151
|
-
return { name, type: 'template', preview, content: makeTemplateSnapshot(elements, name) };
|
|
152
|
-
}
|
|
153
|
-
export const wardleyTemplateCategory = {
|
|
154
|
-
name: 'Wardley',
|
|
155
|
-
templates: [
|
|
156
|
-
...wardleyMaps,
|
|
157
|
-
tpl('Map background', bgPreview(), { bg: bg('classic') }),
|
|
158
|
-
tpl('Opportunity gradient', bgPreview('<rect x="22" y="12" width="98" height="52" fill="#eef4fb" opacity="0.6"/>'), { bg: bg('opportunity') }),
|
|
159
|
-
tpl('Benefit gradient', bgPreview('<rect x="22" y="12" width="98" height="26" fill="#e6eef8" opacity="0.6"/>'), { bg: bg('benefit') }),
|
|
160
|
-
tpl('Evolution gradient', bgPreview('<rect x="22" y="12" width="98" height="52" fill="#e3e2e4" opacity="0.5"/>'), { bg: bg('evolution-gradient') }),
|
|
161
|
-
tpl('Component', dotPreview('#ffffff', 1.5), nodeWithLabel('component', NODE_SIZE, NODE_FILL, 'Component')),
|
|
162
|
-
tpl('Anchor', `<svg ${ATTRS} fill="none"><circle cx="67" cy="40" r="13" fill="#fff" stroke="#1f2328" stroke-width="1.5"/><circle cx="67" cy="36" r="3.5" fill="#1f2328"/><path d="M59 48 q8 -9 16 0" stroke="#1f2328" stroke-width="1.5" fill="none"/></svg>`, nodeWithLabel('anchor', NODE_SIZE, NODE_FILL, 'Anchor')),
|
|
163
|
-
tpl('Ecosystem', `<svg ${ATTRS} fill="none"><circle cx="67" cy="40" r="15" fill="#fff" stroke="#1f2328" stroke-width="1.5"/><circle cx="67" cy="40" r="11" fill="none" stroke="#1f2328"/><circle cx="67" cy="40" r="5" fill="#fff" stroke="#1f2328"/></svg>`, nodeWithLabel('ecosystem', ECOSYSTEM_SIZE, NODE_FILL, 'Ecosystem')),
|
|
164
|
-
tpl('Method', `<svg ${ATTRS} fill="none"><circle cx="67" cy="40" r="15" fill="#d9d9d9" stroke="#1f2328" stroke-width="1.5"/><circle cx="67" cy="40" r="7" fill="#fff" stroke="#1f2328"/></svg>`, nodeWithLabel('method', METHOD_SIZE, METHOD_FILL, 'Component')),
|
|
165
|
-
tpl('Pipeline', `<svg ${ATTRS} fill="none"><rect x="34" y="40" width="66" height="14" fill="#fff" stroke="#1f2328"/><rect x="60" y="33" width="14" height="14" fill="#fff" stroke="#1f2328"/></svg>`, pipeline()),
|
|
166
|
-
tpl('Market', `<svg ${ATTRS} fill="none"><circle cx="67" cy="40" r="16" fill="#fff" stroke="#1f2328"/><circle cx="67" cy="30" r="3.5" fill="#fff" stroke="#1f2328" stroke-width="1.5"/><circle cx="75" cy="46" r="3.5" fill="#fff" stroke="#1f2328" stroke-width="1.5"/><circle cx="59" cy="46" r="3.5" fill="#fff" stroke="#1f2328" stroke-width="1.5"/><path d="M67 30 L75 46 L59 46 Z" stroke="#1f2328" stroke-width="0.8" fill="none"/></svg>`, market()),
|
|
167
|
-
tpl('Inertia', `<svg ${ATTRS} fill="none"><rect x="63" y="22" width="8" height="36" fill="#1f2328"/></svg>`, single(inertia())),
|
|
168
|
-
tpl('Link', `<svg ${ATTRS} fill="none"><path d="M24 40 H110" stroke="#666" stroke-width="2.4"/></svg>`, single(connect({ position: [0, 0] }, { position: [160, 0] }))),
|
|
169
|
-
tpl('Evolution arrow', `<svg ${ATTRS} fill="none"><path d="M24 40 H100" stroke="#d6455d" stroke-width="2.4" stroke-dasharray="6 4"/><path d="M98 33 L112 40 L98 47 Z" fill="#d6455d"/></svg>`, single(connect({ position: [0, 0] }, { position: [160, 0] }, { red: true }))),
|
|
170
|
-
],
|
|
171
|
-
};
|
|
172
|
-
//# sourceMappingURL=index.js.map
|
package/dist/templates/maps.d.ts
DELETED