lexgui 0.1.30 → 0.1.32

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/changelog.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # lexgui.js changelog
2
2
 
3
+ ## 0.1.32
4
+
5
+ Timeline:
6
+ - Allow addition of widgets in top bar.
7
+ - General improvements.
8
+ - Docs started.
9
+
10
+ New VideoEditor component (still wip).
11
+ Added skipCallback for `Widget.set()`.
12
+ Minor bug fixes.
13
+
14
+ ## 0.1.31
15
+
16
+ GraphEditor:
17
+ - Graph/function renaming.
18
+ - Copy/Paste nodes.
19
+
20
+ Fixed precision in Number/Vector widgets.
21
+ Minor bug fixes.
22
+
3
23
  ## 0.1.30
4
24
 
5
25
  GraphEditor:
@@ -50,7 +50,8 @@
50
50
  'Dialogs',
51
51
  // 'Immediate UI',
52
52
  'Node Graph',
53
- 'Side Bar'
53
+ 'Side Bar',
54
+ "Timeline"
54
55
  ];
55
56
 
56
57
  let panel = leftArea.addPanel({ className: "lexexamplespanel" });
@@ -45,7 +45,6 @@
45
45
 
46
46
  } );
47
47
 
48
- graph_editor.loadGraph( "../data/function_sample.json" );
49
48
  graph_editor.loadGraph( "../data/graph_sample.json" );
50
49
 
