lexgui 0.1.0 → 0.1.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/README.md +19 -5
- package/build/components/imui.js +315 -0
- package/build/components/nodegraph.js +395 -395
- package/build/components/timeline.js +24 -28
- package/build/lexgui.js +26 -3
- package/build/lexgui.module.js +26 -3
- package/demo.js +0 -2
- package/examples/area_tabs.html +14 -4
- package/examples/asset_view.html +19 -9
- package/examples/code_editor.html +14 -4
- package/examples/dialogs.html +14 -4
- package/examples/immediate_ui.html +77 -0
- package/examples/index.html +18 -6
- package/examples/node_graph.html +15 -5
- package/examples/overlay_area.html +15 -5
- package/examples/previews/asset_view.png +0 -0
- package/examples/previews/code_editor.png +0 -0
- package/examples/previews/node_graph.png +0 -0
- package/package.json +1 -1
|
@@ -1,534 +1,534 @@
|
|
|
1
|
-
|
|
1
|
+
import { LX } from 'lexgui';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
if(!LX) {
|
|
4
|
+
throw("lexgui.js missing!");
|
|
5
|
+
}
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
LX.components.push( 'Graph' );
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
function flushCss(element) {
|
|
10
|
+
// By reading the offsetHeight property, we are forcing
|
|
11
|
+
// the browser to flush the pending CSS changes (which it
|
|
12
|
+
// does to ensure the value obtained is accurate).
|
|
13
|
+
element.offsetHeight;
|
|
14
|
+
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
function swapElements (obj, a, b) {
|
|
17
|
+
[obj[a], obj[b]] = [obj[b], obj[a]];
|
|
18
|
+
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
function swapArrayElements (array, id0, id1) {
|
|
21
|
+
[array[id0], array[id1]] = [array[id1], array[id0]];
|
|
22
|
+
};
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
function sliceChar(str, idx) {
|
|
25
|
+
return str.substr(0, idx) + str.substr(idx + 1);
|
|
26
|
+
}
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
let ASYNC_ENABLED = true;
|
|
28
|
+
function firstNonspaceIndex(str) {
|
|
29
|
+
return str.search(/\S|$/);
|
|
30
|
+
}
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
if( ASYNC_ENABLED )
|
|
36
|
-
setTimeout( fn, ms ?? 0 );
|
|
37
|
-
else
|
|
38
|
-
fn();
|
|
39
|
-
}
|
|
32
|
+
let ASYNC_ENABLED = true;
|
|
40
33
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
34
|
+
function doAsync( fn, ms ) {
|
|
35
|
+
if( ASYNC_ENABLED )
|
|
36
|
+
setTimeout( fn, ms ?? 0 );
|
|
37
|
+
else
|
|
38
|
+
fn();
|
|
39
|
+
}
|
|
44
40
|
|
|
45
|
-
|
|
41
|
+
/**
|
|
42
|
+
* @class GraphCanvas
|
|
43
|
+
*/
|
|
46
44
|
|
|
47
|
-
|
|
45
|
+
class GraphCanvas {
|
|
48
46
|
|
|
49
|
-
|
|
47
|
+
static __instances = [];
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
static NODE_TITLE_HEIGHT = 24;
|
|
53
|
-
static NODE_ROW_HEIGHT = 16;
|
|
49
|
+
static BACK_IMAGE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAAXNSR0IArs4c6QAAAplJREFUeF7tm8FqwzAQRG2DDynEvaT//5fNKXFRCqZQkjLSyEzxC/Qmb5eZN9pYasfL5WMd+MQoMBZDxnEc5nl+2tS6rkP5mabpZeNlzf1+f6wrNZ99jrau6HC73f7UpazbDDmfFwsl1+vncDq9WWqVIkerhyGN6LiBwRAM0RRwE5hej4RofPxa7TYYQzBEU8BNYHo9EqLxsc+WVX7Lsrw3tvb9eDqB6f2RkEYM3QZjCIZoCrgJTK9HQjQ+9hnq5WSWw8U6Z9yJIyF1PmxPYUiYgBiCIZoCbmKOVu8xQ4rkr65wNUtY3aIAQ71FvQ5HRRiCIZoCh5whvBhqkPxc7QaGLaveiy7XDRiCIZoC7i0hvR4J0fjgtDedaHd/25s6d+p1UeliCF9768zo8UcdzJB6L/ja26hdFwHZshpdcQvorseWFWYwhmCIpoB7S0ivR0I0PnhTTyfa3R936o0JcT/OltWoaJeEcHRS7wqG1GvHm3qjdv9CQBLS6LJbQHc9hnqYwRiCIZoC7i0hvR4J0fjY5+ik/Bbu1OuccSeOhNT5sD2FIWECYgiGaAq4iTlaPWaIxts+37I47a13xZ1gElLvRZfDTwzBEE0B95aQXo87dY2P7qvZsholdicOQzBEU8BNYHo9EqLxwYthOtHu/kgICdEUcBOYXo+EaHwwQ9KJdvfH/6mTEE0BN4Hp9ZghGh/MkHSi3f2REBKiKeAmML0eCdH4YIakE+3uj4SQEE0BN4Hp9bhT1/jovpotq1Fid+IwBEM0BdwEptcjIRofvIekE+3uj4SQEE0BN4Hp9UiIxgczJJ1od38khIRoCrgJTK9HQjQ+mCHpRLv7IyEkRFPATWB6PRKi8cEMSSfa3R8JISGaAm4C0+t9AfQNJzgm7/oIAAAAAElFTkSuQmCC";
|
|
54
50
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
// Node Drawing
|
|
52
|
+
static NODE_TITLE_HEIGHT = 24;
|
|
53
|
+
static NODE_ROW_HEIGHT = 16;
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
static NODE_SHAPE_RADIUS = 4;
|
|
56
|
+
static NODE_TITLE_RADIUS = [GraphCanvas.NODE_SHAPE_RADIUS, GraphCanvas.NODE_SHAPE_RADIUS, 0, 0];
|
|
57
|
+
static NODE_BODY_RADIUS = [GraphCanvas.NODE_SHAPE_RADIUS, GraphCanvas.NODE_SHAPE_RADIUS, GraphCanvas.NODE_SHAPE_RADIUS, GraphCanvas.NODE_SHAPE_RADIUS];
|
|
61
58
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
*
|
|
65
|
-
*/
|
|
59
|
+
static DEFAULT_NODE_TITLE_COLOR = "#4a59b0";
|
|
60
|
+
static DEFAULT_NODE_BODY_COLOR = "#111";
|
|
66
61
|
|
|
67
|
-
|
|
62
|
+
/**
|
|
63
|
+
* @param {*} options
|
|
64
|
+
*
|
|
65
|
+
*/
|
|
68
66
|
|
|
69
|
-
|
|
67
|
+
constructor( area, options = {} ) {
|
|
70
68
|
|
|
71
|
-
|
|
72
|
-
this.area = new LX.Area( { className: "lexGraph" } );
|
|
69
|
+
GraphCanvas.__instances.push( this );
|
|
73
70
|
|
|
74
|
-
|
|
71
|
+
this.base_area = area;
|
|
72
|
+
this.area = new LX.Area( { className: "lexGraph" } );
|
|
75
73
|
|
|
76
|
-
|
|
77
|
-
area.attach( this.root );
|
|
74
|
+
area.root.classList.add('grapharea');
|
|
78
75
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this.dom.width = bb.width;
|
|
82
|
-
this.dom.height = bb.height;
|
|
83
|
-
this._backDirty = true;
|
|
84
|
-
this._frontDirty = true;
|
|
85
|
-
};
|
|
76
|
+
this.root = this.area.root;
|
|
77
|
+
area.attach( this.root );
|
|
86
78
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
this.
|
|
90
|
-
this.
|
|
91
|
-
this.
|
|
92
|
-
this.
|
|
93
|
-
|
|
94
|
-
|
|
79
|
+
// Bind resize
|
|
80
|
+
area.onresize = ( bb ) => {
|
|
81
|
+
this.dom.width = bb.width;
|
|
82
|
+
this.dom.height = bb.height;
|
|
83
|
+
this._backDirty = true;
|
|
84
|
+
this._frontDirty = true;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
this.root.addEventListener( 'keydown', this._processKey.bind(this), true);
|
|
88
|
+
this.root.addEventListener( 'mousedown', this._processMouse.bind(this) );
|
|
89
|
+
this.root.addEventListener( 'mouseup', this._processMouse.bind(this) );
|
|
90
|
+
this.root.addEventListener( 'mousemove', this._processMouse.bind(this) );
|
|
91
|
+
this.root.addEventListener( 'click', this._processMouse.bind(this) );
|
|
92
|
+
this.root.addEventListener( 'contextmenu', this._processMouse.bind(this) );
|
|
93
|
+
this.root.addEventListener( 'focus', this._processFocus.bind(this, true) );
|
|
94
|
+
this.root.addEventListener( 'focusout', this._processFocus.bind(this, false) );
|
|
95
|
+
|
|
96
|
+
// State
|
|
97
|
+
|
|
98
|
+
this.drawAllFrames = false;
|
|
99
|
+
this.isFocused = false;
|
|
100
|
+
this._backDirty = true;
|
|
101
|
+
this._frontDirty = true;
|
|
102
|
+
|
|
103
|
+
// Canvas
|
|
104
|
+
|
|
105
|
+
this.dom = document.createElement('canvas');
|
|
106
|
+
this.dom.width = area.size[0];
|
|
107
|
+
this.dom.height = area.size[1];
|
|
108
|
+
this.dom.tabIndex = -1;
|
|
109
|
+
this.area.attach( this.dom );
|
|
110
|
+
|
|
111
|
+
this.frames = 0;
|
|
112
|
+
this.fps = 0;
|
|
113
|
+
this._lastDrawTime = 0;
|
|
114
|
+
this._drawTime = 0;
|
|
115
|
+
|
|
116
|
+
this.font = new FontFace("Ubuntu", "url(../data/Ubuntu-Bold.ttf)");
|
|
117
|
+
this.font.load().then(
|
|
118
|
+
( font ) => {
|
|
119
|
+
document.fonts.add( font );
|
|
120
|
+
requestAnimationFrame( this.frame.bind(this) );
|
|
121
|
+
},
|
|
122
|
+
(err) => {
|
|
123
|
+
console.error(err);
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
}
|
|
95
127
|
|
|
96
|
-
|
|
128
|
+
static getInstances()
|
|
129
|
+
{
|
|
130
|
+
return GraphCanvas.__instances;
|
|
131
|
+
}
|
|
97
132
|
|
|
98
|
-
|
|
99
|
-
this.isFocused = false;
|
|
100
|
-
this._backDirty = true;
|
|
101
|
-
this._frontDirty = true;
|
|
133
|
+
_processFocus( active ) {
|
|
102
134
|
|
|
103
|
-
|
|
135
|
+
this.isFocused = active;
|
|
136
|
+
}
|
|
104
137
|
|
|
105
|
-
|
|
106
|
-
this.dom.width = area.size[0];
|
|
107
|
-
this.dom.height = area.size[1];
|
|
108
|
-
this.dom.tabIndex = -1;
|
|
109
|
-
this.area.attach( this.dom );
|
|
138
|
+
_processKey(e) {
|
|
110
139
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
this._drawTime = 0;
|
|
140
|
+
var key = e.key ?? e.detail.key;
|
|
141
|
+
console.log( key );
|
|
142
|
+
}
|
|
115
143
|
|
|
116
|
-
|
|
117
|
-
this.font.load().then(
|
|
118
|
-
( font ) => {
|
|
119
|
-
document.fonts.add( font );
|
|
120
|
-
requestAnimationFrame( this.frame.bind(this) );
|
|
121
|
-
},
|
|
122
|
-
(err) => {
|
|
123
|
-
console.error(err);
|
|
124
|
-
},
|
|
125
|
-
);
|
|
126
|
-
}
|
|
144
|
+
_processMouse(e) {
|
|
127
145
|
|
|
128
|
-
|
|
146
|
+
if( e.type == 'mousedown' )
|
|
129
147
|
{
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
_processFocus( active ) {
|
|
134
|
-
|
|
135
|
-
this.isFocused = active;
|
|
148
|
+
this.lastMouseDown = LX.getTime();
|
|
136
149
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
150
|
+
|
|
151
|
+
else if( e.type == 'mouseup' )
|
|
152
|
+
{
|
|
153
|
+
if( (LX.getTime() - this.lastMouseDown) < 300 ) {
|
|
154
|
+
this._processClick(e);
|
|
155
|
+
}
|
|
142
156
|
}
|
|
143
157
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if( e.type == 'mousedown' )
|
|
147
|
-
{
|
|
148
|
-
this.lastMouseDown = LX.getTime();
|
|
149
|
-
}
|
|
158
|
+
else if( e.type == 'mousemove' )
|
|
159
|
+
{
|
|
150
160
|
|
|
151
|
-
|
|
152
|
-
{
|
|
153
|
-
if( (LX.getTime() - this.lastMouseDown) < 300 ) {
|
|
154
|
-
this._processClick(e);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
else if( e.type == 'mousemove' )
|
|
159
|
-
{
|
|
160
|
-
|
|
161
|
-
}
|
|
161
|
+
}
|
|
162
162
|
|
|
163
|
-
|
|
163
|
+
else if ( e.type == 'click' ) // trip
|
|
164
|
+
{
|
|
165
|
+
switch( e.detail )
|
|
164
166
|
{
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
case LX.MOUSE_TRIPLE_CLICK:
|
|
170
|
-
break;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
else if ( e.type == 'contextmenu' ) {
|
|
175
|
-
e.preventDefault()
|
|
176
|
-
this._processContextMenu( e );
|
|
167
|
+
case LX.MOUSE_DOUBLE_CLICK:
|
|
168
|
+
break;
|
|
169
|
+
case LX.MOUSE_TRIPLE_CLICK:
|
|
170
|
+
break;
|
|
177
171
|
}
|
|
178
172
|
}
|
|
179
173
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
174
|
+
else if ( e.type == 'contextmenu' ) {
|
|
175
|
+
e.preventDefault()
|
|
176
|
+
this._processContextMenu( e );
|
|
183
177
|
}
|
|
178
|
+
}
|
|
184
179
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
LX.addContextMenu( "Test", e, m => {
|
|
188
|
-
m.add( "option 1", () => { } );
|
|
189
|
-
m.add( "option 2", () => { } );
|
|
190
|
-
});
|
|
191
|
-
}
|
|
180
|
+
_processClick( e ) {
|
|
192
181
|
|
|
193
|
-
|
|
182
|
+
|
|
183
|
+
}
|
|
194
184
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
185
|
+
_processContextMenu( e ) {
|
|
186
|
+
|
|
187
|
+
LX.addContextMenu( "Test", e, m => {
|
|
188
|
+
m.add( "option 1", () => { } );
|
|
189
|
+
m.add( "option 2", () => { } );
|
|
190
|
+
});
|
|
191
|
+
}
|
|
198
192
|
|
|
199
|
-
|
|
200
|
-
* @method setGraph
|
|
201
|
-
* @param {Graph} graph:
|
|
202
|
-
*/
|
|
193
|
+
_forceDraw() {
|
|
203
194
|
|
|
204
|
-
|
|
195
|
+
this._backDirty = true;
|
|
196
|
+
this._frontDirty = true;
|
|
197
|
+
}
|
|
205
198
|
|
|
206
|
-
|
|
207
|
-
|
|
199
|
+
/**
|
|
200
|
+
* @method setGraph
|
|
201
|
+
* @param {Graph} graph:
|
|
202
|
+
*/
|
|
208
203
|
|
|
209
|
-
|
|
210
|
-
* @method clear
|
|
211
|
-
*/
|
|
204
|
+
setGraph( graph ) {
|
|
212
205
|
|
|
213
|
-
|
|
206
|
+
this.graph = graph;
|
|
207
|
+
}
|
|
214
208
|
|
|
215
|
-
|
|
209
|
+
/**
|
|
210
|
+
* @method clear
|
|
211
|
+
*/
|
|
216
212
|
|
|
217
|
-
|
|
218
|
-
* @method frame
|
|
219
|
-
*/
|
|
213
|
+
clear( ) {
|
|
220
214
|
|
|
221
|
-
|
|
215
|
+
}
|
|
222
216
|
|
|
223
|
-
|
|
224
|
-
|
|
217
|
+
/**
|
|
218
|
+
* @method frame
|
|
219
|
+
*/
|
|
225
220
|
|
|
226
|
-
|
|
227
|
-
}
|
|
221
|
+
frame() {
|
|
228
222
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
*/
|
|
223
|
+
// this.update();
|
|
224
|
+
this.draw();
|
|
232
225
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
console.log("Update");
|
|
236
|
-
}
|
|
226
|
+
requestAnimationFrame( this.frame.bind(this) );
|
|
227
|
+
}
|
|
237
228
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
229
|
+
/**
|
|
230
|
+
* @method update
|
|
231
|
+
*/
|
|
241
232
|
|
|
242
|
-
|
|
233
|
+
update() {
|
|
234
|
+
|
|
235
|
+
console.log("Update");
|
|
236
|
+
}
|
|
243
237
|
|
|
244
|
-
|
|
245
|
-
|
|
238
|
+
/**
|
|
239
|
+
* @method draw
|
|
240
|
+
*/
|
|
246
241
|
|
|
247
|
-
|
|
248
|
-
var now = LX.getTime();
|
|
249
|
-
this._drawTime = (now - this._lastDrawTime) * 0.001;
|
|
250
|
-
this._lastDrawTime = now;
|
|
242
|
+
draw() {
|
|
251
243
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
// }
|
|
244
|
+
if (!this.dom || !this.dom.width || !this.dom.height)
|
|
245
|
+
return;
|
|
255
246
|
|
|
256
|
-
|
|
247
|
+
// Count Fps
|
|
248
|
+
var now = LX.getTime();
|
|
249
|
+
this._drawTime = (now - this._lastDrawTime) * 0.001;
|
|
250
|
+
this._lastDrawTime = now;
|
|
257
251
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
this._drawFront();
|
|
264
|
-
}
|
|
252
|
+
// if (this.graph) {
|
|
253
|
+
// this.ds.computeVisibleArea(this.viewport);
|
|
254
|
+
// }
|
|
255
|
+
|
|
256
|
+
const forceDraw = this.drawAllFrames || (this._backDirty || this._frontDirty);
|
|
265
257
|
|
|
266
|
-
|
|
267
|
-
|
|
258
|
+
if ( forceDraw )
|
|
259
|
+
{
|
|
260
|
+
if( this._backDirty )
|
|
261
|
+
this._drawBack();
|
|
262
|
+
if ( this._frontDirty )
|
|
263
|
+
this._drawFront();
|
|
268
264
|
}
|
|
269
265
|
|
|
270
|
-
|
|
266
|
+
this.fps = this._drawTime ? (1.0 / this._drawTime) : 0;
|
|
267
|
+
this.frames += 1;
|
|
268
|
+
}
|
|
271
269
|
|
|
272
|
-
|
|
270
|
+
_drawBack() {
|
|
273
271
|
|
|
274
|
-
|
|
272
|
+
console.log( "_drawBack" );
|
|
275
273
|
|
|
276
|
-
|
|
277
|
-
return;
|
|
274
|
+
var ctx = this.dom.getContext("2d");
|
|
278
275
|
|
|
279
|
-
|
|
276
|
+
if ( !GraphCanvas.BACK_IMAGE_SRC )
|
|
277
|
+
return;
|
|
280
278
|
|
|
281
|
-
|
|
282
|
-
this._backImage = new Image();
|
|
283
|
-
this._backImage.src = GraphCanvas.BACK_IMAGE_SRC;
|
|
284
|
-
this._backImage.onload = this._forceDraw.bind(this);
|
|
285
|
-
}
|
|
279
|
+
ctx.imageSmoothingEnabled = false;
|
|
286
280
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
281
|
+
if ( !this._backImage ) {
|
|
282
|
+
this._backImage = new Image();
|
|
283
|
+
this._backImage.src = GraphCanvas.BACK_IMAGE_SRC;
|
|
284
|
+
this._backImage.onload = this._forceDraw.bind(this);
|
|
285
|
+
}
|
|
290
286
|
|
|
291
|
-
|
|
287
|
+
if ( !this._pattern && this._backImage.width > 0) {
|
|
288
|
+
this._pattern = ctx.createPattern(this._backImage, "repeat");
|
|
289
|
+
}
|
|
292
290
|
|
|
293
|
-
|
|
294
|
-
ctx.fillStyle = this._pattern;
|
|
295
|
-
ctx.fillRect(0, 0, this.dom.width, this.dom.height);
|
|
296
|
-
ctx.fillStyle = "transparent";
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
ctx.globalAlpha = 1.0;
|
|
300
|
-
ctx.imageSmoothingEnabled = true;
|
|
291
|
+
// Draw background
|
|
301
292
|
|
|
302
|
-
|
|
293
|
+
if (this._pattern) {
|
|
294
|
+
ctx.fillStyle = this._pattern;
|
|
295
|
+
ctx.fillRect(0, 0, this.dom.width, this.dom.height);
|
|
296
|
+
ctx.fillStyle = "transparent";
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
ctx.globalAlpha = 1.0;
|
|
300
|
+
ctx.imageSmoothingEnabled = true;
|
|
303
301
|
|
|
304
|
-
|
|
302
|
+
// Draw node connections
|
|
305
303
|
|
|
306
|
-
|
|
307
|
-
}
|
|
304
|
+
this._drawConnections();
|
|
308
305
|
|
|
309
|
-
|
|
306
|
+
this._backDirty = false;
|
|
307
|
+
}
|
|
310
308
|
|
|
311
|
-
|
|
309
|
+
_drawFront() {
|
|
312
310
|
|
|
313
|
-
|
|
311
|
+
console.log( "_drawFront" );
|
|
314
312
|
|
|
315
|
-
|
|
316
|
-
{
|
|
317
|
-
this._drawNode( node );
|
|
318
|
-
}
|
|
313
|
+
let nodes = this._getVisibleNodes();
|
|
319
314
|
|
|
320
|
-
|
|
315
|
+
for( let node of nodes )
|
|
316
|
+
{
|
|
317
|
+
this._drawNode( node );
|
|
321
318
|
}
|
|
322
319
|
|
|
323
|
-
|
|
320
|
+
this._frontDirty = false;
|
|
321
|
+
}
|
|
324
322
|
|
|
325
|
-
|
|
326
|
-
ctx.shadowOffsetY = 0;
|
|
327
|
-
ctx.shadowBlur = 0;
|
|
328
|
-
ctx.shadowColor = "rgba(0,0,0,0)";
|
|
329
|
-
}
|
|
323
|
+
_resetCanvasShadows( ctx ) {
|
|
330
324
|
|
|
331
|
-
|
|
325
|
+
ctx.shadowOffsetX = 0;
|
|
326
|
+
ctx.shadowOffsetY = 0;
|
|
327
|
+
ctx.shadowBlur = 0;
|
|
328
|
+
ctx.shadowColor = "rgba(0,0,0,0)";
|
|
329
|
+
}
|
|
332
330
|
|
|
333
|
-
|
|
334
|
-
var textMetrics = ctx.measureText( node.name );
|
|
331
|
+
_computeNodeSize( node ) {
|
|
335
332
|
|
|
336
|
-
|
|
333
|
+
const ctx = this.dom.getContext("2d");
|
|
334
|
+
var textMetrics = ctx.measureText( node.name );
|
|
337
335
|
|
|
338
|
-
|
|
339
|
-
let sY = rows * GraphCanvas.NODE_ROW_HEIGHT + GraphCanvas.NODE_TITLE_HEIGHT;
|
|
336
|
+
let sX = 32 + textMetrics.width * 1.475;
|
|
340
337
|
|
|
341
|
-
|
|
342
|
-
|
|
338
|
+
const rows = Math.max(1, Math.max(node.inputs.length, node.outputs.length));
|
|
339
|
+
let sY = rows * GraphCanvas.NODE_ROW_HEIGHT + GraphCanvas.NODE_TITLE_HEIGHT;
|
|
343
340
|
|
|
344
|
-
|
|
341
|
+
return [sX, sY];
|
|
342
|
+
}
|
|
345
343
|
|
|
346
|
-
|
|
344
|
+
_drawConnections() {
|
|
347
345
|
|
|
348
|
-
|
|
346
|
+
console.log( "_drawConnections" );
|
|
349
347
|
|
|
350
|
-
|
|
348
|
+
const ctx = this.dom.getContext("2d");
|
|
351
349
|
|
|
352
|
-
|
|
353
|
-
let cp1 = { x: 230, y: 30 };
|
|
354
|
-
let cp2 = { x: 150, y: 80 };
|
|
355
|
-
let end = { x: 250, y: 100 };
|
|
350
|
+
let nodes = this._getVisibleNodes();
|
|
356
351
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
ctx.stroke();
|
|
352
|
+
let start = { x: 50, y: 20 };
|
|
353
|
+
let cp1 = { x: 230, y: 30 };
|
|
354
|
+
let cp2 = { x: 150, y: 80 };
|
|
355
|
+
let end = { x: 250, y: 100 };
|
|
362
356
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
// }
|
|
357
|
+
// Cubic Bézier curve
|
|
358
|
+
ctx.beginPath();
|
|
359
|
+
ctx.moveTo(start.x, start.y);
|
|
360
|
+
ctx.bezierCurveTo(cp1.x, cp1.y, cp2.x, cp2.y, end.x, end.y);
|
|
361
|
+
ctx.stroke();
|
|
369
362
|
|
|
370
|
-
|
|
363
|
+
// for( let node of nodes )
|
|
364
|
+
// {
|
|
365
|
+
// // Discard nodes without inputs...
|
|
366
|
+
// if (!node.inputs || !node.inputs.length) {
|
|
367
|
+
// continue;
|
|
368
|
+
// }
|
|
371
369
|
|
|
370
|
+
// for (let input of node.inputs) {
|
|
372
371
|
|
|
373
|
-
// }
|
|
374
|
-
// }
|
|
375
|
-
}
|
|
376
372
|
|
|
377
|
-
|
|
373
|
+
// }
|
|
374
|
+
// }
|
|
375
|
+
}
|
|
378
376
|
|
|
379
|
-
|
|
377
|
+
_drawNode( node ) {
|
|
380
378
|
|
|
381
|
-
|
|
382
|
-
node.size = node.size ?? this._computeNodeSize( node );
|
|
383
|
-
node.color = node.color ?? GraphCanvas.DEFAULT_NODE_BODY_COLOR;
|
|
384
|
-
node.titleColor = node.titleColor ?? GraphCanvas.DEFAULT_NODE_TITLE_COLOR;
|
|
379
|
+
console.log( node.name );
|
|
385
380
|
|
|
386
|
-
|
|
387
|
-
|
|
381
|
+
// Process some attributes
|
|
382
|
+
node.size = node.size ?? this._computeNodeSize( node );
|
|
383
|
+
node.color = node.color ?? GraphCanvas.DEFAULT_NODE_BODY_COLOR;
|
|
384
|
+
node.titleColor = node.titleColor ?? GraphCanvas.DEFAULT_NODE_TITLE_COLOR;
|
|
388
385
|
|
|
389
|
-
|
|
390
|
-
|
|
386
|
+
let [pX, pY] = node.position;
|
|
387
|
+
let [sX, sY] = node.size;
|
|
391
388
|
|
|
392
|
-
|
|
389
|
+
const ctx = this.dom.getContext("2d");
|
|
390
|
+
const offsetY = GraphCanvas.NODE_TITLE_HEIGHT;
|
|
393
391
|
|
|
394
|
-
|
|
395
|
-
ctx.shadowColor = "#000";
|
|
392
|
+
// Body
|
|
396
393
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
ctx.roundRect( pX, pY, sX, sY, GraphCanvas.NODE_BODY_RADIUS );
|
|
400
|
-
ctx.fill();
|
|
394
|
+
ctx.shadowBlur = 8;
|
|
395
|
+
ctx.shadowColor = "#000";
|
|
401
396
|
|
|
402
|
-
|
|
397
|
+
ctx.beginPath();
|
|
398
|
+
ctx.fillStyle = node.color;
|
|
399
|
+
ctx.roundRect( pX, pY, sX, sY, GraphCanvas.NODE_BODY_RADIUS );
|
|
400
|
+
ctx.fill();
|
|
403
401
|
|
|
404
|
-
|
|
405
|
-
ctx.beginPath();
|
|
406
|
-
ctx.strokeStyle = "#555";
|
|
407
|
-
ctx.roundRect( pX, pY, sX, sY, GraphCanvas.NODE_BODY_RADIUS );
|
|
408
|
-
ctx.stroke();
|
|
402
|
+
this._resetCanvasShadows( ctx );
|
|
409
403
|
|
|
410
|
-
|
|
404
|
+
// Draw border
|
|
405
|
+
ctx.beginPath();
|
|
406
|
+
ctx.strokeStyle = "#555";
|
|
407
|
+
ctx.roundRect( pX, pY, sX, sY, GraphCanvas.NODE_BODY_RADIUS );
|
|
408
|
+
ctx.stroke();
|
|
411
409
|
|
|
412
|
-
|
|
413
|
-
var titleGrd = ctx.createLinearGradient(pX, pY, pX + sX, pY + offsetY);
|
|
414
|
-
titleGrd.addColorStop(0, node.color);
|
|
415
|
-
titleGrd.addColorStop(1, node.titleColor);
|
|
410
|
+
// Title
|
|
416
411
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
412
|
+
ctx.beginPath();
|
|
413
|
+
var titleGrd = ctx.createLinearGradient(pX, pY, pX + sX, pY + offsetY);
|
|
414
|
+
titleGrd.addColorStop(0, node.color);
|
|
415
|
+
titleGrd.addColorStop(1, node.titleColor);
|
|
420
416
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
}
|
|
417
|
+
ctx.fillStyle = titleGrd;
|
|
418
|
+
ctx.roundRect( pX + 1, pY, sX - 2, offsetY, GraphCanvas.NODE_TITLE_RADIUS );
|
|
419
|
+
ctx.fill();
|
|
425
420
|
|
|
426
|
-
|
|
421
|
+
ctx.font = "14px Ubuntu";
|
|
422
|
+
ctx.fillStyle = "#ddd";
|
|
423
|
+
ctx.fillText( node.name, pX + 16, pY + offsetY * 0.75);
|
|
424
|
+
}
|
|
427
425
|
|
|
428
|
-
|
|
429
|
-
{
|
|
430
|
-
console.warn( "No graph set" );
|
|
431
|
-
return [];
|
|
432
|
-
}
|
|
426
|
+
_getVisibleNodes() {
|
|
433
427
|
|
|
434
|
-
|
|
435
|
-
|
|
428
|
+
if( !this.graph )
|
|
429
|
+
{
|
|
430
|
+
console.warn( "No graph set" );
|
|
431
|
+
return [];
|
|
436
432
|
}
|
|
437
433
|
|
|
434
|
+
// TODO: Return the ones in the viewport
|
|
435
|
+
return this.graph.nodes;
|
|
438
436
|
}
|
|
439
437
|
|
|
440
|
-
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
LX.GraphCanvas = GraphCanvas;
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* @class Graph
|
|
444
|
+
*/
|
|
445
|
+
|
|
446
|
+
class Graph {
|
|
441
447
|
|
|
442
448
|
/**
|
|
443
|
-
* @
|
|
449
|
+
* @param {*} options
|
|
450
|
+
*
|
|
444
451
|
*/
|
|
445
452
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
name: "Node 2",
|
|
489
|
-
size: [120, 100],
|
|
490
|
-
position: [500, 350],
|
|
491
|
-
inputs: [],
|
|
492
|
-
outputs: []
|
|
493
|
-
})
|
|
494
|
-
];
|
|
495
|
-
}
|
|
453
|
+
constructor( options = {} ) {
|
|
454
|
+
|
|
455
|
+
// Nodes
|
|
456
|
+
|
|
457
|
+
this.nodes = [
|
|
458
|
+
new GraphNode({
|
|
459
|
+
name: "Node 1",
|
|
460
|
+
xsize: [120, 100],
|
|
461
|
+
position: [200, 200],
|
|
462
|
+
inputs: [
|
|
463
|
+
{
|
|
464
|
+
name: "Speed",
|
|
465
|
+
type: "number"
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
name: "Offset",
|
|
469
|
+
type: "number"
|
|
470
|
+
}
|
|
471
|
+
],
|
|
472
|
+
outputs: [
|
|
473
|
+
{
|
|
474
|
+
name: "Speed",
|
|
475
|
+
type: "number"
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
name: "Offset",
|
|
479
|
+
type: "number"
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
name: "Loop",
|
|
483
|
+
type: "bool"
|
|
484
|
+
}
|
|
485
|
+
]
|
|
486
|
+
}),
|
|
487
|
+
new GraphNode({
|
|
488
|
+
name: "Node 2",
|
|
489
|
+
size: [120, 100],
|
|
490
|
+
position: [500, 350],
|
|
491
|
+
inputs: [],
|
|
492
|
+
outputs: []
|
|
493
|
+
})
|
|
494
|
+
];
|
|
496
495
|
}
|
|
496
|
+
}
|
|
497
497
|
|
|
498
|
-
|
|
498
|
+
LX.Graph = Graph;
|
|
499
499
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
500
|
+
/**
|
|
501
|
+
* @class GraphNode
|
|
502
|
+
*/
|
|
503
503
|
|
|
504
|
-
|
|
504
|
+
class GraphNode {
|
|
505
505
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
506
|
+
/**
|
|
507
|
+
* @param {*} options
|
|
508
|
+
*
|
|
509
|
+
*/
|
|
510
510
|
|
|
511
|
-
|
|
511
|
+
constructor( options = {} ) {
|
|
512
512
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
513
|
+
this.name = options.name ?? "Unnamed";
|
|
514
|
+
this.size = options.size;
|
|
515
|
+
this.position = options.position ?? [0, 0];
|
|
516
|
+
|
|
517
|
+
this.inputs = options.inputs ?? [];
|
|
518
|
+
this.outputs = options.outputs ?? [];
|
|
519
|
+
}
|
|
520
520
|
|
|
521
|
-
|
|
521
|
+
computeSize() {
|
|
522
522
|
|
|
523
|
-
|
|
523
|
+
let sX = 16 + this.name.length * 10;
|
|
524
524
|
|
|
525
|
-
|
|
526
|
-
|
|
525
|
+
const rows = Math.max(1, Math.max(this.inputs.length, this.outputs.length));
|
|
526
|
+
let sY = rows * GraphCanvas.NODE_ROW_HEIGHT + GraphCanvas.NODE_TITLE_HEIGHT;
|
|
527
527
|
|
|
528
|
-
|
|
529
|
-
}
|
|
528
|
+
return [sX, sY];
|
|
530
529
|
}
|
|
530
|
+
}
|
|
531
531
|
|
|
532
|
-
|
|
532
|
+
LX.GraphNode = GraphNode;
|
|
533
533
|
|
|
534
|
-
|
|
534
|
+
export { GraphCanvas, Graph, GraphNode };
|