@mulsense/xnew 0.1.6 → 0.1.8
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/dist/addons/xmatter.js +7 -9
- package/dist/addons/xmatter.mjs +7 -9
- package/dist/addons/xpixi.js +6 -8
- package/dist/addons/xpixi.mjs +6 -8
- package/dist/addons/xrapier2d.d.ts +1 -1
- package/dist/addons/xrapier2d.js +30 -27
- package/dist/addons/xrapier2d.mjs +30 -27
- package/dist/addons/xthree.js +2 -2
- package/dist/addons/xthree.mjs +2 -2
- package/dist/types/audio/audio.d.ts +2 -13
- package/dist/types/audio/file.d.ts +12 -0
- package/dist/types/audio/loader.d.ts +12 -0
- package/dist/types/audio/synthesizer.d.ts +26 -53
- package/dist/types/basics/Accordion.d.ts +5 -5
- package/dist/types/basics/Controller.d.ts +20 -18
- package/dist/types/basics/Drag.d.ts +6 -0
- package/dist/types/basics/Input.d.ts +2 -2
- package/dist/types/basics/KeyEvent.d.ts +2 -0
- package/dist/types/basics/KeyboardEvent.d.ts +2 -0
- package/dist/types/basics/Modal.d.ts +3 -3
- package/dist/types/basics/PointerEvent.d.ts +2 -0
- package/dist/types/basics/ResizeEvent.d.ts +2 -1
- package/dist/types/basics/Screen.d.ts +3 -7
- package/dist/types/basics/Tab.d.ts +5 -5
- package/dist/types/basics/UserEvent.d.ts +1 -1
- package/dist/types/core/time.d.ts +4 -7
- package/dist/types/core/unit.d.ts +18 -20
- package/dist/types/core/xnew.d.ts +189 -4
- package/dist/types/index.d.ts +18 -15
- package/dist/xnew.d.ts +297 -128
- package/dist/xnew.js +820 -759
- package/dist/xnew.mjs +820 -759
- package/package.json +1 -1
package/dist/xnew.mjs
CHANGED
|
@@ -1,53 +1,35 @@
|
|
|
1
|
-
function ResizeEvent(resize) {
|
|
2
|
-
const observer = new ResizeObserver((entries) => {
|
|
3
|
-
for (const entry of entries) {
|
|
4
|
-
resize.emit('-resize');
|
|
5
|
-
break;
|
|
6
|
-
}
|
|
7
|
-
});
|
|
8
|
-
if (resize.element) {
|
|
9
|
-
observer.observe(resize.element);
|
|
10
|
-
}
|
|
11
|
-
resize.on('finalize', () => {
|
|
12
|
-
if (resize.element) {
|
|
13
|
-
observer.unobserve(resize.element);
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
|
|
18
1
|
//----------------------------------------------------------------------------------------------------
|
|
19
2
|
// ticker
|
|
20
3
|
//----------------------------------------------------------------------------------------------------
|
|
21
4
|
class Ticker {
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
5
|
+
constructor(callback) {
|
|
6
|
+
const self = this;
|
|
7
|
+
this.id = null;
|
|
8
|
+
let previous = 0;
|
|
9
|
+
ticker();
|
|
10
|
+
function ticker() {
|
|
11
|
+
const time = Date.now();
|
|
12
|
+
const interval = 1000 / 60;
|
|
13
|
+
if (time - previous > interval * 0.9) {
|
|
14
|
+
callback(time);
|
|
15
|
+
previous = time;
|
|
16
|
+
}
|
|
17
|
+
self.id = requestAnimationFrame(ticker);
|
|
28
18
|
}
|
|
29
|
-
Ticker.animation = requestAnimationFrame(Ticker.ticker);
|
|
30
19
|
}
|
|
31
|
-
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
|
|
20
|
+
clear() {
|
|
21
|
+
if (this.id !== null) {
|
|
22
|
+
cancelAnimationFrame(this.id);
|
|
23
|
+
this.id = null;
|
|
35
24
|
}
|
|
36
|
-
Ticker.callbacks.add(callback);
|
|
37
|
-
}
|
|
38
|
-
static clear(callback) {
|
|
39
|
-
Ticker.callbacks.delete(callback);
|
|
40
25
|
}
|
|
41
26
|
}
|
|
42
|
-
Ticker.animation = null;
|
|
43
|
-
Ticker.callbacks = new Set;
|
|
44
|
-
Ticker.previous = 0.0;
|
|
45
27
|
//----------------------------------------------------------------------------------------------------
|
|
46
28
|
// timer
|
|
47
29
|
//----------------------------------------------------------------------------------------------------
|
|
48
30
|
class Timer {
|
|
49
31
|
constructor(timeout, transition, delay, loop = false) {
|
|
50
|
-
var _a
|
|
32
|
+
var _a;
|
|
51
33
|
this.timeout = timeout;
|
|
52
34
|
this.transition = transition;
|
|
53
35
|
this.delay = delay;
|
|
@@ -56,33 +38,21 @@ class Timer {
|
|
|
56
38
|
this.time = 0.0;
|
|
57
39
|
this.offset = 0.0;
|
|
58
40
|
this.status = 0;
|
|
59
|
-
this.ticker = (time) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (this.delay <= 0) {
|
|
65
|
-
timeout();
|
|
66
|
-
(_b = this.transition) === null || _b === void 0 ? void 0 : _b.call(this, 1.0);
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
if (document instanceof Document) {
|
|
70
|
-
this.visibilitychange = () => document.hidden === false ? this._start() : this._stop();
|
|
71
|
-
document.addEventListener('visibilitychange', this.visibilitychange);
|
|
72
|
-
}
|
|
73
|
-
this.start();
|
|
74
|
-
Ticker.set(this.ticker);
|
|
41
|
+
this.ticker = new Ticker((time) => { var _a; return (_a = this.transition) === null || _a === void 0 ? void 0 : _a.call(this, this.elapsed() / this.delay); });
|
|
42
|
+
this.visibilitychange = () => document.hidden === false ? this._start() : this._stop();
|
|
43
|
+
document.addEventListener('visibilitychange', this.visibilitychange);
|
|
44
|
+
if (this.delay > 0.0) {
|
|
45
|
+
(_a = this.transition) === null || _a === void 0 ? void 0 : _a.call(this, 0.0);
|
|
75
46
|
}
|
|
47
|
+
this.start();
|
|
76
48
|
}
|
|
77
49
|
clear() {
|
|
78
50
|
if (this.id !== null) {
|
|
79
51
|
clearTimeout(this.id);
|
|
80
52
|
this.id = null;
|
|
81
53
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
Ticker.clear(this.ticker);
|
|
54
|
+
document.removeEventListener('visibilitychange', this.visibilitychange);
|
|
55
|
+
this.ticker.clear();
|
|
86
56
|
}
|
|
87
57
|
elapsed() {
|
|
88
58
|
return this.offset + (this.id !== null ? (Date.now() - this.time) : 0);
|
|
@@ -98,13 +68,18 @@ class Timer {
|
|
|
98
68
|
_start() {
|
|
99
69
|
if (this.status === 1 && this.id === null) {
|
|
100
70
|
this.id = setTimeout(() => {
|
|
71
|
+
var _a;
|
|
101
72
|
this.timeout();
|
|
73
|
+
(_a = this.transition) === null || _a === void 0 ? void 0 : _a.call(this, 1.0);
|
|
102
74
|
this.id = null;
|
|
103
75
|
this.time = 0.0;
|
|
104
76
|
this.offset = 0.0;
|
|
105
77
|
if (this.loop) {
|
|
106
78
|
this.start();
|
|
107
79
|
}
|
|
80
|
+
else {
|
|
81
|
+
this.clear();
|
|
82
|
+
}
|
|
108
83
|
}, this.delay - this.offset);
|
|
109
84
|
this.time = Date.now();
|
|
110
85
|
}
|
|
@@ -217,13 +192,11 @@ class MapMap extends Map {
|
|
|
217
192
|
}
|
|
218
193
|
|
|
219
194
|
//----------------------------------------------------------------------------------------------------
|
|
220
|
-
//
|
|
195
|
+
// utils
|
|
221
196
|
//----------------------------------------------------------------------------------------------------
|
|
222
197
|
const SYSTEM_EVENTS = ['start', 'update', 'stop', 'finalize'];
|
|
223
198
|
class UnitPromise {
|
|
224
|
-
constructor(promise) {
|
|
225
|
-
this.promise = promise;
|
|
226
|
-
}
|
|
199
|
+
constructor(promise) { this.promise = promise; }
|
|
227
200
|
then(callback) {
|
|
228
201
|
this.promise = this.promise.then(Unit.wrap(Unit.current, callback));
|
|
229
202
|
return this;
|
|
@@ -238,7 +211,7 @@ class UnitPromise {
|
|
|
238
211
|
}
|
|
239
212
|
}
|
|
240
213
|
//----------------------------------------------------------------------------------------------------
|
|
241
|
-
//
|
|
214
|
+
// unit
|
|
242
215
|
//----------------------------------------------------------------------------------------------------
|
|
243
216
|
class Unit {
|
|
244
217
|
constructor(parent, target, component, props) {
|
|
@@ -258,10 +231,10 @@ class Unit {
|
|
|
258
231
|
baseComponent = component;
|
|
259
232
|
}
|
|
260
233
|
else if (typeof component === 'string') {
|
|
261
|
-
baseComponent = (
|
|
234
|
+
baseComponent = (unit) => { unit.element.textContent = component; };
|
|
262
235
|
}
|
|
263
236
|
else {
|
|
264
|
-
baseComponent = (
|
|
237
|
+
baseComponent = (unit) => { };
|
|
265
238
|
}
|
|
266
239
|
const baseContext = (_a = parent === null || parent === void 0 ? void 0 : parent._.currentContext) !== null && _a !== void 0 ? _a : { stack: null };
|
|
267
240
|
this._ = { parent, target, baseElement, baseContext, baseComponent, props };
|
|
@@ -290,10 +263,10 @@ class Unit {
|
|
|
290
263
|
}
|
|
291
264
|
reboot() {
|
|
292
265
|
var _a, _b;
|
|
266
|
+
const anchor = (_b = (_a = this._.elements[0]) === null || _a === void 0 ? void 0 : _a.nextElementSibling) !== null && _b !== void 0 ? _b : null;
|
|
293
267
|
Unit.stop(this);
|
|
294
|
-
const anchorElement = (_b = (_a = this._.elements[0]) === null || _a === void 0 ? void 0 : _a.nextElementSibling) !== null && _b !== void 0 ? _b : null;
|
|
295
268
|
Unit.finalize(this);
|
|
296
|
-
Unit.initialize(this,
|
|
269
|
+
Unit.initialize(this, anchor);
|
|
297
270
|
}
|
|
298
271
|
static initialize(unit, anchor) {
|
|
299
272
|
const backup = Unit.current;
|
|
@@ -323,27 +296,20 @@ class Unit {
|
|
|
323
296
|
// whether the unit promise was resolved
|
|
324
297
|
Promise.all(unit._.promises).then(() => unit._.state = 'initialized');
|
|
325
298
|
// setup capture
|
|
326
|
-
let
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
if (capture.checker(unit)) {
|
|
330
|
-
capture.execute(unit);
|
|
331
|
-
captured = true;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
299
|
+
for (let current = unit; current !== null; current = current._.parent) {
|
|
300
|
+
if (current._.captures.find((capture) => capture(unit)) !== undefined)
|
|
301
|
+
break;
|
|
334
302
|
}
|
|
335
303
|
Unit.current = backup;
|
|
336
304
|
}
|
|
337
305
|
static finalize(unit) {
|
|
338
|
-
if (unit._.state !== 'finalized'
|
|
339
|
-
unit._.state = '
|
|
306
|
+
if (unit._.state !== 'finalized') {
|
|
307
|
+
unit._.state = 'finalized';
|
|
340
308
|
unit._.children.forEach((child) => child.finalize());
|
|
341
309
|
unit._.systems.finalize.forEach((listener) => Unit.scope(Unit.snapshot(unit), listener));
|
|
342
310
|
unit.off();
|
|
343
311
|
Unit.suboff(unit, null);
|
|
344
|
-
unit._.components.forEach((component) =>
|
|
345
|
-
Unit.componentUnits.delete(component, unit);
|
|
346
|
-
});
|
|
312
|
+
unit._.components.forEach((component) => Unit.componentUnits.delete(component, unit));
|
|
347
313
|
if (unit._.elements.length > 0) {
|
|
348
314
|
unit._.baseElement.removeChild(unit._.elements[0]);
|
|
349
315
|
unit._.currentElement = unit._.baseElement;
|
|
@@ -355,7 +321,6 @@ class Unit {
|
|
|
355
321
|
}
|
|
356
322
|
});
|
|
357
323
|
unit._.defines = {};
|
|
358
|
-
unit._.state = 'finalized';
|
|
359
324
|
}
|
|
360
325
|
}
|
|
361
326
|
static nest(unit, tag) {
|
|
@@ -389,34 +354,35 @@ class Unit {
|
|
|
389
354
|
throw new Error(`The property "${key}" already exists.`);
|
|
390
355
|
}
|
|
391
356
|
const descriptor = Object.getOwnPropertyDescriptor(defines, key);
|
|
392
|
-
const
|
|
357
|
+
const wrapper = { configurable: true, enumerable: true };
|
|
393
358
|
if (descriptor === null || descriptor === void 0 ? void 0 : descriptor.get) {
|
|
394
|
-
|
|
359
|
+
wrapper.get = Unit.wrap(unit, descriptor.get);
|
|
395
360
|
}
|
|
396
361
|
if (descriptor === null || descriptor === void 0 ? void 0 : descriptor.set) {
|
|
397
|
-
|
|
362
|
+
wrapper.set = Unit.wrap(unit, descriptor.set);
|
|
398
363
|
}
|
|
399
364
|
if (typeof (descriptor === null || descriptor === void 0 ? void 0 : descriptor.value) === 'function') {
|
|
400
|
-
|
|
365
|
+
wrapper.value = Unit.wrap(unit, descriptor.value);
|
|
401
366
|
}
|
|
402
367
|
else if ((descriptor === null || descriptor === void 0 ? void 0 : descriptor.value) !== undefined) {
|
|
403
|
-
|
|
404
|
-
|
|
368
|
+
wrapper.writable = true;
|
|
369
|
+
wrapper.value = descriptor.value;
|
|
405
370
|
}
|
|
406
|
-
Object.defineProperty(unit._.defines, key,
|
|
407
|
-
Object.defineProperty(unit, key,
|
|
371
|
+
Object.defineProperty(unit._.defines, key, wrapper);
|
|
372
|
+
Object.defineProperty(unit, key, wrapper);
|
|
408
373
|
});
|
|
374
|
+
return Object.assign({}, unit._.defines);
|
|
409
375
|
}
|
|
410
|
-
static start(unit
|
|
376
|
+
static start(unit) {
|
|
411
377
|
if (unit._.tostart === false)
|
|
412
378
|
return;
|
|
413
379
|
if (unit._.state === 'initialized' || unit._.state === 'stopped') {
|
|
414
380
|
unit._.state = 'started';
|
|
415
|
-
unit._.children.forEach((child) => Unit.start(child
|
|
381
|
+
unit._.children.forEach((child) => Unit.start(child));
|
|
416
382
|
unit._.systems.start.forEach((listener) => Unit.scope(Unit.snapshot(unit), listener));
|
|
417
383
|
}
|
|
418
384
|
else if (unit._.state === 'started') {
|
|
419
|
-
unit._.children.forEach((child) => Unit.start(child
|
|
385
|
+
unit._.children.forEach((child) => Unit.start(child));
|
|
420
386
|
}
|
|
421
387
|
}
|
|
422
388
|
static stop(unit) {
|
|
@@ -426,29 +392,22 @@ class Unit {
|
|
|
426
392
|
unit._.systems.stop.forEach((listener) => Unit.scope(Unit.snapshot(unit), listener));
|
|
427
393
|
}
|
|
428
394
|
}
|
|
429
|
-
static update(unit
|
|
395
|
+
static update(unit) {
|
|
430
396
|
if (unit._.state === 'started') {
|
|
431
|
-
unit._.children.forEach((child) => Unit.update(child
|
|
397
|
+
unit._.children.forEach((child) => Unit.update(child));
|
|
432
398
|
unit._.systems.update.forEach((listener) => Unit.scope(Unit.snapshot(unit), listener));
|
|
433
399
|
}
|
|
434
400
|
}
|
|
435
|
-
static ticker(time) {
|
|
436
|
-
if (Unit.root !== null) {
|
|
437
|
-
Unit.start(Unit.root, time);
|
|
438
|
-
Unit.update(Unit.root, time);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
401
|
static reset() {
|
|
442
|
-
var _a;
|
|
402
|
+
var _a, _b;
|
|
443
403
|
(_a = Unit.root) === null || _a === void 0 ? void 0 : _a.finalize();
|
|
444
|
-
Unit.root = new Unit(null, null);
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
//----------------------------------------------------------------------------------------------------
|
|
404
|
+
Unit.current = Unit.root = new Unit(null, null);
|
|
405
|
+
(_b = Unit.ticker) === null || _b === void 0 ? void 0 : _b.clear();
|
|
406
|
+
Unit.ticker = new Ticker((time) => {
|
|
407
|
+
Unit.start(Unit.root);
|
|
408
|
+
Unit.update(Unit.root);
|
|
409
|
+
});
|
|
410
|
+
}
|
|
452
411
|
static wrap(unit, listener) {
|
|
453
412
|
const snapshot = Unit.snapshot(unit);
|
|
454
413
|
return (...args) => Unit.scope(snapshot, listener, ...args);
|
|
@@ -474,13 +433,14 @@ class Unit {
|
|
|
474
433
|
static snapshot(unit) {
|
|
475
434
|
return { unit, context: unit._.currentContext, element: unit._.currentElement };
|
|
476
435
|
}
|
|
477
|
-
static
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
436
|
+
static context(unit, key, value) {
|
|
437
|
+
if (value !== undefined) {
|
|
438
|
+
unit._.currentContext = { stack: unit._.currentContext, key, value };
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
for (let context = unit._.currentContext; context.stack !== null; context = context.stack) {
|
|
442
|
+
if (context.key === key)
|
|
443
|
+
return context.value;
|
|
484
444
|
}
|
|
485
445
|
}
|
|
486
446
|
}
|
|
@@ -565,15 +525,14 @@ class Unit {
|
|
|
565
525
|
});
|
|
566
526
|
}
|
|
567
527
|
}
|
|
568
|
-
Unit.root = null;
|
|
569
528
|
Unit.componentUnits = new MapSet();
|
|
570
529
|
//----------------------------------------------------------------------------------------------------
|
|
571
530
|
// event
|
|
572
531
|
//----------------------------------------------------------------------------------------------------
|
|
573
532
|
Unit.typeUnits = new MapSet();
|
|
574
533
|
|
|
575
|
-
const xnew$1 = function (...args) {
|
|
576
|
-
if (Unit.root ===
|
|
534
|
+
const xnew$1 = Object.assign(function (...args) {
|
|
535
|
+
if (Unit.root === undefined) {
|
|
577
536
|
Unit.reset();
|
|
578
537
|
}
|
|
579
538
|
let target;
|
|
@@ -596,257 +555,403 @@ const xnew$1 = function (...args) {
|
|
|
596
555
|
target = null;
|
|
597
556
|
}
|
|
598
557
|
return new Unit(Unit.current, target, ...args);
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
}
|
|
614
|
-
else {
|
|
615
|
-
throw new Error('This function can not be called after initialized.');
|
|
616
|
-
}
|
|
617
|
-
};
|
|
618
|
-
xnew$1.context = (key, value = undefined) => {
|
|
619
|
-
try {
|
|
620
|
-
if (value !== undefined) {
|
|
621
|
-
Unit.stack(Unit.current, key, value);
|
|
558
|
+
}, {
|
|
559
|
+
/**
|
|
560
|
+
* Creates a nested HTML/SVG element within the current component
|
|
561
|
+
* @param tag - HTML or SVG tag name (e.g., '<div>', '<span>', '<svg>')
|
|
562
|
+
* @returns The created HTML/SVG element
|
|
563
|
+
* @throws Error if called after component initialization
|
|
564
|
+
* @example
|
|
565
|
+
* const div = xnew.nest('<div>')
|
|
566
|
+
* div.textContent = 'Hello'
|
|
567
|
+
*/
|
|
568
|
+
nest(tag) {
|
|
569
|
+
var _a;
|
|
570
|
+
if (((_a = Unit.current) === null || _a === void 0 ? void 0 : _a._.state) === 'invoked') {
|
|
571
|
+
return Unit.nest(Unit.current, tag);
|
|
622
572
|
}
|
|
623
573
|
else {
|
|
624
|
-
|
|
574
|
+
throw new Error('xnew.nest: This function can not be called after initialized.');
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
/**
|
|
578
|
+
* Extends the current component with another component's functionality
|
|
579
|
+
* @param component - Component function to extend with
|
|
580
|
+
* @param props - Optional properties to pass to the extended component
|
|
581
|
+
* @returns The extended component's return value
|
|
582
|
+
* @throws Error if called after component initialization
|
|
583
|
+
* @example
|
|
584
|
+
* const api = xnew.extend(BaseComponent, { data: {} })
|
|
585
|
+
*/
|
|
586
|
+
extend(component, props) {
|
|
587
|
+
var _a;
|
|
588
|
+
if (((_a = Unit.current) === null || _a === void 0 ? void 0 : _a._.state) === 'invoked') {
|
|
589
|
+
return Unit.extend(Unit.current, component, props);
|
|
625
590
|
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
catch (error) {
|
|
646
|
-
console.error('xnew.then(mix): ', error);
|
|
647
|
-
throw error;
|
|
648
|
-
}
|
|
649
|
-
};
|
|
650
|
-
xnew$1.catch = (callback) => {
|
|
651
|
-
try {
|
|
652
|
-
return new UnitPromise(Promise.all(Unit.current._.promises)).catch(callback);
|
|
653
|
-
}
|
|
654
|
-
catch (error) {
|
|
655
|
-
console.error('xnew.catch(mix): ', error);
|
|
656
|
-
throw error;
|
|
657
|
-
}
|
|
658
|
-
};
|
|
659
|
-
xnew$1.finally = (callback) => {
|
|
660
|
-
try {
|
|
661
|
-
return new UnitPromise(Promise.all(Unit.current._.promises)).finally(callback);
|
|
662
|
-
}
|
|
663
|
-
catch (error) {
|
|
664
|
-
console.error('xnew.finally(mix): ', error);
|
|
665
|
-
throw error;
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
xnew$1.fetch = (url, options) => {
|
|
669
|
-
try {
|
|
670
|
-
const promise = fetch(url, options);
|
|
671
|
-
Unit.current._.promises.push(promise);
|
|
672
|
-
return new UnitPromise(promise);
|
|
673
|
-
}
|
|
674
|
-
catch (error) {
|
|
675
|
-
console.error('xnew.promise(mix): ', error);
|
|
676
|
-
throw error;
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
xnew$1.scope = (callback) => {
|
|
680
|
-
const snapshot = Unit.snapshot(Unit.current);
|
|
681
|
-
return (...args) => Unit.scope(snapshot, callback, ...args);
|
|
682
|
-
};
|
|
683
|
-
xnew$1.find = (component) => {
|
|
684
|
-
if (typeof component === 'function') {
|
|
685
|
-
return Unit.find(component);
|
|
686
|
-
}
|
|
687
|
-
else {
|
|
688
|
-
throw new Error(`The argument [component] is invalid.`);
|
|
689
|
-
}
|
|
690
|
-
};
|
|
691
|
-
xnew$1.append = (base, ...args) => {
|
|
692
|
-
if (typeof base === 'function') {
|
|
693
|
-
for (let unit of Unit.find(base)) {
|
|
694
|
-
Unit.scope(Unit.snapshot(unit), xnew$1, ...args);
|
|
591
|
+
else {
|
|
592
|
+
throw new Error('xnew.extend: This function can not be called after initialized.');
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
/**
|
|
596
|
+
* Gets or sets a context value that can be accessed by child components
|
|
597
|
+
* @param key - Context key
|
|
598
|
+
* @param value - Optional value to set (if undefined, gets the value)
|
|
599
|
+
* @returns The context value if getting, undefined if setting
|
|
600
|
+
* @example
|
|
601
|
+
* // Set context in parent
|
|
602
|
+
* xnew.context('theme', 'dark')
|
|
603
|
+
*
|
|
604
|
+
* // Get context in child
|
|
605
|
+
* const theme = xnew.context('theme')
|
|
606
|
+
*/
|
|
607
|
+
context(key, value = undefined) {
|
|
608
|
+
try {
|
|
609
|
+
return Unit.context(Unit.current, key, value);
|
|
695
610
|
}
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
611
|
+
catch (error) {
|
|
612
|
+
console.error('xnew.context(key: string, value?: any): ', error);
|
|
613
|
+
throw error;
|
|
614
|
+
}
|
|
615
|
+
},
|
|
616
|
+
/**
|
|
617
|
+
* Registers a promise with the current component for lifecycle management
|
|
618
|
+
* @param promise - Promise to register
|
|
619
|
+
* @returns UnitPromise wrapper for chaining
|
|
620
|
+
* @example
|
|
621
|
+
* xnew.promise(fetchData()).then(data => console.log(data))
|
|
622
|
+
*/
|
|
623
|
+
promise(promise) {
|
|
624
|
+
try {
|
|
625
|
+
Unit.current._.promises.push(promise);
|
|
626
|
+
return new UnitPromise(promise);
|
|
627
|
+
}
|
|
628
|
+
catch (error) {
|
|
629
|
+
console.error('xnew.promise(promise: Promise<any>): ', error);
|
|
630
|
+
throw error;
|
|
631
|
+
}
|
|
632
|
+
},
|
|
633
|
+
/**
|
|
634
|
+
* Handles successful resolution of all registered promises in the current component
|
|
635
|
+
* @param callback - Function to call when all promises resolve
|
|
636
|
+
* @returns UnitPromise for chaining
|
|
637
|
+
* @example
|
|
638
|
+
* xnew.then(results => console.log('All promises resolved', results))
|
|
639
|
+
*/
|
|
640
|
+
then(callback) {
|
|
641
|
+
try {
|
|
642
|
+
return new UnitPromise(Promise.all(Unit.current._.promises)).then(callback);
|
|
643
|
+
}
|
|
644
|
+
catch (error) {
|
|
645
|
+
console.error('xnew.then(callback: Function): ', error);
|
|
646
|
+
throw error;
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
/**
|
|
650
|
+
* Handles rejection of any registered promise in the current component
|
|
651
|
+
* @param callback - Function to call if any promise rejects
|
|
652
|
+
* @returns UnitPromise for chaining
|
|
653
|
+
* @example
|
|
654
|
+
* xnew.catch(error => console.error('Promise failed', error))
|
|
655
|
+
*/
|
|
656
|
+
catch(callback) {
|
|
657
|
+
try {
|
|
658
|
+
return new UnitPromise(Promise.all(Unit.current._.promises)).catch(callback);
|
|
659
|
+
}
|
|
660
|
+
catch (error) {
|
|
661
|
+
console.error('xnew.catch(callback: Function): ', error);
|
|
662
|
+
throw error;
|
|
663
|
+
}
|
|
664
|
+
},
|
|
665
|
+
/**
|
|
666
|
+
* Executes callback after all registered promises settle (resolve or reject)
|
|
667
|
+
* @param callback - Function to call after promises settle
|
|
668
|
+
* @returns UnitPromise for chaining
|
|
669
|
+
* @example
|
|
670
|
+
* xnew.finally(() => console.log('All promises settled'))
|
|
671
|
+
*/
|
|
672
|
+
finally(callback) {
|
|
673
|
+
try {
|
|
674
|
+
return new UnitPromise(Promise.all(Unit.current._.promises)).finally(callback);
|
|
675
|
+
}
|
|
676
|
+
catch (error) {
|
|
677
|
+
console.error('xnew.finally(callback: Function): ', error);
|
|
678
|
+
throw error;
|
|
679
|
+
}
|
|
680
|
+
},
|
|
681
|
+
/**
|
|
682
|
+
* Fetches a resource and registers the promise with the current component
|
|
683
|
+
* @param url - URL to fetch
|
|
684
|
+
* @param options - Optional fetch options (method, headers, body, etc.)
|
|
685
|
+
* @returns UnitPromise wrapping the fetch promise
|
|
686
|
+
* @example
|
|
687
|
+
* xnew.fetch('/api/users').then(res => res.json()).then(data => console.log(data))
|
|
688
|
+
*/
|
|
689
|
+
fetch(url, options) {
|
|
690
|
+
try {
|
|
691
|
+
const promise = fetch(url, options);
|
|
692
|
+
Unit.current._.promises.push(promise);
|
|
693
|
+
return new UnitPromise(promise);
|
|
694
|
+
}
|
|
695
|
+
catch (error) {
|
|
696
|
+
console.error('xnew.promise(url: string, options?: object): ', error);
|
|
697
|
+
throw error;
|
|
698
|
+
}
|
|
699
|
+
},
|
|
700
|
+
/**
|
|
701
|
+
* Creates a scoped callback that captures the current component context
|
|
702
|
+
* @param callback - Function to wrap with current scope
|
|
703
|
+
* @returns Function that executes callback in the captured scope
|
|
704
|
+
* @example
|
|
705
|
+
* setTimeout(xnew.scope(() => {
|
|
706
|
+
* console.log('This runs in the xnew component scope')
|
|
707
|
+
* }), 1000)
|
|
708
|
+
*/
|
|
709
|
+
scope(callback) {
|
|
710
|
+
const snapshot = Unit.snapshot(Unit.current);
|
|
711
|
+
return (...args) => Unit.scope(snapshot, callback, ...args);
|
|
712
|
+
},
|
|
713
|
+
/**
|
|
714
|
+
* Finds all instances of a component in the component tree
|
|
715
|
+
* @param component - Component function to search for
|
|
716
|
+
* @returns Array of Unit instances matching the component
|
|
717
|
+
* @throws Error if component parameter is invalid
|
|
718
|
+
* @example
|
|
719
|
+
* const buttons = xnew.find(ButtonComponent)
|
|
720
|
+
* buttons.forEach(btn => btn.finalize())
|
|
721
|
+
*/
|
|
722
|
+
find(component) {
|
|
723
|
+
if (typeof component === 'function') {
|
|
724
|
+
return Unit.find(component);
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
throw new Error('xnew.find(component: Function): [component] is invalid.');
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
/**
|
|
731
|
+
* Appends new components to existing component(s) in the tree
|
|
732
|
+
* @param anchor - Component function or Unit instance to append to
|
|
733
|
+
* @param args - Arguments to pass to xnew for creating child components
|
|
734
|
+
* @throws Error if anchor parameter is invalid
|
|
735
|
+
* @example
|
|
736
|
+
* xnew.append(MyContainer, ChildComponent, { prop: 'value' })
|
|
737
|
+
* xnew.append(unitInstance, AnotherComponent)
|
|
738
|
+
*/
|
|
739
|
+
append(anchor, ...args) {
|
|
740
|
+
if (typeof anchor === 'function') {
|
|
741
|
+
const units = Unit.find(anchor);
|
|
742
|
+
Unit.scope(Unit.snapshot(units[0]), xnew$1, ...args);
|
|
743
|
+
}
|
|
744
|
+
else if (anchor instanceof Unit) {
|
|
745
|
+
Unit.scope(Unit.snapshot(anchor), xnew$1, ...args);
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
throw new Error('xnew.append(anchor: Function | Unit, xnew arguments): [anchor] is invalid.');
|
|
749
|
+
}
|
|
750
|
+
},
|
|
751
|
+
/**
|
|
752
|
+
* Executes a callback once after a delay, managed by component lifecycle
|
|
753
|
+
* @param callback - Function to execute after delay
|
|
754
|
+
* @param delay - Delay in milliseconds
|
|
755
|
+
* @returns Object with clear() method to cancel the timeout
|
|
756
|
+
* @example
|
|
757
|
+
* const timer = xnew.timeout(() => console.log('Delayed'), 1000)
|
|
758
|
+
* // Cancel if needed: timer.clear()
|
|
759
|
+
*/
|
|
760
|
+
timeout(callback, delay) {
|
|
761
|
+
const snapshot = Unit.snapshot(Unit.current);
|
|
762
|
+
const unit = xnew$1((self) => {
|
|
763
|
+
const timer = new Timer(() => {
|
|
764
|
+
Unit.scope(snapshot, callback);
|
|
765
|
+
self.finalize();
|
|
766
|
+
}, null, delay, false);
|
|
767
|
+
self.on('finalize', () => timer.clear());
|
|
713
768
|
});
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
769
|
+
return { clear: () => unit.finalize() };
|
|
770
|
+
},
|
|
771
|
+
/**
|
|
772
|
+
* Executes a callback repeatedly at specified intervals, managed by component lifecycle
|
|
773
|
+
* @param callback - Function to execute at each interval
|
|
774
|
+
* @param delay - Interval duration in milliseconds
|
|
775
|
+
* @returns Object with clear() method to stop the interval
|
|
776
|
+
* @example
|
|
777
|
+
* const timer = xnew.interval(() => console.log('Tick'), 1000)
|
|
778
|
+
* // Stop when needed: timer.clear()
|
|
779
|
+
*/
|
|
780
|
+
interval(callback, delay) {
|
|
781
|
+
const snapshot = Unit.snapshot(Unit.current);
|
|
782
|
+
const unit = xnew$1((self) => {
|
|
783
|
+
const timer = new Timer(() => {
|
|
784
|
+
Unit.scope(snapshot, callback);
|
|
785
|
+
}, null, delay, true);
|
|
786
|
+
self.on('finalize', () => timer.clear());
|
|
725
787
|
});
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
Unit.scope(snapshot, callback, progress);
|
|
788
|
+
return { clear: () => unit.finalize() };
|
|
789
|
+
},
|
|
790
|
+
/**
|
|
791
|
+
* Creates a transition animation with easing, executing callback with progress values
|
|
792
|
+
* @param callback - Function called with progress value (0.0 to 1.0)
|
|
793
|
+
* @param interval - Duration of transition in milliseconds
|
|
794
|
+
* @param easing - Easing function: 'linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out' (default: 'linear')
|
|
795
|
+
* @returns Object with clear() and next() methods for controlling transitions
|
|
796
|
+
* @example
|
|
797
|
+
* xnew.transition(progress => {
|
|
798
|
+
* element.style.opacity = progress
|
|
799
|
+
* }, 500, 'ease-out').next(progress => {
|
|
800
|
+
* element.style.transform = `scale(${progress})`
|
|
801
|
+
* }, 300)
|
|
802
|
+
*/
|
|
803
|
+
transition(callback, interval, easing = 'linear') {
|
|
804
|
+
const snapshot = Unit.snapshot(Unit.current);
|
|
805
|
+
let stacks = [];
|
|
806
|
+
let unit = xnew$1(Local, { callback, interval, easing });
|
|
807
|
+
let isRunning = true;
|
|
808
|
+
const timer = { clear, next };
|
|
809
|
+
return timer;
|
|
810
|
+
function execute() {
|
|
811
|
+
if (isRunning === false && stacks.length > 0) {
|
|
812
|
+
unit = xnew$1(Local, stacks.shift());
|
|
813
|
+
isRunning = true;
|
|
753
814
|
}
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
815
|
+
}
|
|
816
|
+
function clear() {
|
|
817
|
+
stacks = [];
|
|
818
|
+
unit.finalize();
|
|
819
|
+
}
|
|
820
|
+
function next(callback, interval = 0, easing = 'linear') {
|
|
821
|
+
stacks.push({ callback, interval, easing });
|
|
758
822
|
execute();
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
823
|
+
return timer;
|
|
824
|
+
}
|
|
825
|
+
function Local(self, { callback, interval, easing }) {
|
|
826
|
+
const timer = new Timer(() => {
|
|
827
|
+
Unit.scope(snapshot, callback, 1.0);
|
|
828
|
+
self.finalize();
|
|
829
|
+
}, (progress) => {
|
|
830
|
+
if (progress < 1.0) {
|
|
831
|
+
if (easing === 'ease-out') {
|
|
832
|
+
progress = Math.pow((1.0 - Math.pow((1.0 - progress), 2.0)), 0.5);
|
|
833
|
+
}
|
|
834
|
+
else if (easing === 'ease-in') {
|
|
835
|
+
progress = Math.pow((1.0 - Math.pow((1.0 - progress), 0.5)), 2.0);
|
|
836
|
+
}
|
|
837
|
+
else if (easing === 'ease') {
|
|
838
|
+
progress = (1.0 - Math.cos(progress * Math.PI)) / 2.0;
|
|
839
|
+
}
|
|
840
|
+
else if (easing === 'ease-in-out') {
|
|
841
|
+
progress = (1.0 - Math.cos(progress * Math.PI)) / 2.0;
|
|
842
|
+
}
|
|
843
|
+
Unit.scope(snapshot, callback, progress);
|
|
844
|
+
}
|
|
845
|
+
}, interval);
|
|
846
|
+
self.on('finalize', () => {
|
|
847
|
+
timer.clear();
|
|
848
|
+
isRunning = false;
|
|
849
|
+
execute();
|
|
850
|
+
});
|
|
767
851
|
}
|
|
852
|
+
},
|
|
853
|
+
/**
|
|
854
|
+
* Creates an event listener manager for a target element with automatic cleanup
|
|
855
|
+
* @param target - Element, Window, or Document to attach listeners to
|
|
856
|
+
* @returns Object with on() and off() methods for managing event listeners
|
|
857
|
+
* @example
|
|
858
|
+
* const mouse = xnew.listener(window)
|
|
859
|
+
* mouse.on('mousemove', (e) => console.log(e.clientX, e.clientY))
|
|
860
|
+
* // Automatically cleaned up when component finalizes
|
|
861
|
+
*/
|
|
862
|
+
listener(target) {
|
|
863
|
+
return {
|
|
864
|
+
on(type, listener, options) {
|
|
865
|
+
Unit.subon(Unit.current, target, type, listener, options);
|
|
866
|
+
},
|
|
867
|
+
off(type, listener) {
|
|
868
|
+
Unit.suboff(Unit.current, target, type, listener);
|
|
869
|
+
}
|
|
870
|
+
};
|
|
871
|
+
},
|
|
872
|
+
/**
|
|
873
|
+
* Registers a capture function that can intercept and handle child component events
|
|
874
|
+
* @param execute - Function that receives child unit and returns boolean (true to stop propagation)
|
|
875
|
+
* @example
|
|
876
|
+
* xnew.capture((childUnit) => {
|
|
877
|
+
* console.log('Child component created:', childUnit)
|
|
878
|
+
* return false // Continue propagation
|
|
879
|
+
* })
|
|
880
|
+
*/
|
|
881
|
+
capture(execute) {
|
|
882
|
+
Unit.current._.captures.push(Unit.wrap(Unit.current, (unit) => execute(unit)));
|
|
883
|
+
},
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
function ResizeEvent(resize) {
|
|
887
|
+
const observer = new ResizeObserver((entries) => {
|
|
888
|
+
for (const entry of entries) {
|
|
889
|
+
resize.emit('-resize');
|
|
890
|
+
break;
|
|
891
|
+
}
|
|
892
|
+
});
|
|
893
|
+
if (resize.element) {
|
|
894
|
+
observer.observe(resize.element);
|
|
768
895
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
}
|
|
773
|
-
function next(callback, interval, easing = 'linear') {
|
|
774
|
-
stacks.push({ callback, interval, easing });
|
|
775
|
-
execute();
|
|
776
|
-
return timer;
|
|
777
|
-
}
|
|
778
|
-
timer = { clear, next };
|
|
779
|
-
return timer;
|
|
780
|
-
};
|
|
781
|
-
xnew$1.listener = function (target) {
|
|
782
|
-
return {
|
|
783
|
-
on(type, listener, options) {
|
|
784
|
-
Unit.subon(Unit.current, target, type, listener, options);
|
|
785
|
-
},
|
|
786
|
-
off(type, listener) {
|
|
787
|
-
Unit.suboff(Unit.current, target, type, listener);
|
|
896
|
+
resize.on('finalize', () => {
|
|
897
|
+
if (resize.element) {
|
|
898
|
+
observer.unobserve(resize.element);
|
|
788
899
|
}
|
|
789
|
-
};
|
|
790
|
-
}
|
|
791
|
-
xnew$1.capture = function (checker, execute) {
|
|
792
|
-
Unit.current._.captures.push({ checker, execute: Unit.wrap(Unit.current, (unit) => execute(unit)) });
|
|
793
|
-
};
|
|
900
|
+
});
|
|
901
|
+
}
|
|
794
902
|
|
|
795
|
-
function
|
|
796
|
-
const
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
903
|
+
function PointerEvent(unit) {
|
|
904
|
+
const internal = xnew$1();
|
|
905
|
+
internal.on('pointerdown', (event) => unit.emit('-pointerdown', { event, position: getPosition(unit.element, event) }));
|
|
906
|
+
internal.on('pointermove', (event) => unit.emit('-pointermove', { event, position: getPosition(unit.element, event) }));
|
|
907
|
+
internal.on('pointerup', (event) => unit.emit('-pointerup', { event, position: getPosition(unit.element, event) }));
|
|
908
|
+
internal.on('wheel', (event) => unit.emit('-wheel', { event, delta: { x: event.wheelDeltaX, y: event.wheelDeltaY } }));
|
|
909
|
+
internal.on('mouseover', (event) => unit.emit('-mouseover', { event, position: getPosition(unit.element, event) }));
|
|
910
|
+
internal.on('mouseout', (event) => unit.emit('-mouseout', { event, position: getPosition(unit.element, event) }));
|
|
801
911
|
const drag = xnew$1(DragEvent);
|
|
802
|
-
drag.on('-dragstart', (...args) =>
|
|
803
|
-
drag.on('-dragmove', (...args) =>
|
|
804
|
-
drag.on('-dragend', (...args) =>
|
|
805
|
-
drag.on('-dragcancel', (...args) =>
|
|
912
|
+
drag.on('-dragstart', (...args) => unit.emit('-dragstart', ...args));
|
|
913
|
+
drag.on('-dragmove', (...args) => unit.emit('-dragmove', ...args));
|
|
914
|
+
drag.on('-dragend', (...args) => unit.emit('-dragend', ...args));
|
|
915
|
+
drag.on('-dragcancel', (...args) => unit.emit('-dragcancel', ...args));
|
|
806
916
|
const gesture = xnew$1(GestureEvent);
|
|
807
|
-
gesture.on('-gesturestart', (...args) =>
|
|
808
|
-
gesture.on('-gesturemove', (...args) =>
|
|
809
|
-
gesture.on('-gestureend', (...args) =>
|
|
810
|
-
gesture.on('-gesturecancel', (...args) =>
|
|
811
|
-
const keyborad = xnew$1(Keyboard);
|
|
812
|
-
keyborad.on('-keydown', (...args) => self.emit('-keydown', ...args));
|
|
813
|
-
keyborad.on('-keyup', (...args) => self.emit('-keyup', ...args));
|
|
814
|
-
keyborad.on('-arrowkeydown', (...args) => self.emit('-arrowkeydown', ...args));
|
|
815
|
-
keyborad.on('-arrowkeyup', (...args) => self.emit('-arrowkeyup', ...args));
|
|
917
|
+
gesture.on('-gesturestart', (...args) => unit.emit('-gesturestart', ...args));
|
|
918
|
+
gesture.on('-gesturemove', (...args) => unit.emit('-gesturemove', ...args));
|
|
919
|
+
gesture.on('-gestureend', (...args) => unit.emit('-gestureend', ...args));
|
|
920
|
+
gesture.on('-gesturecancel', (...args) => unit.emit('-gesturecancel', ...args));
|
|
816
921
|
}
|
|
817
|
-
function DragEvent(
|
|
922
|
+
function DragEvent(unit) {
|
|
818
923
|
xnew$1().on('pointerdown', (event) => {
|
|
819
924
|
const id = event.pointerId;
|
|
820
|
-
const position = getPosition(
|
|
925
|
+
const position = getPosition(unit.element, event);
|
|
821
926
|
let previous = position;
|
|
822
927
|
xnew$1(() => {
|
|
823
928
|
xnew$1.listener(window).on('pointermove', (event) => {
|
|
824
929
|
if (event.pointerId === id) {
|
|
825
|
-
const position = getPosition(
|
|
930
|
+
const position = getPosition(unit.element, event);
|
|
826
931
|
const delta = { x: position.x - previous.x, y: position.y - previous.y };
|
|
827
|
-
|
|
932
|
+
unit.emit('-dragmove', { event, position, delta });
|
|
828
933
|
previous = position;
|
|
829
934
|
}
|
|
830
935
|
});
|
|
831
936
|
xnew$1.listener(window).on('pointerup', (event) => {
|
|
832
937
|
if (event.pointerId === id) {
|
|
833
|
-
const position = getPosition(
|
|
834
|
-
|
|
938
|
+
const position = getPosition(unit.element, event);
|
|
939
|
+
unit.emit('-dragend', { event, position, });
|
|
835
940
|
xnew$1.listener(window).off();
|
|
836
941
|
}
|
|
837
942
|
});
|
|
838
943
|
xnew$1.listener(window).on('pointercancel', (event) => {
|
|
839
944
|
if (event.pointerId === id) {
|
|
840
|
-
const position = getPosition(
|
|
841
|
-
|
|
945
|
+
const position = getPosition(unit.element, event);
|
|
946
|
+
unit.emit('-dragcancel', { event, position, });
|
|
842
947
|
xnew$1.listener(window).off();
|
|
843
948
|
}
|
|
844
949
|
});
|
|
845
950
|
});
|
|
846
|
-
|
|
951
|
+
unit.emit('-dragstart', { event, position });
|
|
847
952
|
});
|
|
848
953
|
}
|
|
849
|
-
function GestureEvent(
|
|
954
|
+
function GestureEvent(unit) {
|
|
850
955
|
const drag = xnew$1(DragEvent);
|
|
851
956
|
let isActive = false;
|
|
852
957
|
const map = new Map();
|
|
@@ -854,7 +959,7 @@ function GestureEvent(self) {
|
|
|
854
959
|
map.set(event.pointerId, Object.assign({}, position));
|
|
855
960
|
isActive = map.size === 2 ? true : false;
|
|
856
961
|
if (isActive === true) {
|
|
857
|
-
|
|
962
|
+
unit.emit('-gesturestart', {});
|
|
858
963
|
}
|
|
859
964
|
});
|
|
860
965
|
drag.on('-dragmove', ({ event, position, delta }) => {
|
|
@@ -880,20 +985,20 @@ function GestureEvent(self) {
|
|
|
880
985
|
// rotate = sign > 0.0 ? +angle : -angle;
|
|
881
986
|
// }
|
|
882
987
|
// }
|
|
883
|
-
|
|
988
|
+
unit.emit('-gesturemove', { event, position, delta, scale });
|
|
884
989
|
}
|
|
885
990
|
map.set(event.pointerId, position);
|
|
886
991
|
});
|
|
887
992
|
drag.on('-dragend', ({ event }) => {
|
|
888
993
|
if (isActive === true) {
|
|
889
|
-
|
|
994
|
+
unit.emit('-gestureend', {});
|
|
890
995
|
}
|
|
891
996
|
isActive = false;
|
|
892
997
|
map.delete(event.pointerId);
|
|
893
998
|
});
|
|
894
999
|
drag.on('-dragcancel', ({ event }) => {
|
|
895
1000
|
if (isActive === true) {
|
|
896
|
-
|
|
1001
|
+
unit.emit('-gesturecancel', { event });
|
|
897
1002
|
}
|
|
898
1003
|
isActive = false;
|
|
899
1004
|
map.delete(event.pointerId);
|
|
@@ -906,21 +1011,26 @@ function GestureEvent(self) {
|
|
|
906
1011
|
return others;
|
|
907
1012
|
}
|
|
908
1013
|
}
|
|
909
|
-
function
|
|
1014
|
+
function getPosition(element, event) {
|
|
1015
|
+
const rect = element.getBoundingClientRect();
|
|
1016
|
+
return { x: event.clientX - rect.left, y: event.clientY - rect.top };
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
function KeyboardEvent(unit) {
|
|
910
1020
|
const state = {};
|
|
911
1021
|
xnew$1.listener(window).on('keydown', (event) => {
|
|
912
1022
|
state[event.code] = 1;
|
|
913
|
-
|
|
1023
|
+
unit.emit('-keydown', { event, type: '-keydown', code: event.code });
|
|
914
1024
|
});
|
|
915
1025
|
xnew$1.listener(window).on('keyup', (event) => {
|
|
916
1026
|
state[event.code] = 0;
|
|
917
|
-
|
|
1027
|
+
unit.emit('-keyup', { event, type: '-keyup', code: event.code });
|
|
918
1028
|
});
|
|
919
1029
|
xnew$1.listener(window).on('keydown', (event) => {
|
|
920
|
-
|
|
1030
|
+
unit.emit('-arrowkeydown', { event, type: '-arrowkeydown', code: event.code, vector: getVector() });
|
|
921
1031
|
});
|
|
922
1032
|
xnew$1.listener(window).on('keyup', (event) => {
|
|
923
|
-
|
|
1033
|
+
unit.emit('-arrowkeyup', { event, type: '-arrowkeyup', code: event.code, vector: getVector() });
|
|
924
1034
|
});
|
|
925
1035
|
function getVector() {
|
|
926
1036
|
return {
|
|
@@ -929,16 +1039,12 @@ function Keyboard(self) {
|
|
|
929
1039
|
};
|
|
930
1040
|
}
|
|
931
1041
|
}
|
|
932
|
-
function getPosition(element, event) {
|
|
933
|
-
const rect = element.getBoundingClientRect();
|
|
934
|
-
return { x: event.clientX - rect.left, y: event.clientY - rect.top };
|
|
935
|
-
}
|
|
936
1042
|
|
|
937
1043
|
function Screen(screen, { width = 640, height = 480, fit = 'contain' } = {}) {
|
|
938
1044
|
const size = { width, height };
|
|
939
1045
|
const wrapper = xnew$1.nest('<div style="position: relative; width: 100%; height: 100%; overflow: hidden;">');
|
|
940
1046
|
const absolute = xnew$1.nest('<div style="position: absolute; margin: auto;">');
|
|
941
|
-
const canvas = xnew$1
|
|
1047
|
+
const canvas = xnew$1(`<canvas width="${width}" height="${height}" style="width: 100%; height: 100%; vertical-align: bottom; user-select: none; user-drag: none; pointer-events: auto;">`);
|
|
942
1048
|
xnew$1(wrapper, ResizeEvent).on('-resize', resize);
|
|
943
1049
|
resize();
|
|
944
1050
|
function resize() {
|
|
@@ -969,36 +1075,34 @@ function Screen(screen, { width = 640, height = 480, fit = 'contain' } = {}) {
|
|
|
969
1075
|
}
|
|
970
1076
|
return {
|
|
971
1077
|
get canvas() {
|
|
972
|
-
return canvas;
|
|
1078
|
+
return canvas.element;
|
|
973
1079
|
},
|
|
974
1080
|
resize(width, height) {
|
|
975
1081
|
size.width = width;
|
|
976
1082
|
size.height = height;
|
|
977
|
-
canvas.setAttribute('width', width + 'px');
|
|
978
|
-
canvas.setAttribute('height', height + 'px');
|
|
1083
|
+
canvas.element.setAttribute('width', width + 'px');
|
|
1084
|
+
canvas.element.setAttribute('height', height + 'px');
|
|
979
1085
|
resize();
|
|
980
1086
|
},
|
|
981
|
-
get scale() {
|
|
982
|
-
return { x: size.width / canvas.clientWidth, y: size.height / canvas.clientHeight };
|
|
983
|
-
}
|
|
984
1087
|
};
|
|
985
1088
|
}
|
|
986
1089
|
|
|
987
1090
|
function InputFrame(frame, {} = {}) {
|
|
988
1091
|
xnew$1.nest('<div>');
|
|
989
1092
|
xnew$1.capture((unit) => {
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1093
|
+
if (unit.element.tagName.toLowerCase() === 'input') {
|
|
1094
|
+
const element = unit.element;
|
|
1095
|
+
xnew$1.listener(element).on('input', (event) => {
|
|
1096
|
+
frame.emit('-input', { event });
|
|
1097
|
+
});
|
|
1098
|
+
xnew$1.listener(element).on('change', (event) => {
|
|
1099
|
+
frame.emit('-change', { event });
|
|
1100
|
+
});
|
|
1101
|
+
xnew$1.listener(element).on('click', (event) => {
|
|
1102
|
+
frame.emit('-click', { event });
|
|
1103
|
+
});
|
|
1104
|
+
return true;
|
|
1105
|
+
}
|
|
1002
1106
|
});
|
|
1003
1107
|
}
|
|
1004
1108
|
|
|
@@ -1033,14 +1137,14 @@ function ModalContent(content, { background = 'rgba(0, 0, 0, 0.1)' } = {}) {
|
|
|
1033
1137
|
};
|
|
1034
1138
|
}
|
|
1035
1139
|
|
|
1036
|
-
function TabFrame(frame, {
|
|
1140
|
+
function TabFrame(frame, { select } = {}) {
|
|
1037
1141
|
const internal = xnew$1((internal) => {
|
|
1038
1142
|
const buttons = new Map();
|
|
1039
1143
|
const contents = new Map();
|
|
1040
1144
|
return { frame, buttons, contents };
|
|
1041
1145
|
});
|
|
1042
1146
|
xnew$1.context('xnew.tabframe', internal);
|
|
1043
|
-
xnew$1.timeout(() => internal.emit('-select', { key:
|
|
1147
|
+
xnew$1.timeout(() => internal.emit('-select', { key: select !== null && select !== void 0 ? select : [...internal.buttons.keys()][0] }));
|
|
1044
1148
|
}
|
|
1045
1149
|
function TabButton(button, { key } = {}) {
|
|
1046
1150
|
const internal = xnew$1.context('xnew.tabframe');
|
|
@@ -1177,18 +1281,30 @@ function DragFrame(frame, { x = 0, y = 0 } = {}) {
|
|
|
1177
1281
|
function DragTarget(target, {} = {}) {
|
|
1178
1282
|
const { frame, absolute } = xnew$1.context('xnew.dragframe');
|
|
1179
1283
|
xnew$1.nest('<div>');
|
|
1180
|
-
const
|
|
1284
|
+
const pointer = xnew$1(absolute.parentElement, PointerEvent);
|
|
1181
1285
|
const current = { x: 0, y: 0 };
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1286
|
+
const offset = { x: 0, y: 0 };
|
|
1287
|
+
let dragged = false;
|
|
1288
|
+
pointer.on('-dragstart', ({ event, position }) => {
|
|
1289
|
+
if (target.element.contains(event.target) === false)
|
|
1290
|
+
return;
|
|
1291
|
+
dragged = true;
|
|
1292
|
+
offset.x = position.x - parseFloat(absolute.style.left || '0');
|
|
1293
|
+
offset.y = position.y - parseFloat(absolute.style.top || '0');
|
|
1294
|
+
current.x = position.x - offset.x;
|
|
1295
|
+
current.y = position.y - offset.y;
|
|
1185
1296
|
});
|
|
1186
|
-
|
|
1297
|
+
pointer.on('-dragmove', ({ event, delta }) => {
|
|
1298
|
+
if (dragged !== true)
|
|
1299
|
+
return;
|
|
1187
1300
|
current.x += delta.x;
|
|
1188
1301
|
current.y += delta.y;
|
|
1189
1302
|
absolute.style.left = `${current.x}px`;
|
|
1190
1303
|
absolute.style.top = `${current.y}px`;
|
|
1191
1304
|
});
|
|
1305
|
+
pointer.on('-dragcancel -dragend', ({ event }) => {
|
|
1306
|
+
dragged = false;
|
|
1307
|
+
});
|
|
1192
1308
|
}
|
|
1193
1309
|
|
|
1194
1310
|
//----------------------------------------------------------------------------------------------------
|
|
@@ -1197,439 +1313,382 @@ function DragTarget(target, {} = {}) {
|
|
|
1197
1313
|
function SVGTemplate(self, { fill = null, fillOpacity = 0.8, stroke = null, strokeOpacity = 0.8, strokeWidth = 2, strokeLinejoin = 'round' }) {
|
|
1198
1314
|
xnew$1.nest(`<svg
|
|
1199
1315
|
viewBox="0 0 100 100"
|
|
1200
|
-
style="position: absolute; width: 100%; height: 100%;
|
|
1316
|
+
style="position: absolute; width: 100%; height: 100%; pointer-select: none;
|
|
1201
1317
|
${fill ? `fill: ${fill}; fill-opacity: ${fillOpacity};` : ''}
|
|
1202
1318
|
${stroke ? `stroke: ${stroke}; stroke-opacity: ${strokeOpacity}; stroke-width: ${strokeWidth}; stroke-linejoin: ${strokeLinejoin};` : ''}
|
|
1203
1319
|
">`);
|
|
1204
1320
|
}
|
|
1205
|
-
function
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
xnew$1('<polygon points="50 93 40 83 60 83">');
|
|
1212
|
-
xnew$1('<polygon points=" 7 50 18 40 18 60">');
|
|
1213
|
-
xnew$1('<polygon points="93 50 83 40 83 60">');
|
|
1214
|
-
});
|
|
1215
|
-
const target = xnew$1((self) => {
|
|
1216
|
-
xnew$1.extend(SVGTemplate, { fill, fillOpacity, stroke, strokeOpacity, strokeWidth, strokeLinejoin });
|
|
1217
|
-
xnew$1('<circle cx="50" cy="50" r="23">');
|
|
1218
|
-
});
|
|
1219
|
-
const user = xnew$1(UserEvent);
|
|
1220
|
-
user.on('-dragstart', ({ event, position }) => {
|
|
1221
|
-
const vector = getVector(position);
|
|
1222
|
-
target.element.style.filter = 'brightness(90%)';
|
|
1223
|
-
target.element.style.left = vector.x * size / 4 + 'px';
|
|
1224
|
-
target.element.style.top = vector.y * size / 4 + 'px';
|
|
1225
|
-
self.emit('-down', { vector });
|
|
1226
|
-
});
|
|
1227
|
-
user.on('-dragmove', ({ event, position }) => {
|
|
1228
|
-
const vector = getVector(position);
|
|
1229
|
-
target.element.style.filter = 'brightness(90%)';
|
|
1230
|
-
target.element.style.left = vector.x * size / 4 + 'px';
|
|
1231
|
-
target.element.style.top = vector.y * size / 4 + 'px';
|
|
1232
|
-
self.emit('-move', { vector });
|
|
1233
|
-
});
|
|
1234
|
-
user.on('-dragend', ({ event }) => {
|
|
1235
|
-
const vector = { x: 0, y: 0 };
|
|
1236
|
-
target.element.style.filter = '';
|
|
1237
|
-
target.element.style.left = vector.x * size / 4 + 'px';
|
|
1238
|
-
target.element.style.top = vector.y * size / 4 + 'px';
|
|
1239
|
-
self.emit('-up', { vector });
|
|
1240
|
-
});
|
|
1241
|
-
function getVector(position) {
|
|
1242
|
-
const x = position.x - size / 2;
|
|
1243
|
-
const y = position.y - size / 2;
|
|
1244
|
-
const d = Math.min(1.0, Math.sqrt(x * x + y * y) / (size / 4));
|
|
1245
|
-
const a = (y !== 0 || x !== 0) ? Math.atan2(y, x) : 0;
|
|
1246
|
-
return { x: Math.cos(a) * d, y: Math.sin(a) * d };
|
|
1321
|
+
function AnalogStick(self, { size, fill = '#FFF', fillOpacity = 0.8, stroke = '#000', strokeOpacity = 0.8, strokeWidth = 2, strokeLinejoin = 'round' } = {}) {
|
|
1322
|
+
xnew$1.nest(`<div style="position: relative; width: 100%; height: 100%;">`);
|
|
1323
|
+
let internal;
|
|
1324
|
+
let newsize;
|
|
1325
|
+
if (size) {
|
|
1326
|
+
newsize = size;
|
|
1247
1327
|
}
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
'<polygon points="50 50 35 35 35 5 37 3 63 3 65 5 65 35">',
|
|
1254
|
-
'<polygon points="50 50 35 65 35 95 37 97 63 97 65 95 65 65">',
|
|
1255
|
-
'<polygon points="50 50 35 35 5 35 3 37 3 63 5 65 35 65">',
|
|
1256
|
-
'<polygon points="50 50 65 35 95 35 97 37 97 63 95 65 65 65">'
|
|
1257
|
-
];
|
|
1258
|
-
const targets = polygons.map((polygon) => {
|
|
1259
|
-
return xnew$1((self) => {
|
|
1260
|
-
xnew$1.extend(SVGTemplate, { fill, fillOpacity });
|
|
1261
|
-
xnew$1(polygon);
|
|
1328
|
+
else {
|
|
1329
|
+
newsize = Math.min(self.element.clientWidth, self.element.clientHeight);
|
|
1330
|
+
xnew$1(self.element, ResizeEvent).on('-resize', () => {
|
|
1331
|
+
newsize = Math.min(self.element.clientWidth, self.element.clientHeight);
|
|
1332
|
+
internal === null || internal === void 0 ? void 0 : internal.reboot();
|
|
1262
1333
|
});
|
|
1263
|
-
});
|
|
1264
|
-
xnew$1((self) => {
|
|
1265
|
-
xnew$1.extend(SVGTemplate, { fill: 'none', stroke, strokeOpacity, strokeWidth, strokeLinejoin });
|
|
1266
|
-
xnew$1('<polyline points="35 35 35 5 37 3 63 3 65 5 65 35">');
|
|
1267
|
-
xnew$1('<polyline points="35 65 35 95 37 97 63 97 65 95 65 65">');
|
|
1268
|
-
xnew$1('<polyline points="35 35 5 35 3 37 3 63 5 65 35 65">');
|
|
1269
|
-
xnew$1('<polyline points="65 35 95 35 97 37 97 63 95 65 65 65">');
|
|
1270
|
-
xnew$1('<polygon points="50 11 42 20 58 20">');
|
|
1271
|
-
xnew$1('<polygon points="50 89 42 80 58 80">');
|
|
1272
|
-
xnew$1('<polygon points="11 50 20 42 20 58">');
|
|
1273
|
-
xnew$1('<polygon points="89 50 80 42 80 58">');
|
|
1274
|
-
});
|
|
1275
|
-
const user = xnew$1(UserEvent);
|
|
1276
|
-
user.on('-dragstart', ({ event, position }) => {
|
|
1277
|
-
const vector = getVector(position);
|
|
1278
|
-
targets[0].element.style.filter = (vector.y < 0) ? 'brightness(90%)' : '';
|
|
1279
|
-
targets[1].element.style.filter = (vector.y > 0) ? 'brightness(90%)' : '';
|
|
1280
|
-
targets[2].element.style.filter = (vector.x < 0) ? 'brightness(90%)' : '';
|
|
1281
|
-
targets[3].element.style.filter = (vector.x > 0) ? 'brightness(90%)' : '';
|
|
1282
|
-
self.emit('-down', { vector });
|
|
1283
|
-
});
|
|
1284
|
-
user.on('-dragmove', ({ event, position }) => {
|
|
1285
|
-
const vector = getVector(position);
|
|
1286
|
-
targets[0].element.style.filter = (vector.y < 0) ? 'brightness(90%)' : '';
|
|
1287
|
-
targets[1].element.style.filter = (vector.y > 0) ? 'brightness(90%)' : '';
|
|
1288
|
-
targets[2].element.style.filter = (vector.x < 0) ? 'brightness(90%)' : '';
|
|
1289
|
-
targets[3].element.style.filter = (vector.x > 0) ? 'brightness(90%)' : '';
|
|
1290
|
-
self.emit('-move', { vector });
|
|
1291
|
-
});
|
|
1292
|
-
user.on('-dragend', ({ event }) => {
|
|
1293
|
-
const vector = { x: 0, y: 0 };
|
|
1294
|
-
targets[0].element.style.filter = '';
|
|
1295
|
-
targets[1].element.style.filter = '';
|
|
1296
|
-
targets[2].element.style.filter = '';
|
|
1297
|
-
targets[3].element.style.filter = '';
|
|
1298
|
-
self.emit('-up', { vector });
|
|
1299
|
-
});
|
|
1300
|
-
function getVector(position) {
|
|
1301
|
-
const x = position.x - size / 2;
|
|
1302
|
-
const y = position.y - size / 2;
|
|
1303
|
-
const a = (y !== 0 || x !== 0) ? Math.atan2(y, x) : 0;
|
|
1304
|
-
const d = Math.min(1.0, Math.sqrt(x * x + y * y) / (size / 4));
|
|
1305
|
-
const vector = { x: Math.cos(a) * d, y: Math.sin(a) * d };
|
|
1306
|
-
vector.x = Math.abs(vector.x) > 0.5 ? Math.sign(vector.x) : 0;
|
|
1307
|
-
vector.y = Math.abs(vector.y) > 0.5 ? Math.sign(vector.y) : 0;
|
|
1308
|
-
return vector;
|
|
1309
1334
|
}
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1335
|
+
internal = xnew$1(() => {
|
|
1336
|
+
xnew$1.nest(`<div style="position: absolute; width: ${newsize}px; height: ${newsize}px; margin: auto; inset: 0; cursor: pointer; pointer-select: none; pointer-events: auto; overflow: hidden;">`);
|
|
1337
|
+
xnew$1((self) => {
|
|
1338
|
+
xnew$1.extend(SVGTemplate, { fill, fillOpacity, stroke, strokeOpacity, strokeWidth, strokeLinejoin });
|
|
1339
|
+
xnew$1('<polygon points="50 7 40 18 60 18">');
|
|
1340
|
+
xnew$1('<polygon points="50 93 40 83 60 83">');
|
|
1341
|
+
xnew$1('<polygon points=" 7 50 18 40 18 60">');
|
|
1342
|
+
xnew$1('<polygon points="93 50 83 40 83 60">');
|
|
1343
|
+
});
|
|
1344
|
+
const target = xnew$1((self) => {
|
|
1345
|
+
xnew$1.extend(SVGTemplate, { fill, fillOpacity, stroke, strokeOpacity, strokeWidth, strokeLinejoin });
|
|
1346
|
+
xnew$1('<circle cx="50" cy="50" r="23">');
|
|
1347
|
+
});
|
|
1348
|
+
const pointer = xnew$1(PointerEvent);
|
|
1349
|
+
pointer.on('-dragstart', ({ event, position }) => {
|
|
1350
|
+
const vector = getVector(position);
|
|
1351
|
+
target.element.style.filter = 'brightness(90%)';
|
|
1352
|
+
target.element.style.left = vector.x * newsize / 4 + 'px';
|
|
1353
|
+
target.element.style.top = vector.y * newsize / 4 + 'px';
|
|
1354
|
+
self.emit('-down', { vector });
|
|
1355
|
+
});
|
|
1356
|
+
pointer.on('-dragmove', ({ event, position }) => {
|
|
1357
|
+
const vector = getVector(position);
|
|
1358
|
+
target.element.style.filter = 'brightness(90%)';
|
|
1359
|
+
target.element.style.left = vector.x * newsize / 4 + 'px';
|
|
1360
|
+
target.element.style.top = vector.y * newsize / 4 + 'px';
|
|
1361
|
+
self.emit('-move', { vector });
|
|
1362
|
+
});
|
|
1363
|
+
pointer.on('-dragend', ({ event }) => {
|
|
1364
|
+
const vector = { x: 0, y: 0 };
|
|
1365
|
+
target.element.style.filter = '';
|
|
1366
|
+
target.element.style.left = vector.x * newsize / 4 + 'px';
|
|
1367
|
+
target.element.style.top = vector.y * newsize / 4 + 'px';
|
|
1368
|
+
self.emit('-up', { vector });
|
|
1369
|
+
});
|
|
1370
|
+
function getVector(position) {
|
|
1371
|
+
const x = position.x - newsize / 2;
|
|
1372
|
+
const y = position.y - newsize / 2;
|
|
1373
|
+
const d = Math.min(1.0, Math.sqrt(x * x + y * y) / (newsize / 4));
|
|
1374
|
+
const a = (y !== 0 || x !== 0) ? Math.atan2(y, x) : 0;
|
|
1375
|
+
return { x: Math.cos(a) * d, y: Math.sin(a) * d };
|
|
1376
|
+
}
|
|
1326
1377
|
});
|
|
1327
1378
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
Audio.master = Audio.context.createGain();
|
|
1335
|
-
Audio.master.gain.value = 1.0;
|
|
1336
|
-
Audio.master.connect(Audio.context.destination);
|
|
1337
|
-
}
|
|
1379
|
+
function DirectionalPad(self, { size, diagonal = true, fill = '#FFF', fillOpacity = 0.8, stroke = '#000', strokeOpacity = 0.8, strokeWidth = 2, strokeLinejoin = 'round' } = {}) {
|
|
1380
|
+
xnew$1.nest(`<div style="position: relative; width: 100%; height: 100%;">`);
|
|
1381
|
+
let internal;
|
|
1382
|
+
let newsize;
|
|
1383
|
+
if (size) {
|
|
1384
|
+
newsize = size;
|
|
1338
1385
|
}
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
const [type, props, ...to] = params[key];
|
|
1345
|
-
nodes[key] = Audio.context[`create${type}`]();
|
|
1346
|
-
Object.keys(props).forEach((name) => {
|
|
1347
|
-
var _a;
|
|
1348
|
-
if (((_a = nodes[key][name]) === null || _a === void 0 ? void 0 : _a.value) !== undefined) {
|
|
1349
|
-
nodes[key][name].value = props[name];
|
|
1350
|
-
}
|
|
1351
|
-
else {
|
|
1352
|
-
nodes[key][name] = props[name];
|
|
1353
|
-
}
|
|
1354
|
-
});
|
|
1386
|
+
else {
|
|
1387
|
+
newsize = Math.min(self.element.clientWidth, self.element.clientHeight);
|
|
1388
|
+
xnew$1(self.element, ResizeEvent).on('-resize', () => {
|
|
1389
|
+
newsize = Math.min(self.element.clientWidth, self.element.clientHeight);
|
|
1390
|
+
internal === null || internal === void 0 ? void 0 : internal.reboot();
|
|
1355
1391
|
});
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
nodes[key].connect(dest);
|
|
1392
|
+
}
|
|
1393
|
+
internal = xnew$1(() => {
|
|
1394
|
+
xnew$1.nest(`<div style="position: absolute; width: ${newsize}px; height: ${newsize}px; margin: auto; inset: 0; cursor: pointer; pointer-select: none; pointer-events: auto; overflow: hidden;">`);
|
|
1395
|
+
const polygons = [
|
|
1396
|
+
'<polygon points="50 50 35 35 35 5 37 3 63 3 65 5 65 35">',
|
|
1397
|
+
'<polygon points="50 50 35 65 35 95 37 97 63 97 65 95 65 65">',
|
|
1398
|
+
'<polygon points="50 50 35 35 5 35 3 37 3 63 5 65 35 65">',
|
|
1399
|
+
'<polygon points="50 50 65 35 95 35 97 37 97 63 95 65 65 65">'
|
|
1400
|
+
];
|
|
1401
|
+
const targets = polygons.map((polygon) => {
|
|
1402
|
+
return xnew$1((self) => {
|
|
1403
|
+
xnew$1.extend(SVGTemplate, { fill, fillOpacity });
|
|
1404
|
+
xnew$1(polygon);
|
|
1370
1405
|
});
|
|
1371
1406
|
});
|
|
1372
|
-
|
|
1373
|
-
|
|
1407
|
+
xnew$1((self) => {
|
|
1408
|
+
xnew$1.extend(SVGTemplate, { fill: 'none', stroke, strokeOpacity, strokeWidth, strokeLinejoin });
|
|
1409
|
+
xnew$1('<polyline points="35 35 35 5 37 3 63 3 65 5 65 35">');
|
|
1410
|
+
xnew$1('<polyline points="35 65 35 95 37 97 63 97 65 95 65 65">');
|
|
1411
|
+
xnew$1('<polyline points="35 35 5 35 3 37 3 63 5 65 35 65">');
|
|
1412
|
+
xnew$1('<polyline points="65 35 95 35 97 37 97 63 95 65 65 65">');
|
|
1413
|
+
xnew$1('<polygon points="50 11 42 20 58 20">');
|
|
1414
|
+
xnew$1('<polygon points="50 89 42 80 58 80">');
|
|
1415
|
+
xnew$1('<polygon points="11 50 20 42 20 58">');
|
|
1416
|
+
xnew$1('<polygon points="89 50 80 42 80 58">');
|
|
1417
|
+
});
|
|
1418
|
+
const pointer = xnew$1(PointerEvent);
|
|
1419
|
+
pointer.on('-dragstart', ({ event, position }) => {
|
|
1420
|
+
const vector = getVector(position);
|
|
1421
|
+
targets[0].element.style.filter = (vector.y < 0) ? 'brightness(90%)' : '';
|
|
1422
|
+
targets[1].element.style.filter = (vector.y > 0) ? 'brightness(90%)' : '';
|
|
1423
|
+
targets[2].element.style.filter = (vector.x < 0) ? 'brightness(90%)' : '';
|
|
1424
|
+
targets[3].element.style.filter = (vector.x > 0) ? 'brightness(90%)' : '';
|
|
1425
|
+
self.emit('-down', { vector });
|
|
1426
|
+
});
|
|
1427
|
+
pointer.on('-dragmove', ({ event, position }) => {
|
|
1428
|
+
const vector = getVector(position);
|
|
1429
|
+
targets[0].element.style.filter = (vector.y < 0) ? 'brightness(90%)' : '';
|
|
1430
|
+
targets[1].element.style.filter = (vector.y > 0) ? 'brightness(90%)' : '';
|
|
1431
|
+
targets[2].element.style.filter = (vector.x < 0) ? 'brightness(90%)' : '';
|
|
1432
|
+
targets[3].element.style.filter = (vector.x > 0) ? 'brightness(90%)' : '';
|
|
1433
|
+
self.emit('-move', { vector });
|
|
1434
|
+
});
|
|
1435
|
+
pointer.on('-dragend', ({ event }) => {
|
|
1436
|
+
const vector = { x: 0, y: 0 };
|
|
1437
|
+
targets[0].element.style.filter = '';
|
|
1438
|
+
targets[1].element.style.filter = '';
|
|
1439
|
+
targets[2].element.style.filter = '';
|
|
1440
|
+
targets[3].element.style.filter = '';
|
|
1441
|
+
self.emit('-up', { vector });
|
|
1442
|
+
});
|
|
1443
|
+
function getVector(position) {
|
|
1444
|
+
const x = position.x - newsize / 2;
|
|
1445
|
+
const y = position.y - newsize / 2;
|
|
1446
|
+
const a = (y !== 0 || x !== 0) ? Math.atan2(y, x) : 0;
|
|
1447
|
+
const d = Math.min(1.0, Math.sqrt(x * x + y * y) / (newsize / 4));
|
|
1448
|
+
const vector = { x: Math.cos(a) * d, y: Math.sin(a) * d };
|
|
1449
|
+
if (diagonal === true) {
|
|
1450
|
+
vector.x = Math.abs(vector.x) > 0.5 ? Math.sign(vector.x) : 0;
|
|
1451
|
+
vector.y = Math.abs(vector.y) > 0.5 ? Math.sign(vector.y) : 0;
|
|
1452
|
+
}
|
|
1453
|
+
else if (Math.abs(vector.x) > Math.abs(vector.y)) {
|
|
1454
|
+
vector.x = Math.abs(vector.x) > 0.5 ? Math.sign(vector.x) : 0;
|
|
1455
|
+
vector.y = 0;
|
|
1456
|
+
}
|
|
1457
|
+
else {
|
|
1458
|
+
vector.x = 0;
|
|
1459
|
+
vector.y = Math.abs(vector.y) > 0.5 ? Math.sign(vector.y) : 0;
|
|
1460
|
+
}
|
|
1461
|
+
return vector;
|
|
1462
|
+
}
|
|
1463
|
+
});
|
|
1374
1464
|
}
|
|
1375
|
-
Audio.context = null;
|
|
1376
|
-
Audio.master = null;
|
|
1377
|
-
Audio.initialize();
|
|
1378
1465
|
|
|
1379
|
-
|
|
1380
|
-
|
|
1466
|
+
const context = new AudioContext();
|
|
1467
|
+
const master = context.createGain();
|
|
1468
|
+
master.gain.value = 1.0;
|
|
1469
|
+
master.connect(context.destination);
|
|
1470
|
+
|
|
1471
|
+
function load(path) {
|
|
1472
|
+
return new AudioFile(path);
|
|
1381
1473
|
}
|
|
1382
|
-
|
|
1383
|
-
|
|
1474
|
+
const store = new Map();
|
|
1475
|
+
class AudioFile {
|
|
1476
|
+
constructor(path) {
|
|
1477
|
+
if (store.has(path)) {
|
|
1478
|
+
this.buffer = store.get(path);
|
|
1479
|
+
this.promise = Promise.resolve();
|
|
1480
|
+
}
|
|
1481
|
+
else {
|
|
1482
|
+
this.promise = fetch(path)
|
|
1483
|
+
.then((response) => response.arrayBuffer())
|
|
1484
|
+
.then((response) => context.decodeAudioData(response))
|
|
1485
|
+
.then((response) => {
|
|
1486
|
+
this.buffer = response;
|
|
1487
|
+
})
|
|
1488
|
+
.catch(() => {
|
|
1489
|
+
console.warn(`"${path}" could not be loaded.`);
|
|
1490
|
+
});
|
|
1491
|
+
store.set(path, this.buffer);
|
|
1492
|
+
}
|
|
1493
|
+
this.start = null;
|
|
1494
|
+
}
|
|
1495
|
+
// set volume(value: number) {
|
|
1496
|
+
// this.amp.gain.value = value;
|
|
1497
|
+
// }
|
|
1498
|
+
// get volume(): number {
|
|
1499
|
+
// return this.amp.gain.value;
|
|
1500
|
+
// }
|
|
1501
|
+
play(offset = 0, loop = false) {
|
|
1502
|
+
if (this.buffer !== undefined && this.start === null) {
|
|
1503
|
+
this.source = context.createBufferSource();
|
|
1504
|
+
this.source.buffer = this.buffer;
|
|
1505
|
+
this.source.loop = loop;
|
|
1506
|
+
this.amp = context.createGain();
|
|
1507
|
+
this.amp.gain.value = 1.0;
|
|
1508
|
+
this.source.connect(this.amp);
|
|
1509
|
+
this.amp.connect(master);
|
|
1510
|
+
this.start = context.currentTime;
|
|
1511
|
+
this.source.playbackRate.value = 1;
|
|
1512
|
+
this.source.start(context.currentTime, offset / 1000);
|
|
1513
|
+
this.source.onended = () => {
|
|
1514
|
+
var _a, _b;
|
|
1515
|
+
this.start = null;
|
|
1516
|
+
(_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
1517
|
+
(_b = this.amp) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
1518
|
+
};
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
pause() {
|
|
1522
|
+
var _a;
|
|
1523
|
+
if (this.buffer !== undefined && this.start !== null) {
|
|
1524
|
+
(_a = this.source) === null || _a === void 0 ? void 0 : _a.stop(context.currentTime);
|
|
1525
|
+
const elapsed = (context.currentTime - this.start) % this.buffer.duration * 1000;
|
|
1526
|
+
this.start = null;
|
|
1527
|
+
return elapsed;
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1384
1530
|
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1531
|
+
|
|
1532
|
+
function synthesizer(props) {
|
|
1533
|
+
return new Synthesizer(props);
|
|
1387
1534
|
}
|
|
1388
|
-
|
|
1389
|
-
|
|
1535
|
+
window.addEventListener('touchstart', initialize, true);
|
|
1536
|
+
window.addEventListener('mousedown', initialize, true);
|
|
1537
|
+
function initialize() {
|
|
1538
|
+
new Synthesizer({ oscillator: { type: 'sine' }, amp: { envelope: { amount: 0, ADSR: [0, 0, 0, 0] } } }).press(440);
|
|
1539
|
+
window.removeEventListener('touchstart', initialize, true);
|
|
1540
|
+
window.removeEventListener('mousedown', initialize, true);
|
|
1390
1541
|
}
|
|
1542
|
+
const keymap = {
|
|
1543
|
+
'A0': 27.500, 'A#0': 29.135, 'B0': 30.868,
|
|
1544
|
+
'C1': 32.703, 'C#1': 34.648, 'D1': 36.708, 'D#1': 38.891, 'E1': 41.203, 'F1': 43.654, 'F#1': 46.249, 'G1': 48.999, 'G#1': 51.913, 'A1': 55.000, 'A#1': 58.270, 'B1': 61.735,
|
|
1545
|
+
'C2': 65.406, 'C#2': 69.296, 'D2': 73.416, 'D#2': 77.782, 'E2': 82.407, 'F2': 87.307, 'F#2': 92.499, 'G2': 97.999, 'G#2': 103.826, 'A2': 110.000, 'A#2': 116.541, 'B2': 123.471,
|
|
1546
|
+
'C3': 130.813, 'C#3': 138.591, 'D3': 146.832, 'D#3': 155.563, 'E3': 164.814, 'F3': 174.614, 'F#3': 184.997, 'G3': 195.998, 'G#3': 207.652, 'A3': 220.000, 'A#3': 233.082, 'B3': 246.942,
|
|
1547
|
+
'C4': 261.626, 'C#4': 277.183, 'D4': 293.665, 'D#4': 311.127, 'E4': 329.628, 'F4': 349.228, 'F#4': 369.994, 'G4': 391.995, 'G#4': 415.305, 'A4': 440.000, 'A#4': 466.164, 'B4': 493.883,
|
|
1548
|
+
'C5': 523.251, 'C#5': 554.365, 'D5': 587.330, 'D#5': 622.254, 'E5': 659.255, 'F5': 698.456, 'F#5': 739.989, 'G5': 783.991, 'G#5': 830.609, 'A5': 880.000, 'A#5': 932.328, 'B5': 987.767,
|
|
1549
|
+
'C6': 1046.502, 'C#6': 1108.731, 'D6': 1174.659, 'D#6': 1244.508, 'E6': 1318.510, 'F6': 1396.913, 'F#6': 1479.978, 'G6': 1567.982, 'G#6': 1661.219, 'A6': 1760.000, 'A#6': 1864.655, 'B6': 1975.533,
|
|
1550
|
+
'C7': 2093.005, 'C#7': 2217.461, 'D7': 2349.318, 'D#7': 2489.016, 'E7': 2637.020, 'F7': 2793.826, 'F#7': 2959.955, 'G7': 3135.963, 'G#7': 3322.438, 'A7': 3520.000, 'A#7': 3729.310, 'B7': 3951.066,
|
|
1551
|
+
'C8': 4186.009,
|
|
1552
|
+
};
|
|
1553
|
+
const notemap = {
|
|
1554
|
+
'1m': 4.000, '2n': 2.000, '4n': 1.000, '8n': 0.500, '16n': 0.250, '32n': 0.125,
|
|
1555
|
+
};
|
|
1391
1556
|
class Synthesizer {
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
window.addEventListener('mousedown', initialize, true);
|
|
1395
|
-
function initialize() {
|
|
1396
|
-
new Synthesizer().press(440);
|
|
1397
|
-
window.removeEventListener('touchstart', initialize, true);
|
|
1398
|
-
window.removeEventListener('mousedown', initialize, true);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
constructor({ oscillator = null, filter = null, amp = null } = {}, { bmp = null, reverb = null, delay = null } = {}) {
|
|
1402
|
-
this.oscillator = isObject(oscillator) ? oscillator : {};
|
|
1403
|
-
this.oscillator.type = setType(this.oscillator.type, ['sine', 'triangle', 'square', 'sawtooth']);
|
|
1404
|
-
this.oscillator.envelope = setEnvelope(this.oscillator.envelope, -36, +36);
|
|
1405
|
-
this.oscillator.LFO = setLFO(this.oscillator.LFO, 36);
|
|
1406
|
-
this.filter = isObject(filter) ? filter : {};
|
|
1407
|
-
this.filter.type = setType(this.filter.type, ['lowpass', 'highpass', 'bandpass']);
|
|
1408
|
-
this.filter.Q = isNumber(this.filter.Q) ? clamp(this.filter.Q, 0, 32) : 0;
|
|
1409
|
-
// cutoffはundefinedを使う
|
|
1410
|
-
this.filter.cutoff = isNumber(this.filter.cutoff) ? clamp(this.filter.cutoff, 4, 8192) : undefined;
|
|
1411
|
-
this.filter.envelope = setEnvelope(this.filter.envelope, -36, +36);
|
|
1412
|
-
this.filter.LFO = setLFO(this.filter.LFO, 36);
|
|
1413
|
-
this.amp = isObject(amp) ? amp : {};
|
|
1414
|
-
this.amp.envelope = setEnvelope(this.amp.envelope, 0, 1);
|
|
1415
|
-
this.amp.LFO = setLFO(this.amp.LFO, 36);
|
|
1416
|
-
this.bmp = isNumber(bmp) ? clamp(bmp, 60, 240) : 120;
|
|
1417
|
-
this.options = { bmp: this.bmp };
|
|
1418
|
-
this.reverb = isObject(reverb) ? reverb : {};
|
|
1419
|
-
this.reverb.time = isNumber(this.reverb.time) ? clamp(this.reverb.time, 0, 2000) : 0.0;
|
|
1420
|
-
this.reverb.mix = isNumber(this.reverb.mix) ? clamp(this.reverb.mix, 0, 1.0) : 0.0;
|
|
1421
|
-
this.delay = isObject(delay) ? delay : {};
|
|
1422
|
-
this.delay.time = isNumber(this.delay.time) ? clamp(this.delay.time, 0, 2000) : 0.0;
|
|
1423
|
-
this.delay.feedback = isNumber(this.delay.feedback) ? clamp(this.delay.feedback, 0.0, 0.9) : 0.0;
|
|
1424
|
-
this.delay.mix = isNumber(this.delay.mix) ? clamp(this.delay.mix, 0.0, 1.0) : 0.0;
|
|
1425
|
-
function setType(type, list, value = 0) {
|
|
1426
|
-
return list.includes(type) ? type : list[value];
|
|
1427
|
-
}
|
|
1428
|
-
function setEnvelope(envelope, minAmount, maxAmount) {
|
|
1429
|
-
var _a, _b, _c, _d;
|
|
1430
|
-
if (!isObject(envelope))
|
|
1431
|
-
return null;
|
|
1432
|
-
const result = {
|
|
1433
|
-
amount: isNumber(envelope.amount) ? clamp(envelope.amount, minAmount, maxAmount) : 0,
|
|
1434
|
-
ADSR: [
|
|
1435
|
-
isNumber((_a = envelope.ADSR) === null || _a === void 0 ? void 0 : _a[0]) ? clamp(envelope.ADSR[0], 0, 8000) : 0,
|
|
1436
|
-
isNumber((_b = envelope.ADSR) === null || _b === void 0 ? void 0 : _b[1]) ? clamp(envelope.ADSR[1], 0, 8000) : 0,
|
|
1437
|
-
isNumber((_c = envelope.ADSR) === null || _c === void 0 ? void 0 : _c[2]) ? clamp(envelope.ADSR[2], 0, 1) : 0,
|
|
1438
|
-
isNumber((_d = envelope.ADSR) === null || _d === void 0 ? void 0 : _d[3]) ? clamp(envelope.ADSR[3], 0, 8000) : 0,
|
|
1439
|
-
]
|
|
1440
|
-
};
|
|
1441
|
-
return result;
|
|
1442
|
-
}
|
|
1443
|
-
function setLFO(LFO, maxAmount) {
|
|
1444
|
-
if (!isObject(LFO))
|
|
1445
|
-
return null;
|
|
1446
|
-
const oscTypes = ['sine', 'triangle', 'square', 'sawtooth'];
|
|
1447
|
-
const type = oscTypes.includes(LFO.type)
|
|
1448
|
-
? LFO.type
|
|
1449
|
-
: 'sine';
|
|
1450
|
-
const result = {
|
|
1451
|
-
amount: isNumber(LFO.amount) ? clamp(LFO.amount, 0, maxAmount) : 0,
|
|
1452
|
-
type,
|
|
1453
|
-
rate: isNumber(LFO.rate) ? clamp(LFO.rate, 1, 128) : 1,
|
|
1454
|
-
};
|
|
1455
|
-
return result;
|
|
1456
|
-
}
|
|
1557
|
+
constructor(props) {
|
|
1558
|
+
this.props = props;
|
|
1457
1559
|
}
|
|
1458
|
-
press(frequency, duration
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
const
|
|
1462
|
-
|
|
1463
|
-
const
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1560
|
+
press(frequency, duration, wait) {
|
|
1561
|
+
var _a;
|
|
1562
|
+
const props = this.props;
|
|
1563
|
+
const freq = typeof frequency === 'string' ? keymap[frequency] : frequency;
|
|
1564
|
+
const dura = typeof duration === 'string' ? (notemap[duration] * 60 / ((_a = props.bpm) !== null && _a !== void 0 ? _a : 120)) : (typeof duration === 'number' ? (duration / 1000) : 0);
|
|
1565
|
+
const start = context.currentTime + (wait !== null && wait !== void 0 ? wait : 0) / 1000;
|
|
1566
|
+
const nodes = {};
|
|
1567
|
+
nodes.oscillator = context.createOscillator();
|
|
1568
|
+
nodes.oscillator.type = props.oscillator.type;
|
|
1569
|
+
nodes.oscillator.frequency.value = freq;
|
|
1570
|
+
if (props.oscillator.LFO) {
|
|
1571
|
+
nodes.oscillatorLFO = context.createOscillator();
|
|
1572
|
+
nodes.oscillatorLFODepth = context.createGain();
|
|
1573
|
+
nodes.oscillatorLFODepth.gain.value = freq * (Math.pow(2.0, props.oscillator.LFO.amount / 12.0) - 1.0);
|
|
1574
|
+
nodes.oscillatorLFO.type = props.oscillator.LFO.type;
|
|
1575
|
+
nodes.oscillatorLFO.frequency.value = props.oscillator.LFO.rate;
|
|
1576
|
+
nodes.oscillatorLFO.start(start);
|
|
1577
|
+
nodes.oscillatorLFO.connect(nodes.oscillatorLFODepth);
|
|
1578
|
+
nodes.oscillatorLFODepth.connect(nodes.oscillator.frequency);
|
|
1579
|
+
}
|
|
1580
|
+
nodes.amp = context.createGain();
|
|
1581
|
+
nodes.amp.gain.value = 0.0;
|
|
1582
|
+
nodes.target = context.createGain();
|
|
1583
|
+
nodes.target.gain.value = 1.0;
|
|
1584
|
+
nodes.amp.connect(nodes.target);
|
|
1585
|
+
nodes.target.connect(master);
|
|
1586
|
+
if (props.filter && props.filter.type && props.filter.cutoff) {
|
|
1587
|
+
nodes.filter = context.createBiquadFilter();
|
|
1588
|
+
nodes.filter.type = props.filter.type;
|
|
1589
|
+
nodes.filter.frequency.value = props.filter.cutoff;
|
|
1590
|
+
nodes.oscillator.connect(nodes.filter);
|
|
1591
|
+
nodes.filter.connect(nodes.amp);
|
|
1467
1592
|
}
|
|
1468
1593
|
else {
|
|
1469
|
-
|
|
1470
|
-
}
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
if (this.filter.LFO) {
|
|
1489
|
-
params.filterLFO = ['Oscillator', {}, 'filterLFODepth'];
|
|
1490
|
-
params.filterLFODepth = ['Gain', {}, 'filter.frequency'];
|
|
1491
|
-
}
|
|
1492
|
-
if (this.amp.LFO) {
|
|
1493
|
-
params.ampLFO = ['Oscillator', {}, 'ampLFODepth'];
|
|
1494
|
-
params.ampLFODepth = ['Gain', {}, 'amp.gain'];
|
|
1495
|
-
}
|
|
1496
|
-
const nodes = Audio.connect(params);
|
|
1497
|
-
nodes.oscillator.type = this.oscillator.type;
|
|
1498
|
-
nodes.oscillator.frequency.value = clamp(frequency, 10.0, 5000.0);
|
|
1499
|
-
if (this.filter.type && this.filter.cutoff) {
|
|
1500
|
-
nodes.filter.type = this.filter.type;
|
|
1501
|
-
nodes.filter.frequency.value = this.filter.cutoff;
|
|
1502
|
-
}
|
|
1503
|
-
if (this.reverb.time > 0.0 && this.reverb.mix > 0.0) {
|
|
1504
|
-
nodes.target.gain.value *= (1.0 - this.reverb.mix);
|
|
1505
|
-
nodes.convolverDepth.gain.value *= this.reverb.mix;
|
|
1506
|
-
}
|
|
1507
|
-
if (this.delay.time > 0.0 && this.delay.mix > 0.0) {
|
|
1508
|
-
console.log(this.delay.time / 1000);
|
|
1509
|
-
nodes.delay.delayTime.value = this.delay.time / 1000;
|
|
1510
|
-
nodes.target.gain.value *= (1.0 - this.delay.mix);
|
|
1511
|
-
nodes.delayDepth.gain.value *= this.delay.mix;
|
|
1512
|
-
}
|
|
1513
|
-
{
|
|
1514
|
-
if (this.oscillator.LFO) {
|
|
1515
|
-
nodes.oscillatorLFODepth.gain.value = frequency * (Math.pow(2.0, this.oscillator.LFO.amount / 12.0) - 1.0);
|
|
1516
|
-
nodes.oscillatorLFO.type = this.oscillator.LFO.type;
|
|
1517
|
-
nodes.oscillatorLFO.frequency.value = this.oscillator.LFO.rate;
|
|
1518
|
-
nodes.oscillatorLFO.start(start);
|
|
1519
|
-
}
|
|
1520
|
-
if (this.filter.LFO) {
|
|
1521
|
-
nodes.filterLFODepth.gain.value = frequency * (Math.pow(2.0, this.filter.LFO.amount / 12.0) - 1.0);
|
|
1522
|
-
nodes.filterLFO.type = this.filter.LFO.type;
|
|
1523
|
-
nodes.filterLFO.frequency.value = this.filter.LFO.rate;
|
|
1524
|
-
nodes.filterLFO.start(start);
|
|
1525
|
-
}
|
|
1526
|
-
if (this.amp.LFO) {
|
|
1527
|
-
nodes.ampLFODepth.gain.value = this.amp.LFO.amount;
|
|
1528
|
-
nodes.ampLFO.type = this.amp.LFO.type;
|
|
1529
|
-
nodes.ampLFO.frequency.value = this.amp.LFO.rate;
|
|
1530
|
-
nodes.ampLFO.start(start);
|
|
1531
|
-
}
|
|
1532
|
-
if (this.oscillator.envelope) {
|
|
1533
|
-
const amount = frequency * (Math.pow(2.0, this.oscillator.envelope.amount / 12.0) - 1.0);
|
|
1534
|
-
startEnvelope(nodes.oscillator.frequency, frequency, amount, this.oscillator.envelope.ADSR);
|
|
1535
|
-
}
|
|
1536
|
-
if (this.filter.envelope) {
|
|
1537
|
-
const amount = this.filter.cutoff * (Math.pow(2.0, this.filter.envelope.amount / 12.0) - 1.0);
|
|
1538
|
-
startEnvelope(nodes.filter.frequency, this.filter.cutoff, amount, this.filter.envelope.ADSR);
|
|
1539
|
-
}
|
|
1540
|
-
if (this.amp.envelope) {
|
|
1541
|
-
startEnvelope(nodes.amp.gain, 0.0, this.amp.envelope.amount, this.amp.envelope.ADSR);
|
|
1542
|
-
}
|
|
1543
|
-
nodes.oscillator.start(start);
|
|
1594
|
+
nodes.oscillator.connect(nodes.amp);
|
|
1595
|
+
}
|
|
1596
|
+
if (props.reverb) {
|
|
1597
|
+
nodes.convolver = context.createConvolver();
|
|
1598
|
+
nodes.convolver.buffer = impulseResponse({ time: props.reverb.time });
|
|
1599
|
+
nodes.convolverDepth = context.createGain();
|
|
1600
|
+
nodes.convolverDepth.gain.value = 1.0;
|
|
1601
|
+
nodes.convolverDepth.gain.value *= props.reverb.mix;
|
|
1602
|
+
nodes.target.gain.value *= (1.0 - props.reverb.mix);
|
|
1603
|
+
nodes.amp.connect(nodes.convolver);
|
|
1604
|
+
nodes.convolver.connect(nodes.convolverDepth);
|
|
1605
|
+
nodes.convolverDepth.connect(master);
|
|
1606
|
+
}
|
|
1607
|
+
if (props.oscillator.envelope) {
|
|
1608
|
+
const amount = freq * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
|
|
1609
|
+
startEnvelope(nodes.oscillator.frequency, freq, amount, props.oscillator.envelope.ADSR);
|
|
1610
|
+
}
|
|
1611
|
+
if (props.amp.envelope) {
|
|
1612
|
+
startEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
|
|
1544
1613
|
}
|
|
1545
|
-
|
|
1546
|
-
|
|
1614
|
+
let stop = null;
|
|
1615
|
+
nodes.oscillator.start(start);
|
|
1616
|
+
if (dura > 0) {
|
|
1617
|
+
release();
|
|
1618
|
+
}
|
|
1619
|
+
else {
|
|
1620
|
+
return { release };
|
|
1547
1621
|
}
|
|
1548
1622
|
function release() {
|
|
1549
|
-
|
|
1550
|
-
if (
|
|
1551
|
-
const ADSR =
|
|
1623
|
+
const end = dura > 0 ? dura : (context.currentTime - start);
|
|
1624
|
+
if (props.amp.envelope) {
|
|
1625
|
+
const ADSR = props.amp.envelope.ADSR;
|
|
1552
1626
|
const adsr = [ADSR[0] / 1000, ADSR[1] / 1000, ADSR[2], ADSR[3] / 1000];
|
|
1553
|
-
const rate = adsr[0] === 0.0 ? 1.0 : Math.min(
|
|
1554
|
-
stop = start + Math.max((adsr[0] + adsr[1]) * rate,
|
|
1627
|
+
const rate = adsr[0] === 0.0 ? 1.0 : Math.min(end / adsr[0], 1.0);
|
|
1628
|
+
stop = start + Math.max((adsr[0] + adsr[1]) * rate, end) + adsr[3];
|
|
1555
1629
|
}
|
|
1556
1630
|
else {
|
|
1557
|
-
stop = start +
|
|
1631
|
+
stop = start + end;
|
|
1558
1632
|
}
|
|
1559
|
-
if (
|
|
1633
|
+
if (nodes.oscillatorLFO) {
|
|
1560
1634
|
nodes.oscillatorLFO.stop(stop);
|
|
1561
1635
|
}
|
|
1562
|
-
if (
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
if (this.oscillator.envelope) {
|
|
1566
|
-
const amount = frequency * (Math.pow(2.0, this.oscillator.envelope.amount / 12.0) - 1.0);
|
|
1567
|
-
stopEnvelope(nodes.oscillator.frequency, frequency, amount, this.oscillator.envelope.ADSR);
|
|
1636
|
+
if (props.oscillator.envelope) {
|
|
1637
|
+
const amount = freq * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
|
|
1638
|
+
stopEnvelope(nodes.oscillator.frequency, freq, amount, props.oscillator.envelope.ADSR);
|
|
1568
1639
|
}
|
|
1569
|
-
if (
|
|
1570
|
-
|
|
1571
|
-
stopEnvelope(nodes.filter.frequency, this.filter.cutoff, amount, this.filter.envelope.ADSR);
|
|
1572
|
-
}
|
|
1573
|
-
if (this.amp.envelope) {
|
|
1574
|
-
stopEnvelope(nodes.amp.gain, 0.0, this.amp.envelope.amount, this.amp.envelope.ADSR);
|
|
1640
|
+
if (props.amp.envelope) {
|
|
1641
|
+
stopEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
|
|
1575
1642
|
}
|
|
1576
1643
|
nodes.oscillator.stop(stop);
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1644
|
+
setTimeout(() => {
|
|
1645
|
+
var _a, _b, _c, _d, _e;
|
|
1646
|
+
nodes.oscillator.disconnect();
|
|
1647
|
+
nodes.amp.disconnect();
|
|
1648
|
+
nodes.target.disconnect();
|
|
1649
|
+
(_a = nodes.oscillatorLFO) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
1650
|
+
(_b = nodes.oscillatorLFODepth) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
1651
|
+
(_c = nodes.filter) === null || _c === void 0 ? void 0 : _c.disconnect();
|
|
1652
|
+
(_d = nodes.convolver) === null || _d === void 0 ? void 0 : _d.disconnect();
|
|
1653
|
+
(_e = nodes.convolverDepth) === null || _e === void 0 ? void 0 : _e.disconnect();
|
|
1654
|
+
}, 2000);
|
|
1584
1655
|
}
|
|
1585
1656
|
function stopEnvelope(param, base, amount, ADSR) {
|
|
1586
|
-
const
|
|
1587
|
-
const rate = adsr[0] === 0.0 ? 1.0 : Math.min(duration / adsr[0], 1.0);
|
|
1657
|
+
const rate = ADSR[0] === 0.0 ? 1.0 : Math.min(dura / (ADSR[0] / 1000), 1.0);
|
|
1588
1658
|
if (rate < 1.0) {
|
|
1589
1659
|
param.cancelScheduledValues(start);
|
|
1590
1660
|
param.setValueAtTime(base, start);
|
|
1591
|
-
param.linearRampToValueAtTime(base + amount * rate, start +
|
|
1592
|
-
param.linearRampToValueAtTime(base + amount * rate *
|
|
1661
|
+
param.linearRampToValueAtTime(base + amount * rate, start + ADSR[0] / 1000 * rate);
|
|
1662
|
+
param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000 * rate);
|
|
1593
1663
|
}
|
|
1594
|
-
param.linearRampToValueAtTime(base + amount * rate *
|
|
1595
|
-
param.linearRampToValueAtTime(base, start + Math.max((
|
|
1664
|
+
param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, dura));
|
|
1665
|
+
param.linearRampToValueAtTime(base, start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, dura) + ADSR[3] / 1000);
|
|
1666
|
+
}
|
|
1667
|
+
function startEnvelope(param, base, amount, ADSR) {
|
|
1668
|
+
param.value = base;
|
|
1669
|
+
param.setValueAtTime(base, start);
|
|
1670
|
+
param.linearRampToValueAtTime(base + amount, start + ADSR[0] / 1000);
|
|
1671
|
+
param.linearRampToValueAtTime(base + amount * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000);
|
|
1672
|
+
}
|
|
1673
|
+
function impulseResponse({ time, decay = 2.0 }) {
|
|
1674
|
+
const length = context.sampleRate * time / 1000;
|
|
1675
|
+
const impulse = context.createBuffer(2, length, context.sampleRate);
|
|
1676
|
+
const ch0 = impulse.getChannelData(0);
|
|
1677
|
+
const ch1 = impulse.getChannelData(1);
|
|
1678
|
+
for (let i = 0; i < length; i++) {
|
|
1679
|
+
ch0[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
|
|
1680
|
+
ch1[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
|
|
1681
|
+
}
|
|
1682
|
+
return impulse;
|
|
1596
1683
|
}
|
|
1597
|
-
return {
|
|
1598
|
-
release: release.bind(this),
|
|
1599
|
-
};
|
|
1600
1684
|
}
|
|
1601
1685
|
}
|
|
1602
|
-
Synthesizer.keymap = {
|
|
1603
|
-
'A0': 27.500, 'A#0': 29.135, 'B0': 30.868,
|
|
1604
|
-
'C1': 32.703, 'C#1': 34.648, 'D1': 36.708, 'D#1': 38.891, 'E1': 41.203, 'F1': 43.654, 'F#1': 46.249, 'G1': 48.999, 'G#1': 51.913, 'A1': 55.000, 'A#1': 58.270, 'B1': 61.735,
|
|
1605
|
-
'C2': 65.406, 'C#2': 69.296, 'D2': 73.416, 'D#2': 77.782, 'E2': 82.407, 'F2': 87.307, 'F#2': 92.499, 'G2': 97.999, 'G#2': 103.826, 'A2': 110.000, 'A#2': 116.541, 'B2': 123.471,
|
|
1606
|
-
'C3': 130.813, 'C#3': 138.591, 'D3': 146.832, 'D#3': 155.563, 'E3': 164.814, 'F3': 174.614, 'F#3': 184.997, 'G3': 195.998, 'G#3': 207.652, 'A3': 220.000, 'A#3': 233.082, 'B3': 246.942,
|
|
1607
|
-
'C4': 261.626, 'C#4': 277.183, 'D4': 293.665, 'D#4': 311.127, 'E4': 329.628, 'F4': 349.228, 'F#4': 369.994, 'G4': 391.995, 'G#4': 415.305, 'A4': 440.000, 'A#4': 466.164, 'B4': 493.883,
|
|
1608
|
-
'C5': 523.251, 'C#5': 554.365, 'D5': 587.330, 'D#5': 622.254, 'E5': 659.255, 'F5': 698.456, 'F#5': 739.989, 'G5': 783.991, 'G#5': 830.609, 'A5': 880.000, 'A#5': 932.328, 'B5': 987.767,
|
|
1609
|
-
'C6': 1046.502, 'C#6': 1108.731, 'D6': 1174.659, 'D#6': 1244.508, 'E6': 1318.510, 'F6': 1396.913, 'F#6': 1479.978, 'G6': 1567.982, 'G#6': 1661.219, 'A6': 1760.000, 'A#6': 1864.655, 'B6': 1975.533,
|
|
1610
|
-
'C7': 2093.005, 'C#7': 2217.461, 'D7': 2349.318, 'D#7': 2489.016, 'E7': 2637.020, 'F7': 2793.826, 'F#7': 2959.955, 'G7': 3135.963, 'G#7': 3322.438, 'A7': 3520.000, 'A#7': 3729.310, 'B7': 3951.066,
|
|
1611
|
-
'C8': 4186.009,
|
|
1612
|
-
};
|
|
1613
|
-
Synthesizer.notemap = {
|
|
1614
|
-
'1m': 4.000, '2n': 2.000, '4n': 1.000, '8n': 0.500, '16n': 0.250, '32n': 0.125,
|
|
1615
|
-
};
|
|
1616
|
-
Synthesizer.initialize();
|
|
1617
|
-
function impulseResponse({ time, decay = 2.0 }) {
|
|
1618
|
-
const length = Audio.context.sampleRate * time / 1000;
|
|
1619
|
-
const impulse = Audio.context.createBuffer(2, length, Audio.context.sampleRate);
|
|
1620
|
-
const ch0 = impulse.getChannelData(0);
|
|
1621
|
-
const ch1 = impulse.getChannelData(1);
|
|
1622
|
-
for (let i = 0; i < length; i++) {
|
|
1623
|
-
ch0[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
|
|
1624
|
-
ch1[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
|
|
1625
|
-
}
|
|
1626
|
-
return impulse;
|
|
1627
|
-
}
|
|
1628
1686
|
|
|
1629
1687
|
const basics = {
|
|
1630
1688
|
Screen,
|
|
1631
|
-
|
|
1689
|
+
PointerEvent,
|
|
1632
1690
|
ResizeEvent,
|
|
1691
|
+
KeyboardEvent,
|
|
1633
1692
|
ModalFrame,
|
|
1634
1693
|
ModalContent,
|
|
1635
1694
|
AccordionFrame,
|
|
@@ -1642,16 +1701,18 @@ const basics = {
|
|
|
1642
1701
|
InputFrame,
|
|
1643
1702
|
DragFrame,
|
|
1644
1703
|
DragTarget,
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
TouchButton,
|
|
1704
|
+
AnalogStick,
|
|
1705
|
+
DirectionalPad,
|
|
1648
1706
|
};
|
|
1649
1707
|
const audio = {
|
|
1650
|
-
|
|
1708
|
+
master,
|
|
1709
|
+
context,
|
|
1710
|
+
synthesizer,
|
|
1711
|
+
load
|
|
1651
1712
|
};
|
|
1652
1713
|
const xnew = Object.assign(xnew$1, {
|
|
1653
1714
|
basics,
|
|
1654
|
-
audio
|
|
1715
|
+
audio
|
|
1655
1716
|
});
|
|
1656
1717
|
|
|
1657
1718
|
export { xnew as default };
|