51
50
  function loop(dt) {
@@ -0,0 +1,279 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
5
+ <title>LexGUI Timelines Demo</title>
6
+ <link rel="stylesheet" href="../build/lexgui.css">
7
+ <link rel="icon" href="../images/icon.png">
8
+ <script type="importmap">
9
+ {
10
+ "imports": {
11
+ "lexgui": "../build/lexgui.module.js",
12
+ "lexgui/components/": "../build/components/"
13
+ }
14
+ }
15
+ </script>
16
+ </head>
17
+ <body></body>
18
+ <script type="module">
19
+
20
+ import { LX } from 'lexgui';
21
+ import { Timeline, KeyFramesTimeline, ClipsTimeline, CurvesTimeline } from 'lexgui/components/timeline.js';
22
+
23
+ // init library and get main area
24
+ let area = LX.init();
25
+
26
+ // split main area
27
+ var [leftArea, rightArea] = area.split({sizes:["75%","25%"]});
28
+ // split left area
29
+ var [upArea, bottomArea] = leftArea.split({ type: 'vertical', sizes:["50%", null], minimizable: true });
30
+
31
+ // add canvas to left upper part
32
+ var canvas = document.createElement('canvas');
33
+ canvas.id = "mycanvas";
34
+ canvas.width = leftArea.root.clientWidth;
35
+ canvas.height = leftArea.root.clientHeight;
36
+ canvas.style.width = "100%";
37
+ canvas.style.height = "100%";
38
+
39
+ upArea.attach(canvas);
40
+
41
+ // add on resize event to control canvas size
42
+ leftArea.onresize = function( bounding ) {
43
+ canvas.width = bounding.width;
44
+ canvas.height = bounding.height;
45
+ };
46
+
47
+ const bottomTabs = bottomArea.addTabs();
48
+ const types = { KEYFRAMES: 0, CLIPS: 1, CURVES: 2};
49
+
50
+ let panel = new LX.Panel();
51
+ panel = rightArea.addPanel(panel);
52
+ fillPanel( panel );
53
+
54
+ let activeTimeline = null
55
+ createKyeframeTimeline( bottomTabs );
56
+ createClipsTimeline( bottomTabs );
57
+ createCurvesTimeline( bottomTabs );
58
+
59
+ let mode = types.KEYFRAMES;
60
+
61
+ bottomArea.onresize = (size) => {
62
+ activeTimeline.resize(size);
63
+ }
64
+
65
+ function loop(dt) {
66
+
67
+ if (!lastTime) {
68
+ lastTime = dt;
69
+ }
70
+
71
+ let elapsed = dt - lastTime;
72
+ lastTime = dt;
73
+
74
+ if(activeTimeline) {
75
+ activeTimeline.draw();
76
+ if(activeTimeline.playing) {
77
+
78
+ activeTimeline.currentTime += elapsed* 0.001;
79
+ activeTimeline.onSetTime(activeTimeline.currentTime);
80
+ if(activeTimeline.currentTime >= activeTimeline.animationClip.duration) {
81
+ activeTimeline.currentTime = 0;
82
+ if(!activeTimeline.loop) {
83
+ activeTimeline.changeState();
84
+ }
85
+ }
86
+
87
+ }
88
+ }
89
+
90
+ if(mode == types.KEYFRAMES) {
91
+ let ctx = canvas.getContext("2d");
92
+ ctx.fillStyle = LX.getThemeColor("global-selected-light");
93
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
94
+ ctx.font = panel.getValue('Font Size') + "px Monospace";
95
+ ctx.fillStyle = panel.getValue('Font Color');
96
+
97
+ // Get values from panel widgets (e.g. position value)
98
+ const text = panel.getValue('Text');
99
+ const pos2D = panel.getValue('2D Position');
100
+ ctx.fillText(text, pos2D[0], pos2D[1]);
101
+ }
102
+ requestAnimationFrame(loop);
103
+ }
104
+
105
+ let lastTime = 0;
106
+ requestAnimationFrame(loop);
107
+
108
+ // **** **** **** **** **** **** **** **** **** **** **** ****
109
+
110
+ function fillPanel( panel ) {
111
+ panel.clear();
112
+ panel.branch("Canvas", {icon: "fa-solid fa-palette", filter: true});
113
+ panel.addColor("Background", LX.getThemeColor("global-selected-light"));
114
+ panel.addText("Track", "", null)
115
+ panel.addText("Text", "Lexgui.js @evallsg", null, {placeholder: "e.g. ColorPicker", icon: "fa fa-font"});
116
+ panel.addColor("Font Color", [0.1, 0.1, 0.8], (value, event) => {
117
+ console.log("Font Color: ", value);
118
+ });
119
+ panel.addNumber("Font Size", 36, (value, event) => {
120
+ console.log(value);
121
+ }, { min: 1, max: 48, step: 1});
122
+ panel.addVector2("2D Position", [250, 350], (value, event) => {
123
+ console.log(value);
124
+ }, { min: 0, max: 1024 });
125
+ panel.branch_open = true;
126
+ panel.merge();
127
+ }
128
+
129
+
130
+ function fillClipPanel( panel, clip ) {
131
+
132
+ panel.clear();
133
+
134
+ if(!clip) {
135
+ return;
136
+ }
137
+
138
+ panel.branch(clip.name || "Clip", {icon: "fa-solid fa-clip", filter: true});
139
+ panel.addNumber("Start", clip.start, (v) => {
140
+ const diff = v - clip.start;
141
+ clip.start = v;
142
+ clip.fadein += diff;
143
+ clip.fadeout += diff;
144
+ LX.emit("@on_start_change_fadein", clip.fadein);
145
+ LX.emit("@on_start_change_fadeout", clip.fadeout);
146
+ }, {step: 0.01});
147
+ if(clip.fadein != undefined) {
148
+ panel.addNumber("Fade-In", clip.fadein, (v) => {
149
+ clip.fadein = v;
150
+ }, {min: clip.start, max: clip.fadeout, step: 0.01, signal: "@on_start_change_fadein"});
151
+ }
152
+ if(clip.fadeout != undefined) {
153
+ panel.addNumber("Fade-Out", clip.fadeout, (v) => {
154
+ clip.fadeout = v;
155
+ }, {min: clip.fadein, max: clip.start + clip.duration, step: 0.01, signal: "@on_start_change_fadeout"});
156
+ }
157
+ panel.addNumber("Duration", clip.duration, (v) => {
158
+ clip.duration = v;
159
+ }, {step: 0.01});
160
+
161
+ panel.merge();
162
+ }
163
+
164
+ function createKyeframeTimeline( bottomTabs ) {
165
+
166
+ let keyframesPanel = new LX.Panel();
167
+ bottomTabs.add( "Keyframes", keyframesPanel, {onSelect: () => {
168
+ activeTimeline = kfTimeline;
169
+ kfTimeline.show();
170
+ fillPanel(panel);
171
+ mode = types.KEYFRAMES;
172
+ }} );
173
+ keyframesPanel.onresize = () => {
174
+ kfTimeline.resize();
175
+ }
176
+ let kfTimeline = new LX.KeyFramesTimeline('', {
177
+ disableNewTracks: true,
178
+ onBeforeCreateTopBar: (panel) => {
179
+ panel.addDropdown("Animation", ["Anim 1", "Anim 2", "Anim 3"], "Anim 1", ()=> {})
180
+ },
181
+ onAfterCreateTopBar: (panel) => {
182
+ panel.addButton("", "autoKeyEnable", null, { icon: 'fa fa-wand-magic-sparkles', name: 'autoKeyEnabled', width: "40px" });
183
+ panel.addButton("", "unselectAll", (value, event) => { kfTimeline.unSelectAllKeyFrames();}, { icon: 'fa-regular fa-rectangle-xmark', name: 'unselectAll', callback: (value, event) => { kfTimeline.unSelectAllKeyFrames();}, width: "40px"});
184
+ }
185
+ });
186
+
187
+ keyframesPanel.attach(kfTimeline.root);
188
+ kfTimeline.setSelectedItems(["Item 1", "Item 2", "Item 3"]);
189
+ kfTimeline.setAnimationClip({tracks: [{name: "Item 1.position", values: [250, 350, 250, 250, 250, 350], times: [0, 0.1, 0.2, 0.3]}, {name: "Item 1.scale", values: [0,1,0, 0.5], times: [0, 0.1, 0.2, 0.3]}, {name: "Item 2", values: [0,1,0,1], times: [0.1, 0.2, 0.3, 0.8]}, {name: "Item 3.position", values: [0,1,0], times: [0, 0.1, 0.2, 0.3]}, {name: "Item 3.scale", values: [0,1,0], times: [0, 0.1, 0.2, 0.3]}], duration: 1});
190
+ activeTimeline = kfTimeline;
191
+ kfTimeline.show();
192
+
193
+
194
+ kfTimeline.onSelectKeyFrame = (data, currentSelection, keyFrameIndex) => {
195
+ if(data.multipleSelection) {
196
+ rightArea.hide();
197
+ return;
198
+ }
199
+ rightArea.show();
200
+ let id = data.track.idx;
201
+ let values = kfTimeline.animationClip.tracks[id].values;
202
+ panel.setValue("Track", data.track.name)
203
+ panel.setValue("2D Position", values.slice(keyFrameIndex, keyFrameIndex+2))
204
+ //kfTimeline.animationClip.tracks[currentSelection[0][0]];
205
+ }
206
+
207
+ kfTimeline.onSetTime = ( time ) => {
208
+ rightArea.show();
209
+ let keyframes = kfTimeline.getKeyFramesInRange(kfTimeline.animationClip.tracks[0], time , time, 0.15);
210
+
211
+ let values = kfTimeline.animationClip.tracks[0].values;
212
+ let valueX = values[keyframes[0] * 2];
213
+ let valueY = values[keyframes[0] * 2 + 1];
214
+ if(keyframes.length > 1) {
215
+ let t = Math.abs(kfTimeline.animationClip.tracks[0].times[keyframes[0] * 2] - time);
216
+ valueX = valueX * (1 - t) + values[keyframes[1] * 2] * t;
217
+ valueY = valueY * (1 - t) + values[keyframes[1] * 2 + 1] * t;
218
+ }
219
+ panel.setValue("2D Position", [valueX, valueY]);
220
+ }
221
+ }
222
+
223
+ function createClipsTimeline( bottomTabs ) {
224
+
225
+ let clipsPanel = new LX.Panel();
226
+ bottomTabs.add( "Clips", clipsPanel, {onSelect: () => {
227
+ activeTimeline = clipsTimeline;
228
+ clipsTimeline.show();
229
+ panel.clear();
230
+ mode = types.CLIPS;
231
+ }});
232
+
233
+ let clipsTimeline = new LX.ClipsTimeline("clips-timeline");
234
+ clipsPanel.attach(clipsTimeline.root);
235
+
236
+ let clip = {id:"Clip 1", start:0, duration:1, type:""};
237
+ clipsTimeline.addClip(clip);
238
+ clip = {id:"Clip 2", start:0, fadein: 0.5, fadeout: 0.8, duration:1, type:""};
239
+ clipsTimeline.addClip(clip);
240
+ clip = {id:"Clip 3", start:0, fadein: 0.5, fadeout: 0.8, duration:1, type:""};
241
+ clipsTimeline.addClip(clip);
242
+ clip = {id:"Clip 4", start:0, fadein: 0.5, fadeout: 0.8, duration:1, type:""};
243
+ clipsTimeline.addClip(clip);
244
+ clip = {id:"Clip 5", start:0, fadein: 0.5, fadeout: 0.8, duration:1, type:""};
245
+ clipsTimeline.addClip(clip);
246
+
247
+ // clipsTimeline.setAnimationClip({tracks: [{clips: [clip]}], duration: 2});
248
+ clipsTimeline.selectedItems = ["Clip 1"];
249
+ clipsTimeline.show();
250
+
251
+ clipsTimeline.onSelectClip = (clip) => {
252
+ rightArea.show();
253
+ fillClipPanel(panel, clip);
254
+ }
255
+
256
+ clipsTimeline.draw(0);
257
+ }
258
+
259
+ function createCurvesTimeline( bottomTabs ) {
260
+
261
+ let curvesPanel = new LX.Panel();
262
+ bottomTabs.add( "Curves", curvesPanel, {onSelect: () => {
263
+ activeTimeline = curvesTimeline;
264
+ curvesTimeline.show();
265
+ panel.clear();
266
+ mode = types.CLIPS;
267
+
268
+ }});
269
+
270
+ let curvesTimeline = new LX.CurvesTimeline("curves-timeline", { range: [-1,1]});
271
+ curvesPanel.attach(curvesTimeline.root);
272
+ curvesTimeline.setSelectedItems(["Item 1", "Item 2", "Item 3"]);
273
+ curvesTimeline.setAnimationClip({tracks: [{name: "Item 1.position", values: [0,1,0,-1], times: [0, 0.1, 0.2, 0.3]}, {name: "Item 1.scale", values: [0,1,0, 0.5], times: [0, 0.1, 0.2, 0.3]}, {name: "Item 2", values: [0,1,0,1], times: [0.1, 0.2, 0.3, 0.8]}, {name: "Item 3.position", values: [0,0,0,1], times: [0, 0.1, 0.2, 0.3]}, {name: "Item 3.scale", values: [0,1,0], times: [0, 0.1, 0.2, 0.3]}], duration: 1});
274
+ curvesTimeline.show();
275
+ curvesTimeline.draw(0);
276
+ }
277
+
278
+ </script>
279
+ </html>
@@ -0,0 +1,35 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
5
+ <title>LexGUI Video Editor Demo</title>
6
+ <link rel="stylesheet" href="../build/lexgui.css">
7
+ <link rel="icon" href="../images/icon.png">
8
+ <script type="importmap">
9
+ {
10
+ "imports": {
11
+ "lexgui": "../build/lexgui.module.js",
12
+ "lexgui/components/": "../build/components/"
13
+ }
14
+ }
15
+ </script>
16
+ </head>
17
+ <body></body>
18
+ <script type="module">
19
+
20
+ import { LX } from 'lexgui';
21
+ import { VideoEditor } from 'lexgui/components/videoeditor.js';
22
+ // init library and get main area
23
+ let area = LX.init();
24
+
25
+ // split main area
26
+ let [leftArea, rightArea] = area.split({sizes:["75%","25%"], minimizable: true});
27
+ area.extend();
28
+
29
+ let videoEditor = new LX.VideoEditor(leftArea, { src: "../data/video.mp4"})
30
+
31
+ let panel = new LX.Panel();
32
+ panel = rightArea.addPanel(panel);
33
+
34
+ </script>
35
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lexgui",
3
- "version": "0.1.30",
3
+ "version": "0.1.32",
4
4
  "description": "JS library to create web graphical user interfaces",
5
5
  "type": "module",
6
6
  "main": "./build/lexgui.js",