@vectojs/core 1.38.0 → 1.39.0
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/{chunk-QVTCKWDO.mjs → chunk-7PYD5UDX.mjs} +93 -43
- package/dist/{chunk-ZYYP2M5D.js → chunk-KRUDTGNR.js} +168 -76
- package/dist/{chunk-SRXU3ZXK.js → chunk-POPXUPKR.js} +141 -91
- package/dist/{chunk-LWEMD34D.mjs → chunk-RUM2KEDI.mjs} +119 -27
- package/dist/index.js +689 -396
- package/dist/index.mjs +375 -82
- package/dist/renderer/CanvasRenderer.d.ts +6 -0
- package/dist/renderer/SVGRenderer.d.ts +17 -2
- package/dist/renderer/WebGPUParticleSystemManager.d.ts +2 -0
- package/dist/renderer.js +2 -2
- package/dist/renderer.mjs +1 -1
- package/dist/text/MSDFTextEntity.d.ts +0 -1
- package/dist/text.js +2 -2
- package/dist/text.mjs +1 -1
- package/dist/tree/Entity.d.ts +8 -2
- package/dist/tree/Scene.d.ts +106 -0
- package/dist/tree/scene/A11yProjectionManager.d.ts +12 -0
- package/dist/tree/scene/HitTester.d.ts +14 -2
- package/dist/tree/scene/WasmBackendFacade.d.ts +17 -0
- package/dist/tree/scene/keyboard.d.ts +56 -0
- package/dist/wasm/backend.d.ts +7 -7
- package/dist/wasm/vectojs_core.wasm +0 -0
- package/package.json +6 -6
|
@@ -400,6 +400,18 @@ var Entity = (_class2 = class {
|
|
|
400
400
|
}
|
|
401
401
|
/** Attach a single child (the O(1) common path). See {@link add}. */
|
|
402
402
|
_addOne(child) {
|
|
403
|
+
if (child === this) {
|
|
404
|
+
throw new Error(`Entity.add(): cannot add entity "${child.id}" under itself.`);
|
|
405
|
+
}
|
|
406
|
+
let ancestor = this.parent;
|
|
407
|
+
while (ancestor) {
|
|
408
|
+
if (ancestor === child) {
|
|
409
|
+
throw new Error(
|
|
410
|
+
`Entity.add(): cannot add entity "${child.id}" under "${this.id}" \u2014 an entity cannot be added under its own descendant.`
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
ancestor = ancestor.parent;
|
|
414
|
+
}
|
|
403
415
|
if (child.parent) child.parent.remove(child);
|
|
404
416
|
child.parent = this;
|
|
405
417
|
this.children.push(child);
|
|
@@ -487,13 +499,26 @@ var Entity = (_class2 = class {
|
|
|
487
499
|
* @example entity.animate({ x: 400, opacity: 0 }, 500);
|
|
488
500
|
*/
|
|
489
501
|
animate(targetProps, durationMs) {
|
|
502
|
+
if (!Number.isFinite(durationMs) || durationMs <= 0) {
|
|
503
|
+
for (const key in targetProps) {
|
|
504
|
+
const end = targetProps[key];
|
|
505
|
+
if (typeof end !== "number") continue;
|
|
506
|
+
if (ANIMATABLE_PROPS.has(key)) {
|
|
507
|
+
this._applyAnimated(key, end);
|
|
508
|
+
} else {
|
|
509
|
+
this[key] = end;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
_optionalChain([this, 'access', _51 => _51.scene, 'optionalAccess', _52 => _52.markDirty, 'call', _53 => _53({ entity: this.id, reason: "animation-start" })]);
|
|
513
|
+
return this;
|
|
514
|
+
}
|
|
490
515
|
(this.animations ??= []).push({
|
|
491
516
|
target: targetProps,
|
|
492
517
|
duration: durationMs,
|
|
493
518
|
startTime: -1,
|
|
494
519
|
startProps: {}
|
|
495
520
|
});
|
|
496
|
-
_optionalChain([this, 'access',
|
|
521
|
+
_optionalChain([this, 'access', _54 => _54.scene, 'optionalAccess', _55 => _55.markDirty, 'call', _56 => _56({ entity: this.id, reason: "animation-start" })]);
|
|
497
522
|
return this;
|
|
498
523
|
}
|
|
499
524
|
/** Write a driver-computed value to a backing field without re-triggering the setter. */
|
|
@@ -540,26 +565,26 @@ var Entity = (_class2 = class {
|
|
|
540
565
|
* that need to seed a starting state (e.g. the presence helper's enter `from`).
|
|
541
566
|
*/
|
|
542
567
|
setImmediate(prop, v) {
|
|
543
|
-
const existing = _optionalChain([this, 'access',
|
|
568
|
+
const existing = _optionalChain([this, 'access', _57 => _57._drivers, 'optionalAccess', _58 => _58.get, 'call', _59 => _59(prop)]);
|
|
544
569
|
if (existing) this._settleDriver(existing);
|
|
545
|
-
_optionalChain([this, 'access',
|
|
570
|
+
_optionalChain([this, 'access', _60 => _60._drivers, 'optionalAccess', _61 => _61.delete, 'call', _62 => _62(prop)]);
|
|
546
571
|
this._applyAnimated(prop, v);
|
|
547
572
|
}
|
|
548
573
|
_settleDriver(driver) {
|
|
549
574
|
const active = driver;
|
|
550
575
|
const onDone = active.onDone;
|
|
551
576
|
active.onDone = void 0;
|
|
552
|
-
_optionalChain([onDone, 'optionalCall',
|
|
577
|
+
_optionalChain([onDone, 'optionalCall', _63 => _63()]);
|
|
553
578
|
}
|
|
554
579
|
_spawnDriver(prop, to, cfg) {
|
|
555
|
-
if (prop !== "opacity" && _optionalChain([this, 'access',
|
|
556
|
-
const existing2 = _optionalChain([this, 'access',
|
|
580
|
+
if (prop !== "opacity" && _optionalChain([this, 'access', _64 => _64.scene, 'optionalAccess', _65 => _65.prefersReducedMotion])) {
|
|
581
|
+
const existing2 = _optionalChain([this, 'access', _66 => _66._drivers, 'optionalAccess', _67 => _67.get, 'call', _68 => _68(prop)]);
|
|
557
582
|
if (existing2) this._settleDriver(existing2);
|
|
558
|
-
_optionalChain([this, 'access',
|
|
583
|
+
_optionalChain([this, 'access', _69 => _69._drivers, 'optionalAccess', _70 => _70.delete, 'call', _71 => _71(prop)]);
|
|
559
584
|
this._applyAnimated(prop, to);
|
|
560
585
|
return;
|
|
561
586
|
}
|
|
562
|
-
const existing = _optionalChain([this, 'access',
|
|
587
|
+
const existing = _optionalChain([this, 'access', _72 => _72._drivers, 'optionalAccess', _73 => _73.get, 'call', _74 => _74(prop)]);
|
|
563
588
|
if (existing) {
|
|
564
589
|
this._settleDriver(existing);
|
|
565
590
|
existing.retarget(to);
|
|
@@ -568,12 +593,17 @@ var Entity = (_class2 = class {
|
|
|
568
593
|
const from = this._currentOf(prop);
|
|
569
594
|
const driver = _animation.isTweenConfig.call(void 0, cfg) ? new (0, _animation.TweenDriver)(from, to, cfg) : new (0, _animation.SpringDriver)(from, to, cfg === "spring" ? {} : cfg);
|
|
570
595
|
(this._drivers ??= /* @__PURE__ */ new Map()).set(prop, driver);
|
|
571
|
-
|
|
572
|
-
|
|
596
|
+
const s = this.scene;
|
|
597
|
+
if (s && this._driversTickedFrame === s.currentFrame && s._updateWalkDt !== null) {
|
|
598
|
+
driver.tick(s._updateWalkDt);
|
|
599
|
+
this._applyDriverTick(prop, driver);
|
|
600
|
+
}
|
|
601
|
+
_optionalChain([this, 'access', _75 => _75.scene, 'optionalAccess', _76 => _76.markDirty, 'call', _77 => _77({ entity: this.id, reason: "driver-added" })]);
|
|
602
|
+
_optionalChain([this, 'access', _78 => _78.scene, 'optionalAccess', _79 => _79._registerActiveDriverEntity, 'call', _80 => _80(this)]);
|
|
573
603
|
}
|
|
574
604
|
/** Assignment path when a declarative transition is configured for `prop`. */
|
|
575
605
|
_animateProp(prop, to) {
|
|
576
|
-
const cfg = _optionalChain([this, 'access',
|
|
606
|
+
const cfg = _optionalChain([this, 'access', _81 => _81._transitions, 'optionalAccess', _82 => _82.get, 'call', _83 => _83(prop)]);
|
|
577
607
|
if (!cfg) {
|
|
578
608
|
this._applyAnimated(prop, to);
|
|
579
609
|
return;
|
|
@@ -602,7 +632,7 @@ var Entity = (_class2 = class {
|
|
|
602
632
|
entries.map(
|
|
603
633
|
(e) => new Promise((resolve) => {
|
|
604
634
|
this._spawnDriver(e[0], e[1], cfg);
|
|
605
|
-
const d = _optionalChain([this, 'access',
|
|
635
|
+
const d = _optionalChain([this, 'access', _84 => _84._drivers, 'optionalAccess', _85 => _85.get, 'call', _86 => _86(e[0])]);
|
|
606
636
|
if (!d)
|
|
607
637
|
resolve();
|
|
608
638
|
else d.onDone = resolve;
|
|
@@ -624,7 +654,7 @@ var Entity = (_class2 = class {
|
|
|
624
654
|
this._applyAnimated(prop, driver.value);
|
|
625
655
|
}
|
|
626
656
|
}
|
|
627
|
-
_optionalChain([this, 'access',
|
|
657
|
+
_optionalChain([this, 'access', _87 => _87.scene, 'optionalAccess', _88 => _88.markDirty, 'call', _89 => _89({ entity: this.id, reason: "driver-tick" })]);
|
|
628
658
|
}
|
|
629
659
|
/**
|
|
630
660
|
* Internal: this entity's active-driver map (read-only view), or `null` if
|
|
@@ -649,15 +679,11 @@ var Entity = (_class2 = class {
|
|
|
649
679
|
if (driver.isDone()) {
|
|
650
680
|
this._applyAnimated(prop, driver.target);
|
|
651
681
|
this._settleDriver(driver);
|
|
652
|
-
_optionalChain([this, 'access',
|
|
682
|
+
_optionalChain([this, 'access', _90 => _90._drivers, 'optionalAccess', _91 => _91.delete, 'call', _92 => _92(prop)]);
|
|
653
683
|
} else {
|
|
654
684
|
this._applyAnimated(prop, driver.value);
|
|
655
685
|
}
|
|
656
686
|
}
|
|
657
|
-
/** Internal: true if this entity currently has any active property driver. */
|
|
658
|
-
_hasActiveDrivers() {
|
|
659
|
-
return !!this._drivers && this._drivers.size > 0;
|
|
660
|
-
}
|
|
661
687
|
/**
|
|
662
688
|
* Advance the entity's internal state for one frame.
|
|
663
689
|
*
|
|
@@ -710,7 +736,7 @@ var Entity = (_class2 = class {
|
|
|
710
736
|
* @example entity.on('click', (e) => console.log('clicked', e));
|
|
711
737
|
*/
|
|
712
738
|
on(event, callback, options) {
|
|
713
|
-
const map = _optionalChain([options, 'optionalAccess',
|
|
739
|
+
const map = _optionalChain([options, 'optionalAccess', _93 => _93.capture]) ? this.captureListeners ??= /* @__PURE__ */ new Map() : this.listeners ??= /* @__PURE__ */ new Map();
|
|
714
740
|
if (!map.has(event)) {
|
|
715
741
|
map.set(event, []);
|
|
716
742
|
}
|
|
@@ -726,7 +752,7 @@ var Entity = (_class2 = class {
|
|
|
726
752
|
* @returns `this` for method chaining.
|
|
727
753
|
*/
|
|
728
754
|
off(event, callback, options) {
|
|
729
|
-
const handlers = _optionalChain([(_optionalChain([options, 'optionalAccess',
|
|
755
|
+
const handlers = _optionalChain([(_optionalChain([options, 'optionalAccess', _94 => _94.capture]) ? this.captureListeners : this.listeners), 'optionalAccess', _95 => _95.get, 'call', _96 => _96(event)]);
|
|
730
756
|
if (handlers) {
|
|
731
757
|
const idx = handlers.indexOf(callback);
|
|
732
758
|
if (idx !== -1) handlers.splice(idx, 1);
|
|
@@ -763,8 +789,8 @@ var Entity = (_class2 = class {
|
|
|
763
789
|
}
|
|
764
790
|
this._drivers.clear();
|
|
765
791
|
}
|
|
766
|
-
_optionalChain([this, 'access',
|
|
767
|
-
_optionalChain([this, 'access',
|
|
792
|
+
_optionalChain([this, 'access', _97 => _97.listeners, 'optionalAccess', _98 => _98.clear, 'call', _99 => _99()]);
|
|
793
|
+
_optionalChain([this, 'access', _100 => _100.captureListeners, 'optionalAccess', _101 => _101.clear, 'call', _102 => _102()]);
|
|
768
794
|
if (this.parent) {
|
|
769
795
|
this.parent.remove(this);
|
|
770
796
|
}
|
|
@@ -779,7 +805,7 @@ var Entity = (_class2 = class {
|
|
|
779
805
|
* @param payload - Arbitrary data forwarded to each listener.
|
|
780
806
|
*/
|
|
781
807
|
emit(event, payload) {
|
|
782
|
-
const handlers = _optionalChain([this, 'access',
|
|
808
|
+
const handlers = _optionalChain([this, 'access', _103 => _103.listeners, 'optionalAccess', _104 => _104.get, 'call', _105 => _105(event)]);
|
|
783
809
|
if (handlers) {
|
|
784
810
|
handlers.forEach((h) => h(payload));
|
|
785
811
|
}
|
|
@@ -793,19 +819,19 @@ var Entity = (_class2 = class {
|
|
|
793
819
|
* with `requestAnimationFrame(() => document.getElementById(id)?.focus())`.
|
|
794
820
|
*/
|
|
795
821
|
focus() {
|
|
796
|
-
const el = _optionalChain([this, 'access',
|
|
822
|
+
const el = _optionalChain([this, 'access', _106 => _106.scene, 'optionalAccess', _107 => _107.getA11yElement, 'call', _108 => _108(this.id)]);
|
|
797
823
|
if (el) {
|
|
798
824
|
el.focus();
|
|
799
825
|
return;
|
|
800
826
|
}
|
|
801
827
|
requestAnimationFrame(() => {
|
|
802
|
-
const retry = _optionalChain([this, 'access',
|
|
828
|
+
const retry = _optionalChain([this, 'access', _109 => _109.scene, 'optionalAccess', _110 => _110.getA11yElement, 'call', _111 => _111(this.id)]);
|
|
803
829
|
if (retry) retry.focus();
|
|
804
830
|
});
|
|
805
831
|
}
|
|
806
832
|
/** Run one node's listeners for the event, honoring stopImmediatePropagation. */
|
|
807
833
|
fireListeners(node, map, event) {
|
|
808
|
-
const handlers = _optionalChain([map, 'optionalAccess',
|
|
834
|
+
const handlers = _optionalChain([map, 'optionalAccess', _112 => _112.get, 'call', _113 => _113(event.type)]);
|
|
809
835
|
if (!handlers) return;
|
|
810
836
|
event.currentTarget = node;
|
|
811
837
|
for (const h of handlers.slice()) {
|
|
@@ -1026,6 +1052,14 @@ var Entity = (_class2 = class {
|
|
|
1026
1052
|
* Accumulated world rotation: this entity's own `rotation` plus
|
|
1027
1053
|
* that of every ancestor.
|
|
1028
1054
|
*
|
|
1055
|
+
* Valid only under positive scales: the sum models the composed matrix
|
|
1056
|
+
* `T*S*R` correctly while every ancestor's `scaleX`/`scaleY` is positive,
|
|
1057
|
+
* but a mirrored (negative-scale) ancestor flips handedness, which an
|
|
1058
|
+
* additive sum cannot represent — the result is then off by the mirror.
|
|
1059
|
+
* For mirror-safe rotation, derive the angle from
|
|
1060
|
+
* {@link getWorldTransform}'s matrix (e.g. `atan2(b, a)`), as SVGEntity's
|
|
1061
|
+
* signed-scale handling already does.
|
|
1062
|
+
*
|
|
1029
1063
|
* @returns The accumulated world rotation in radians.
|
|
1030
1064
|
*/
|
|
1031
1065
|
getWorldRotation() {
|
|
@@ -1211,7 +1245,7 @@ var Entity = (_class2 = class {
|
|
|
1211
1245
|
* @returns `true` if at least one animation or property driver remains.
|
|
1212
1246
|
*/
|
|
1213
1247
|
hasPendingAnimations() {
|
|
1214
|
-
return (_nullishCoalesce(_optionalChain([this, 'access',
|
|
1248
|
+
return (_nullishCoalesce(_optionalChain([this, 'access', _114 => _114.animations, 'optionalAccess', _115 => _115.length]), () => ( 0))) > 0 || (_nullishCoalesce(_optionalChain([this, 'access', _116 => _116._drivers, 'optionalAccess', _117 => _117.size]), () => ( 0))) > 0;
|
|
1215
1249
|
}
|
|
1216
1250
|
}, _class2);
|
|
1217
1251
|
|
|
@@ -1244,17 +1278,16 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1244
1278
|
// long-lived shared atlas image would retain the whole entity.
|
|
1245
1279
|
__init47() {this.atlasDecodeTarget = null}
|
|
1246
1280
|
__init48() {this.atlasDecodeHandler = null}
|
|
1247
|
-
__init49() {this.
|
|
1248
|
-
__init50() {this.
|
|
1249
|
-
__init51() {this.layoutResult = null}
|
|
1281
|
+
__init49() {this.fontStringCache = []}
|
|
1282
|
+
__init50() {this.layoutResult = null}
|
|
1250
1283
|
/**
|
|
1251
1284
|
* Visual rows rebuilt from {@link layoutResult} (see
|
|
1252
1285
|
* {@link rebuildProjectionLines}). Empty until a layout reply lands and the
|
|
1253
1286
|
* reply's shaped glyphs can be mapped back to the source text 1:1.
|
|
1254
1287
|
*/
|
|
1255
|
-
|
|
1288
|
+
__init51() {this.projectionLines = []}
|
|
1256
1289
|
constructor(text, options) {
|
|
1257
|
-
super();_class3.prototype.__init42.call(this);_class3.prototype.__init43.call(this);_class3.prototype.__init44.call(this);_class3.prototype.__init45.call(this);_class3.prototype.__init46.call(this);_class3.prototype.__init47.call(this);_class3.prototype.__init48.call(this);_class3.prototype.__init49.call(this);_class3.prototype.__init50.call(this);_class3.prototype.__init51.call(this)
|
|
1290
|
+
super();_class3.prototype.__init42.call(this);_class3.prototype.__init43.call(this);_class3.prototype.__init44.call(this);_class3.prototype.__init45.call(this);_class3.prototype.__init46.call(this);_class3.prototype.__init47.call(this);_class3.prototype.__init48.call(this);_class3.prototype.__init49.call(this);_class3.prototype.__init50.call(this);_class3.prototype.__init51.call(this);;
|
|
1258
1291
|
this.font = options.font;
|
|
1259
1292
|
this.texture = options.texture;
|
|
1260
1293
|
this.fallbackFont = _nullishCoalesce(options.fallbackFont, () => ( "sans-serif"));
|
|
@@ -1299,7 +1332,7 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1299
1332
|
const target = this.texture;
|
|
1300
1333
|
this.atlasDecodeHandler = () => {
|
|
1301
1334
|
this.detachAtlasDecodeListener();
|
|
1302
|
-
_optionalChain([this, 'access',
|
|
1335
|
+
_optionalChain([this, 'access', _118 => _118.scene, 'optionalAccess', _119 => _119.markDirty, 'call', _120 => _120()]);
|
|
1303
1336
|
};
|
|
1304
1337
|
target.addEventListener("load", this.atlasDecodeHandler);
|
|
1305
1338
|
target.addEventListener("error", this.atlasDecodeHandler);
|
|
@@ -1381,7 +1414,7 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1381
1414
|
this.layoutResult = res;
|
|
1382
1415
|
this.contentEpoch++;
|
|
1383
1416
|
this.rebuildProjectionLines();
|
|
1384
|
-
_optionalChain([this, 'access',
|
|
1417
|
+
_optionalChain([this, 'access', _121 => _121.scene, 'optionalAccess', _122 => _122.markDirty, 'call', _123 => _123()]);
|
|
1385
1418
|
}
|
|
1386
1419
|
});
|
|
1387
1420
|
}
|
|
@@ -1400,8 +1433,8 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1400
1433
|
getContentProjection() {
|
|
1401
1434
|
if (!this.text) return null;
|
|
1402
1435
|
const metrics = this.font.data.metrics;
|
|
1403
|
-
const asc = _nullishCoalesce(_optionalChain([metrics, 'optionalAccess',
|
|
1404
|
-
const desc = _nullishCoalesce(_optionalChain([metrics, 'optionalAccess',
|
|
1436
|
+
const asc = _nullishCoalesce(_optionalChain([metrics, 'optionalAccess', _124 => _124.ascender]), () => ( 0.8));
|
|
1437
|
+
const desc = _nullishCoalesce(_optionalChain([metrics, 'optionalAccess', _125 => _125.descender]), () => ( -0.2));
|
|
1405
1438
|
const actualLineHeight = _nullishCoalesce(this.lineHeight, () => ( this.fontSize * (asc - desc)));
|
|
1406
1439
|
return {
|
|
1407
1440
|
text: this.text,
|
|
@@ -1431,18 +1464,33 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1431
1464
|
shaped.push(String.fromCodePoint(res.codePoints[i]));
|
|
1432
1465
|
}
|
|
1433
1466
|
const sourceWithoutNewlines = this.text.replace(/\n/g, "");
|
|
1434
|
-
if (this.textAlign !== "left" ||
|
|
1467
|
+
if (this.textAlign !== "left" || // The layout worker breaks lines on \n only, so a \r survives as a real
|
|
1468
|
+
// glyph — a phantom ~1em advance at every CRLF line end — yet would
|
|
1469
|
+
// still compare equal below after \n is stripped from both sides. The
|
|
1470
|
+
// contract promises the coarse branch whenever the reply cannot
|
|
1471
|
+
// reproduce the source exactly, and that includes any \r (#692).
|
|
1472
|
+
this.text.includes("\r") || shaped.join("") !== sourceWithoutNewlines || res.yCoords.length !== res.codePoints.length) {
|
|
1435
1473
|
this.projectionLines = [];
|
|
1436
1474
|
return;
|
|
1437
1475
|
}
|
|
1438
1476
|
const metrics = this.font.data.metrics;
|
|
1439
|
-
const asc = _nullishCoalesce(_optionalChain([metrics, 'optionalAccess',
|
|
1440
|
-
const desc = _nullishCoalesce(_optionalChain([metrics, 'optionalAccess',
|
|
1477
|
+
const asc = _nullishCoalesce(_optionalChain([metrics, 'optionalAccess', _126 => _126.ascender]), () => ( 0.8));
|
|
1478
|
+
const desc = _nullishCoalesce(_optionalChain([metrics, 'optionalAccess', _127 => _127.descender]), () => ( -0.2));
|
|
1441
1479
|
const actualLineHeight = _nullishCoalesce(this.lineHeight, () => ( this.fontSize * (asc - desc)));
|
|
1442
1480
|
const baseline = asc * this.fontSize;
|
|
1443
|
-
const
|
|
1444
|
-
|
|
1445
|
-
|
|
1481
|
+
const srcStart = [];
|
|
1482
|
+
const srcEnd = [];
|
|
1483
|
+
{
|
|
1484
|
+
let cursor = 0;
|
|
1485
|
+
while (cursor < this.text.length) {
|
|
1486
|
+
const code = this.text.codePointAt(cursor);
|
|
1487
|
+
const width = code > 65535 ? 2 : 1;
|
|
1488
|
+
if (code !== 10) {
|
|
1489
|
+
srcStart.push(cursor);
|
|
1490
|
+
srcEnd.push(cursor + width);
|
|
1491
|
+
}
|
|
1492
|
+
cursor += width;
|
|
1493
|
+
}
|
|
1446
1494
|
}
|
|
1447
1495
|
const glyphsByLine = /* @__PURE__ */ new Map();
|
|
1448
1496
|
let maxIdx = -1;
|
|
@@ -1458,8 +1506,8 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1458
1506
|
let previousEnd = 0;
|
|
1459
1507
|
for (let i = 0; i <= maxIdx; i++) {
|
|
1460
1508
|
const glyphs = _nullishCoalesce(glyphsByLine.get(i), () => ( []));
|
|
1461
|
-
const start = glyphs.length > 0 ?
|
|
1462
|
-
const end = glyphs.length > 0 ?
|
|
1509
|
+
const start = glyphs.length > 0 ? srcStart[glyphs[0]] : previousEnd;
|
|
1510
|
+
const end = glyphs.length > 0 ? srcEnd[glyphs[glyphs.length - 1]] : start;
|
|
1463
1511
|
starts.push(start);
|
|
1464
1512
|
ends.push(end);
|
|
1465
1513
|
previousEnd = Math.max(previousEnd, end);
|
|
@@ -1512,7 +1560,6 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1512
1560
|
const code = this.layoutResult.codePoints[i];
|
|
1513
1561
|
const nodeX = this.layoutResult.xCoords[i];
|
|
1514
1562
|
const nodeY = this.layoutResult.yCoords[i];
|
|
1515
|
-
const packedStyle = this.layoutResult.packedStyles[i];
|
|
1516
1563
|
const def = this.font.getGlyph(code);
|
|
1517
1564
|
if (!def || !def.atlasBounds || !def.planeBounds) continue;
|
|
1518
1565
|
const { atlasBounds: ab, planeBounds: pb } = def;
|
|
@@ -1526,15 +1573,6 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1526
1573
|
const glyphH = (pb.top - pb.bottom) * this.fontSize * worldScaleY;
|
|
1527
1574
|
const v0 = this.font.data.atlas.yOrigin === "bottom" ? 1 - ab.top / ah : ab.top / ah;
|
|
1528
1575
|
const v1 = this.font.data.atlas.yOrigin === "bottom" ? 1 - ab.bottom / ah : ab.bottom / ah;
|
|
1529
|
-
const colorVal = packedStyle >>> 8;
|
|
1530
|
-
let runColor = this.rgbColorCache.get(colorVal);
|
|
1531
|
-
if (!runColor) {
|
|
1532
|
-
const r = colorVal >> 16 & 255;
|
|
1533
|
-
const g = colorVal >> 8 & 255;
|
|
1534
|
-
const b = colorVal & 255;
|
|
1535
|
-
runColor = `rgb(${r},${g},${b})`;
|
|
1536
|
-
this.rgbColorCache.set(colorVal, runColor);
|
|
1537
|
-
}
|
|
1538
1576
|
scene.pointRenderer.addGlyph(
|
|
1539
1577
|
glyphX,
|
|
1540
1578
|
glyphY,
|
|
@@ -1544,7 +1582,7 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1544
1582
|
v0,
|
|
1545
1583
|
ab.right / aw,
|
|
1546
1584
|
v1,
|
|
1547
|
-
|
|
1585
|
+
this.color,
|
|
1548
1586
|
worldOpacity,
|
|
1549
1587
|
worldRot
|
|
1550
1588
|
);
|
|
@@ -1564,16 +1602,7 @@ var MSDFTextEntity = (_class3 = class extends Entity {
|
|
|
1564
1602
|
const nodeY = this.layoutResult.yCoords[i];
|
|
1565
1603
|
const packedStyle = this.layoutResult.packedStyles[i];
|
|
1566
1604
|
const fontString = this.fontStringCache[packedStyle & 3];
|
|
1567
|
-
|
|
1568
|
-
let runColor = this.rgbColorCache.get(colorVal);
|
|
1569
|
-
if (!runColor) {
|
|
1570
|
-
const r = colorVal >> 16 & 255;
|
|
1571
|
-
const g = colorVal >> 8 & 255;
|
|
1572
|
-
const b = colorVal & 255;
|
|
1573
|
-
runColor = `rgb(${r},${g},${b})`;
|
|
1574
|
-
this.rgbColorCache.set(colorVal, runColor);
|
|
1575
|
-
}
|
|
1576
|
-
renderer.fillText(String.fromCodePoint(code), nodeX, nodeY, fontString, runColor);
|
|
1605
|
+
renderer.fillText(String.fromCodePoint(code), nodeX, nodeY, fontString, this.color);
|
|
1577
1606
|
}
|
|
1578
1607
|
}
|
|
1579
1608
|
destroy() {
|
|
@@ -1588,11 +1617,32 @@ var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
|
1588
1617
|
function isSvgWhitespace(ch) {
|
|
1589
1618
|
return ch === " " || ch === " " || ch === "\n" || ch === "\r";
|
|
1590
1619
|
}
|
|
1620
|
+
function findSvgTagEnd(source, from) {
|
|
1621
|
+
let quote = null;
|
|
1622
|
+
for (let i = from; i < source.length; i++) {
|
|
1623
|
+
const ch = source[i];
|
|
1624
|
+
if (quote !== null) {
|
|
1625
|
+
if (ch === quote) quote = null;
|
|
1626
|
+
} else if (ch === '"' || ch === "'") {
|
|
1627
|
+
quote = ch;
|
|
1628
|
+
} else if (ch === ">") {
|
|
1629
|
+
return i;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
return -1;
|
|
1633
|
+
}
|
|
1634
|
+
function isPercentDimension(value) {
|
|
1635
|
+
return value.trim().endsWith("%");
|
|
1636
|
+
}
|
|
1637
|
+
function viewBoxDimensions(value) {
|
|
1638
|
+
const parts = value.split(/[\s,]+/).map(parseFloat);
|
|
1639
|
+
return parts.length === 4 && parts.every(Number.isFinite) ? { width: parts[2], height: parts[3] } : null;
|
|
1640
|
+
}
|
|
1591
1641
|
function readSvgAttribute(source, name) {
|
|
1592
1642
|
const lowerSource = source.toLowerCase();
|
|
1593
1643
|
const svgStart = lowerSource.indexOf("<svg");
|
|
1594
1644
|
if (svgStart < 0) return null;
|
|
1595
|
-
const tagEnd = source
|
|
1645
|
+
const tagEnd = findSvgTagEnd(source, svgStart + 4);
|
|
1596
1646
|
if (tagEnd < 0) return null;
|
|
1597
1647
|
const tag = source.slice(svgStart + 4, tagEnd);
|
|
1598
1648
|
const lowerTag = tag.toLowerCase();
|
|
@@ -1621,23 +1671,23 @@ var SVGEntity = (_class4 = class extends Entity {
|
|
|
1621
1671
|
* rasterized. Set to `'transparent'` to opt out and keep the box empty.
|
|
1622
1672
|
* Default `'rgba(248,113,113,0.9)'`.
|
|
1623
1673
|
*/
|
|
1624
|
-
|
|
1674
|
+
__init52() {this.fallbackStroke = "rgba(248,113,113,0.9)"}
|
|
1625
1675
|
/** Fill behind the fallback marker. Default `'rgba(248,113,113,0.12)'`. */
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1676
|
+
__init53() {this.fallbackFill = "rgba(248,113,113,0.12)"}
|
|
1677
|
+
__init54() {this.svgSource = ""}
|
|
1678
|
+
__init55() {this.imageBitmap = null}
|
|
1679
|
+
__init56() {this.imageElement = null}
|
|
1680
|
+
__init57() {this.blobURL = null}
|
|
1681
|
+
__init58() {this.currentImg = null}
|
|
1682
|
+
__init59() {this.lodTimeout = null}
|
|
1683
|
+
__init60() {this.rasterFailed = false}
|
|
1684
|
+
__init61() {this.cachedDoc = null}
|
|
1685
|
+
__init62() {this.baseWidth = 100}
|
|
1686
|
+
__init63() {this.baseHeight = 100}
|
|
1687
|
+
__init64() {this.lastRasterizedScale = 1}
|
|
1688
|
+
__init65() {this.targetScale = 1}
|
|
1639
1689
|
constructor(svgSource, id) {
|
|
1640
|
-
super(id);_class4.prototype.__init53.call(this);_class4.prototype.__init54.call(this);_class4.prototype.__init55.call(this);_class4.prototype.__init56.call(this);_class4.prototype.__init57.call(this);_class4.prototype.__init58.call(this);_class4.prototype.__init59.call(this);_class4.prototype.__init60.call(this);_class4.prototype.__init61.call(this);_class4.prototype.__init62.call(this);_class4.prototype.__init63.call(this);_class4.prototype.__init64.call(this);_class4.prototype.__init65.call(this)
|
|
1690
|
+
super(id);_class4.prototype.__init52.call(this);_class4.prototype.__init53.call(this);_class4.prototype.__init54.call(this);_class4.prototype.__init55.call(this);_class4.prototype.__init56.call(this);_class4.prototype.__init57.call(this);_class4.prototype.__init58.call(this);_class4.prototype.__init59.call(this);_class4.prototype.__init60.call(this);_class4.prototype.__init61.call(this);_class4.prototype.__init62.call(this);_class4.prototype.__init63.call(this);_class4.prototype.__init64.call(this);_class4.prototype.__init65.call(this);;
|
|
1641
1691
|
this.setSVGSource(svgSource);
|
|
1642
1692
|
}
|
|
1643
1693
|
setSVGSource(svgSource) {
|
|
@@ -1664,14 +1714,14 @@ var SVGEntity = (_class4 = class extends Entity {
|
|
|
1664
1714
|
const wAttr = svgEl.getAttribute("width");
|
|
1665
1715
|
const hAttr = svgEl.getAttribute("height");
|
|
1666
1716
|
const vbAttr = svgEl.getAttribute("viewBox");
|
|
1667
|
-
if (wAttr && hAttr) {
|
|
1717
|
+
if (wAttr && hAttr && !isPercentDimension(wAttr) && !isPercentDimension(hAttr)) {
|
|
1668
1718
|
width = parseFloat(wAttr) || 100;
|
|
1669
1719
|
height = parseFloat(hAttr) || 100;
|
|
1670
1720
|
} else if (vbAttr) {
|
|
1671
|
-
const
|
|
1672
|
-
if (
|
|
1673
|
-
width =
|
|
1674
|
-
height =
|
|
1721
|
+
const dims = viewBoxDimensions(vbAttr);
|
|
1722
|
+
if (dims) {
|
|
1723
|
+
width = dims.width;
|
|
1724
|
+
height = dims.height;
|
|
1675
1725
|
}
|
|
1676
1726
|
}
|
|
1677
1727
|
}
|
|
@@ -1683,14 +1733,14 @@ var SVGEntity = (_class4 = class extends Entity {
|
|
|
1683
1733
|
const wAttr = readSvgAttribute(this.svgSource, "width");
|
|
1684
1734
|
const hAttr = readSvgAttribute(this.svgSource, "height");
|
|
1685
1735
|
const vbAttr = readSvgAttribute(this.svgSource, "viewBox");
|
|
1686
|
-
if (wAttr && hAttr) {
|
|
1736
|
+
if (wAttr && hAttr && !isPercentDimension(wAttr) && !isPercentDimension(hAttr)) {
|
|
1687
1737
|
width = parseFloat(wAttr) || 100;
|
|
1688
1738
|
height = parseFloat(hAttr) || 100;
|
|
1689
1739
|
} else if (vbAttr) {
|
|
1690
|
-
const
|
|
1691
|
-
if (
|
|
1692
|
-
width =
|
|
1693
|
-
height =
|
|
1740
|
+
const dims = viewBoxDimensions(vbAttr);
|
|
1741
|
+
if (dims) {
|
|
1742
|
+
width = dims.width;
|
|
1743
|
+
height = dims.height;
|
|
1694
1744
|
}
|
|
1695
1745
|
}
|
|
1696
1746
|
}
|