Skip to content

Commit 765208d

Browse files
committed
image widget
1 parent 5194d75 commit 765208d

12 files changed

+184
-15
lines changed

esbuild.dev.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const buildOptsWeb: BuildOptions = {
2727
// format: 'cjs',
2828
bundle: true,
2929
sourcemap: true,
30-
minify: true,
30+
minify: false,
3131
treeShaking: true,
3232
plugins: [
3333
// NodeModulesPolyfillPlugin(),

index.html

+6-9
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,8 @@
3434
<canvas id="canvas"></canvas>
3535
<script>
3636
const canvas = document.getElementById("canvas");
37-
// function resizeCanvas() {
38-
// canvas.width = window.innerWidth;
39-
// canvas.height = window.innerHeight;
40-
// }
41-
// window.addEventListener('resize', resizeCanvas, false);
42-
// resizeCanvas();
43-
4437
NodeFlowTheme.FontFamily = "Source Code Pro";
4538

46-
47-
4839
const node3 = new FlowNode({
4940
title: "Node 3",
5041
position: { x: 850, y: 150 },
@@ -286,6 +277,12 @@
286277
{
287278
type: "number",
288279
config: { value: 2 }
280+
},
281+
{
282+
type: "image",
283+
config: {
284+
image: "https://i.imgur.com/qRZgWC0.jpeg"
285+
}
289286
}
290287
]
291288
})

src/graph.ts

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { NoteSubsystem } from "./notes/subsystem";
1313
import { ConnectionRendererConfiguration, NodeSubsystem } from "./nodes/subsystem";
1414
import { Connection } from './connection';
1515
import { Organize } from './organize';
16+
import { Publisher } from './nodes/publisher';
1617

1718
export type GraphRenderer = (canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, position: Vector2, scale: number) => void;
1819

@@ -177,6 +178,10 @@ export class NodeFlowGraph {
177178
Organize(this.#ctx, this);
178179
}
179180

181+
addPublisher(identifier: string, publisher: Publisher): void {
182+
this.#mainNodeSubsystem.addPublisher(identifier, publisher);
183+
}
184+
180185
getNodes(): Array<FlowNode> {
181186
return this.#mainNodeSubsystem.getNodes();
182187
}

src/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ globalThis.NodeFlowGraph = NodeFlowGraph;
55
globalThis.FlowNode = FlowNode;
66
globalThis.NodeFlowTheme = Theme;
77
globalThis.FlowNote = FlowNote;
8+
globalThis.NodePublisher = Publisher;
89

910
// Widgets
1011
import { NumberWidget } from './widgets/number';
@@ -15,10 +16,13 @@ import { ToggleWidget } from './widgets/toggle';
1516
import { SliderWidget } from './widgets/slider';
1617
import { GlobalWidgetFactory } from './widgets/factory';
1718
import { FlowNote } from './notes/note';
19+
import { Publisher } from './nodes/publisher';
20+
import { ImageWidget } from './widgets/image';
1821
globalThis.NumberWidget = NumberWidget;
1922
globalThis.ColorWidget = ColorWidget;
2023
globalThis.StringWidget = StringWidget;
2124
globalThis.ButtonWidget = ButtonWidget;
2225
globalThis.ToggleWidget = ToggleWidget;
2326
globalThis.SliderWidget = SliderWidget;
27+
globalThis.ImageWidget = ImageWidget;
2428
globalThis.GlobalWidgetFactory = GlobalWidgetFactory;

src/node.ts

+4
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,10 @@ export class FlowNode {
243243

244244
public setProperty(name: string, value: any): void {
245245
const oldValue = this.#data[name];
246+
if (oldValue === value) {
247+
return;
248+
}
249+
246250
this.#data[name] = value;
247251

248252
for (let i = 0; i < this.#registeredAnyPropertyChangeCallbacks.length; i++) {

src/nodes/publisher.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { ContextMenuConfig, ContextMenuItemConfig } from "../contextMenu";
2-
import { NodeFlowGraph } from "../graph";
32
import { FlowNode, FlowNodeConfig } from '../node';
43
import { Vector2 } from "../types/vector2";
54
import { NodeSubsystem } from "./subsystem";

src/nodes/subsystem.ts

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { CursorStyle } from "../styles/cursor";
88
import { Vector2 } from "../types/vector2";
99
import { Widget } from "../widgets/widget";
1010
import { NodeFactory, NodeFactoryConfig } from "./factory";
11+
import { Publisher } from "./publisher";
1112

1213
export interface ConnectionRendererConfiguration {
1314
size?: number;
@@ -81,6 +82,10 @@ export class NodeSubsystem {
8182
this.#idleConnectionRenderer = BuildConnectionRenderer(config?.idleConnection);
8283
}
8384

85+
addPublisher(identifier: string, publisher: Publisher): void {
86+
this.#nodeFactory.addPublisher(identifier, publisher);
87+
}
88+
8489
clickStart(mousePosition: Vector2, ctrlKey: boolean): boolean {
8590
let hoveringSomething = false;
8691
if (this.#nodeHovering > -1) {

src/widgets/color.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ export class ColorWidget {
4848
constructor(node: FlowNode, config?: ColorWidgetConfig) {
4949
this.#node = node;
5050
this.#nodeProperty = config?.property;
51-
this.Set(config?.value === undefined ? "#000000" : config?.value);
5251
this.#textBoxStyle = new TextBoxStyle({
5352
box: {
5453
color: this.#value,
@@ -59,6 +58,7 @@ export class ColorWidget {
5958
},
6059
text: config?.textStyle
6160
});
61+
this.Set(config?.value === undefined ? "#000000" : config?.value);
6262
this.#callback = config?.callback;
6363

6464
if (this.#nodeProperty !== undefined) {

src/widgets/factory.ts

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { SliderWidget, SliderWidgetConfig } from './slider';
66
import { StringWidget, StringWidgetConfig } from './string';
77
import { ToggleWidget, ToggleWidgetConfig } from './toggle';
88
import { FlowNode } from "../node";
9+
import { ImageWidget, ImageWidgetConfig } from "./image";
910

1011
export type WidgetBuilder = (node: FlowNode, confg?: any) => Widget;
1112

@@ -38,5 +39,6 @@ GlobalWidgetFactory.register("color", (node: FlowNode, config?: ColorWidgetConfi
3839
GlobalWidgetFactory.register("slider", (node: FlowNode, config?: SliderWidgetConfig) => new SliderWidget(node, config));
3940
GlobalWidgetFactory.register("string", (node: FlowNode, config?: StringWidgetConfig) => new StringWidget(node, config));
4041
GlobalWidgetFactory.register("toggle", (node: FlowNode, config?: ToggleWidgetConfig) => new ToggleWidget(node, config));
42+
GlobalWidgetFactory.register("image", (node: FlowNode, config?: ImageWidgetConfig) => new ImageWidget(config));
4143

4244
export { GlobalWidgetFactory };

src/widgets/image.ts

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import { Box } from "../types/box";
2+
import { Vector2 } from "../types/vector2";
3+
4+
const margin = 15;
5+
6+
export interface ImageWidgetConfig {
7+
image?: string;
8+
maxWidth?: number
9+
maxHeight?: number
10+
}
11+
12+
/**
13+
* constructor(lightNode, nodeManager, id, parameterData, app) {
14+
this.lightNode = lightNode;
15+
this.id = id;
16+
this.app = app;
17+
this.lightNode.title = parameterData.name;
18+
19+
this.lightNode.onDropFile = (file) => {
20+
// console.log(file)
21+
var reader = new FileReader();
22+
reader.onload = (evt) => {
23+
console.log(evt.target.result)
24+
nodeManager.nodeParameterChanged({
25+
id: id,
26+
data: evt.target.result,
27+
binary: true
28+
});
29+
}
30+
reader.readAsArrayBuffer(file);
31+
32+
const url = URL.createObjectURL(file);
33+
// this.loadImage(this._url, function (img) {
34+
// that.size[1] = (img.height / img.width) * that.size[0];
35+
// });
36+
this.loadImgFromURL(url);
37+
}
38+
}
39+
40+
loadImgFromURL(url) {
41+
const img = document.createElement("img");
42+
img.src = url;
43+
img.onload = () => {
44+
// if (callback) {
45+
// callback(this);
46+
// }
47+
// console.log("Image loaded, size: " + img.width + "x" + img.height);
48+
// this.dirty = true;
49+
// that.boxcolor = "#9F9";f
50+
// that.setDirtyCanvas(true);
51+
this.lightNode.widgets[0].image = img
52+
this.lightNode.setSize(this.lightNode.computeSize());
53+
};
54+
img.onerror = () => {
55+
console.log("error loading the image:" + url);
56+
}
57+
}
58+
59+
update(parameterData) {
60+
console.log("image parameter", parameterData)
61+
const curVal = parameterData.currentValue;
62+
this.app.RequestManager.getParameterValue(this.id, (response) => {
63+
const url = URL.createObjectURL(response);
64+
this.loadImgFromURL(url)
65+
})
66+
}
67+
*/
68+
69+
export class ImageWidget {
70+
71+
#url: string | undefined;
72+
73+
#image: HTMLImageElement | undefined;
74+
75+
#maxWidth: number;
76+
77+
#maxHeight: number;
78+
79+
constructor(config?: ImageWidgetConfig) {
80+
this.#maxWidth = config?.maxWidth === undefined ? 150 : config?.maxWidth;
81+
this.#maxHeight = config?.maxHeight === undefined ? 150 : config?.maxHeight;
82+
if (config?.image) {
83+
this.Set(config?.image);
84+
}
85+
}
86+
87+
Set(url: string) {
88+
this.#image = undefined;
89+
this.#url = url;
90+
91+
const img = document.createElement("img");
92+
img.src = url;
93+
img.onload = () => {
94+
this.#image = img;
95+
};
96+
img.onerror = (event) => {
97+
console.log("error loading image:", url, event);
98+
}
99+
}
100+
101+
Size(): Vector2 {
102+
if (this.#image === undefined) {
103+
return { "x": 0, "y": 0 }
104+
}
105+
106+
let adjust = 1;
107+
if (this.#image.width > this.#maxWidth) {
108+
adjust = this.#maxWidth / this.#image.width
109+
}
110+
111+
if (this.#image.height > this.#maxHeight) {
112+
let heightAdjust = this.#maxHeight / this.#image.height
113+
if (heightAdjust < adjust) {
114+
adjust = heightAdjust;
115+
}
116+
}
117+
118+
return {
119+
"x": adjust * this.#image.width,
120+
"y": adjust * this.#image.height
121+
}
122+
}
123+
124+
ClickStart(): void {
125+
}
126+
127+
ClickEnd(): void {
128+
}
129+
130+
Draw(ctx: CanvasRenderingContext2D, position: Vector2, scale: number, mousePosition: Vector2 | undefined): Box {
131+
const size = this.Size();
132+
const box: Box = {
133+
Position: position,
134+
Size: {
135+
x: size.x * scale,
136+
y: size.y * scale,
137+
}
138+
}
139+
140+
if (!this.#image) {
141+
return box;
142+
}
143+
144+
ctx.drawImage(
145+
this.#image,
146+
position.x,
147+
position.y,
148+
box.Size.x,
149+
box.Size.y
150+
);
151+
return box;
152+
}
153+
}

src/widgets/number.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ export class NumberWidget {
3737
constructor(node: FlowNode, config?: NumberWidgetConfig) {
3838
this.#node = node;
3939
this.#nodeProperty = config?.property;
40-
this.Set(config?.value === undefined ? 0 : config?.value);
4140
this.#idleBoxStyle = new TextBoxStyle(TextBoxStyleWithFallback(config?.idleBoxStyle, {
4241
box: {
4342
color: Theme.Widget.BackgroundColor,
@@ -60,6 +59,7 @@ export class NumberWidget {
6059
},
6160
text: { color: Theme.Widget.FontColor },
6261
}));
62+
this.Set(config?.value === undefined ? 0 : config?.value);
6363
this.#callback = config?.callback;
6464

6565
if (this.#nodeProperty !== undefined) {

src/widgets/toggle.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,6 @@ export class ToggleWidget {
126126
this.#node = node;
127127
this.#nodeProperty = config?.property;
128128
this.#text = config?.text === undefined ? "Toggle" : config?.text;
129-
this.Set(config?.value === undefined ? false : config?.value);
130-
this.#callback = config?.callback;
131129

132130
this.#enabledStyle = new ToggleStyle({
133131
idle: TextBoxStyleWithFallback(config?.enabledStyle?.idle, {
@@ -159,6 +157,8 @@ export class ToggleWidget {
159157
lightColor: config?.disabledStyle?.lightColor === undefined ? "#004400" : config?.enabledStyle?.lightColor,
160158
});
161159

160+
this.Set(config?.value === undefined ? false : config?.value);
161+
this.#callback = config?.callback;
162162
if (this.#nodeProperty !== undefined) {
163163
this.#node.subscribeToProperty(this.#nodeProperty, (oldVal, newVal) => {
164164
this.Set(newVal);

0 commit comments

Comments
 (0)