@tonybfox/threejs-tools 1.0.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/README.md +321 -0
- package/dist/asset-loader/index.cjs +376 -0
- package/dist/asset-loader/index.cjs.map +1 -0
- package/dist/asset-loader/index.d.mts +101 -0
- package/dist/asset-loader/index.d.ts +101 -0
- package/dist/asset-loader/index.mjs +7 -0
- package/dist/asset-loader/index.mjs.map +1 -0
- package/dist/camera/index.cjs +313 -0
- package/dist/camera/index.cjs.map +1 -0
- package/dist/camera/index.d.mts +82 -0
- package/dist/camera/index.d.ts +82 -0
- package/dist/camera/index.mjs +7 -0
- package/dist/camera/index.mjs.map +1 -0
- package/dist/chunk-5DP6WDB3.mjs +1161 -0
- package/dist/chunk-5DP6WDB3.mjs.map +1 -0
- package/dist/chunk-BJKSICFA.mjs +1579 -0
- package/dist/chunk-BJKSICFA.mjs.map +1 -0
- package/dist/chunk-BYRZCHE7.mjs +277 -0
- package/dist/chunk-BYRZCHE7.mjs.map +1 -0
- package/dist/chunk-EIROAPF7.mjs +387 -0
- package/dist/chunk-EIROAPF7.mjs.map +1 -0
- package/dist/chunk-EQDOX34V.mjs +164 -0
- package/dist/chunk-EQDOX34V.mjs.map +1 -0
- package/dist/chunk-IIAZ2WJJ.mjs +405 -0
- package/dist/chunk-IIAZ2WJJ.mjs.map +1 -0
- package/dist/chunk-L4VIIJZD.mjs +340 -0
- package/dist/chunk-L4VIIJZD.mjs.map +1 -0
- package/dist/chunk-P35QJCOG.mjs +339 -0
- package/dist/chunk-P35QJCOG.mjs.map +1 -0
- package/dist/chunk-R64RVBRM.mjs +394 -0
- package/dist/chunk-R64RVBRM.mjs.map +1 -0
- package/dist/compass/index.cjs +375 -0
- package/dist/compass/index.cjs.map +1 -0
- package/dist/compass/index.d.mts +58 -0
- package/dist/compass/index.d.ts +58 -0
- package/dist/compass/index.mjs +7 -0
- package/dist/compass/index.mjs.map +1 -0
- package/dist/grid/index.cjs +200 -0
- package/dist/grid/index.cjs.map +1 -0
- package/dist/grid/index.d.mts +43 -0
- package/dist/grid/index.d.ts +43 -0
- package/dist/grid/index.mjs +7 -0
- package/dist/grid/index.mjs.map +1 -0
- package/dist/index.cjs +5049 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.mjs +47 -0
- package/dist/index.mjs.map +1 -0
- package/dist/measurements/index.cjs +1198 -0
- package/dist/measurements/index.cjs.map +1 -0
- package/dist/measurements/index.d.mts +449 -0
- package/dist/measurements/index.d.ts +449 -0
- package/dist/measurements/index.mjs +9 -0
- package/dist/measurements/index.mjs.map +1 -0
- package/dist/sunlight/index.cjs +441 -0
- package/dist/sunlight/index.cjs.map +1 -0
- package/dist/sunlight/index.d.mts +92 -0
- package/dist/sunlight/index.d.ts +92 -0
- package/dist/sunlight/index.mjs +7 -0
- package/dist/sunlight/index.mjs.map +1 -0
- package/dist/terrain/index.cjs +423 -0
- package/dist/terrain/index.cjs.map +1 -0
- package/dist/terrain/index.d.mts +219 -0
- package/dist/terrain/index.d.ts +219 -0
- package/dist/terrain/index.mjs +7 -0
- package/dist/terrain/index.mjs.map +1 -0
- package/dist/transform-controls/index.cjs +1587 -0
- package/dist/transform-controls/index.cjs.map +1 -0
- package/dist/transform-controls/index.d.mts +162 -0
- package/dist/transform-controls/index.d.ts +162 -0
- package/dist/transform-controls/index.mjs +13 -0
- package/dist/transform-controls/index.mjs.map +1 -0
- package/dist/view-helper/index.cjs +430 -0
- package/dist/view-helper/index.cjs.map +1 -0
- package/dist/view-helper/index.d.mts +75 -0
- package/dist/view-helper/index.d.ts +75 -0
- package/dist/view-helper/index.mjs +7 -0
- package/dist/view-helper/index.mjs.map +1 -0
- package/package.json +124 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// packages/compass/src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
CompassOverlay: () => CompassOverlay
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(src_exports);
|
|
36
|
+
|
|
37
|
+
// packages/compass/src/CompassOverlay.ts
|
|
38
|
+
var THREE = __toESM(require("three"));
|
|
39
|
+
var CompassOverlay = class extends THREE.EventDispatcher {
|
|
40
|
+
constructor(camera, options = {}) {
|
|
41
|
+
super();
|
|
42
|
+
this.isActive = false;
|
|
43
|
+
this.currentRotation = 0;
|
|
44
|
+
this.camera = camera;
|
|
45
|
+
this.options = {
|
|
46
|
+
container: options.container || document.body,
|
|
47
|
+
size: options.size || 100,
|
|
48
|
+
position: options.position || "bottom-right",
|
|
49
|
+
offset: options.offset || { x: 20, y: 20 },
|
|
50
|
+
colors: {
|
|
51
|
+
background: options.colors?.background || "#1a1a1a",
|
|
52
|
+
border: options.colors?.border || "#333333",
|
|
53
|
+
arrow: options.colors?.arrow || "#ff4444",
|
|
54
|
+
text: options.colors?.text || "#ffffff",
|
|
55
|
+
ticks: options.colors?.ticks || "#666666",
|
|
56
|
+
...options.colors
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
this.container = this.options.container;
|
|
60
|
+
this.createCompassElement();
|
|
61
|
+
this.setupStyles();
|
|
62
|
+
}
|
|
63
|
+
createCompassElement() {
|
|
64
|
+
this.compassElement = document.createElement("div");
|
|
65
|
+
this.compassElement.className = "threejs-compass-overlay";
|
|
66
|
+
const compassBg = document.createElement("div");
|
|
67
|
+
compassBg.className = "compass-background";
|
|
68
|
+
const directions = [
|
|
69
|
+
{ label: "N", angle: 0 },
|
|
70
|
+
{ label: "E", angle: 90 },
|
|
71
|
+
{ label: "S", angle: 180 },
|
|
72
|
+
{ label: "W", angle: 270 }
|
|
73
|
+
];
|
|
74
|
+
for (let i = 0; i < 360; i += 11.25) {
|
|
75
|
+
const tick = document.createElement("div");
|
|
76
|
+
tick.className = i % 45 === 0 ? "compass-tick-major" : "compass-tick-minor";
|
|
77
|
+
const tickLength = i % 30 === 0 ? 8 : 4;
|
|
78
|
+
tick.style.transform = `rotate(${i}deg) translateY(-${this.options.size / 2 - tickLength - 2}px)`;
|
|
79
|
+
compassBg.appendChild(tick);
|
|
80
|
+
}
|
|
81
|
+
directions.forEach(({ label, angle }) => {
|
|
82
|
+
const dirLabel = document.createElement("div");
|
|
83
|
+
dirLabel.className = "compass-label";
|
|
84
|
+
dirLabel.textContent = label;
|
|
85
|
+
dirLabel.style.transform = `rotate(${angle}deg) translateY(-${this.options.size / 2 - 15}px) rotate(-${angle}deg)`;
|
|
86
|
+
compassBg.appendChild(dirLabel);
|
|
87
|
+
});
|
|
88
|
+
this.arrowElement = document.createElement("div");
|
|
89
|
+
this.arrowElement.className = "compass-arrow";
|
|
90
|
+
this.arrowElement.innerHTML = `
|
|
91
|
+
<svg width="20" height="20" viewBox="0 0 20 20">
|
|
92
|
+
<polygon points="10,2 14,12 10,10 6,12" fill="${this.options.colors.arrow}" stroke="#000" stroke-width="0.5"/>
|
|
93
|
+
</svg>
|
|
94
|
+
`;
|
|
95
|
+
this.compassElement.appendChild(compassBg);
|
|
96
|
+
this.compassElement.appendChild(this.arrowElement);
|
|
97
|
+
this.container.appendChild(this.compassElement);
|
|
98
|
+
this.setupDoubleClickHandler();
|
|
99
|
+
}
|
|
100
|
+
setupStyles() {
|
|
101
|
+
if (document.getElementById("threejs-compass-styles")) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const style = document.createElement("style");
|
|
105
|
+
style.id = "threejs-compass-styles";
|
|
106
|
+
style.textContent = `
|
|
107
|
+
.threejs-compass-overlay {
|
|
108
|
+
position: fixed;
|
|
109
|
+
width: ${this.options.size}px;
|
|
110
|
+
height: ${this.options.size}px;
|
|
111
|
+
background: ${this.options.colors.background};
|
|
112
|
+
border: 2px solid ${this.options.colors.border};
|
|
113
|
+
border-radius: 50%;
|
|
114
|
+
z-index: 1000;
|
|
115
|
+
pointer-events: none;
|
|
116
|
+
user-select: none;
|
|
117
|
+
transition: opacity 0.2s ease;
|
|
118
|
+
${this.getPositionStyles()};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.compass-background {
|
|
122
|
+
position: relative;
|
|
123
|
+
width: 100%;
|
|
124
|
+
height: 100%;
|
|
125
|
+
border-radius: 50%;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.compass-label {
|
|
129
|
+
position: absolute;
|
|
130
|
+
top: 50%;
|
|
131
|
+
left: 50%;
|
|
132
|
+
transform-origin: center;
|
|
133
|
+
color: ${this.options.colors.text};
|
|
134
|
+
font-family: Arial, sans-serif;
|
|
135
|
+
font-size: 12px;
|
|
136
|
+
font-weight: bold;
|
|
137
|
+
text-align: center;
|
|
138
|
+
width: 12px;
|
|
139
|
+
height: 12px;
|
|
140
|
+
line-height: 12px;
|
|
141
|
+
margin-left: -6px;
|
|
142
|
+
margin-top: -6px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.compass-tick-major {
|
|
146
|
+
position: absolute;
|
|
147
|
+
top: 50%;
|
|
148
|
+
left: 50%;
|
|
149
|
+
width: 2px;
|
|
150
|
+
height: 8px;
|
|
151
|
+
background: ${this.options.colors.ticks};
|
|
152
|
+
transform-origin: center top;
|
|
153
|
+
margin-left: -1px;
|
|
154
|
+
margin-top: -4px;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.compass-tick-minor {
|
|
158
|
+
position: absolute;
|
|
159
|
+
top: 50%;
|
|
160
|
+
left: 50%;
|
|
161
|
+
width: 1px;
|
|
162
|
+
height: 4px;
|
|
163
|
+
background: ${this.options.colors.ticks};
|
|
164
|
+
transform-origin: center top;
|
|
165
|
+
margin-left: -0.5px;
|
|
166
|
+
margin-top: -2px;
|
|
167
|
+
opacity: 0.6;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.compass-arrow {
|
|
171
|
+
position: absolute;
|
|
172
|
+
top: 50%;
|
|
173
|
+
left: 50%;
|
|
174
|
+
transform: translate(-50%, -50%);
|
|
175
|
+
transform-origin: center;
|
|
176
|
+
transition: transform 0.1s ease-out;
|
|
177
|
+
z-index: 1;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.compass-arrow svg {
|
|
181
|
+
display: block;
|
|
182
|
+
filter: drop-shadow(0 0 2px rgba(0,0,0,0.5));
|
|
183
|
+
}
|
|
184
|
+
`;
|
|
185
|
+
document.head.appendChild(style);
|
|
186
|
+
}
|
|
187
|
+
setupDoubleClickHandler() {
|
|
188
|
+
this.compassElement.style.pointerEvents = "auto";
|
|
189
|
+
this.compassElement.style.cursor = "pointer";
|
|
190
|
+
this.compassElement.addEventListener("dblclick", (event) => {
|
|
191
|
+
event.preventDefault();
|
|
192
|
+
event.stopPropagation();
|
|
193
|
+
this.dispatchEvent({ type: "resetToNorth" });
|
|
194
|
+
});
|
|
195
|
+
this.compassElement.addEventListener("mouseenter", () => {
|
|
196
|
+
this.compassElement.style.opacity = "0.8";
|
|
197
|
+
});
|
|
198
|
+
this.compassElement.addEventListener("mouseleave", () => {
|
|
199
|
+
this.compassElement.style.opacity = "1";
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
updateTicksAndLabels() {
|
|
203
|
+
const majorTicks = this.compassElement.querySelectorAll(
|
|
204
|
+
".compass-tick-major"
|
|
205
|
+
);
|
|
206
|
+
const minorTicks = this.compassElement.querySelectorAll(
|
|
207
|
+
".compass-tick-minor"
|
|
208
|
+
);
|
|
209
|
+
majorTicks.forEach((tick, index) => {
|
|
210
|
+
const angle = index * 30 % 360;
|
|
211
|
+
const tickLength = 8;
|
|
212
|
+
tick.style.transform = `rotate(${angle}deg) translateY(-${this.options.size / 2 - tickLength - 2}px)`;
|
|
213
|
+
});
|
|
214
|
+
minorTicks.forEach((tick, index) => {
|
|
215
|
+
const allAngles = [];
|
|
216
|
+
for (let i = 0; i < 360; i += 10) {
|
|
217
|
+
if (i % 30 !== 0) {
|
|
218
|
+
allAngles.push(i);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const angle = allAngles[index] || 0;
|
|
222
|
+
const tickLength = 4;
|
|
223
|
+
tick.style.transform = `rotate(${angle}deg) translateY(-${this.options.size / 2 - tickLength - 2}px)`;
|
|
224
|
+
});
|
|
225
|
+
const labels = this.compassElement.querySelectorAll(".compass-label");
|
|
226
|
+
labels.forEach((label, index) => {
|
|
227
|
+
const directions = [
|
|
228
|
+
{ label: "N", angle: 0 },
|
|
229
|
+
{ label: "E", angle: 90 },
|
|
230
|
+
{ label: "S", angle: 180 },
|
|
231
|
+
{ label: "W", angle: 270 }
|
|
232
|
+
];
|
|
233
|
+
const { angle } = directions[index];
|
|
234
|
+
label.style.transform = `rotate(${angle}deg) translateY(-${this.options.size / 2 - 15}px) rotate(-${angle}deg)`;
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
getPositionStyles() {
|
|
238
|
+
const { position, offset } = this.options;
|
|
239
|
+
switch (position) {
|
|
240
|
+
case "top-left":
|
|
241
|
+
return `top: ${offset.y}px; left: ${offset.x}px;`;
|
|
242
|
+
case "top-right":
|
|
243
|
+
return `top: ${offset.y}px; right: ${offset.x}px;`;
|
|
244
|
+
case "bottom-left":
|
|
245
|
+
return `bottom: ${offset.y}px; left: ${offset.x}px;`;
|
|
246
|
+
case "bottom-right":
|
|
247
|
+
default:
|
|
248
|
+
return `bottom: ${offset.y}px; right: ${offset.x}px;`;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
start() {
|
|
252
|
+
if (this.isActive) return;
|
|
253
|
+
this.isActive = true;
|
|
254
|
+
this.update();
|
|
255
|
+
}
|
|
256
|
+
stop() {
|
|
257
|
+
this.isActive = false;
|
|
258
|
+
}
|
|
259
|
+
update() {
|
|
260
|
+
if (!this.isActive) return;
|
|
261
|
+
const cameraMatrix = new THREE.Matrix4();
|
|
262
|
+
this.camera.updateMatrixWorld();
|
|
263
|
+
cameraMatrix.copy(this.camera.matrixWorld);
|
|
264
|
+
const forward = new THREE.Vector3(0, 0, -1);
|
|
265
|
+
forward.transformDirection(cameraMatrix);
|
|
266
|
+
forward.y = 0;
|
|
267
|
+
forward.normalize();
|
|
268
|
+
const targetAngle = Math.atan2(-forward.x, -forward.z) * (180 / Math.PI);
|
|
269
|
+
let angleDiff = targetAngle - this.currentRotation;
|
|
270
|
+
while (angleDiff > 180) angleDiff -= 360;
|
|
271
|
+
while (angleDiff < -180) angleDiff += 360;
|
|
272
|
+
this.currentRotation += angleDiff;
|
|
273
|
+
this.arrowElement.style.transform = `translate(-50%, -50%) rotate(${-this.currentRotation}deg)`;
|
|
274
|
+
if (this.isActive) {
|
|
275
|
+
requestAnimationFrame(() => this.update());
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
setCamera(camera) {
|
|
279
|
+
this.camera = camera;
|
|
280
|
+
}
|
|
281
|
+
setSize(size) {
|
|
282
|
+
this.options.size = size;
|
|
283
|
+
this.compassElement.style.width = `${size}px`;
|
|
284
|
+
this.compassElement.style.height = `${size}px`;
|
|
285
|
+
this.updateTicksAndLabels();
|
|
286
|
+
this.updateStyles();
|
|
287
|
+
}
|
|
288
|
+
setPosition(position, offset) {
|
|
289
|
+
if (position) {
|
|
290
|
+
this.options.position = position;
|
|
291
|
+
}
|
|
292
|
+
if (offset) {
|
|
293
|
+
this.options.offset = offset;
|
|
294
|
+
}
|
|
295
|
+
const positionStyles = this.getPositionStyles();
|
|
296
|
+
const styles = positionStyles.split(";").filter((s) => s.trim());
|
|
297
|
+
this.compassElement.style.top = "";
|
|
298
|
+
this.compassElement.style.right = "";
|
|
299
|
+
this.compassElement.style.bottom = "";
|
|
300
|
+
this.compassElement.style.left = "";
|
|
301
|
+
styles.forEach((style) => {
|
|
302
|
+
const [property, value] = style.split(":").map((s) => s.trim());
|
|
303
|
+
if (property && value) {
|
|
304
|
+
;
|
|
305
|
+
this.compassElement.style[property] = value;
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
setColors(colors) {
|
|
310
|
+
this.options.colors = { ...this.options.colors, ...colors };
|
|
311
|
+
this.updateStyles();
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Helper method to reset camera to look north (world Z- direction)
|
|
315
|
+
* This is a convenience method that can be called when handling the 'resetToNorth' event
|
|
316
|
+
*/
|
|
317
|
+
static resetCameraToNorth(camera, smooth = true) {
|
|
318
|
+
if (smooth) {
|
|
319
|
+
const startQuaternion = camera.quaternion.clone();
|
|
320
|
+
const targetQuaternion = new THREE.Quaternion();
|
|
321
|
+
const targetMatrix = new THREE.Matrix4();
|
|
322
|
+
targetMatrix.lookAt(
|
|
323
|
+
camera.position,
|
|
324
|
+
camera.position.clone().add(new THREE.Vector3(0, 0, -1)),
|
|
325
|
+
new THREE.Vector3(0, 1, 0)
|
|
326
|
+
);
|
|
327
|
+
targetQuaternion.setFromRotationMatrix(targetMatrix);
|
|
328
|
+
const duration = 500;
|
|
329
|
+
const startTime = Date.now();
|
|
330
|
+
const animate = () => {
|
|
331
|
+
const elapsed = Date.now() - startTime;
|
|
332
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
333
|
+
const easeProgress = 1 - Math.pow(1 - progress, 3);
|
|
334
|
+
camera.quaternion.slerpQuaternions(
|
|
335
|
+
startQuaternion,
|
|
336
|
+
targetQuaternion,
|
|
337
|
+
easeProgress
|
|
338
|
+
);
|
|
339
|
+
if (progress < 1) {
|
|
340
|
+
requestAnimationFrame(animate);
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
animate();
|
|
344
|
+
} else {
|
|
345
|
+
camera.lookAt(camera.position.clone().add(new THREE.Vector3(0, 0, -1)));
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
updateStyles() {
|
|
349
|
+
const existingStyle = document.getElementById("threejs-compass-styles");
|
|
350
|
+
if (existingStyle) {
|
|
351
|
+
existingStyle.remove();
|
|
352
|
+
}
|
|
353
|
+
this.setupStyles();
|
|
354
|
+
}
|
|
355
|
+
dispose() {
|
|
356
|
+
this.stop();
|
|
357
|
+
if (this.compassElement && this.compassElement.parentNode) {
|
|
358
|
+
this.compassElement.parentNode.removeChild(this.compassElement);
|
|
359
|
+
}
|
|
360
|
+
const compassElements = document.querySelectorAll(
|
|
361
|
+
".threejs-compass-overlay"
|
|
362
|
+
);
|
|
363
|
+
if (compassElements.length === 0) {
|
|
364
|
+
const style = document.getElementById("threejs-compass-styles");
|
|
365
|
+
if (style) {
|
|
366
|
+
style.remove();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
372
|
+
0 && (module.exports = {
|
|
373
|
+
CompassOverlay
|
|
374
|
+
});
|
|
375
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../packages/compass/src/index.ts","../../packages/compass/src/CompassOverlay.ts"],"sourcesContent":["export * from './CompassOverlay'\n","import * as THREE from 'three'\n\nexport interface CompassOverlayOptions {\n container?: HTMLElement\n size?: number\n position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'\n offset?: { x: number; y: number }\n colors?: {\n background: string\n border: string\n arrow: string\n text: string\n ticks: string\n }\n}\n\n// Define event types for the compass\ninterface CompassOverlayEventMap {\n resetToNorth: {}\n}\n\nexport interface CompassOverlayEvent {\n type: 'resetToNorth'\n}\n\nexport class CompassOverlay extends THREE.EventDispatcher<CompassOverlayEventMap> {\n private camera: THREE.Camera\n private container: HTMLElement\n private compassElement!: HTMLElement\n private arrowElement!: HTMLElement\n private isActive: boolean = false\n private options: Required<CompassOverlayOptions>\n private currentRotation: number = 0\n\n constructor(camera: THREE.Camera, options: CompassOverlayOptions = {}) {\n super()\n this.camera = camera\n\n // Set default options\n this.options = {\n container: options.container || document.body,\n size: options.size || 100,\n position: options.position || 'bottom-right',\n offset: options.offset || { x: 20, y: 20 },\n colors: {\n background: options.colors?.background || '#1a1a1a',\n border: options.colors?.border || '#333333',\n arrow: options.colors?.arrow || '#ff4444',\n text: options.colors?.text || '#ffffff',\n ticks: options.colors?.ticks || '#666666',\n ...options.colors,\n },\n }\n\n this.container = this.options.container\n this.createCompassElement()\n this.setupStyles()\n }\n\n private createCompassElement(): void {\n // Create main compass container\n this.compassElement = document.createElement('div')\n this.compassElement.className = 'threejs-compass-overlay'\n\n // Create compass background with ticks\n const compassBg = document.createElement('div')\n compassBg.className = 'compass-background'\n\n // Create cardinal direction labels\n const directions = [\n { label: 'N', angle: 0 },\n { label: 'E', angle: 90 },\n { label: 'S', angle: 180 },\n { label: 'W', angle: 270 },\n ]\n\n // Create tick marks\n for (let i = 0; i < 360; i += 11.25) {\n const tick = document.createElement('div')\n tick.className =\n i % 45 === 0 ? 'compass-tick-major' : 'compass-tick-minor'\n const tickLength = i % 30 === 0 ? 8 : 4\n tick.style.transform = `rotate(${i}deg) translateY(-${this.options.size / 2 - tickLength - 2}px)`\n compassBg.appendChild(tick)\n }\n\n directions.forEach(({ label, angle }) => {\n const dirLabel = document.createElement('div')\n dirLabel.className = 'compass-label'\n dirLabel.textContent = label\n dirLabel.style.transform = `rotate(${angle}deg) translateY(-${this.options.size / 2 - 15}px) rotate(-${angle}deg)`\n compassBg.appendChild(dirLabel)\n })\n\n // Create arrow element\n this.arrowElement = document.createElement('div')\n this.arrowElement.className = 'compass-arrow'\n\n // Arrow SVG\n this.arrowElement.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\">\n <polygon points=\"10,2 14,12 10,10 6,12\" fill=\"${this.options.colors.arrow}\" stroke=\"#000\" stroke-width=\"0.5\"/>\n </svg>\n `\n\n this.compassElement.appendChild(compassBg)\n this.compassElement.appendChild(this.arrowElement)\n this.container.appendChild(this.compassElement)\n\n // Add double-click event to reset camera to north\n this.setupDoubleClickHandler()\n }\n\n private setupStyles(): void {\n // Check if styles already exist\n if (document.getElementById('threejs-compass-styles')) {\n return\n }\n\n const style = document.createElement('style')\n style.id = 'threejs-compass-styles'\n style.textContent = `\n .threejs-compass-overlay {\n position: fixed;\n width: ${this.options.size}px;\n height: ${this.options.size}px;\n background: ${this.options.colors.background};\n border: 2px solid ${this.options.colors.border};\n border-radius: 50%;\n z-index: 1000;\n pointer-events: none;\n user-select: none;\n transition: opacity 0.2s ease;\n ${this.getPositionStyles()};\n }\n\n .compass-background {\n position: relative;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n }\n\n .compass-label {\n position: absolute;\n top: 50%;\n left: 50%;\n transform-origin: center;\n color: ${this.options.colors.text};\n font-family: Arial, sans-serif;\n font-size: 12px;\n font-weight: bold;\n text-align: center;\n width: 12px;\n height: 12px;\n line-height: 12px;\n margin-left: -6px;\n margin-top: -6px;\n }\n\n .compass-tick-major {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 2px;\n height: 8px;\n background: ${this.options.colors.ticks};\n transform-origin: center top;\n margin-left: -1px;\n margin-top: -4px;\n }\n\n .compass-tick-minor {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 1px;\n height: 4px;\n background: ${this.options.colors.ticks};\n transform-origin: center top;\n margin-left: -0.5px;\n margin-top: -2px;\n opacity: 0.6;\n }\n\n .compass-arrow {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n transform-origin: center;\n transition: transform 0.1s ease-out;\n z-index: 1;\n }\n\n .compass-arrow svg {\n display: block;\n filter: drop-shadow(0 0 2px rgba(0,0,0,0.5));\n }\n `\n\n document.head.appendChild(style)\n }\n\n private setupDoubleClickHandler(): void {\n // Enable pointer events for interaction\n this.compassElement.style.pointerEvents = 'auto'\n this.compassElement.style.cursor = 'pointer'\n\n // Add double-click event listener\n this.compassElement.addEventListener('dblclick', (event) => {\n event.preventDefault()\n event.stopPropagation()\n\n // Dispatch custom event\n this.dispatchEvent({ type: 'resetToNorth' })\n })\n\n // Add visual feedback on hover\n this.compassElement.addEventListener('mouseenter', () => {\n this.compassElement.style.opacity = '0.8'\n })\n\n this.compassElement.addEventListener('mouseleave', () => {\n this.compassElement.style.opacity = '1'\n })\n }\n\n private updateTicksAndLabels(): void {\n // Update compass labels\n\n // Update tick marks\n const majorTicks = this.compassElement.querySelectorAll(\n '.compass-tick-major'\n )\n const minorTicks = this.compassElement.querySelectorAll(\n '.compass-tick-minor'\n )\n\n majorTicks.forEach((tick, index) => {\n const angle = (index * 30) % 360 // Major ticks every 30 degrees\n const tickLength = 8\n ;(tick as HTMLElement).style.transform =\n `rotate(${angle}deg) translateY(-${this.options.size / 2 - tickLength - 2}px)`\n })\n\n minorTicks.forEach((tick, index) => {\n // Minor ticks are at angles that aren't multiples of 30\n const allAngles = []\n for (let i = 0; i < 360; i += 10) {\n if (i % 30 !== 0) {\n // Skip major tick positions\n allAngles.push(i)\n }\n }\n const angle = allAngles[index] || 0\n const tickLength = 4\n ;(tick as HTMLElement).style.transform =\n `rotate(${angle}deg) translateY(-${this.options.size / 2 - tickLength - 2}px)`\n })\n\n const labels = this.compassElement.querySelectorAll('.compass-label')\n labels.forEach((label, index) => {\n const directions = [\n { label: 'N', angle: 0 },\n { label: 'E', angle: 90 },\n { label: 'S', angle: 180 },\n { label: 'W', angle: 270 },\n ]\n const { angle } = directions[index]\n ;(label as HTMLElement).style.transform =\n `rotate(${angle}deg) translateY(-${this.options.size / 2 - 15}px) rotate(-${angle}deg)`\n })\n }\n\n private getPositionStyles(): string {\n const { position, offset } = this.options\n\n switch (position) {\n case 'top-left':\n return `top: ${offset.y}px; left: ${offset.x}px;`\n case 'top-right':\n return `top: ${offset.y}px; right: ${offset.x}px;`\n case 'bottom-left':\n return `bottom: ${offset.y}px; left: ${offset.x}px;`\n case 'bottom-right':\n default:\n return `bottom: ${offset.y}px; right: ${offset.x}px;`\n }\n }\n\n public start(): void {\n if (this.isActive) return\n this.isActive = true\n this.update()\n }\n\n public stop(): void {\n this.isActive = false\n }\n\n public update(): void {\n if (!this.isActive) return\n\n // Get the camera's world matrix\n const cameraMatrix = new THREE.Matrix4()\n this.camera.updateMatrixWorld()\n cameraMatrix.copy(this.camera.matrixWorld)\n\n // Extract the camera's forward direction (negative Z in camera space)\n const forward = new THREE.Vector3(0, 0, -1)\n forward.transformDirection(cameraMatrix)\n\n // Project to XZ plane (ignore Y component for top-down compass view)\n forward.y = 0\n forward.normalize()\n\n // Calculate angle from world -Z axis (north)\n // World Z- is \"north\", X- is \"east\" (flipped X axis)\n const targetAngle = Math.atan2(-forward.x, -forward.z) * (180 / Math.PI)\n\n // Calculate the shortest rotation path to avoid spinning around\n let angleDiff = targetAngle - this.currentRotation\n\n // Normalize the angle difference to be between -180 and 180\n while (angleDiff > 180) angleDiff -= 360\n while (angleDiff < -180) angleDiff += 360\n\n // Update current rotation with smooth transition\n this.currentRotation += angleDiff\n\n // Update arrow rotation (negative because we want the arrow to point to north, not where camera is facing)\n this.arrowElement.style.transform = `translate(-50%, -50%) rotate(${-this.currentRotation}deg)`\n\n // Continue updating if active\n if (this.isActive) {\n requestAnimationFrame(() => this.update())\n }\n }\n\n public setCamera(camera: THREE.Camera): void {\n this.camera = camera\n }\n\n public setSize(size: number): void {\n this.options.size = size\n this.compassElement.style.width = `${size}px`\n this.compassElement.style.height = `${size}px`\n this.updateTicksAndLabels()\n this.updateStyles()\n }\n\n public setPosition(\n position: CompassOverlayOptions['position'],\n offset?: { x: number; y: number }\n ): void {\n if (position) {\n this.options.position = position\n }\n if (offset) {\n this.options.offset = offset\n }\n\n // Update position styles\n const positionStyles = this.getPositionStyles()\n const styles = positionStyles.split(';').filter((s) => s.trim())\n\n // Clear existing position styles\n this.compassElement.style.top = ''\n this.compassElement.style.right = ''\n this.compassElement.style.bottom = ''\n this.compassElement.style.left = ''\n\n // Apply new position styles\n styles.forEach((style) => {\n const [property, value] = style.split(':').map((s) => s.trim())\n if (property && value) {\n ;(this.compassElement.style as any)[property] = value\n }\n })\n }\n\n public setColors(colors: Partial<CompassOverlayOptions['colors']>): void {\n this.options.colors = { ...this.options.colors, ...colors }\n this.updateStyles()\n }\n\n /**\n * Helper method to reset camera to look north (world Z- direction)\n * This is a convenience method that can be called when handling the 'resetToNorth' event\n */\n public static resetCameraToNorth(\n camera: THREE.Camera,\n smooth: boolean = true\n ): void {\n if (smooth) {\n // Create a smooth rotation animation to north\n const startQuaternion = camera.quaternion.clone()\n const targetQuaternion = new THREE.Quaternion()\n\n // Set target rotation to look at north (Z-)\n const targetMatrix = new THREE.Matrix4()\n targetMatrix.lookAt(\n camera.position,\n camera.position.clone().add(new THREE.Vector3(0, 0, -1)),\n new THREE.Vector3(0, 1, 0)\n )\n targetQuaternion.setFromRotationMatrix(targetMatrix)\n\n // Animate rotation\n const duration = 500 // milliseconds\n const startTime = Date.now()\n\n const animate = () => {\n const elapsed = Date.now() - startTime\n const progress = Math.min(elapsed / duration, 1)\n\n // Use smooth easing\n const easeProgress = 1 - Math.pow(1 - progress, 3)\n\n camera.quaternion.slerpQuaternions(\n startQuaternion,\n targetQuaternion,\n easeProgress\n )\n\n if (progress < 1) {\n requestAnimationFrame(animate)\n }\n }\n animate()\n } else {\n // Instant rotation to north\n camera.lookAt(camera.position.clone().add(new THREE.Vector3(0, 0, -1)))\n }\n }\n\n private updateStyles(): void {\n // Remove existing styles\n const existingStyle = document.getElementById('threejs-compass-styles')\n if (existingStyle) {\n existingStyle.remove()\n }\n\n // Recreate styles with new values\n this.setupStyles()\n }\n\n public dispose(): void {\n this.stop()\n\n if (this.compassElement && this.compassElement.parentNode) {\n this.compassElement.parentNode.removeChild(this.compassElement)\n }\n\n // Remove styles if no other compass instances exist\n const compassElements = document.querySelectorAll(\n '.threejs-compass-overlay'\n )\n if (compassElements.length === 0) {\n const style = document.getElementById('threejs-compass-styles')\n if (style) {\n style.remove()\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
|
|
3
|
+
interface CompassOverlayOptions {
|
|
4
|
+
container?: HTMLElement;
|
|
5
|
+
size?: number;
|
|
6
|
+
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
7
|
+
offset?: {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
};
|
|
11
|
+
colors?: {
|
|
12
|
+
background: string;
|
|
13
|
+
border: string;
|
|
14
|
+
arrow: string;
|
|
15
|
+
text: string;
|
|
16
|
+
ticks: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
interface CompassOverlayEventMap {
|
|
20
|
+
resetToNorth: {};
|
|
21
|
+
}
|
|
22
|
+
interface CompassOverlayEvent {
|
|
23
|
+
type: 'resetToNorth';
|
|
24
|
+
}
|
|
25
|
+
declare class CompassOverlay extends THREE.EventDispatcher<CompassOverlayEventMap> {
|
|
26
|
+
private camera;
|
|
27
|
+
private container;
|
|
28
|
+
private compassElement;
|
|
29
|
+
private arrowElement;
|
|
30
|
+
private isActive;
|
|
31
|
+
private options;
|
|
32
|
+
private currentRotation;
|
|
33
|
+
constructor(camera: THREE.Camera, options?: CompassOverlayOptions);
|
|
34
|
+
private createCompassElement;
|
|
35
|
+
private setupStyles;
|
|
36
|
+
private setupDoubleClickHandler;
|
|
37
|
+
private updateTicksAndLabels;
|
|
38
|
+
private getPositionStyles;
|
|
39
|
+
start(): void;
|
|
40
|
+
stop(): void;
|
|
41
|
+
update(): void;
|
|
42
|
+
setCamera(camera: THREE.Camera): void;
|
|
43
|
+
setSize(size: number): void;
|
|
44
|
+
setPosition(position: CompassOverlayOptions['position'], offset?: {
|
|
45
|
+
x: number;
|
|
46
|
+
y: number;
|
|
47
|
+
}): void;
|
|
48
|
+
setColors(colors: Partial<CompassOverlayOptions['colors']>): void;
|
|
49
|
+
/**
|
|
50
|
+
* Helper method to reset camera to look north (world Z- direction)
|
|
51
|
+
* This is a convenience method that can be called when handling the 'resetToNorth' event
|
|
52
|
+
*/
|
|
53
|
+
static resetCameraToNorth(camera: THREE.Camera, smooth?: boolean): void;
|
|
54
|
+
private updateStyles;
|
|
55
|
+
dispose(): void;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { CompassOverlay, type CompassOverlayEvent, type CompassOverlayOptions };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
|
|
3
|
+
interface CompassOverlayOptions {
|
|
4
|
+
container?: HTMLElement;
|
|
5
|
+
size?: number;
|
|
6
|
+
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
7
|
+
offset?: {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
};
|
|
11
|
+
colors?: {
|
|
12
|
+
background: string;
|
|
13
|
+
border: string;
|
|
14
|
+
arrow: string;
|
|
15
|
+
text: string;
|
|
16
|
+
ticks: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
interface CompassOverlayEventMap {
|
|
20
|
+
resetToNorth: {};
|
|
21
|
+
}
|
|
22
|
+
interface CompassOverlayEvent {
|
|
23
|
+
type: 'resetToNorth';
|
|
24
|
+
}
|
|
25
|
+
declare class CompassOverlay extends THREE.EventDispatcher<CompassOverlayEventMap> {
|
|
26
|
+
private camera;
|
|
27
|
+
private container;
|
|
28
|
+
private compassElement;
|
|
29
|
+
private arrowElement;
|
|
30
|
+
private isActive;
|
|
31
|
+
private options;
|
|
32
|
+
private currentRotation;
|
|
33
|
+
constructor(camera: THREE.Camera, options?: CompassOverlayOptions);
|
|
34
|
+
private createCompassElement;
|
|
35
|
+
private setupStyles;
|
|
36
|
+
private setupDoubleClickHandler;
|
|
37
|
+
private updateTicksAndLabels;
|
|
38
|
+
private getPositionStyles;
|
|
39
|
+
start(): void;
|
|
40
|
+
stop(): void;
|
|
41
|
+
update(): void;
|
|
42
|
+
setCamera(camera: THREE.Camera): void;
|
|
43
|
+
setSize(size: number): void;
|
|
44
|
+
setPosition(position: CompassOverlayOptions['position'], offset?: {
|
|
45
|
+
x: number;
|
|
46
|
+
y: number;
|
|
47
|
+
}): void;
|
|
48
|
+
setColors(colors: Partial<CompassOverlayOptions['colors']>): void;
|
|
49
|
+
/**
|
|
50
|
+
* Helper method to reset camera to look north (world Z- direction)
|
|
51
|
+
* This is a convenience method that can be called when handling the 'resetToNorth' event
|
|
52
|
+
*/
|
|
53
|
+
static resetCameraToNorth(camera: THREE.Camera, smooth?: boolean): void;
|
|
54
|
+
private updateStyles;
|
|
55
|
+
dispose(): void;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { CompassOverlay, type CompassOverlayEvent, type CompassOverlayOptions };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|