@vectojs/three 0.1.1 → 0.1.3
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/ThreeAdapter.d.ts +67 -0
- package/dist/ThreeRenderer.d.ts +67 -0
- package/dist/index.d.ts +2 -123
- package/dist/index.js +149 -54
- package/dist/index.mjs +149 -54
- package/package.json +2 -2
- package/dist/index.d.mts +0 -123
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { Scene as VectoScene, SceneOptions } from '@vectojs/core';
|
|
3
|
+
export interface ThreeAdapterOptions {
|
|
4
|
+
/** Physical layout width of the 2D UI canvas. */
|
|
5
|
+
width: number;
|
|
6
|
+
/** Physical layout height of the 2D UI canvas. */
|
|
7
|
+
height: number;
|
|
8
|
+
/** Optional pre-existing canvas element. If omitted, a new canvas is created. */
|
|
9
|
+
canvas?: HTMLCanvasElement;
|
|
10
|
+
/** Options passed to the VectoScene constructor. */
|
|
11
|
+
sceneOptions?: SceneOptions;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Adapts a VectoJS Scene into a Three.js CanvasTexture, allowing VectoJS
|
|
15
|
+
* components to be rendered in 3D space (e.g. on a plane, screen, or VR dashboard).
|
|
16
|
+
*/
|
|
17
|
+
export declare class ThreeAdapter {
|
|
18
|
+
/** The Three.js CanvasTexture wrapping the offscreen Vecto canvas. */
|
|
19
|
+
texture: THREE.CanvasTexture;
|
|
20
|
+
/** The active VectoJS Scene instance. */
|
|
21
|
+
vectoScene: VectoScene;
|
|
22
|
+
/** The offscreen HTMLCanvasElement on which Vecto draws. */
|
|
23
|
+
canvas: HTMLCanvasElement;
|
|
24
|
+
/** A pre-built THREE.Mesh with PlaneGeometry and this texture for immediate use. */
|
|
25
|
+
mesh: THREE.Mesh;
|
|
26
|
+
/** Track hover states independently per pointerId for WebXR / Multi-Touch. */
|
|
27
|
+
private activePointers;
|
|
28
|
+
/**
|
|
29
|
+
* Holds the original `vectoScene.render` reference so {@link dispose} can
|
|
30
|
+
* restore it. Without restoring, a later render call would write
|
|
31
|
+
* `needsUpdate` on a disposed (deleted) `CanvasTexture`, which Three.js
|
|
32
|
+
* flags with `"THREE.Texture: trying to use deleted texture"`.
|
|
33
|
+
*/
|
|
34
|
+
private _originalRender;
|
|
35
|
+
/** Tracks whether this adapter owns the canvas it is rendering to. */
|
|
36
|
+
private _ownsCanvas;
|
|
37
|
+
private _disposed;
|
|
38
|
+
constructor(options: ThreeAdapterOptions);
|
|
39
|
+
/**
|
|
40
|
+
* Processes 3D Raycasting intersections and forwards pointer/scroll events.
|
|
41
|
+
* Call this from window/document event listeners passing the raycaster.
|
|
42
|
+
*
|
|
43
|
+
* @param raycaster Three.js Raycaster instance.
|
|
44
|
+
* @param type Pointer event type: 'pointerdown' | 'pointerup' | 'pointermove' | 'wheel' | 'click'.
|
|
45
|
+
* @param originalEvent Optional original DOM Event to forward scroll deltas or button states.
|
|
46
|
+
* @returns true if the ray intersected the VectoJS mesh; false otherwise.
|
|
47
|
+
*/
|
|
48
|
+
updateIntersection(raycaster: THREE.Raycaster, type: 'pointerdown' | 'pointerup' | 'pointermove' | 'wheel' | 'click', originalEvent?: Event): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Dispatches pointer events mapped from UV coordinates [0, 1] to VectoJS entities.
|
|
51
|
+
*/
|
|
52
|
+
private dispatchAtUv;
|
|
53
|
+
/**
|
|
54
|
+
* Routes events to the associated A11y DOM element, or Vecto's own event dispatch system.
|
|
55
|
+
*/
|
|
56
|
+
private dispatchEventToTarget;
|
|
57
|
+
private createDOMEvent;
|
|
58
|
+
private findEntityById;
|
|
59
|
+
/**
|
|
60
|
+
* Resizes the offscreen canvas and VectoScene dimensions.
|
|
61
|
+
*/
|
|
62
|
+
resize(width: number, height: number): void;
|
|
63
|
+
/**
|
|
64
|
+
* Disposes of Three.js textures, geometries, and VectoJS scenes to prevent memory leaks.
|
|
65
|
+
*/
|
|
66
|
+
dispose(): void;
|
|
67
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { IRenderer } from '@vectojs/core';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
export declare class WebGLGradient {
|
|
4
|
+
x0: number;
|
|
5
|
+
y0: number;
|
|
6
|
+
x1: number;
|
|
7
|
+
y1: number;
|
|
8
|
+
colorStops: {
|
|
9
|
+
stop: number;
|
|
10
|
+
color: string;
|
|
11
|
+
}[];
|
|
12
|
+
type: string;
|
|
13
|
+
constructor(x0: number, y0: number, x1: number, y1: number, colorStops: {
|
|
14
|
+
stop: number;
|
|
15
|
+
color: string;
|
|
16
|
+
}[]);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* WebGL/Three.js implementation of {@link IRenderer}.
|
|
20
|
+
*
|
|
21
|
+
* Bridges VectoJS's 2D canvas API to Three.js for 3D hardware-accelerated rendering.
|
|
22
|
+
*/
|
|
23
|
+
export declare class ThreeRenderer implements IRenderer {
|
|
24
|
+
scene: THREE.Scene;
|
|
25
|
+
camera: THREE.OrthographicCamera;
|
|
26
|
+
renderer: THREE.WebGLRenderer;
|
|
27
|
+
private width;
|
|
28
|
+
private height;
|
|
29
|
+
private matrix;
|
|
30
|
+
private stack;
|
|
31
|
+
private globalAlpha;
|
|
32
|
+
private alphaStack;
|
|
33
|
+
private currentPath;
|
|
34
|
+
private activeObjects;
|
|
35
|
+
private scissorStack;
|
|
36
|
+
constructor(canvas: HTMLCanvasElement);
|
|
37
|
+
resize(width: number, height: number): void;
|
|
38
|
+
clear(): void;
|
|
39
|
+
private disposeActiveObjects;
|
|
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
|
+
private disposed;
|
|
66
|
+
dispose(): void;
|
|
67
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,123 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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 };
|
|
1
|
+
export * from './ThreeRenderer';
|
|
2
|
+
export * from './ThreeAdapter';
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,10 @@ module.exports = __toCommonJS(index_exports);
|
|
|
39
39
|
// src/ThreeRenderer.ts
|
|
40
40
|
var import_core = require("@vectojs/core");
|
|
41
41
|
var THREE = __toESM(require("three"));
|
|
42
|
+
function parseThreeColor(value) {
|
|
43
|
+
const [r, g, b, alpha] = (0, import_core.parseColorToRGBA)(value);
|
|
44
|
+
return { color: new THREE.Color(r, g, b), alpha };
|
|
45
|
+
}
|
|
42
46
|
var WebGLGradient = class {
|
|
43
47
|
constructor(x0, y0, x1, y1, colorStops) {
|
|
44
48
|
this.x0 = x0;
|
|
@@ -111,14 +115,16 @@ var ThreeRenderer = class {
|
|
|
111
115
|
activeObjects = [];
|
|
112
116
|
scissorStack = [];
|
|
113
117
|
constructor(canvas) {
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
const cw = canvas.width > 0 ? canvas.width : typeof window !== "undefined" ? window.innerWidth : 1024;
|
|
119
|
+
const ch = canvas.height > 0 ? canvas.height : typeof window !== "undefined" ? window.innerHeight : 1024;
|
|
120
|
+
this.width = cw;
|
|
121
|
+
this.height = ch;
|
|
116
122
|
this.scene = new THREE.Scene();
|
|
117
123
|
this.camera = new THREE.OrthographicCamera(0, this.width, 0, this.height, 0.1, 1e3);
|
|
118
124
|
this.camera.position.z = 1;
|
|
119
125
|
this.renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true });
|
|
120
126
|
this.renderer.setSize(this.width, this.height);
|
|
121
|
-
this.renderer.setPixelRatio(window.devicePixelRatio || 1);
|
|
127
|
+
this.renderer.setPixelRatio(typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1);
|
|
122
128
|
this.matrix = new THREE.Matrix4().identity();
|
|
123
129
|
}
|
|
124
130
|
resize(width, height) {
|
|
@@ -130,26 +136,42 @@ var ThreeRenderer = class {
|
|
|
130
136
|
this.camera.updateProjectionMatrix();
|
|
131
137
|
}
|
|
132
138
|
clear() {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
139
|
+
this.disposeActiveObjects();
|
|
140
|
+
this.currentPath = null;
|
|
141
|
+
this.matrix.identity();
|
|
142
|
+
this.stack.length = 0;
|
|
143
|
+
this.globalAlpha = 1;
|
|
144
|
+
this.alphaStack.length = 0;
|
|
145
|
+
this.scissorStack.length = 0;
|
|
146
|
+
this.renderer.clear();
|
|
147
|
+
this.renderer.setScissorTest(false);
|
|
148
|
+
}
|
|
149
|
+
disposeActiveObjects() {
|
|
150
|
+
const disposedGeometries = /* @__PURE__ */ new Set();
|
|
151
|
+
const disposedMaterials = /* @__PURE__ */ new Set();
|
|
152
|
+
const disposedTextures = /* @__PURE__ */ new Set();
|
|
153
|
+
for (const object of this.activeObjects) {
|
|
154
|
+
this.scene.remove(object);
|
|
155
|
+
if (!(object instanceof THREE.Mesh || object instanceof THREE.Line)) continue;
|
|
156
|
+
const geometry = object.geometry;
|
|
157
|
+
if (!disposedGeometries.has(geometry)) {
|
|
158
|
+
disposedGeometries.add(geometry);
|
|
159
|
+
geometry.dispose();
|
|
160
|
+
}
|
|
161
|
+
const materials = Array.isArray(object.material) ? object.material : [object.material];
|
|
162
|
+
for (const material of materials) {
|
|
163
|
+
const map = material.map;
|
|
164
|
+
if (map && !disposedTextures.has(map)) {
|
|
165
|
+
disposedTextures.add(map);
|
|
166
|
+
map.dispose();
|
|
167
|
+
}
|
|
168
|
+
if (!disposedMaterials.has(material)) {
|
|
169
|
+
disposedMaterials.add(material);
|
|
170
|
+
material.dispose();
|
|
147
171
|
}
|
|
148
172
|
}
|
|
149
173
|
}
|
|
150
|
-
this.activeObjects =
|
|
151
|
-
this.renderer.clear();
|
|
152
|
-
this.renderer.setScissorTest(false);
|
|
174
|
+
this.activeObjects.length = 0;
|
|
153
175
|
}
|
|
154
176
|
save() {
|
|
155
177
|
this.stack.push(this.matrix.clone());
|
|
@@ -186,16 +208,33 @@ var ThreeRenderer = class {
|
|
|
186
208
|
this.globalAlpha = alpha;
|
|
187
209
|
}
|
|
188
210
|
clip(x, y, width, height) {
|
|
189
|
-
const
|
|
190
|
-
|
|
211
|
+
const corners = [
|
|
212
|
+
new THREE.Vector3(x, y, 0),
|
|
213
|
+
new THREE.Vector3(x + width, y, 0),
|
|
214
|
+
new THREE.Vector3(x, y + height, 0),
|
|
215
|
+
new THREE.Vector3(x + width, y + height, 0)
|
|
216
|
+
].map((point) => point.applyMatrix4(this.matrix));
|
|
217
|
+
const minX = Math.min(...corners.map((point) => point.x));
|
|
218
|
+
const minY = Math.min(...corners.map((point) => point.y));
|
|
219
|
+
const maxX = Math.max(...corners.map((point) => point.x));
|
|
220
|
+
const maxY = Math.max(...corners.map((point) => point.y));
|
|
191
221
|
const dpr = window.devicePixelRatio || 1;
|
|
192
222
|
const canvasHeight = this.renderer.domElement.height / dpr;
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
223
|
+
let scissorX = minX * dpr;
|
|
224
|
+
let scissorY = (canvasHeight - maxY) * dpr;
|
|
225
|
+
let scissorWidth = (maxX - minX) * dpr;
|
|
226
|
+
let scissorHeight = (maxY - minY) * dpr;
|
|
227
|
+
if (this.renderer.getScissorTest()) {
|
|
228
|
+
const current = new THREE.Vector4();
|
|
229
|
+
this.renderer.getScissor(current);
|
|
230
|
+
const right = Math.min(scissorX + scissorWidth, current.x + current.z);
|
|
231
|
+
const top = Math.min(scissorY + scissorHeight, current.y + current.w);
|
|
232
|
+
scissorX = Math.max(scissorX, current.x);
|
|
233
|
+
scissorY = Math.max(scissorY, current.y);
|
|
234
|
+
scissorWidth = Math.max(0, right - scissorX);
|
|
235
|
+
scissorHeight = Math.max(0, top - scissorY);
|
|
236
|
+
}
|
|
237
|
+
this.renderer.setScissor(scissorX, scissorY, scissorWidth, scissorHeight);
|
|
199
238
|
this.renderer.setScissorTest(true);
|
|
200
239
|
}
|
|
201
240
|
beginPath() {
|
|
@@ -414,13 +453,15 @@ var ThreeRenderer = class {
|
|
|
414
453
|
fillSolidShape(colorOrGradient) {
|
|
415
454
|
if (!this.currentPath) return;
|
|
416
455
|
const color = typeof colorOrGradient === "string" ? colorOrGradient : "#ffffff";
|
|
456
|
+
const parsed = parseThreeColor(color);
|
|
417
457
|
const shapes = this.currentPath.toShapes();
|
|
418
458
|
for (const shape of shapes) {
|
|
419
459
|
const geometry = new THREE.ShapeGeometry(shape);
|
|
460
|
+
const opacity = this.globalAlpha * parsed.alpha;
|
|
420
461
|
const material = new THREE.MeshBasicMaterial({
|
|
421
|
-
color:
|
|
422
|
-
transparent:
|
|
423
|
-
opacity
|
|
462
|
+
color: parsed.color,
|
|
463
|
+
transparent: opacity < 1,
|
|
464
|
+
opacity,
|
|
424
465
|
depthWrite: false
|
|
425
466
|
});
|
|
426
467
|
const mesh = new THREE.Mesh(geometry, material);
|
|
@@ -443,10 +484,12 @@ var ThreeRenderer = class {
|
|
|
443
484
|
const points = this.currentPath.getPoints();
|
|
444
485
|
if (points.length === 0) return;
|
|
445
486
|
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
|
487
|
+
const parsed = parseThreeColor(color);
|
|
488
|
+
const opacity = this.globalAlpha * parsed.alpha;
|
|
446
489
|
const material = new THREE.LineBasicMaterial({
|
|
447
|
-
color:
|
|
448
|
-
transparent:
|
|
449
|
-
opacity
|
|
490
|
+
color: parsed.color,
|
|
491
|
+
transparent: opacity < 1,
|
|
492
|
+
opacity,
|
|
450
493
|
linewidth: lineWidth
|
|
451
494
|
});
|
|
452
495
|
const line = new THREE.Line(geometry, material);
|
|
@@ -494,10 +537,12 @@ var ThreeRenderer = class {
|
|
|
494
537
|
}
|
|
495
538
|
fillCircle(cx, cy, radius, color, alpha = 1) {
|
|
496
539
|
const geometry = new THREE.CircleGeometry(radius, 32);
|
|
540
|
+
const parsed = parseThreeColor(color);
|
|
541
|
+
const opacity = this.globalAlpha * alpha * parsed.alpha;
|
|
497
542
|
const material = new THREE.MeshBasicMaterial({
|
|
498
|
-
color:
|
|
499
|
-
transparent:
|
|
500
|
-
opacity
|
|
543
|
+
color: parsed.color,
|
|
544
|
+
transparent: opacity < 1,
|
|
545
|
+
opacity,
|
|
501
546
|
depthWrite: false
|
|
502
547
|
});
|
|
503
548
|
const mesh = new THREE.Mesh(geometry, material);
|
|
@@ -512,6 +557,18 @@ var ThreeRenderer = class {
|
|
|
512
557
|
createLinearGradient(x0, y0, x1, y1, colorStops) {
|
|
513
558
|
return new WebGLGradient(x0, y0, x1, y1, colorStops);
|
|
514
559
|
}
|
|
560
|
+
disposed = false;
|
|
561
|
+
dispose() {
|
|
562
|
+
if (this.disposed) return;
|
|
563
|
+
this.disposed = true;
|
|
564
|
+
this.disposeActiveObjects();
|
|
565
|
+
this.currentPath = null;
|
|
566
|
+
this.stack.length = 0;
|
|
567
|
+
this.alphaStack.length = 0;
|
|
568
|
+
this.scissorStack.length = 0;
|
|
569
|
+
this.renderer.setScissorTest(false);
|
|
570
|
+
this.renderer.dispose();
|
|
571
|
+
}
|
|
515
572
|
};
|
|
516
573
|
|
|
517
574
|
// src/ThreeAdapter.ts
|
|
@@ -528,8 +585,20 @@ var ThreeAdapter = class {
|
|
|
528
585
|
mesh;
|
|
529
586
|
/** Track hover states independently per pointerId for WebXR / Multi-Touch. */
|
|
530
587
|
activePointers = /* @__PURE__ */ new Map();
|
|
588
|
+
/**
|
|
589
|
+
* Holds the original `vectoScene.render` reference so {@link dispose} can
|
|
590
|
+
* restore it. Without restoring, a later render call would write
|
|
591
|
+
* `needsUpdate` on a disposed (deleted) `CanvasTexture`, which Three.js
|
|
592
|
+
* flags with `"THREE.Texture: trying to use deleted texture"`.
|
|
593
|
+
*/
|
|
594
|
+
_originalRender = null;
|
|
595
|
+
/** Tracks whether this adapter owns the canvas it is rendering to. */
|
|
596
|
+
_ownsCanvas;
|
|
597
|
+
_disposed = false;
|
|
531
598
|
constructor(options) {
|
|
532
|
-
|
|
599
|
+
const optCanvas = options.canvas;
|
|
600
|
+
this._ownsCanvas = !optCanvas;
|
|
601
|
+
this.canvas = optCanvas || (typeof document !== "undefined" ? document.createElement("canvas") : { width: options.width, height: options.height });
|
|
533
602
|
this.canvas.width = options.width;
|
|
534
603
|
this.canvas.height = options.height;
|
|
535
604
|
const sceneOptions = {
|
|
@@ -541,7 +610,8 @@ var ThreeAdapter = class {
|
|
|
541
610
|
this.texture = new THREE2.CanvasTexture(this.canvas);
|
|
542
611
|
this.texture.minFilter = THREE2.LinearFilter;
|
|
543
612
|
this.texture.magFilter = THREE2.LinearFilter;
|
|
544
|
-
|
|
613
|
+
this._originalRender = this.vectoScene.render;
|
|
614
|
+
const originalRender = this._originalRender;
|
|
545
615
|
this.vectoScene.render = (renderer, dt, time) => {
|
|
546
616
|
originalRender.call(this.vectoScene, renderer, dt, time);
|
|
547
617
|
this.texture.needsUpdate = true;
|
|
@@ -590,8 +660,8 @@ var ThreeAdapter = class {
|
|
|
590
660
|
* Dispatches pointer events mapped from UV coordinates [0, 1] to VectoJS entities.
|
|
591
661
|
*/
|
|
592
662
|
dispatchAtUv(type, uv, pointerId, originalEvent) {
|
|
593
|
-
const px = uv.x * this.
|
|
594
|
-
const py = (1 - uv.y) * this.
|
|
663
|
+
const px = uv.x * this.vectoScene.width;
|
|
664
|
+
const py = (1 - uv.y) * this.vectoScene.height;
|
|
595
665
|
this.vectoScene.markDirty();
|
|
596
666
|
const hitEntity = this.vectoScene.findEntityAt(px, py);
|
|
597
667
|
const state = this.activePointers.get(pointerId);
|
|
@@ -637,34 +707,51 @@ var ThreeAdapter = class {
|
|
|
637
707
|
a11yEl.focus();
|
|
638
708
|
}
|
|
639
709
|
} else {
|
|
640
|
-
const
|
|
641
|
-
|
|
710
|
+
const vectoEvent = new import_core2.VectoJSEvent(type, entity, originalEvent, type !== "pointerleave", {
|
|
711
|
+
x,
|
|
712
|
+
y
|
|
713
|
+
});
|
|
642
714
|
entity.dispatchEvent(vectoEvent);
|
|
643
715
|
}
|
|
644
716
|
}
|
|
645
717
|
createDOMEvent(type, x, y, pointerId, originalEvent) {
|
|
718
|
+
let event;
|
|
646
719
|
if (type === "wheel") {
|
|
647
720
|
const wheelE = originalEvent instanceof WheelEvent ? originalEvent : void 0;
|
|
648
|
-
|
|
721
|
+
event = new WheelEvent("wheel", {
|
|
649
722
|
clientX: x,
|
|
650
723
|
clientY: y,
|
|
651
724
|
deltaX: wheelE ? wheelE.deltaX : 0,
|
|
652
725
|
deltaY: wheelE ? wheelE.deltaY : 0,
|
|
653
726
|
deltaZ: wheelE ? wheelE.deltaZ : 0,
|
|
654
727
|
deltaMode: wheelE ? wheelE.deltaMode : 0,
|
|
728
|
+
shiftKey: wheelE ? wheelE.shiftKey : false,
|
|
729
|
+
ctrlKey: wheelE ? wheelE.ctrlKey : false,
|
|
730
|
+
altKey: wheelE ? wheelE.altKey : false,
|
|
731
|
+
metaKey: wheelE ? wheelE.metaKey : false,
|
|
732
|
+
bubbles: true,
|
|
733
|
+
cancelable: true
|
|
734
|
+
});
|
|
735
|
+
} else {
|
|
736
|
+
event = new PointerEvent(type, {
|
|
737
|
+
clientX: x,
|
|
738
|
+
clientY: y,
|
|
739
|
+
button: originalEvent instanceof MouseEvent ? originalEvent.button : 0,
|
|
740
|
+
buttons: originalEvent instanceof MouseEvent ? originalEvent.buttons : 0,
|
|
741
|
+
pointerId,
|
|
742
|
+
shiftKey: originalEvent instanceof MouseEvent ? originalEvent.shiftKey : false,
|
|
743
|
+
ctrlKey: originalEvent instanceof MouseEvent ? originalEvent.ctrlKey : false,
|
|
744
|
+
altKey: originalEvent instanceof MouseEvent ? originalEvent.altKey : false,
|
|
745
|
+
metaKey: originalEvent instanceof MouseEvent ? originalEvent.metaKey : false,
|
|
655
746
|
bubbles: true,
|
|
656
747
|
cancelable: true
|
|
657
748
|
});
|
|
658
749
|
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
button: originalEvent instanceof MouseEvent ? originalEvent.button : 0,
|
|
663
|
-
buttons: originalEvent instanceof MouseEvent ? originalEvent.buttons : 0,
|
|
664
|
-
pointerId,
|
|
665
|
-
bubbles: true,
|
|
666
|
-
cancelable: true
|
|
750
|
+
Object.defineProperties(event, {
|
|
751
|
+
vectoSceneX: { value: x },
|
|
752
|
+
vectoSceneY: { value: y }
|
|
667
753
|
});
|
|
754
|
+
return event;
|
|
668
755
|
}
|
|
669
756
|
findEntityById(root, id) {
|
|
670
757
|
if (root.id === id) return root;
|
|
@@ -687,6 +774,12 @@ var ThreeAdapter = class {
|
|
|
687
774
|
* Disposes of Three.js textures, geometries, and VectoJS scenes to prevent memory leaks.
|
|
688
775
|
*/
|
|
689
776
|
dispose() {
|
|
777
|
+
if (this._disposed) return;
|
|
778
|
+
this._disposed = true;
|
|
779
|
+
if (this._originalRender) {
|
|
780
|
+
this.vectoScene.render = this._originalRender;
|
|
781
|
+
this._originalRender = null;
|
|
782
|
+
}
|
|
690
783
|
this.texture.dispose();
|
|
691
784
|
this.mesh.geometry.dispose();
|
|
692
785
|
if (Array.isArray(this.mesh.material)) {
|
|
@@ -699,8 +792,10 @@ var ThreeAdapter = class {
|
|
|
699
792
|
}
|
|
700
793
|
this.vectoScene.destroy();
|
|
701
794
|
this.activePointers.clear();
|
|
702
|
-
this.
|
|
703
|
-
|
|
795
|
+
if (this._ownsCanvas) {
|
|
796
|
+
this.canvas.width = 0;
|
|
797
|
+
this.canvas.height = 0;
|
|
798
|
+
}
|
|
704
799
|
}
|
|
705
800
|
};
|
|
706
801
|
// Annotate the CommonJS export names for ESM import in node:
|
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 && !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
|
-
|
|
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));
|
|
153
183
|
const dpr = window.devicePixelRatio || 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);
|
|
@@ -405,10 +446,12 @@ var ThreeRenderer = class {
|
|
|
405
446
|
const points = this.currentPath.getPoints();
|
|
406
447
|
if (points.length === 0) return;
|
|
407
448
|
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
|
449
|
+
const parsed = parseThreeColor(color);
|
|
450
|
+
const opacity = this.globalAlpha * parsed.alpha;
|
|
408
451
|
const material = new THREE.LineBasicMaterial({
|
|
409
|
-
color:
|
|
410
|
-
transparent:
|
|
411
|
-
opacity
|
|
452
|
+
color: parsed.color,
|
|
453
|
+
transparent: opacity < 1,
|
|
454
|
+
opacity,
|
|
412
455
|
linewidth: lineWidth
|
|
413
456
|
});
|
|
414
457
|
const line = new THREE.Line(geometry, material);
|
|
@@ -456,10 +499,12 @@ var ThreeRenderer = class {
|
|
|
456
499
|
}
|
|
457
500
|
fillCircle(cx, cy, radius, color, alpha = 1) {
|
|
458
501
|
const geometry = new THREE.CircleGeometry(radius, 32);
|
|
502
|
+
const parsed = parseThreeColor(color);
|
|
503
|
+
const opacity = this.globalAlpha * alpha * parsed.alpha;
|
|
459
504
|
const material = new THREE.MeshBasicMaterial({
|
|
460
|
-
color:
|
|
461
|
-
transparent:
|
|
462
|
-
opacity
|
|
505
|
+
color: parsed.color,
|
|
506
|
+
transparent: opacity < 1,
|
|
507
|
+
opacity,
|
|
463
508
|
depthWrite: false
|
|
464
509
|
});
|
|
465
510
|
const mesh = new THREE.Mesh(geometry, material);
|
|
@@ -474,6 +519,18 @@ var ThreeRenderer = class {
|
|
|
474
519
|
createLinearGradient(x0, y0, x1, y1, colorStops) {
|
|
475
520
|
return new WebGLGradient(x0, y0, x1, y1, colorStops);
|
|
476
521
|
}
|
|
522
|
+
disposed = false;
|
|
523
|
+
dispose() {
|
|
524
|
+
if (this.disposed) return;
|
|
525
|
+
this.disposed = true;
|
|
526
|
+
this.disposeActiveObjects();
|
|
527
|
+
this.currentPath = null;
|
|
528
|
+
this.stack.length = 0;
|
|
529
|
+
this.alphaStack.length = 0;
|
|
530
|
+
this.scissorStack.length = 0;
|
|
531
|
+
this.renderer.setScissorTest(false);
|
|
532
|
+
this.renderer.dispose();
|
|
533
|
+
}
|
|
477
534
|
};
|
|
478
535
|
|
|
479
536
|
// src/ThreeAdapter.ts
|
|
@@ -490,8 +547,20 @@ var ThreeAdapter = class {
|
|
|
490
547
|
mesh;
|
|
491
548
|
/** Track hover states independently per pointerId for WebXR / Multi-Touch. */
|
|
492
549
|
activePointers = /* @__PURE__ */ new Map();
|
|
550
|
+
/**
|
|
551
|
+
* Holds the original `vectoScene.render` reference so {@link dispose} can
|
|
552
|
+
* restore it. Without restoring, a later render call would write
|
|
553
|
+
* `needsUpdate` on a disposed (deleted) `CanvasTexture`, which Three.js
|
|
554
|
+
* flags with `"THREE.Texture: trying to use deleted texture"`.
|
|
555
|
+
*/
|
|
556
|
+
_originalRender = null;
|
|
557
|
+
/** Tracks whether this adapter owns the canvas it is rendering to. */
|
|
558
|
+
_ownsCanvas;
|
|
559
|
+
_disposed = false;
|
|
493
560
|
constructor(options) {
|
|
494
|
-
|
|
561
|
+
const optCanvas = options.canvas;
|
|
562
|
+
this._ownsCanvas = !optCanvas;
|
|
563
|
+
this.canvas = optCanvas || (typeof document !== "undefined" ? document.createElement("canvas") : { width: options.width, height: options.height });
|
|
495
564
|
this.canvas.width = options.width;
|
|
496
565
|
this.canvas.height = options.height;
|
|
497
566
|
const sceneOptions = {
|
|
@@ -503,7 +572,8 @@ var ThreeAdapter = class {
|
|
|
503
572
|
this.texture = new THREE2.CanvasTexture(this.canvas);
|
|
504
573
|
this.texture.minFilter = THREE2.LinearFilter;
|
|
505
574
|
this.texture.magFilter = THREE2.LinearFilter;
|
|
506
|
-
|
|
575
|
+
this._originalRender = this.vectoScene.render;
|
|
576
|
+
const originalRender = this._originalRender;
|
|
507
577
|
this.vectoScene.render = (renderer, dt, time) => {
|
|
508
578
|
originalRender.call(this.vectoScene, renderer, dt, time);
|
|
509
579
|
this.texture.needsUpdate = true;
|
|
@@ -552,8 +622,8 @@ var ThreeAdapter = class {
|
|
|
552
622
|
* Dispatches pointer events mapped from UV coordinates [0, 1] to VectoJS entities.
|
|
553
623
|
*/
|
|
554
624
|
dispatchAtUv(type, uv, pointerId, originalEvent) {
|
|
555
|
-
const px = uv.x * this.
|
|
556
|
-
const py = (1 - uv.y) * this.
|
|
625
|
+
const px = uv.x * this.vectoScene.width;
|
|
626
|
+
const py = (1 - uv.y) * this.vectoScene.height;
|
|
557
627
|
this.vectoScene.markDirty();
|
|
558
628
|
const hitEntity = this.vectoScene.findEntityAt(px, py);
|
|
559
629
|
const state = this.activePointers.get(pointerId);
|
|
@@ -599,34 +669,51 @@ var ThreeAdapter = class {
|
|
|
599
669
|
a11yEl.focus();
|
|
600
670
|
}
|
|
601
671
|
} else {
|
|
602
|
-
const
|
|
603
|
-
|
|
672
|
+
const vectoEvent = new VectoJSEvent(type, entity, originalEvent, type !== "pointerleave", {
|
|
673
|
+
x,
|
|
674
|
+
y
|
|
675
|
+
});
|
|
604
676
|
entity.dispatchEvent(vectoEvent);
|
|
605
677
|
}
|
|
606
678
|
}
|
|
607
679
|
createDOMEvent(type, x, y, pointerId, originalEvent) {
|
|
680
|
+
let event;
|
|
608
681
|
if (type === "wheel") {
|
|
609
682
|
const wheelE = originalEvent instanceof WheelEvent ? originalEvent : void 0;
|
|
610
|
-
|
|
683
|
+
event = new WheelEvent("wheel", {
|
|
611
684
|
clientX: x,
|
|
612
685
|
clientY: y,
|
|
613
686
|
deltaX: wheelE ? wheelE.deltaX : 0,
|
|
614
687
|
deltaY: wheelE ? wheelE.deltaY : 0,
|
|
615
688
|
deltaZ: wheelE ? wheelE.deltaZ : 0,
|
|
616
689
|
deltaMode: wheelE ? wheelE.deltaMode : 0,
|
|
690
|
+
shiftKey: wheelE ? wheelE.shiftKey : false,
|
|
691
|
+
ctrlKey: wheelE ? wheelE.ctrlKey : false,
|
|
692
|
+
altKey: wheelE ? wheelE.altKey : false,
|
|
693
|
+
metaKey: wheelE ? wheelE.metaKey : false,
|
|
694
|
+
bubbles: true,
|
|
695
|
+
cancelable: true
|
|
696
|
+
});
|
|
697
|
+
} else {
|
|
698
|
+
event = new PointerEvent(type, {
|
|
699
|
+
clientX: x,
|
|
700
|
+
clientY: y,
|
|
701
|
+
button: originalEvent instanceof MouseEvent ? originalEvent.button : 0,
|
|
702
|
+
buttons: originalEvent instanceof MouseEvent ? originalEvent.buttons : 0,
|
|
703
|
+
pointerId,
|
|
704
|
+
shiftKey: originalEvent instanceof MouseEvent ? originalEvent.shiftKey : false,
|
|
705
|
+
ctrlKey: originalEvent instanceof MouseEvent ? originalEvent.ctrlKey : false,
|
|
706
|
+
altKey: originalEvent instanceof MouseEvent ? originalEvent.altKey : false,
|
|
707
|
+
metaKey: originalEvent instanceof MouseEvent ? originalEvent.metaKey : false,
|
|
617
708
|
bubbles: true,
|
|
618
709
|
cancelable: true
|
|
619
710
|
});
|
|
620
711
|
}
|
|
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
|
|
712
|
+
Object.defineProperties(event, {
|
|
713
|
+
vectoSceneX: { value: x },
|
|
714
|
+
vectoSceneY: { value: y }
|
|
629
715
|
});
|
|
716
|
+
return event;
|
|
630
717
|
}
|
|
631
718
|
findEntityById(root, id) {
|
|
632
719
|
if (root.id === id) return root;
|
|
@@ -649,6 +736,12 @@ var ThreeAdapter = class {
|
|
|
649
736
|
* Disposes of Three.js textures, geometries, and VectoJS scenes to prevent memory leaks.
|
|
650
737
|
*/
|
|
651
738
|
dispose() {
|
|
739
|
+
if (this._disposed) return;
|
|
740
|
+
this._disposed = true;
|
|
741
|
+
if (this._originalRender) {
|
|
742
|
+
this.vectoScene.render = this._originalRender;
|
|
743
|
+
this._originalRender = null;
|
|
744
|
+
}
|
|
652
745
|
this.texture.dispose();
|
|
653
746
|
this.mesh.geometry.dispose();
|
|
654
747
|
if (Array.isArray(this.mesh.material)) {
|
|
@@ -661,8 +754,10 @@ var ThreeAdapter = class {
|
|
|
661
754
|
}
|
|
662
755
|
this.vectoScene.destroy();
|
|
663
756
|
this.activePointers.clear();
|
|
664
|
-
this.
|
|
665
|
-
|
|
757
|
+
if (this._ownsCanvas) {
|
|
758
|
+
this.canvas.width = 0;
|
|
759
|
+
this.canvas.height = 0;
|
|
760
|
+
}
|
|
666
761
|
}
|
|
667
762
|
};
|
|
668
763
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vectojs/three",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
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 };
|