lexgui 0.1.32 → 0.1.34
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/build/components/codeeditor.js +1 -1
- package/build/components/timeline.js +2059 -1443
- package/build/components/videoeditor.js +191 -100
- package/build/lexgui.css +40 -17
- package/build/lexgui.js +326 -256
- package/build/lexgui.module.js +367 -202
- package/changelog.md +14 -0
- package/demo.js +4 -13
- package/examples/timeline.html +39 -24
- package/examples/video_editor.html +30 -13
- package/examples/video_editor2.html +118 -0
- package/package.json +1 -1
package/changelog.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# lexgui.js changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.34
|
|
4
|
+
|
|
5
|
+
Fix setValue on Checkbox.
|
|
6
|
+
Fix position of Dropdown menu when content is scrolled.
|
|
7
|
+
`moveOutAction` option to delete or clamp curve points.
|
|
8
|
+
Minor tweaks.
|
|
9
|
+
|
|
10
|
+
## 0.1.33
|
|
11
|
+
|
|
12
|
+
Work on VideoEditor UI component.
|
|
13
|
+
Improvements Timeline.
|
|
14
|
+
Allow to select multiple options in AssetViewer.
|
|
15
|
+
Minor bug fixes.
|
|
16
|
+
|
|
3
17
|
## 0.1.32
|
|
4
18
|
|
|
5
19
|
Timeline:
|
package/demo.js
CHANGED
|
@@ -433,6 +433,7 @@ function fillPanel( panel ) {
|
|
|
433
433
|
window.tree = panel.addTree("Scene Tree", sceneData, {
|
|
434
434
|
icons: treeIcons,
|
|
435
435
|
// filter: false,
|
|
436
|
+
addDefault: true,
|
|
436
437
|
onevent: (event) => {
|
|
437
438
|
console.log(event.string());
|
|
438
439
|
|
|
@@ -453,19 +454,9 @@ function fillPanel( panel ) {
|
|
|
453
454
|
console.log(event.node.id + " dbl clicked");
|
|
454
455
|
break;
|
|
455
456
|
case LX.TreeEvent.NODE_CONTEXTMENU:
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
m.add( "Select Children", () => console.log("select children") );
|
|
461
|
-
m.add( "Clone", { callback: () => console.log("Clone"), color: "#0d5" } );
|
|
462
|
-
m.add( "Components/Transform");
|
|
463
|
-
m.add( "Components/MeshRenderer");
|
|
464
|
-
m.add( "Move before sibling" );
|
|
465
|
-
m.add( "Move after sibling" );
|
|
466
|
-
m.add( "Move to parent" );
|
|
467
|
-
m.add( "Delete" );
|
|
468
|
-
});
|
|
457
|
+
const m = event.panel;
|
|
458
|
+
m.add( "Components/Transform");
|
|
459
|
+
m.add( "Components/MeshRenderer");
|
|
469
460
|
break;
|
|
470
461
|
case LX.TreeEvent.NODE_DRAGGED:
|
|
471
462
|
console.log(event.node.id + " is now child of " + event.value.id);
|
package/examples/timeline.html
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<script type="module">
|
|
19
19
|
|
|
20
20
|
import { LX } from 'lexgui';
|
|
21
|
-
import { Timeline, KeyFramesTimeline, ClipsTimeline, CurvesTimeline } from 'lexgui/components/timeline.js';
|
|
21
|
+
import { Timeline, KeyFramesTimeline, ClipsTimeline, CurvesTimeline, CurvesKeyFramesTimeline } from 'lexgui/components/timeline.js';
|
|
22
22
|
|
|
23
23
|
// init library and get main area
|
|
24
24
|
let area = LX.init();
|
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
|
|
47
47
|
const bottomTabs = bottomArea.addTabs();
|
|
48
48
|
const types = { KEYFRAMES: 0, CLIPS: 1, CURVES: 2};
|
|
49
|
+
let position = [250, 350];
|
|
50
|
+
let trackName = "";
|
|
49
51
|
|
|
50
52
|
let panel = new LX.Panel();
|
|
51
53
|
panel = rightArea.addPanel(panel);
|
|
@@ -76,14 +78,15 @@
|
|
|
76
78
|
if(activeTimeline.playing) {
|
|
77
79
|
|
|
78
80
|
activeTimeline.currentTime += elapsed* 0.001;
|
|
79
|
-
activeTimeline.onSetTime
|
|
81
|
+
if(activeTimeline.onSetTime) {
|
|
82
|
+
activeTimeline.onSetTime(activeTimeline.currentTime);
|
|
83
|
+
}
|
|
80
84
|
if(activeTimeline.currentTime >= activeTimeline.animationClip.duration) {
|
|
81
85
|
activeTimeline.currentTime = 0;
|
|
82
86
|
if(!activeTimeline.loop) {
|
|
83
87
|
activeTimeline.changeState();
|
|
84
88
|
}
|
|
85
|
-
}
|
|
86
|
-
|
|
89
|
+
}
|
|
87
90
|
}
|
|
88
91
|
}
|
|
89
92
|
|
|
@@ -108,10 +111,10 @@
|
|
|
108
111
|
// **** **** **** **** **** **** **** **** **** **** **** ****
|
|
109
112
|
|
|
110
113
|
function fillPanel( panel ) {
|
|
111
|
-
|
|
114
|
+
panel.clear();
|
|
112
115
|
panel.branch("Canvas", {icon: "fa-solid fa-palette", filter: true});
|
|
113
116
|
panel.addColor("Background", LX.getThemeColor("global-selected-light"));
|
|
114
|
-
panel.addText("Track",
|
|
117
|
+
panel.addText("Track", trackName, null)
|
|
115
118
|
panel.addText("Text", "Lexgui.js @evallsg", null, {placeholder: "e.g. ColorPicker", icon: "fa fa-font"});
|
|
116
119
|
panel.addColor("Font Color", [0.1, 0.1, 0.8], (value, event) => {
|
|
117
120
|
console.log("Font Color: ", value);
|
|
@@ -119,8 +122,9 @@
|
|
|
119
122
|
panel.addNumber("Font Size", 36, (value, event) => {
|
|
120
123
|
console.log(value);
|
|
121
124
|
}, { min: 1, max: 48, step: 1});
|
|
122
|
-
panel.addVector2("2D Position",
|
|
123
|
-
|
|
125
|
+
panel.addVector2("2D Position", position, (value, event) => {
|
|
126
|
+
|
|
127
|
+
activeTimeline.updateSelectedKeyframe(value);
|
|
124
128
|
}, { min: 0, max: 1024 });
|
|
125
129
|
panel.branch_open = true;
|
|
126
130
|
panel.merge();
|
|
@@ -185,8 +189,8 @@
|
|
|
185
189
|
});
|
|
186
190
|
|
|
187
191
|
keyframesPanel.attach(kfTimeline.root);
|
|
188
|
-
kfTimeline.setSelectedItems(["
|
|
189
|
-
kfTimeline.setAnimationClip({tracks: [{name: "
|
|
192
|
+
kfTimeline.setSelectedItems(["Font", "Item 2", "Item 3"]);
|
|
193
|
+
kfTimeline.setAnimationClip({tracks: [{name: "Font.position", values: [250, 350, 250, 250, 250, 350], times: [0, 0.1, 0.2]}, {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]}, {name: "Item 3.position", values: [0,1,0,0,0,0], times: [0.1, 0.2, 0.3]}, {name: "Item 3.scale", values: [0,1,0], times: [ 0.1, 0.2, 0.3]}], duration: 1});
|
|
190
194
|
activeTimeline = kfTimeline;
|
|
191
195
|
kfTimeline.show();
|
|
192
196
|
|
|
@@ -197,26 +201,37 @@
|
|
|
197
201
|
return;
|
|
198
202
|
}
|
|
199
203
|
rightArea.show();
|
|
200
|
-
|
|
204
|
+
trackName = data.track.name;
|
|
205
|
+
if( trackName != "Font" || data.track.type != "position") {
|
|
206
|
+
return
|
|
207
|
+
}
|
|
208
|
+
const id = data.track.clipIdx;
|
|
201
209
|
let values = kfTimeline.animationClip.tracks[id].values;
|
|
202
|
-
|
|
203
|
-
|
|
210
|
+
const dim = kfTimeline.animationClip.tracks[id].dim;
|
|
211
|
+
|
|
212
|
+
position = values.slice(keyFrameIndex * dim, keyFrameIndex * dim + dim);
|
|
213
|
+
fillPanel(panel);
|
|
204
214
|
//kfTimeline.animationClip.tracks[currentSelection[0][0]];
|
|
205
215
|
}
|
|
206
216
|
|
|
207
217
|
kfTimeline.onSetTime = ( time ) => {
|
|
208
218
|
rightArea.show();
|
|
209
|
-
|
|
210
|
-
|
|
219
|
+
const frametime = kfTimeline.getNearestKeyFrame( kfTimeline.animationClip.tracks[0], time);
|
|
220
|
+
let keyframe = kfTimeline.animationClip.tracks[0].times.indexOf(frametime);
|
|
211
221
|
let values = kfTimeline.animationClip.tracks[0].values;
|
|
212
|
-
let valueX = values[
|
|
213
|
-
let valueY = values[
|
|
214
|
-
if(
|
|
215
|
-
let t = Math.abs(
|
|
216
|
-
|
|
217
|
-
|
|
222
|
+
let valueX = values[keyframe * 2];
|
|
223
|
+
let valueY = values[keyframe * 2 + 1];
|
|
224
|
+
if(keyframe != undefined) {
|
|
225
|
+
let t = Math.abs(frametime - time);
|
|
226
|
+
let sign = frametime - time > 0 ? -1 : 1;
|
|
227
|
+
const nearestFrame = keyframe * 2 + sign;
|
|
228
|
+
if (nearestFrame <= values.length - 2 && nearestFrame >= 0) {
|
|
229
|
+
valueX = valueX * (1 - t) + values[keyframe * 2 + sign] * t;
|
|
230
|
+
valueY = valueY * (1 - t) + values[keyframe * 2 + sign + 1] * t;
|
|
231
|
+
}
|
|
218
232
|
}
|
|
219
|
-
|
|
233
|
+
position = [valueX, valueY];
|
|
234
|
+
fillPanel( panel );
|
|
220
235
|
}
|
|
221
236
|
}
|
|
222
237
|
|
|
@@ -267,10 +282,10 @@
|
|
|
267
282
|
|
|
268
283
|
}});
|
|
269
284
|
|
|
270
|
-
let curvesTimeline = new LX.
|
|
285
|
+
let curvesTimeline = new LX.CurvesKeyFramesTimeline("curves-timeline", { range: [-1,1]});
|
|
271
286
|
curvesPanel.attach(curvesTimeline.root);
|
|
272
287
|
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,
|
|
288
|
+
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,1], times: [0]}, {name: "Item 3.scale", values: [0,1,0], times: [0, 0.1, 0.3]}], duration: 1});
|
|
274
289
|
curvesTimeline.show();
|
|
275
290
|
curvesTimeline.draw(0);
|
|
276
291
|
}
|
|
@@ -17,19 +17,36 @@
|
|
|
17
17
|
<body></body>
|
|
18
18
|
<script type="module">
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
const videoArea = new LX.Area({id:'video-area'});
|
|
30
|
+
const video = document.createElement('video');
|
|
31
|
+
video.src = "../data/video.mp4";
|
|
32
|
+
videoArea.attach(video);
|
|
33
|
+
|
|
34
|
+
const videoEditor = new LX.VideoEditor(leftArea, {videoArea, video})
|
|
35
|
+
|
|
36
|
+
const canvas = document.createElement('canvas');
|
|
37
|
+
canvas.width = video.clientWidth;
|
|
38
|
+
canvas.height = video.clientHeight;
|
|
39
|
+
const ctx = canvas.getContext("2d");
|
|
40
|
+
ctx.fillStyle = LX.getThemeColor("global-selected-light");
|
|
41
|
+
ctx.font = "40px Arial";
|
|
42
|
+
ctx.fillText("I'm a canvas above the video!", canvas.width/2, 100);
|
|
43
|
+
|
|
44
|
+
canvas.style.position = "absolute";
|
|
45
|
+
canvas.style.left = "0";
|
|
46
|
+
videoArea.attach(canvas);
|
|
47
|
+
|
|
48
|
+
let panel = new LX.Panel();
|
|
49
|
+
panel = rightArea.addPanel(panel);
|
|
33
50
|
|
|
34
51
|
</script>
|
|
35
52
|
</html>
|
|
@@ -0,0 +1,118 @@
|
|
|
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
|
+
|
|
23
|
+
// Init library and get main area
|
|
24
|
+
let area = LX.init();
|
|
25
|
+
const menubar = area.addMenubar( m => {
|
|
26
|
+
m.setButtonImage("Page", "../data/godot_pixelart.png", null, {float: "left"});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Split main area
|
|
30
|
+
let [leftArea, rightArea] = area.split({sizes:["75%","25%"], minimizable: true});
|
|
31
|
+
let [topArea, bottomArea] = leftArea.split({sizes:["90%", null], minimizable: false, resize: false, type: "vertical"});
|
|
32
|
+
area.extend();
|
|
33
|
+
|
|
34
|
+
/* Create video area with a menubar */
|
|
35
|
+
const videoArea = new LX.Area({id:'video-area'});
|
|
36
|
+
|
|
37
|
+
/* Add video editor with the video into the area*/
|
|
38
|
+
const video = document.createElement('video');
|
|
39
|
+
video.src = "../data/video.mp4";
|
|
40
|
+
videoArea.attach(video);
|
|
41
|
+
const videoEditor = new LX.VideoEditor(topArea, {videoArea, video})
|
|
42
|
+
|
|
43
|
+
/* Add canvas above video */
|
|
44
|
+
const canvas = document.createElement('canvas');
|
|
45
|
+
canvas.width = video.clientWidth;
|
|
46
|
+
canvas.height = video.clientHeight;
|
|
47
|
+
const ctx = canvas.getContext("2d");
|
|
48
|
+
ctx.fillStyle = LX.getThemeColor("global-selected-light");
|
|
49
|
+
ctx.font = "40px Arial";
|
|
50
|
+
ctx.fillText("I'm a canvas above the video!", canvas.width/2, 100);
|
|
51
|
+
|
|
52
|
+
canvas.style.position = "absolute";
|
|
53
|
+
canvas.style.left = "0";
|
|
54
|
+
videoArea.attach(canvas);
|
|
55
|
+
leftArea.onresize = (size) => {
|
|
56
|
+
|
|
57
|
+
canvas.width = video.clientWidth;
|
|
58
|
+
canvas.height = video.clientHeight;
|
|
59
|
+
const ctx = canvas.getContext("2d");
|
|
60
|
+
ctx.fillStyle = LX.getThemeColor("global-selected-light");
|
|
61
|
+
ctx.font = "40px Arial";
|
|
62
|
+
ctx.fillText("I'm a canvas above the video!", canvas.width/2, 100);
|
|
63
|
+
//videoEditor.timebar.resize(size)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Add show/hide right panel button*/
|
|
67
|
+
videoArea.addOverlayButtons([{
|
|
68
|
+
selectable: true,
|
|
69
|
+
selected: true,
|
|
70
|
+
icon: "fa-solid fa-info",
|
|
71
|
+
name: "Properties",
|
|
72
|
+
callback: (v, e) => {
|
|
73
|
+
if(area.split_extended) {
|
|
74
|
+
area.reduce();
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
area.extend();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}], {float: 'tvr'});
|
|
81
|
+
|
|
82
|
+
let p = bottomArea.addPanel({width: "100%", height: "100%", style: {display: "flex", "flex-direction": "row", "justify-content": "center", "align-content": "flex-start", "flex-wrap": "wrap"}});
|
|
83
|
+
p.addButton(null, "Trim", (v) => {
|
|
84
|
+
console.log(videoEditor.getTrimedTimes())
|
|
85
|
+
|
|
86
|
+
videoArea.sections[1].root.resize(["20%", "20%"])
|
|
87
|
+
}, {width: "100px"})
|
|
88
|
+
p.addButton(null, null, (v) => {}, {width: "40px", icon: "fa-solid fa-rotate-left"})
|
|
89
|
+
|
|
90
|
+
/* Create right panel */
|
|
91
|
+
let panel = new LX.Panel({id:"Properties"});
|
|
92
|
+
panel = rightArea.addPanel({id:"Properties"});
|
|
93
|
+
createBlendShapesInspector({"Name 1": 0, "Name 2": 0, "Name 3": 0.5, "Name 4": 0, "Name 5": 1,},
|
|
94
|
+
{inspector: panel});
|
|
95
|
+
|
|
96
|
+
/* Functions */
|
|
97
|
+
function createBlendShapesInspector(bsNames, options = {}) {
|
|
98
|
+
|
|
99
|
+
let inspector = options.inspector || new LX.Panel({id:"blendshapes-inspector"});
|
|
100
|
+
|
|
101
|
+
if(options.clear) {
|
|
102
|
+
inspector.clear();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if(inspector.root.id) {
|
|
106
|
+
inspector.addTitle(inspector.root.id);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for(let name in bsNames) {
|
|
110
|
+
inspector.addProgress(name, bsNames[name], {min: 0, max: 1, low: 0.3, optimum: 1, high: 0.6, editable: options.editable, showNumber: options.showNumber,
|
|
111
|
+
callback: (v,e) => {},
|
|
112
|
+
signal: "@on_change_au_" + name});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return inspector;
|
|
116
|
+
}
|
|
117
|
+
</script>
|
|
118
|
+
</html>
|