@vectojs/three 0.1.2 → 0.1.4
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/README.md +94 -0
- package/dist/ThreeAdapter.d.ts +67 -0
- package/dist/ThreeRenderer.d.ts +89 -0
- package/dist/index.d.ts +2 -123
- package/dist/index.js +226 -77
- package/dist/index.mjs +226 -77
- package/package.json +2 -2
- package/dist/index.d.mts +0 -123
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// src/ThreeRenderer.ts
|
|
2
2
|
import { parseColorToRGBA } from "@vectojs/core";
|
|
3
3
|
import * as THREE from "three";
|
|
4
|
+
function parseThreeColor(value) {
|
|
5
|
+
const [r, g, b, alpha] = parseColorToRGBA(value);
|
|
6
|
+
return { color: new THREE.Color(r, g, b), alpha };
|
|
7
|
+
}
|
|
4
8
|
var WebGLGradient = class {
|
|
5
9
|
constructor(x0, y0, x1, y1, colorStops) {
|
|
6
10
|
this.x0 = x0;
|
|
@@ -73,14 +77,16 @@ var ThreeRenderer = class {
|
|
|
73
77
|
activeObjects = [];
|
|
74
78
|
scissorStack = [];
|
|
75
79
|
constructor(canvas) {
|
|
76
|
-
|
|
77
|
-
|
|
80
|
+
const cw = canvas.width > 0 ? canvas.width : typeof window !== "undefined" ? window.innerWidth : 1024;
|
|
81
|
+
const ch = canvas.height > 0 ? canvas.height : typeof window !== "undefined" ? window.innerHeight : 1024;
|
|
82
|
+
this.width = cw;
|
|
83
|
+
this.height = ch;
|
|
78
84
|
this.scene = new THREE.Scene();
|
|
79
85
|
this.camera = new THREE.OrthographicCamera(0, this.width, 0, this.height, 0.1, 1e3);
|
|
80
86
|
this.camera.position.z = 1;
|
|
81
87
|
this.renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true });
|
|
82
88
|
this.renderer.setSize(this.width, this.height);
|
|
83
|
-
this.renderer.setPixelRatio(window.devicePixelRatio || 1);
|
|
89
|
+
this.renderer.setPixelRatio(typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1);
|
|
84
90
|
this.matrix = new THREE.Matrix4().identity();
|
|
85
91
|
}
|
|
86
92
|
resize(width, height) {
|
|
@@ -92,26 +98,42 @@ var ThreeRenderer = class {
|
|
|
92
98
|
this.camera.updateProjectionMatrix();
|
|
93
99
|
}
|
|
94
100
|
clear() {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
101
|
+
this.disposeActiveObjects();
|
|
102
|
+
this.currentPath = null;
|
|
103
|
+
this.matrix.identity();
|
|
104
|
+
this.stack.length = 0;
|
|
105
|
+
this.globalAlpha = 1;
|
|
106
|
+
this.alphaStack.length = 0;
|
|
107
|
+
this.scissorStack.length = 0;
|
|
108
|
+
this.renderer.clear();
|
|
109
|
+
this.renderer.setScissorTest(false);
|
|
110
|
+
}
|
|
111
|
+
disposeActiveObjects() {
|
|
112
|
+
const disposedGeometries = /* @__PURE__ */ new Set();
|
|
113
|
+
const disposedMaterials = /* @__PURE__ */ new Set();
|
|
114
|
+
const disposedTextures = /* @__PURE__ */ new Set();
|
|
115
|
+
for (const object of this.activeObjects) {
|
|
116
|
+
this.scene.remove(object);
|
|
117
|
+
if (!(object instanceof THREE.Mesh || object instanceof THREE.Line)) continue;
|
|
118
|
+
const geometry = object.geometry;
|
|
119
|
+
if (!disposedGeometries.has(geometry)) {
|
|
120
|
+
disposedGeometries.add(geometry);
|
|
121
|
+
geometry.dispose();
|
|
122
|
+
}
|
|
123
|
+
const materials = Array.isArray(object.material) ? object.material : [object.material];
|
|
124
|
+
for (const material of materials) {
|
|
125
|
+
const map = material.map;
|
|
126
|
+
if (map && !map.userData.vectoCached && !disposedTextures.has(map)) {
|
|
127
|
+
disposedTextures.add(map);
|
|
128
|
+
map.dispose();
|
|
129
|
+
}
|
|
130
|
+
if (!disposedMaterials.has(material)) {
|
|
131
|
+
disposedMaterials.add(material);
|
|
132
|
+
material.dispose();
|
|
109
133
|
}
|
|
110
134
|
}
|
|
111
135
|
}
|
|
112
|
-
this.activeObjects =
|
|
113
|
-
this.renderer.clear();
|
|
114
|
-
this.renderer.setScissorTest(false);
|
|
136
|
+
this.activeObjects.length = 0;
|
|
115
137
|
}
|
|
116
138
|
save() {
|
|
117
139
|
this.stack.push(this.matrix.clone());
|
|
@@ -148,16 +170,33 @@ var ThreeRenderer = class {
|
|
|
148
170
|
this.globalAlpha = alpha;
|
|
149
171
|
}
|
|
150
172
|
clip(x, y, width, height) {
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
173
|
+
const corners = [
|
|
174
|
+
new THREE.Vector3(x, y, 0),
|
|
175
|
+
new THREE.Vector3(x + width, y, 0),
|
|
176
|
+
new THREE.Vector3(x, y + height, 0),
|
|
177
|
+
new THREE.Vector3(x + width, y + height, 0)
|
|
178
|
+
].map((point) => point.applyMatrix4(this.matrix));
|
|
179
|
+
const minX = Math.min(...corners.map((point) => point.x));
|
|
180
|
+
const minY = Math.min(...corners.map((point) => point.y));
|
|
181
|
+
const maxX = Math.max(...corners.map((point) => point.x));
|
|
182
|
+
const maxY = Math.max(...corners.map((point) => point.y));
|
|
183
|
+
const dpr = this.renderer.getPixelRatio() || 1;
|
|
154
184
|
const canvasHeight = this.renderer.domElement.height / dpr;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
185
|
+
let scissorX = minX * dpr;
|
|
186
|
+
let scissorY = (canvasHeight - maxY) * dpr;
|
|
187
|
+
let scissorWidth = (maxX - minX) * dpr;
|
|
188
|
+
let scissorHeight = (maxY - minY) * dpr;
|
|
189
|
+
if (this.renderer.getScissorTest()) {
|
|
190
|
+
const current = new THREE.Vector4();
|
|
191
|
+
this.renderer.getScissor(current);
|
|
192
|
+
const right = Math.min(scissorX + scissorWidth, current.x + current.z);
|
|
193
|
+
const top = Math.min(scissorY + scissorHeight, current.y + current.w);
|
|
194
|
+
scissorX = Math.max(scissorX, current.x);
|
|
195
|
+
scissorY = Math.max(scissorY, current.y);
|
|
196
|
+
scissorWidth = Math.max(0, right - scissorX);
|
|
197
|
+
scissorHeight = Math.max(0, top - scissorY);
|
|
198
|
+
}
|
|
199
|
+
this.renderer.setScissor(scissorX, scissorY, scissorWidth, scissorHeight);
|
|
161
200
|
this.renderer.setScissorTest(true);
|
|
162
201
|
}
|
|
163
202
|
beginPath() {
|
|
@@ -376,13 +415,15 @@ var ThreeRenderer = class {
|
|
|
376
415
|
fillSolidShape(colorOrGradient) {
|
|
377
416
|
if (!this.currentPath) return;
|
|
378
417
|
const color = typeof colorOrGradient === "string" ? colorOrGradient : "#ffffff";
|
|
418
|
+
const parsed = parseThreeColor(color);
|
|
379
419
|
const shapes = this.currentPath.toShapes();
|
|
380
420
|
for (const shape of shapes) {
|
|
381
421
|
const geometry = new THREE.ShapeGeometry(shape);
|
|
422
|
+
const opacity = this.globalAlpha * parsed.alpha;
|
|
382
423
|
const material = new THREE.MeshBasicMaterial({
|
|
383
|
-
color:
|
|
384
|
-
transparent:
|
|
385
|
-
opacity
|
|
424
|
+
color: parsed.color,
|
|
425
|
+
transparent: opacity < 1,
|
|
426
|
+
opacity,
|
|
386
427
|
depthWrite: false
|
|
387
428
|
});
|
|
388
429
|
const mesh = new THREE.Mesh(geometry, material);
|
|
@@ -402,31 +443,35 @@ var ThreeRenderer = class {
|
|
|
402
443
|
color = grad.colorStops[0].color;
|
|
403
444
|
}
|
|
404
445
|
}
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
446
|
+
const parsed = parseThreeColor(color);
|
|
447
|
+
const opacity = this.globalAlpha * parsed.alpha;
|
|
448
|
+
for (const shape of this.currentPath.toShapes()) {
|
|
449
|
+
const points = shape.getPoints();
|
|
450
|
+
if (points.length < 2) continue;
|
|
451
|
+
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
|
452
|
+
const material = new THREE.LineBasicMaterial({
|
|
453
|
+
color: parsed.color,
|
|
454
|
+
transparent: opacity < 1,
|
|
455
|
+
opacity,
|
|
456
|
+
linewidth: lineWidth
|
|
457
|
+
});
|
|
458
|
+
const line = new THREE.Line(geometry, material);
|
|
459
|
+
line.applyMatrix4(this.matrix);
|
|
460
|
+
this.scene.add(line);
|
|
461
|
+
this.activeObjects.push(line);
|
|
462
|
+
}
|
|
418
463
|
}
|
|
464
|
+
/**
|
|
465
|
+
* Rasterized fillText textures keyed by `font|color|text`, LRU-evicted.
|
|
466
|
+
* HUD-style UIs redraw the same labels every frame; without the cache each
|
|
467
|
+
* call allocated a canvas, rasterized it, and uploaded a fresh GPU texture.
|
|
468
|
+
* Entries are skipped by {@link disposeActiveObjects} (flagged via
|
|
469
|
+
* `userData.vectoCached`) and released on eviction or {@link dispose}.
|
|
470
|
+
*/
|
|
471
|
+
textTextureCache = /* @__PURE__ */ new Map();
|
|
472
|
+
textTextureCacheLimit = 256;
|
|
419
473
|
fillText(text, x, y, font, color) {
|
|
420
474
|
if (typeof document === "undefined") return;
|
|
421
|
-
const canvas = document.createElement("canvas");
|
|
422
|
-
const ctx = canvas.getContext("2d");
|
|
423
|
-
ctx.font = font;
|
|
424
|
-
const width = Math.max(1, Math.ceil(ctx.measureText(text).width));
|
|
425
|
-
const fontSize = parseInt(font) || 16;
|
|
426
|
-
const height = Math.max(1, Math.ceil(fontSize * 1.5));
|
|
427
|
-
canvas.width = width;
|
|
428
|
-
canvas.height = height;
|
|
429
|
-
ctx.font = font;
|
|
430
475
|
let fillCol = "#ffffff";
|
|
431
476
|
if (typeof color === "string") {
|
|
432
477
|
fillCol = color;
|
|
@@ -436,11 +481,36 @@ var ThreeRenderer = class {
|
|
|
436
481
|
fillCol = grad.colorStops[0].color;
|
|
437
482
|
}
|
|
438
483
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
484
|
+
const cacheKey = `${font}|${fillCol}|${text}`;
|
|
485
|
+
let entry = this.textTextureCache.get(cacheKey);
|
|
486
|
+
if (entry) {
|
|
487
|
+
this.textTextureCache.delete(cacheKey);
|
|
488
|
+
this.textTextureCache.set(cacheKey, entry);
|
|
489
|
+
} else {
|
|
490
|
+
const canvas = document.createElement("canvas");
|
|
491
|
+
const ctx = canvas.getContext("2d");
|
|
492
|
+
ctx.font = font;
|
|
493
|
+
const width2 = Math.max(1, Math.ceil(ctx.measureText(text).width));
|
|
494
|
+
const fontSize2 = parseInt(font) || 16;
|
|
495
|
+
const height2 = Math.max(1, Math.ceil(fontSize2 * 1.5));
|
|
496
|
+
canvas.width = width2;
|
|
497
|
+
canvas.height = height2;
|
|
498
|
+
ctx.font = font;
|
|
499
|
+
ctx.fillStyle = fillCol;
|
|
500
|
+
ctx.textBaseline = "alphabetic";
|
|
501
|
+
ctx.fillText(text, 0, fontSize2);
|
|
502
|
+
const texture2 = new THREE.CanvasTexture(canvas);
|
|
503
|
+
texture2.minFilter = THREE.LinearFilter;
|
|
504
|
+
texture2.userData.vectoCached = true;
|
|
505
|
+
entry = { texture: texture2, width: width2, height: height2, fontSize: fontSize2 };
|
|
506
|
+
this.textTextureCache.set(cacheKey, entry);
|
|
507
|
+
while (this.textTextureCache.size > Math.max(1, this.textTextureCacheLimit)) {
|
|
508
|
+
const oldestKey = this.textTextureCache.keys().next().value;
|
|
509
|
+
this.textTextureCache.get(oldestKey).texture.dispose();
|
|
510
|
+
this.textTextureCache.delete(oldestKey);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
const { texture, width, height, fontSize } = entry;
|
|
444
514
|
const material = new THREE.MeshBasicMaterial({
|
|
445
515
|
map: texture,
|
|
446
516
|
transparent: true,
|
|
@@ -456,10 +526,12 @@ var ThreeRenderer = class {
|
|
|
456
526
|
}
|
|
457
527
|
fillCircle(cx, cy, radius, color, alpha = 1) {
|
|
458
528
|
const geometry = new THREE.CircleGeometry(radius, 32);
|
|
529
|
+
const parsed = parseThreeColor(color);
|
|
530
|
+
const opacity = this.globalAlpha * alpha * parsed.alpha;
|
|
459
531
|
const material = new THREE.MeshBasicMaterial({
|
|
460
|
-
color:
|
|
461
|
-
transparent:
|
|
462
|
-
opacity
|
|
532
|
+
color: parsed.color,
|
|
533
|
+
transparent: opacity < 1,
|
|
534
|
+
opacity,
|
|
463
535
|
depthWrite: false
|
|
464
536
|
});
|
|
465
537
|
const mesh = new THREE.Mesh(geometry, material);
|
|
@@ -468,12 +540,51 @@ var ThreeRenderer = class {
|
|
|
468
540
|
this.scene.add(mesh);
|
|
469
541
|
this.activeObjects.push(mesh);
|
|
470
542
|
}
|
|
543
|
+
frameDirty = false;
|
|
544
|
+
presentScheduled = false;
|
|
545
|
+
/**
|
|
546
|
+
* The Scene calls flush() around every non-batched node (it commits the
|
|
547
|
+
* Canvas2D circle batch there). Rendering the whole Three scene on each of
|
|
548
|
+
* those calls made a frame cost O(N²) in entity count, so flush() only marks
|
|
549
|
+
* the frame dirty; the actual GL render happens once, in {@link present}.
|
|
550
|
+
*
|
|
551
|
+
* A microtask fallback keeps older `@vectojs/core` Scenes (that never call
|
|
552
|
+
* `present()`) painting: the many same-tick flushes coalesce into one render.
|
|
553
|
+
*/
|
|
471
554
|
flush() {
|
|
555
|
+
this.frameDirty = true;
|
|
556
|
+
if (this.presentScheduled) return;
|
|
557
|
+
this.presentScheduled = true;
|
|
558
|
+
queueMicrotask(() => {
|
|
559
|
+
this.presentScheduled = false;
|
|
560
|
+
if (this.frameDirty && !this.disposed) this.present();
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
/** Render the accumulated frame once. Called by Scene at the end of each render pass. */
|
|
564
|
+
present() {
|
|
565
|
+
if (this.disposed) return;
|
|
566
|
+
this.frameDirty = false;
|
|
472
567
|
this.renderer.render(this.scene, this.camera);
|
|
473
568
|
}
|
|
474
569
|
createLinearGradient(x0, y0, x1, y1, colorStops) {
|
|
475
570
|
return new WebGLGradient(x0, y0, x1, y1, colorStops);
|
|
476
571
|
}
|
|
572
|
+
disposed = false;
|
|
573
|
+
dispose() {
|
|
574
|
+
if (this.disposed) return;
|
|
575
|
+
this.disposed = true;
|
|
576
|
+
this.disposeActiveObjects();
|
|
577
|
+
for (const entry of this.textTextureCache.values()) {
|
|
578
|
+
entry.texture.dispose();
|
|
579
|
+
}
|
|
580
|
+
this.textTextureCache.clear();
|
|
581
|
+
this.currentPath = null;
|
|
582
|
+
this.stack.length = 0;
|
|
583
|
+
this.alphaStack.length = 0;
|
|
584
|
+
this.scissorStack.length = 0;
|
|
585
|
+
this.renderer.setScissorTest(false);
|
|
586
|
+
this.renderer.dispose();
|
|
587
|
+
}
|
|
477
588
|
};
|
|
478
589
|
|
|
479
590
|
// src/ThreeAdapter.ts
|
|
@@ -490,8 +601,20 @@ var ThreeAdapter = class {
|
|
|
490
601
|
mesh;
|
|
491
602
|
/** Track hover states independently per pointerId for WebXR / Multi-Touch. */
|
|
492
603
|
activePointers = /* @__PURE__ */ new Map();
|
|
604
|
+
/**
|
|
605
|
+
* Holds the original `vectoScene.render` reference so {@link dispose} can
|
|
606
|
+
* restore it. Without restoring, a later render call would write
|
|
607
|
+
* `needsUpdate` on a disposed (deleted) `CanvasTexture`, which Three.js
|
|
608
|
+
* flags with `"THREE.Texture: trying to use deleted texture"`.
|
|
609
|
+
*/
|
|
610
|
+
_originalRender = null;
|
|
611
|
+
/** Tracks whether this adapter owns the canvas it is rendering to. */
|
|
612
|
+
_ownsCanvas;
|
|
613
|
+
_disposed = false;
|
|
493
614
|
constructor(options) {
|
|
494
|
-
|
|
615
|
+
const optCanvas = options.canvas;
|
|
616
|
+
this._ownsCanvas = !optCanvas;
|
|
617
|
+
this.canvas = optCanvas || (typeof document !== "undefined" ? document.createElement("canvas") : { width: options.width, height: options.height });
|
|
495
618
|
this.canvas.width = options.width;
|
|
496
619
|
this.canvas.height = options.height;
|
|
497
620
|
const sceneOptions = {
|
|
@@ -503,7 +626,8 @@ var ThreeAdapter = class {
|
|
|
503
626
|
this.texture = new THREE2.CanvasTexture(this.canvas);
|
|
504
627
|
this.texture.minFilter = THREE2.LinearFilter;
|
|
505
628
|
this.texture.magFilter = THREE2.LinearFilter;
|
|
506
|
-
|
|
629
|
+
this._originalRender = this.vectoScene.render;
|
|
630
|
+
const originalRender = this._originalRender;
|
|
507
631
|
this.vectoScene.render = (renderer, dt, time) => {
|
|
508
632
|
originalRender.call(this.vectoScene, renderer, dt, time);
|
|
509
633
|
this.texture.needsUpdate = true;
|
|
@@ -599,34 +723,51 @@ var ThreeAdapter = class {
|
|
|
599
723
|
a11yEl.focus();
|
|
600
724
|
}
|
|
601
725
|
} else {
|
|
602
|
-
const
|
|
603
|
-
|
|
726
|
+
const vectoEvent = new VectoJSEvent(type, entity, originalEvent, type !== "pointerleave", {
|
|
727
|
+
x,
|
|
728
|
+
y
|
|
729
|
+
});
|
|
604
730
|
entity.dispatchEvent(vectoEvent);
|
|
605
731
|
}
|
|
606
732
|
}
|
|
607
733
|
createDOMEvent(type, x, y, pointerId, originalEvent) {
|
|
734
|
+
let event;
|
|
608
735
|
if (type === "wheel") {
|
|
609
736
|
const wheelE = originalEvent instanceof WheelEvent ? originalEvent : void 0;
|
|
610
|
-
|
|
737
|
+
event = new WheelEvent("wheel", {
|
|
611
738
|
clientX: x,
|
|
612
739
|
clientY: y,
|
|
613
740
|
deltaX: wheelE ? wheelE.deltaX : 0,
|
|
614
741
|
deltaY: wheelE ? wheelE.deltaY : 0,
|
|
615
742
|
deltaZ: wheelE ? wheelE.deltaZ : 0,
|
|
616
743
|
deltaMode: wheelE ? wheelE.deltaMode : 0,
|
|
744
|
+
shiftKey: wheelE ? wheelE.shiftKey : false,
|
|
745
|
+
ctrlKey: wheelE ? wheelE.ctrlKey : false,
|
|
746
|
+
altKey: wheelE ? wheelE.altKey : false,
|
|
747
|
+
metaKey: wheelE ? wheelE.metaKey : false,
|
|
748
|
+
bubbles: true,
|
|
749
|
+
cancelable: true
|
|
750
|
+
});
|
|
751
|
+
} else {
|
|
752
|
+
event = new PointerEvent(type, {
|
|
753
|
+
clientX: x,
|
|
754
|
+
clientY: y,
|
|
755
|
+
button: originalEvent instanceof MouseEvent ? originalEvent.button : 0,
|
|
756
|
+
buttons: originalEvent instanceof MouseEvent ? originalEvent.buttons : 0,
|
|
757
|
+
pointerId,
|
|
758
|
+
shiftKey: originalEvent instanceof MouseEvent ? originalEvent.shiftKey : false,
|
|
759
|
+
ctrlKey: originalEvent instanceof MouseEvent ? originalEvent.ctrlKey : false,
|
|
760
|
+
altKey: originalEvent instanceof MouseEvent ? originalEvent.altKey : false,
|
|
761
|
+
metaKey: originalEvent instanceof MouseEvent ? originalEvent.metaKey : false,
|
|
617
762
|
bubbles: true,
|
|
618
763
|
cancelable: true
|
|
619
764
|
});
|
|
620
765
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
button: originalEvent instanceof MouseEvent ? originalEvent.button : 0,
|
|
625
|
-
buttons: originalEvent instanceof MouseEvent ? originalEvent.buttons : 0,
|
|
626
|
-
pointerId,
|
|
627
|
-
bubbles: true,
|
|
628
|
-
cancelable: true
|
|
766
|
+
Object.defineProperties(event, {
|
|
767
|
+
vectoSceneX: { value: x },
|
|
768
|
+
vectoSceneY: { value: y }
|
|
629
769
|
});
|
|
770
|
+
return event;
|
|
630
771
|
}
|
|
631
772
|
findEntityById(root, id) {
|
|
632
773
|
if (root.id === id) return root;
|
|
@@ -649,6 +790,12 @@ var ThreeAdapter = class {
|
|
|
649
790
|
* Disposes of Three.js textures, geometries, and VectoJS scenes to prevent memory leaks.
|
|
650
791
|
*/
|
|
651
792
|
dispose() {
|
|
793
|
+
if (this._disposed) return;
|
|
794
|
+
this._disposed = true;
|
|
795
|
+
if (this._originalRender) {
|
|
796
|
+
this.vectoScene.render = this._originalRender;
|
|
797
|
+
this._originalRender = null;
|
|
798
|
+
}
|
|
652
799
|
this.texture.dispose();
|
|
653
800
|
this.mesh.geometry.dispose();
|
|
654
801
|
if (Array.isArray(this.mesh.material)) {
|
|
@@ -661,8 +808,10 @@ var ThreeAdapter = class {
|
|
|
661
808
|
}
|
|
662
809
|
this.vectoScene.destroy();
|
|
663
810
|
this.activePointers.clear();
|
|
664
|
-
this.
|
|
665
|
-
|
|
811
|
+
if (this._ownsCanvas) {
|
|
812
|
+
this.canvas.width = 0;
|
|
813
|
+
this.canvas.height = 0;
|
|
814
|
+
}
|
|
666
815
|
}
|
|
667
816
|
};
|
|
668
817
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vectojs/three",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dist"
|
|
20
20
|
],
|
|
21
21
|
"scripts": {
|
|
22
|
-
"build": "tsup src/index.ts --format cjs,esm --
|
|
22
|
+
"build": "(cd ../core && bun run build) && tsup src/index.ts --format cjs,esm --clean && tsc -p tsconfig.build.json",
|
|
23
23
|
"test": "vitest run"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
package/dist/index.d.mts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { IRenderer, Scene, SceneOptions } from '@vectojs/core';
|
|
2
|
-
import * as THREE from 'three';
|
|
3
|
-
|
|
4
|
-
declare class WebGLGradient {
|
|
5
|
-
x0: number;
|
|
6
|
-
y0: number;
|
|
7
|
-
x1: number;
|
|
8
|
-
y1: number;
|
|
9
|
-
colorStops: {
|
|
10
|
-
stop: number;
|
|
11
|
-
color: string;
|
|
12
|
-
}[];
|
|
13
|
-
type: string;
|
|
14
|
-
constructor(x0: number, y0: number, x1: number, y1: number, colorStops: {
|
|
15
|
-
stop: number;
|
|
16
|
-
color: string;
|
|
17
|
-
}[]);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* WebGL/Three.js implementation of {@link IRenderer}.
|
|
21
|
-
*
|
|
22
|
-
* Bridges VectoJS's 2D canvas API to Three.js for 3D hardware-accelerated rendering.
|
|
23
|
-
*/
|
|
24
|
-
declare class ThreeRenderer implements IRenderer {
|
|
25
|
-
scene: THREE.Scene;
|
|
26
|
-
camera: THREE.OrthographicCamera;
|
|
27
|
-
renderer: THREE.WebGLRenderer;
|
|
28
|
-
private width;
|
|
29
|
-
private height;
|
|
30
|
-
private matrix;
|
|
31
|
-
private stack;
|
|
32
|
-
private globalAlpha;
|
|
33
|
-
private alphaStack;
|
|
34
|
-
private currentPath;
|
|
35
|
-
private activeObjects;
|
|
36
|
-
private scissorStack;
|
|
37
|
-
constructor(canvas: HTMLCanvasElement);
|
|
38
|
-
resize(width: number, height: number): void;
|
|
39
|
-
clear(): void;
|
|
40
|
-
save(): void;
|
|
41
|
-
restore(): void;
|
|
42
|
-
translate(x: number, y: number): void;
|
|
43
|
-
scale(x: number, y: number): void;
|
|
44
|
-
rotate(angle: number): void;
|
|
45
|
-
setGlobalAlpha(alpha: number): void;
|
|
46
|
-
clip(x: number, y: number, width: number, height: number): void;
|
|
47
|
-
beginPath(): void;
|
|
48
|
-
moveTo(x: number, y: number): void;
|
|
49
|
-
lineTo(x: number, y: number): void;
|
|
50
|
-
bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void;
|
|
51
|
-
closePath(): void;
|
|
52
|
-
arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;
|
|
53
|
-
roundRect(x: number, y: number, width: number, height: number, radii: number | number[]): void;
|
|
54
|
-
drawImage(source: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;
|
|
55
|
-
fill(colorOrGradient: string | any): void;
|
|
56
|
-
private fillSolidShape;
|
|
57
|
-
stroke(colorOrGradient: string | any, lineWidth?: number): void;
|
|
58
|
-
fillText(text: string, x: number, y: number, font: string, color: string | any): void;
|
|
59
|
-
fillCircle(cx: number, cy: number, radius: number, color: string, alpha?: number): void;
|
|
60
|
-
flush(): void;
|
|
61
|
-
createLinearGradient(x0: number, y0: number, x1: number, y1: number, colorStops: {
|
|
62
|
-
stop: number;
|
|
63
|
-
color: string;
|
|
64
|
-
}[]): any;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
interface ThreeAdapterOptions {
|
|
68
|
-
/** Physical layout width of the 2D UI canvas. */
|
|
69
|
-
width: number;
|
|
70
|
-
/** Physical layout height of the 2D UI canvas. */
|
|
71
|
-
height: number;
|
|
72
|
-
/** Optional pre-existing canvas element. If omitted, a new canvas is created. */
|
|
73
|
-
canvas?: HTMLCanvasElement;
|
|
74
|
-
/** Options passed to the VectoScene constructor. */
|
|
75
|
-
sceneOptions?: SceneOptions;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Adapts a VectoJS Scene into a Three.js CanvasTexture, allowing VectoJS
|
|
79
|
-
* components to be rendered in 3D space (e.g. on a plane, screen, or VR dashboard).
|
|
80
|
-
*/
|
|
81
|
-
declare class ThreeAdapter {
|
|
82
|
-
/** The Three.js CanvasTexture wrapping the offscreen Vecto canvas. */
|
|
83
|
-
texture: THREE.CanvasTexture;
|
|
84
|
-
/** The active VectoJS Scene instance. */
|
|
85
|
-
vectoScene: Scene;
|
|
86
|
-
/** The offscreen HTMLCanvasElement on which Vecto draws. */
|
|
87
|
-
canvas: HTMLCanvasElement;
|
|
88
|
-
/** A pre-built THREE.Mesh with PlaneGeometry and this texture for immediate use. */
|
|
89
|
-
mesh: THREE.Mesh;
|
|
90
|
-
/** Track hover states independently per pointerId for WebXR / Multi-Touch. */
|
|
91
|
-
private activePointers;
|
|
92
|
-
constructor(options: ThreeAdapterOptions);
|
|
93
|
-
/**
|
|
94
|
-
* Processes 3D Raycasting intersections and forwards pointer/scroll events.
|
|
95
|
-
* Call this from window/document event listeners passing the raycaster.
|
|
96
|
-
*
|
|
97
|
-
* @param raycaster Three.js Raycaster instance.
|
|
98
|
-
* @param type Pointer event type: 'pointerdown' | 'pointerup' | 'pointermove' | 'wheel' | 'click'.
|
|
99
|
-
* @param originalEvent Optional original DOM Event to forward scroll deltas or button states.
|
|
100
|
-
* @returns true if the ray intersected the VectoJS mesh; false otherwise.
|
|
101
|
-
*/
|
|
102
|
-
updateIntersection(raycaster: THREE.Raycaster, type: 'pointerdown' | 'pointerup' | 'pointermove' | 'wheel' | 'click', originalEvent?: Event): boolean;
|
|
103
|
-
/**
|
|
104
|
-
* Dispatches pointer events mapped from UV coordinates [0, 1] to VectoJS entities.
|
|
105
|
-
*/
|
|
106
|
-
private dispatchAtUv;
|
|
107
|
-
/**
|
|
108
|
-
* Routes events to the associated A11y DOM element, or Vecto's own event dispatch system.
|
|
109
|
-
*/
|
|
110
|
-
private dispatchEventToTarget;
|
|
111
|
-
private createDOMEvent;
|
|
112
|
-
private findEntityById;
|
|
113
|
-
/**
|
|
114
|
-
* Resizes the offscreen canvas and VectoScene dimensions.
|
|
115
|
-
*/
|
|
116
|
-
resize(width: number, height: number): void;
|
|
117
|
-
/**
|
|
118
|
-
* Disposes of Three.js textures, geometries, and VectoJS scenes to prevent memory leaks.
|
|
119
|
-
*/
|
|
120
|
-
dispose(): void;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export { ThreeAdapter, type ThreeAdapterOptions, ThreeRenderer, WebGLGradient };
|