lexgui 0.1.31 → 0.1.33
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/timeline.js +2619 -1677
- package/build/components/videoeditor.js +630 -0
- package/build/lexgui.css +110 -4
- package/build/lexgui.js +335 -282
- package/build/lexgui.module.js +307 -232
- package/changelog.md +18 -0
- package/examples/index.html +2 -1
- package/examples/timeline.html +294 -0
- package/examples/video_editor.html +52 -0
- package/examples/video_editor2.html +118 -0
- package/package.json +1 -1
package/changelog.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# lexgui.js changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.33
|
|
4
|
+
|
|
5
|
+
- New VideoEditor UI component.
|
|
6
|
+
- Improvements Timeline.
|
|
7
|
+
- Allow to select multiple options in AssetViewer.
|
|
8
|
+
- Minor bug fixes.
|
|
9
|
+
|
|
10
|
+
## 0.1.32
|
|
11
|
+
|
|
12
|
+
Timeline:
|
|
13
|
+
- Allow addition of widgets in top bar.
|
|
14
|
+
- General improvements.
|
|
15
|
+
- Docs started.
|
|
16
|
+
|
|
17
|
+
New VideoEditor component (still wip).
|
|
18
|
+
Added skipCallback for `Widget.set()`.
|
|
19
|
+
Minor bug fixes.
|
|
20
|
+
|
|
3
21
|
## 0.1.31
|
|
4
22
|
|
|
5
23
|
GraphEditor:
|
package/examples/index.html
CHANGED
|
@@ -0,0 +1,294 @@
|
|
|
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, CurvesKeyFramesTimeline } 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
|
+
let position = [250, 350];
|
|
50
|
+
let trackName = "";
|
|
51
|
+
|
|
52
|
+
let panel = new LX.Panel();
|
|
53
|
+
panel = rightArea.addPanel(panel);
|
|
54
|
+
fillPanel( panel );
|
|
55
|
+
|
|
56
|
+
let activeTimeline = null
|
|
57
|
+
createKyeframeTimeline( bottomTabs );
|
|
58
|
+
createClipsTimeline( bottomTabs );
|
|
59
|
+
createCurvesTimeline( bottomTabs );
|
|
60
|
+
|
|
61
|
+
let mode = types.KEYFRAMES;
|
|
62
|
+
|
|
63
|
+
bottomArea.onresize = (size) => {
|
|
64
|
+
activeTimeline.resize(size);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function loop(dt) {
|
|
68
|
+
|
|
69
|
+
if (!lastTime) {
|
|
70
|
+
lastTime = dt;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let elapsed = dt - lastTime;
|
|
74
|
+
lastTime = dt;
|
|
75
|
+
|
|
76
|
+
if(activeTimeline) {
|
|
77
|
+
activeTimeline.draw();
|
|
78
|
+
if(activeTimeline.playing) {
|
|
79
|
+
|
|
80
|
+
activeTimeline.currentTime += elapsed* 0.001;
|
|
81
|
+
if(activeTimeline.onSetTime) {
|
|
82
|
+
activeTimeline.onSetTime(activeTimeline.currentTime);
|
|
83
|
+
}
|
|
84
|
+
if(activeTimeline.currentTime >= activeTimeline.animationClip.duration) {
|
|
85
|
+
activeTimeline.currentTime = 0;
|
|
86
|
+
if(!activeTimeline.loop) {
|
|
87
|
+
activeTimeline.changeState();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if(mode == types.KEYFRAMES) {
|
|
94
|
+
let ctx = canvas.getContext("2d");
|
|
95
|
+
ctx.fillStyle = LX.getThemeColor("global-selected-light");
|
|
96
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
97
|
+
ctx.font = panel.getValue('Font Size') + "px Monospace";
|
|
98
|
+
ctx.fillStyle = panel.getValue('Font Color');
|
|
99
|
+
|
|
100
|
+
// Get values from panel widgets (e.g. position value)
|
|
101
|
+
const text = panel.getValue('Text');
|
|
102
|
+
const pos2D = panel.getValue('2D Position');
|
|
103
|
+
ctx.fillText(text, pos2D[0], pos2D[1]);
|
|
104
|
+
}
|
|
105
|
+
requestAnimationFrame(loop);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let lastTime = 0;
|
|
109
|
+
requestAnimationFrame(loop);
|
|
110
|
+
|
|
111
|
+
// **** **** **** **** **** **** **** **** **** **** **** ****
|
|
112
|
+
|
|
113
|
+
function fillPanel( panel ) {
|
|
114
|
+
panel.clear();
|
|
115
|
+
panel.branch("Canvas", {icon: "fa-solid fa-palette", filter: true});
|
|
116
|
+
panel.addColor("Background", LX.getThemeColor("global-selected-light"));
|
|
117
|
+
panel.addText("Track", trackName, null)
|
|
118
|
+
panel.addText("Text", "Lexgui.js @evallsg", null, {placeholder: "e.g. ColorPicker", icon: "fa fa-font"});
|
|
119
|
+
panel.addColor("Font Color", [0.1, 0.1, 0.8], (value, event) => {
|
|
120
|
+
console.log("Font Color: ", value);
|
|
121
|
+
});
|
|
122
|
+
panel.addNumber("Font Size", 36, (value, event) => {
|
|
123
|
+
console.log(value);
|
|
124
|
+
}, { min: 1, max: 48, step: 1});
|
|
125
|
+
panel.addVector2("2D Position", position, (value, event) => {
|
|
126
|
+
|
|
127
|
+
activeTimeline.updateSelectedKeyframe(value);
|
|
128
|
+
}, { min: 0, max: 1024 });
|
|
129
|
+
panel.branch_open = true;
|
|
130
|
+
panel.merge();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
function fillClipPanel( panel, clip ) {
|
|
135
|
+
|
|
136
|
+
panel.clear();
|
|
137
|
+
|
|
138
|
+
if(!clip) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
panel.branch(clip.name || "Clip", {icon: "fa-solid fa-clip", filter: true});
|
|
143
|
+
panel.addNumber("Start", clip.start, (v) => {
|
|
144
|
+
const diff = v - clip.start;
|
|
145
|
+
clip.start = v;
|
|
146
|
+
clip.fadein += diff;
|
|
147
|
+
clip.fadeout += diff;
|
|
148
|
+
LX.emit("@on_start_change_fadein", clip.fadein);
|
|
149
|
+
LX.emit("@on_start_change_fadeout", clip.fadeout);
|
|
150
|
+
}, {step: 0.01});
|
|
151
|
+
if(clip.fadein != undefined) {
|
|
152
|
+
panel.addNumber("Fade-In", clip.fadein, (v) => {
|
|
153
|
+
clip.fadein = v;
|
|
154
|
+
}, {min: clip.start, max: clip.fadeout, step: 0.01, signal: "@on_start_change_fadein"});
|
|
155
|
+
}
|
|
156
|
+
if(clip.fadeout != undefined) {
|
|
157
|
+
panel.addNumber("Fade-Out", clip.fadeout, (v) => {
|
|
158
|
+
clip.fadeout = v;
|
|
159
|
+
}, {min: clip.fadein, max: clip.start + clip.duration, step: 0.01, signal: "@on_start_change_fadeout"});
|
|
160
|
+
}
|
|
161
|
+
panel.addNumber("Duration", clip.duration, (v) => {
|
|
162
|
+
clip.duration = v;
|
|
163
|
+
}, {step: 0.01});
|
|
164
|
+
|
|
165
|
+
panel.merge();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function createKyeframeTimeline( bottomTabs ) {
|
|
169
|
+
|
|
170
|
+
let keyframesPanel = new LX.Panel();
|
|
171
|
+
bottomTabs.add( "Keyframes", keyframesPanel, {onSelect: () => {
|
|
172
|
+
activeTimeline = kfTimeline;
|
|
173
|
+
kfTimeline.show();
|
|
174
|
+
fillPanel(panel);
|
|
175
|
+
mode = types.KEYFRAMES;
|
|
176
|
+
}} );
|
|
177
|
+
keyframesPanel.onresize = () => {
|
|
178
|
+
kfTimeline.resize();
|
|
179
|
+
}
|
|
180
|
+
let kfTimeline = new LX.KeyFramesTimeline('', {
|
|
181
|
+
disableNewTracks: true,
|
|
182
|
+
onBeforeCreateTopBar: (panel) => {
|
|
183
|
+
panel.addDropdown("Animation", ["Anim 1", "Anim 2", "Anim 3"], "Anim 1", ()=> {})
|
|
184
|
+
},
|
|
185
|
+
onAfterCreateTopBar: (panel) => {
|
|
186
|
+
panel.addButton("", "autoKeyEnable", null, { icon: 'fa fa-wand-magic-sparkles', name: 'autoKeyEnabled', width: "40px" });
|
|
187
|
+
panel.addButton("", "unselectAll", (value, event) => { kfTimeline.unSelectAllKeyFrames();}, { icon: 'fa-regular fa-rectangle-xmark', name: 'unselectAll', callback: (value, event) => { kfTimeline.unSelectAllKeyFrames();}, width: "40px"});
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
keyframesPanel.attach(kfTimeline.root);
|
|
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});
|
|
194
|
+
activeTimeline = kfTimeline;
|
|
195
|
+
kfTimeline.show();
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
kfTimeline.onSelectKeyFrame = (data, currentSelection, keyFrameIndex) => {
|
|
199
|
+
if(data.multipleSelection) {
|
|
200
|
+
rightArea.hide();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
rightArea.show();
|
|
204
|
+
trackName = data.track.name;
|
|
205
|
+
if( trackName != "Font" || data.track.type != "position") {
|
|
206
|
+
return
|
|
207
|
+
}
|
|
208
|
+
const id = data.track.clipIdx;
|
|
209
|
+
let values = kfTimeline.animationClip.tracks[id].values;
|
|
210
|
+
const dim = kfTimeline.animationClip.tracks[id].dim;
|
|
211
|
+
|
|
212
|
+
position = values.slice(keyFrameIndex * dim, keyFrameIndex * dim + dim);
|
|
213
|
+
fillPanel(panel);
|
|
214
|
+
//kfTimeline.animationClip.tracks[currentSelection[0][0]];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
kfTimeline.onSetTime = ( time ) => {
|
|
218
|
+
rightArea.show();
|
|
219
|
+
const frametime = kfTimeline.getNearestKeyFrame( kfTimeline.animationClip.tracks[0], time);
|
|
220
|
+
let keyframe = kfTimeline.animationClip.tracks[0].times.indexOf(frametime);
|
|
221
|
+
let values = kfTimeline.animationClip.tracks[0].values;
|
|
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
|
+
}
|
|
232
|
+
}
|
|
233
|
+
position = [valueX, valueY];
|
|
234
|
+
fillPanel( panel );
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function createClipsTimeline( bottomTabs ) {
|
|
239
|
+
|
|
240
|
+
let clipsPanel = new LX.Panel();
|
|
241
|
+
bottomTabs.add( "Clips", clipsPanel, {onSelect: () => {
|
|
242
|
+
activeTimeline = clipsTimeline;
|
|
243
|
+
clipsTimeline.show();
|
|
244
|
+
panel.clear();
|
|
245
|
+
mode = types.CLIPS;
|
|
246
|
+
}});
|
|
247
|
+
|
|
248
|
+
let clipsTimeline = new LX.ClipsTimeline("clips-timeline");
|
|
249
|
+
clipsPanel.attach(clipsTimeline.root);
|
|
250
|
+
|
|
251
|
+
let clip = {id:"Clip 1", start:0, duration:1, type:""};
|
|
252
|
+
clipsTimeline.addClip(clip);
|
|
253
|
+
clip = {id:"Clip 2", start:0, fadein: 0.5, fadeout: 0.8, duration:1, type:""};
|
|
254
|
+
clipsTimeline.addClip(clip);
|
|
255
|
+
clip = {id:"Clip 3", start:0, fadein: 0.5, fadeout: 0.8, duration:1, type:""};
|
|
256
|
+
clipsTimeline.addClip(clip);
|
|
257
|
+
clip = {id:"Clip 4", start:0, fadein: 0.5, fadeout: 0.8, duration:1, type:""};
|
|
258
|
+
clipsTimeline.addClip(clip);
|
|
259
|
+
clip = {id:"Clip 5", start:0, fadein: 0.5, fadeout: 0.8, duration:1, type:""};
|
|
260
|
+
clipsTimeline.addClip(clip);
|
|
261
|
+
|
|
262
|
+
// clipsTimeline.setAnimationClip({tracks: [{clips: [clip]}], duration: 2});
|
|
263
|
+
clipsTimeline.selectedItems = ["Clip 1"];
|
|
264
|
+
clipsTimeline.show();
|
|
265
|
+
|
|
266
|
+
clipsTimeline.onSelectClip = (clip) => {
|
|
267
|
+
rightArea.show();
|
|
268
|
+
fillClipPanel(panel, clip);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
clipsTimeline.draw(0);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function createCurvesTimeline( bottomTabs ) {
|
|
275
|
+
|
|
276
|
+
let curvesPanel = new LX.Panel();
|
|
277
|
+
bottomTabs.add( "Curves", curvesPanel, {onSelect: () => {
|
|
278
|
+
activeTimeline = curvesTimeline;
|
|
279
|
+
curvesTimeline.show();
|
|
280
|
+
panel.clear();
|
|
281
|
+
mode = types.CLIPS;
|
|
282
|
+
|
|
283
|
+
}});
|
|
284
|
+
|
|
285
|
+
let curvesTimeline = new LX.CurvesKeyFramesTimeline("curves-timeline", { range: [-1,1]});
|
|
286
|
+
curvesPanel.attach(curvesTimeline.root);
|
|
287
|
+
curvesTimeline.setSelectedItems(["Item 1", "Item 2", "Item 3"]);
|
|
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});
|
|
289
|
+
curvesTimeline.show();
|
|
290
|
+
curvesTimeline.draw(0);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
</script>
|
|
294
|
+
</html>
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
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);
|
|
50
|
+
|
|
51
|
+
</script>
|
|
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>
|