@elicdavis/node-flow 0.1.7 → 0.1.9
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/LICENSE +21 -0
- package/dist/index.d.mts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +143 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +141 -31
- package/dist/index.mjs.map +1 -1
- package/index.html +9 -0
- package/package.json +1 -1
- package/src/graph.ts +1 -1
- package/src/index.ts +2 -4
- package/src/node.ts +79 -1
- package/src/theme.ts +5 -0
- package/src/types/text.ts +53 -7
package/index.html
CHANGED
|
@@ -296,6 +296,15 @@ node.addOutput({ name: "sum", type: "float32" })
|
|
|
296
296
|
outputs: [
|
|
297
297
|
{ name: "sum", type: "float32", description: "The sum of all connected nodes to our 'numbers' port" }
|
|
298
298
|
],
|
|
299
|
+
messages: [
|
|
300
|
+
{
|
|
301
|
+
message: "I am a message attatched to the node"
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
message: "I am another message attatched to the node with type \"error\"",
|
|
305
|
+
type: "error"
|
|
306
|
+
}
|
|
307
|
+
],
|
|
299
308
|
});
|
|
300
309
|
|
|
301
310
|
graph.addNode(sumNode)
|
package/package.json
CHANGED
package/src/graph.ts
CHANGED
|
@@ -21,7 +21,7 @@ import { QuickMenu } from './quickMenu';
|
|
|
21
21
|
export type GraphRenderer = (canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, position: Vector2, scale: number) => void;
|
|
22
22
|
|
|
23
23
|
function BuildBackgroundRenderer(backgroundColor: string): GraphRenderer {
|
|
24
|
-
return (canvas: HTMLCanvasElement, context: CanvasRenderingContext2D, position: Vector2, scale: number) => {
|
|
24
|
+
return (canvas: HTMLCanvasElement, context: CanvasRenderingContext2D, position: Vector2, scale: number): void => {
|
|
25
25
|
context.fillStyle = backgroundColor;
|
|
26
26
|
context.fillRect(0, 0, canvas.width, canvas.height);
|
|
27
27
|
|
package/src/index.ts
CHANGED
package/src/node.ts
CHANGED
|
@@ -56,11 +56,39 @@ export interface FlowNodeStyle {
|
|
|
56
56
|
portText?: TextStyleConfig;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
export enum MessageType {
|
|
60
|
+
Info = "info",
|
|
61
|
+
Warning = "warning",
|
|
62
|
+
Error = "error"
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function MessageTypeColor(messageType: MessageType): string {
|
|
66
|
+
switch (messageType) {
|
|
67
|
+
case MessageType.Info:
|
|
68
|
+
return Theme.Node.Message.InfoColor;
|
|
69
|
+
|
|
70
|
+
case MessageType.Warning:
|
|
71
|
+
return Theme.Node.Message.WarnColor;
|
|
72
|
+
|
|
73
|
+
case MessageType.Error:
|
|
74
|
+
return Theme.Node.Message.ErrorColor;
|
|
75
|
+
|
|
76
|
+
default:
|
|
77
|
+
throw new Error(`unrecognized message type ${messageType}`)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface NodeMessageConfig {
|
|
82
|
+
message: string;
|
|
83
|
+
type?: MessageType;
|
|
84
|
+
}
|
|
85
|
+
|
|
59
86
|
export interface FlowNodeConfig {
|
|
60
87
|
position?: Vector2;
|
|
61
88
|
title?: string;
|
|
62
89
|
subTitle?: string;
|
|
63
90
|
info?: string;
|
|
91
|
+
messages?: Array<NodeMessageConfig>
|
|
64
92
|
locked?: boolean;
|
|
65
93
|
data?: Metadata;
|
|
66
94
|
contextMenu?: ContextMenuConfig;
|
|
@@ -111,6 +139,29 @@ export interface NodeIntersection {
|
|
|
111
139
|
|
|
112
140
|
}
|
|
113
141
|
|
|
142
|
+
class MessageRenderer {
|
|
143
|
+
|
|
144
|
+
#text: Text;
|
|
145
|
+
|
|
146
|
+
constructor(config: NodeMessageConfig) {
|
|
147
|
+
this.#text = new Text(config.message,
|
|
148
|
+
{
|
|
149
|
+
color: MessageTypeColor(config.type ? config.type : MessageType.Info),
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
LineSpacing: 2.5,
|
|
153
|
+
MaxWidth: 200
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
render(ctx: CanvasRenderingContext2D, scale: number, position: Vector2): number {
|
|
159
|
+
ctx.textAlign = TextAlign.Center;
|
|
160
|
+
this.#text.render(ctx, scale, position);
|
|
161
|
+
return this.#text.height(ctx) * scale;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
114
165
|
export class FlowNode {
|
|
115
166
|
|
|
116
167
|
#position: Vector2;
|
|
@@ -123,6 +174,8 @@ export class FlowNode {
|
|
|
123
174
|
|
|
124
175
|
#infoText: string;
|
|
125
176
|
|
|
177
|
+
#messages: Array<MessageRenderer>
|
|
178
|
+
|
|
126
179
|
#input: Array<Port>;
|
|
127
180
|
|
|
128
181
|
#output: Array<Port>;
|
|
@@ -203,6 +256,14 @@ export class FlowNode {
|
|
|
203
256
|
this.#contextMenu = config?.contextMenu === undefined ? null : config.contextMenu;
|
|
204
257
|
this.#metadata = config?.metadata;
|
|
205
258
|
|
|
259
|
+
this.#messages = [];
|
|
260
|
+
if (config?.messages) {
|
|
261
|
+
for (let i = 0; i < config.messages.length; i++) {
|
|
262
|
+
const message = config.messages[i];
|
|
263
|
+
this.#messages.push(new MessageRenderer(message));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
206
267
|
this.#selected = false;
|
|
207
268
|
this.#onSelect = new Array<() => void>();
|
|
208
269
|
this.#onUnselect = new Array<() => void>();
|
|
@@ -879,7 +940,6 @@ export class FlowNode {
|
|
|
879
940
|
console.warn("setInfo instruction ignored, as node has been marked un-editable");
|
|
880
941
|
}
|
|
881
942
|
|
|
882
|
-
|
|
883
943
|
let cleaned = newInfo;
|
|
884
944
|
if (cleaned === null || cleaned === undefined) {
|
|
885
945
|
cleaned = "";
|
|
@@ -935,6 +995,14 @@ export class FlowNode {
|
|
|
935
995
|
return boxStyle;
|
|
936
996
|
}
|
|
937
997
|
|
|
998
|
+
addMessage(message: NodeMessageConfig): void {
|
|
999
|
+
this.#messages.push(new MessageRenderer(message));
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
clearMessages(): void {
|
|
1003
|
+
this.#messages = [];
|
|
1004
|
+
}
|
|
1005
|
+
|
|
938
1006
|
render(ctx: CanvasRenderingContext2D, camera: Camera, state: NodeState, mousePosition: Vector2 | undefined, postProcess: PassSubsystem): void {
|
|
939
1007
|
VectorPool.run(() => {
|
|
940
1008
|
const tempMeasurement = VectorPool.get();
|
|
@@ -1113,6 +1181,7 @@ export class FlowNode {
|
|
|
1113
1181
|
startY += tempMeasurement.y + scaledElementSpacing;
|
|
1114
1182
|
}
|
|
1115
1183
|
|
|
1184
|
+
// Widgets
|
|
1116
1185
|
for (let i = 0; i < this.#widgets.length; i++) {
|
|
1117
1186
|
const widget = this.#widgets[i];
|
|
1118
1187
|
const widgetSize = widget.Size();
|
|
@@ -1125,6 +1194,15 @@ export class FlowNode {
|
|
|
1125
1194
|
this.#widgetPositions.Push(widget.Draw(ctx, position, camera.zoom, mousePosition));
|
|
1126
1195
|
startY += (widgetSize.y * camera.zoom) + scaledElementSpacing;
|
|
1127
1196
|
}
|
|
1197
|
+
|
|
1198
|
+
// Messages
|
|
1199
|
+
const messageStart = VectorPool.get();
|
|
1200
|
+
messageStart.x = nodeBounds.Position.x + (nodeBounds.Size.x / 2);
|
|
1201
|
+
messageStart.y = nodeBounds.Position.y + nodeBounds.Size.y + (15 * camera.zoom);
|
|
1202
|
+
for (let i = 0; i < this.#messages.length; i++) {
|
|
1203
|
+
const message = this.#messages[i];
|
|
1204
|
+
messageStart.y += message.render(ctx, camera.zoom, messageStart) + (10 * camera.zoom);
|
|
1205
|
+
}
|
|
1128
1206
|
})
|
|
1129
1207
|
}
|
|
1130
1208
|
}
|
package/src/theme.ts
CHANGED
package/src/types/text.ts
CHANGED
|
@@ -2,6 +2,11 @@ import { FontWeight, TextStyle, TextStyleConfig } from "../styles/text";
|
|
|
2
2
|
import { splitString, splitStringIntoLines } from "../utils/string";
|
|
3
3
|
import { CopyVector2, ScaleVector, Vector2, Zero } from "./vector2";
|
|
4
4
|
|
|
5
|
+
export interface MultilineTextConfig {
|
|
6
|
+
MaxWidth?: number;
|
|
7
|
+
LineSpacing?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
5
10
|
export class Text {
|
|
6
11
|
|
|
7
12
|
#measured: boolean
|
|
@@ -12,11 +17,20 @@ export class Text {
|
|
|
12
17
|
|
|
13
18
|
#value: string
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
#maxWidth: number;
|
|
21
|
+
|
|
22
|
+
#lineSpacing: number;
|
|
23
|
+
|
|
24
|
+
#textToRender: Array<string>;
|
|
25
|
+
|
|
26
|
+
constructor(value: string, style?: TextStyleConfig, config?: MultilineTextConfig) {
|
|
16
27
|
this.#value = value;
|
|
17
28
|
this.#measured = false;
|
|
18
29
|
this.#size = Zero();
|
|
19
30
|
this.#style = new TextStyle(style);
|
|
31
|
+
this.#maxWidth = config?.MaxWidth ? config?.MaxWidth : -1;
|
|
32
|
+
this.#lineSpacing = config?.LineSpacing ? config?.LineSpacing : 5;
|
|
33
|
+
this.#textToRender = [value];
|
|
20
34
|
|
|
21
35
|
if (!document.fonts.check(`16px "${this.#style.getFont()}"`)) {
|
|
22
36
|
document.fonts.addEventListener("loadingdone", (event) => {
|
|
@@ -96,10 +110,28 @@ export class Text {
|
|
|
96
110
|
return;
|
|
97
111
|
}
|
|
98
112
|
|
|
113
|
+
|
|
99
114
|
this.#style.setupStyle(ctx, 1);
|
|
100
|
-
|
|
101
|
-
this.#
|
|
102
|
-
|
|
115
|
+
|
|
116
|
+
if (this.#maxWidth == -1) {
|
|
117
|
+
const measurements = ctx.measureText(this.#value);
|
|
118
|
+
this.#size.x = measurements.width;
|
|
119
|
+
this.#size.y = measurements.actualBoundingBoxAscent + measurements.actualBoundingBoxDescent;
|
|
120
|
+
this.#textToRender = [this.#value];
|
|
121
|
+
this.#measured = true;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
this.#textToRender = splitStringIntoLines(ctx, this.#value, this.#maxWidth);
|
|
126
|
+
|
|
127
|
+
this.#size.x = 0;
|
|
128
|
+
this.#size.y = 0;
|
|
129
|
+
for (let i = 0; i < this.#textToRender.length; i++) {
|
|
130
|
+
const measurements = ctx.measureText(this.#textToRender[i]);
|
|
131
|
+
this.#size.x = Math.max(this.#size.x, measurements.width);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.#size.y += ((this.#textToRender.length - 1) * this.#lineSpacing) + (this.#style.getSize() * this.#textToRender.length);
|
|
103
135
|
this.#measured = true;
|
|
104
136
|
}
|
|
105
137
|
|
|
@@ -109,10 +141,15 @@ export class Text {
|
|
|
109
141
|
ScaleVector(out, scale);
|
|
110
142
|
}
|
|
111
143
|
|
|
144
|
+
height(ctx: CanvasRenderingContext2D): number {
|
|
145
|
+
this.#measure(ctx);
|
|
146
|
+
return this.#size.y;
|
|
147
|
+
}
|
|
148
|
+
|
|
112
149
|
setColor(color: string): void {
|
|
113
150
|
this.#style.setColor(color);
|
|
114
151
|
}
|
|
115
|
-
|
|
152
|
+
|
|
116
153
|
getColor(): string {
|
|
117
154
|
return this.#style.getColor();
|
|
118
155
|
}
|
|
@@ -126,8 +163,17 @@ export class Text {
|
|
|
126
163
|
}
|
|
127
164
|
|
|
128
165
|
render(ctx: CanvasRenderingContext2D, scale: number, position: Vector2): void {
|
|
129
|
-
this.#
|
|
130
|
-
|
|
166
|
+
this.#measure(ctx);
|
|
167
|
+
this.#style.setupStyle(ctx, scale);
|
|
168
|
+
let yOffset = 0;
|
|
169
|
+
for (let i = 0; i < this.#textToRender.length; i++) {
|
|
170
|
+
ctx.fillText(
|
|
171
|
+
this.#textToRender[i],
|
|
172
|
+
position.x,
|
|
173
|
+
position.y + yOffset
|
|
174
|
+
);
|
|
175
|
+
yOffset += (this.#style.getSize() + this.#lineSpacing) * scale
|
|
176
|
+
}
|
|
131
177
|
}
|
|
132
178
|
|
|
133
179
|
style(): TextStyle {
|