worldorbit 3.0.5 → 3.0.7
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 +2 -2
- package/dist/browser/viewer/dist/embed.js +86 -13
- package/dist/browser/viewer/dist/runtime-3d.js +396 -117
- package/dist/browser/viewer/dist/theme.js +27 -0
- package/dist/browser/viewer/dist/types.d.ts +17 -0
- package/dist/browser/viewer/dist/viewer.js +268 -12
- package/dist/unpkg/viewer/dist/embed.js +86 -13
- package/dist/unpkg/viewer/dist/runtime-3d.js +396 -117
- package/dist/unpkg/viewer/dist/theme.js +27 -0
- package/dist/unpkg/viewer/dist/types.d.ts +17 -0
- package/dist/unpkg/viewer/dist/viewer.js +268 -12
- package/dist/unpkg/worldorbit-editor.min.js +368 -314
- package/dist/unpkg/worldorbit-markdown.min.js +13 -13
- package/dist/unpkg/worldorbit-viewer.min.js +272 -218
- package/dist/unpkg/worldorbit.js +735 -127
- package/dist/unpkg/worldorbit.min.js +265 -211
- package/package.json +1 -1
- package/packages/viewer/dist/embed.js +86 -13
- package/packages/viewer/dist/runtime-3d.js +396 -117
- package/packages/viewer/dist/theme.js +27 -0
- package/packages/viewer/dist/types.d.ts +17 -0
- package/packages/viewer/dist/viewer.js +268 -12
package/dist/unpkg/worldorbit.js
CHANGED
|
@@ -37777,6 +37777,15 @@ void main() {
|
|
|
37777
37777
|
starCore: "#ffcc67",
|
|
37778
37778
|
starStroke: "rgba(255, 245, 203, 0.85)",
|
|
37779
37779
|
starGlow: "#ffe8a3",
|
|
37780
|
+
spaceFog: "#07131d",
|
|
37781
|
+
starfield: "rgba(226, 239, 255, 0.9)",
|
|
37782
|
+
starfieldDim: "rgba(164, 194, 228, 0.45)",
|
|
37783
|
+
objectSpecular: "#f5f8ff",
|
|
37784
|
+
orbitOpacity: 0.34,
|
|
37785
|
+
orbitBandOpacity: 0.24,
|
|
37786
|
+
selectionHalo: "rgba(255, 214, 139, 0.9)",
|
|
37787
|
+
atmosphere: "rgba(143, 202, 255, 0.4)",
|
|
37788
|
+
cometTail: "rgba(193, 243, 255, 0.7)",
|
|
37780
37789
|
fontFamily: '"Segoe UI Variable", "Bahnschrift", sans-serif',
|
|
37781
37790
|
displayFont: '"Bahnschrift", "Segoe UI Variable", sans-serif'
|
|
37782
37791
|
},
|
|
@@ -37800,6 +37809,15 @@ void main() {
|
|
|
37800
37809
|
starCore: "#e5f98c",
|
|
37801
37810
|
starStroke: "rgba(246, 255, 217, 0.9)",
|
|
37802
37811
|
starGlow: "#fffab4",
|
|
37812
|
+
spaceFog: "#071723",
|
|
37813
|
+
starfield: "rgba(220, 255, 245, 0.9)",
|
|
37814
|
+
starfieldDim: "rgba(124, 212, 195, 0.42)",
|
|
37815
|
+
objectSpecular: "#ecfffb",
|
|
37816
|
+
orbitOpacity: 0.3,
|
|
37817
|
+
orbitBandOpacity: 0.22,
|
|
37818
|
+
selectionHalo: "rgba(120, 255, 215, 0.85)",
|
|
37819
|
+
atmosphere: "rgba(120, 255, 215, 0.32)",
|
|
37820
|
+
cometTail: "rgba(181, 255, 236, 0.68)",
|
|
37803
37821
|
fontFamily: '"Segoe UI Variable", "Bahnschrift", sans-serif',
|
|
37804
37822
|
displayFont: '"Bahnschrift", "Segoe UI Variable", sans-serif'
|
|
37805
37823
|
},
|
|
@@ -37823,6 +37841,15 @@ void main() {
|
|
|
37823
37841
|
starCore: "#ffb766",
|
|
37824
37842
|
starStroke: "rgba(255, 236, 205, 0.88)",
|
|
37825
37843
|
starGlow: "#ffe2ad",
|
|
37844
|
+
spaceFog: "#1c0d12",
|
|
37845
|
+
starfield: "rgba(255, 232, 214, 0.88)",
|
|
37846
|
+
starfieldDim: "rgba(255, 176, 138, 0.38)",
|
|
37847
|
+
objectSpecular: "#fff0e6",
|
|
37848
|
+
orbitOpacity: 0.3,
|
|
37849
|
+
orbitBandOpacity: 0.24,
|
|
37850
|
+
selectionHalo: "rgba(255, 178, 125, 0.85)",
|
|
37851
|
+
atmosphere: "rgba(255, 190, 140, 0.26)",
|
|
37852
|
+
cometTail: "rgba(255, 214, 173, 0.62)",
|
|
37826
37853
|
fontFamily: '"Segoe UI Variable", "Bahnschrift", sans-serif',
|
|
37827
37854
|
displayFont: '"Bahnschrift", "Segoe UI Variable", sans-serif'
|
|
37828
37855
|
}
|
|
@@ -38872,10 +38899,12 @@ void main() {
|
|
|
38872
38899
|
let currentVisibleObjectIds = /* @__PURE__ */ new Set();
|
|
38873
38900
|
let currentSelectedObjectId = null;
|
|
38874
38901
|
let currentHoveredObjectId = null;
|
|
38875
|
-
let currentTimeSeconds = 0;
|
|
38876
38902
|
let currentPositions = /* @__PURE__ */ new Map();
|
|
38877
38903
|
let pendingUpdate = null;
|
|
38878
38904
|
let destroyed = false;
|
|
38905
|
+
let smoothedCameraPosition = null;
|
|
38906
|
+
let smoothedCameraTarget = null;
|
|
38907
|
+
let currentEnvironmentKey = "";
|
|
38879
38908
|
const objectVisuals = /* @__PURE__ */ new Map();
|
|
38880
38909
|
const orbitVisuals = /* @__PURE__ */ new Map();
|
|
38881
38910
|
const raycastTargets = [];
|
|
@@ -38884,7 +38913,7 @@ void main() {
|
|
|
38884
38913
|
return;
|
|
38885
38914
|
}
|
|
38886
38915
|
const scene3d = new THREE.Scene();
|
|
38887
|
-
const camera = new THREE.PerspectiveCamera(
|
|
38916
|
+
const camera = new THREE.PerspectiveCamera(46, 1, 0.1, 24e3);
|
|
38888
38917
|
const renderer = new THREE.WebGLRenderer({
|
|
38889
38918
|
antialias: true,
|
|
38890
38919
|
alpha: true,
|
|
@@ -38894,27 +38923,40 @@ void main() {
|
|
|
38894
38923
|
renderer.domElement.dataset.worldorbit3dCanvas = "true";
|
|
38895
38924
|
root.innerHTML = "";
|
|
38896
38925
|
root.append(renderer.domElement);
|
|
38897
|
-
const ambientLight = new THREE.AmbientLight(16777215,
|
|
38898
|
-
const
|
|
38899
|
-
|
|
38900
|
-
|
|
38926
|
+
const ambientLight = new THREE.AmbientLight(16777215, 0.24);
|
|
38927
|
+
const fillLight = new THREE.DirectionalLight(13625855, 0.36);
|
|
38928
|
+
const rimLight = new THREE.DirectionalLight(8304895, 0.24);
|
|
38929
|
+
const keyLight = new THREE.PointLight(16773327, 2.6, 0, 2);
|
|
38930
|
+
fillLight.position.set(-360, 260, 220);
|
|
38931
|
+
rimLight.position.set(340, 180, -280);
|
|
38901
38932
|
const orbitLayer = new THREE.Group();
|
|
38902
38933
|
const objectLayer = new THREE.Group();
|
|
38934
|
+
const starfield = createStarfield(THREE, 320);
|
|
38935
|
+
const raycaster = new THREE.Raycaster();
|
|
38936
|
+
raycaster.params.Line = { threshold: 7 };
|
|
38937
|
+
scene3d.add(ambientLight);
|
|
38938
|
+
scene3d.add(fillLight);
|
|
38939
|
+
scene3d.add(rimLight);
|
|
38940
|
+
scene3d.add(keyLight);
|
|
38941
|
+
scene3d.add(starfield);
|
|
38903
38942
|
scene3d.add(orbitLayer);
|
|
38904
38943
|
scene3d.add(objectLayer);
|
|
38905
|
-
const raycaster = new THREE.Raycaster();
|
|
38906
|
-
raycaster.params.Line = { threshold: 10 };
|
|
38907
38944
|
runtime = {
|
|
38908
38945
|
THREE,
|
|
38909
38946
|
scene3d,
|
|
38910
38947
|
camera,
|
|
38911
38948
|
renderer,
|
|
38949
|
+
ambientLight,
|
|
38950
|
+
fillLight,
|
|
38951
|
+
rimLight,
|
|
38912
38952
|
keyLight,
|
|
38953
|
+
starfield,
|
|
38913
38954
|
orbitLayer,
|
|
38914
38955
|
objectLayer,
|
|
38915
38956
|
raycaster,
|
|
38916
38957
|
pointer: new THREE.Vector2()
|
|
38917
38958
|
};
|
|
38959
|
+
configureRenderer(renderer, THREE, "balanced");
|
|
38918
38960
|
if (pendingUpdate) {
|
|
38919
38961
|
applyUpdate(pendingUpdate);
|
|
38920
38962
|
}
|
|
@@ -38973,6 +39015,8 @@ void main() {
|
|
|
38973
39015
|
destroyed = true;
|
|
38974
39016
|
pendingUpdate = null;
|
|
38975
39017
|
runtime?.renderer.dispose();
|
|
39018
|
+
runtime?.starfield?.geometry?.dispose?.();
|
|
39019
|
+
runtime?.starfield?.material?.dispose?.();
|
|
38976
39020
|
root.remove();
|
|
38977
39021
|
objectVisuals.clear();
|
|
38978
39022
|
orbitVisuals.clear();
|
|
@@ -38991,7 +39035,16 @@ void main() {
|
|
|
38991
39035
|
currentVisibleObjectIds = next.visibleObjectIds;
|
|
38992
39036
|
currentSelectedObjectId = next.selectedObjectId;
|
|
38993
39037
|
currentHoveredObjectId = next.hoveredObjectId;
|
|
38994
|
-
|
|
39038
|
+
configureRenderer(runtime.renderer, runtime.THREE, currentRenderOptions?.quality ?? "balanced");
|
|
39039
|
+
const nextEnvironmentKey = JSON.stringify({
|
|
39040
|
+
theme: currentRenderOptions?.theme ?? null,
|
|
39041
|
+
quality: currentRenderOptions?.quality ?? "balanced",
|
|
39042
|
+
style3d: currentRenderOptions?.style3d ?? "symbolic"
|
|
39043
|
+
});
|
|
39044
|
+
if (nextEnvironmentKey !== currentEnvironmentKey) {
|
|
39045
|
+
updateEnvironment(runtime, currentRenderOptions);
|
|
39046
|
+
currentEnvironmentKey = nextEnvironmentKey;
|
|
39047
|
+
}
|
|
38995
39048
|
if (sceneChanged) {
|
|
38996
39049
|
rebuildScene(next.spatialScene);
|
|
38997
39050
|
}
|
|
@@ -39001,8 +39054,9 @@ void main() {
|
|
|
39001
39054
|
updateOrbitTransforms();
|
|
39002
39055
|
updateVisibility();
|
|
39003
39056
|
updateInteractionState();
|
|
39057
|
+
updateLighting();
|
|
39004
39058
|
updateCamera();
|
|
39005
|
-
|
|
39059
|
+
runtime.renderer.render(runtime.scene3d, runtime.camera);
|
|
39006
39060
|
}
|
|
39007
39061
|
function rebuildScene(spatialScene) {
|
|
39008
39062
|
if (!runtime) {
|
|
@@ -39013,8 +39067,9 @@ void main() {
|
|
|
39013
39067
|
objectVisuals.clear();
|
|
39014
39068
|
orbitVisuals.clear();
|
|
39015
39069
|
raycastTargets.length = 0;
|
|
39070
|
+
smoothedCameraPosition = null;
|
|
39071
|
+
smoothedCameraTarget = null;
|
|
39016
39072
|
const theme = resolveTheme(currentRenderOptions?.theme);
|
|
39017
|
-
runtime.scene3d.background = new runtime.THREE.Color(theme.backgroundStart);
|
|
39018
39073
|
for (const orbit of spatialScene.orbits) {
|
|
39019
39074
|
const visual = createOrbitVisual2(runtime.THREE, orbit, theme);
|
|
39020
39075
|
runtime.orbitLayer.add(visual.root);
|
|
@@ -39032,10 +39087,9 @@ void main() {
|
|
|
39032
39087
|
for (const object of currentScene?.objects ?? []) {
|
|
39033
39088
|
const visual = objectVisuals.get(object.objectId);
|
|
39034
39089
|
const position = currentPositions.get(object.objectId);
|
|
39035
|
-
if (
|
|
39036
|
-
|
|
39090
|
+
if (visual && position) {
|
|
39091
|
+
visual.root.position.set(position.x, position.y, position.z);
|
|
39037
39092
|
}
|
|
39038
|
-
visual.root.position.set(position.x, position.y, position.z);
|
|
39039
39093
|
}
|
|
39040
39094
|
}
|
|
39041
39095
|
function updateOrbitTransforms() {
|
|
@@ -39056,8 +39110,7 @@ void main() {
|
|
|
39056
39110
|
continue;
|
|
39057
39111
|
}
|
|
39058
39112
|
const hideStructure = layers.structures === false && (object.object.type === "structure" || object.object.type === "phenomenon");
|
|
39059
|
-
|
|
39060
|
-
visual.root.visible = !object.hidden && currentVisibleObjectIds.has(object.objectId) && !hideStructure && !hideObjects;
|
|
39113
|
+
visual.root.visible = !object.hidden && currentVisibleObjectIds.has(object.objectId) && layers.objects !== false && !hideStructure;
|
|
39061
39114
|
}
|
|
39062
39115
|
for (const orbit of currentScene?.orbits ?? []) {
|
|
39063
39116
|
const visual = orbitVisuals.get(orbit.objectId);
|
|
@@ -39073,14 +39126,27 @@ void main() {
|
|
|
39073
39126
|
return;
|
|
39074
39127
|
}
|
|
39075
39128
|
for (const visual of objectVisuals.values()) {
|
|
39076
|
-
|
|
39077
|
-
const
|
|
39129
|
+
const selected = currentSelectedObjectId === visual.objectId;
|
|
39130
|
+
const hovered = currentHoveredObjectId === visual.objectId;
|
|
39131
|
+
applyVisualState(runtime.THREE, visual.materials, selected, hovered);
|
|
39132
|
+
const scale = selected ? 1.16 : hovered ? 1.08 : 1;
|
|
39078
39133
|
visual.root.scale.set(scale, scale, scale);
|
|
39134
|
+
if (visual.halo) {
|
|
39135
|
+
visual.halo.visible = selected || hovered;
|
|
39136
|
+
}
|
|
39079
39137
|
}
|
|
39080
39138
|
for (const visual of orbitVisuals.values()) {
|
|
39081
|
-
applyVisualState(runtime.THREE, visual.materials,
|
|
39139
|
+
applyVisualState(runtime.THREE, visual.materials, currentSelectedObjectId === visual.objectId, currentHoveredObjectId === visual.objectId);
|
|
39082
39140
|
}
|
|
39083
39141
|
}
|
|
39142
|
+
function updateLighting() {
|
|
39143
|
+
if (!runtime || !currentScene) {
|
|
39144
|
+
return;
|
|
39145
|
+
}
|
|
39146
|
+
const primaryStar = currentScene.objects.find((object) => object.object.type === "star" && !object.hidden) ?? null;
|
|
39147
|
+
const starPosition = primaryStar ? currentPositions.get(primaryStar.objectId) ?? primaryStar.position : { x: 0, y: 40, z: 0 };
|
|
39148
|
+
runtime.keyLight.position.set(starPosition.x, starPosition.y + 20, starPosition.z);
|
|
39149
|
+
}
|
|
39084
39150
|
function updateCamera() {
|
|
39085
39151
|
if (!runtime || !currentScene || !currentState) {
|
|
39086
39152
|
return;
|
|
@@ -39088,19 +39154,27 @@ void main() {
|
|
|
39088
39154
|
const sceneCamera = currentRenderOptions?.camera ?? currentScene.camera;
|
|
39089
39155
|
const bounds = currentScene.contentBounds;
|
|
39090
39156
|
const size = Math.max(bounds.width, bounds.depth, bounds.height, 160);
|
|
39091
|
-
const yaw = degreesToRadians3((sceneCamera?.azimuth ??
|
|
39092
|
-
const pitch = degreesToRadians3(clampValue(sceneCamera?.elevation ??
|
|
39093
|
-
const zoomDistanceFactor = clampValue(2.
|
|
39094
|
-
const semanticDistance = clampValue(sceneCamera?.distance ??
|
|
39095
|
-
const distance = clampValue(size * zoomDistanceFactor * (semanticDistance /
|
|
39157
|
+
const yaw = degreesToRadians3((sceneCamera?.azimuth ?? 30) + currentState.rotationDeg);
|
|
39158
|
+
const pitch = degreesToRadians3(clampValue(sceneCamera?.elevation ?? 22, -75, 75));
|
|
39159
|
+
const zoomDistanceFactor = clampValue(2.2 / Math.max(currentState.scale, 0.1), 0.35, 7.2);
|
|
39160
|
+
const semanticDistance = clampValue(sceneCamera?.distance ?? 5.4, 2, 24);
|
|
39161
|
+
const distance = clampValue(size * zoomDistanceFactor * (semanticDistance / 5.4), 24, 8e3);
|
|
39096
39162
|
const panFactor = Math.max(size / 900, 0.12);
|
|
39097
39163
|
const target = new runtime.THREE.Vector3(bounds.center.x - currentState.translateX * panFactor, bounds.center.y, bounds.center.z - currentState.translateY * panFactor);
|
|
39098
|
-
runtime.
|
|
39099
|
-
|
|
39164
|
+
const desiredPosition = new runtime.THREE.Vector3(target.x + distance * Math.cos(pitch) * Math.sin(yaw), target.y + distance * Math.sin(pitch), target.z + distance * Math.cos(pitch) * Math.cos(yaw));
|
|
39165
|
+
const smoothing = (currentRenderOptions?.style3d ?? "symbolic") === "cinematic" ? 0.16 : 0.32;
|
|
39166
|
+
if (!smoothedCameraPosition || !smoothedCameraTarget) {
|
|
39167
|
+
smoothedCameraPosition = desiredPosition.clone();
|
|
39168
|
+
smoothedCameraTarget = target.clone();
|
|
39169
|
+
} else {
|
|
39170
|
+
smoothedCameraPosition.lerp(desiredPosition, smoothing);
|
|
39171
|
+
smoothedCameraTarget.lerp(target, smoothing);
|
|
39172
|
+
}
|
|
39173
|
+
runtime.camera.position.copy(smoothedCameraPosition);
|
|
39174
|
+
runtime.camera.lookAt(smoothedCameraTarget);
|
|
39100
39175
|
if (sceneCamera?.roll) {
|
|
39101
39176
|
runtime.camera.rotation.z = degreesToRadians3(sceneCamera.roll);
|
|
39102
39177
|
}
|
|
39103
|
-
runtime.keyLight.position.copy(runtime.camera.position);
|
|
39104
39178
|
}
|
|
39105
39179
|
function resizeRenderer(spatialScene) {
|
|
39106
39180
|
if (!runtime) {
|
|
@@ -39112,35 +39186,63 @@ void main() {
|
|
|
39112
39186
|
runtime.camera.aspect = width / height;
|
|
39113
39187
|
runtime.camera.updateProjectionMatrix();
|
|
39114
39188
|
}
|
|
39115
|
-
function renderNow() {
|
|
39116
|
-
if (!runtime) {
|
|
39117
|
-
return;
|
|
39118
|
-
}
|
|
39119
|
-
runtime.renderer.render(runtime.scene3d, runtime.camera);
|
|
39120
|
-
}
|
|
39121
39189
|
}
|
|
39122
39190
|
function createObjectVisual(THREE, object, theme) {
|
|
39123
39191
|
const root = new THREE.Group();
|
|
39124
39192
|
root.userData.objectId = object.objectId;
|
|
39125
39193
|
const baseColor = object.fillColor ?? colorForObject(object);
|
|
39126
|
-
const
|
|
39127
|
-
|
|
39128
|
-
|
|
39129
|
-
emissiveIntensity: object.object.type === "star" ? 0.6 : 0.08,
|
|
39130
|
-
transparent: true,
|
|
39131
|
-
opacity: object.object.type === "phenomenon" ? 0.7 : 1
|
|
39132
|
-
});
|
|
39133
|
-
const geometry = geometryForObject(THREE, object);
|
|
39134
|
-
const body = new THREE.Mesh(geometry, material);
|
|
39194
|
+
const materials = [];
|
|
39195
|
+
const bodyMaterial = materialForObject(THREE, object, baseColor, theme);
|
|
39196
|
+
const body = new THREE.Mesh(geometryForObject(THREE, object), bodyMaterial.material);
|
|
39135
39197
|
body.userData.objectId = object.objectId;
|
|
39136
39198
|
root.add(body);
|
|
39137
|
-
|
|
39138
|
-
|
|
39139
|
-
|
|
39140
|
-
|
|
39141
|
-
|
|
39142
|
-
|
|
39143
|
-
|
|
39199
|
+
materials.push(bodyMaterial);
|
|
39200
|
+
if (shouldRenderAtmosphere(object)) {
|
|
39201
|
+
const atmosphereMaterial = {
|
|
39202
|
+
material: new THREE.MeshBasicMaterial({
|
|
39203
|
+
color: theme.atmosphere,
|
|
39204
|
+
transparent: true,
|
|
39205
|
+
opacity: 0.24,
|
|
39206
|
+
depthWrite: false,
|
|
39207
|
+
side: 2
|
|
39208
|
+
}),
|
|
39209
|
+
baseColor: theme.atmosphere,
|
|
39210
|
+
baseOpacity: 0.24,
|
|
39211
|
+
hoveredOpacity: 0.34,
|
|
39212
|
+
selectedOpacity: 0.42
|
|
39213
|
+
};
|
|
39214
|
+
const atmosphere = new THREE.Mesh(new THREE.SphereGeometry(Math.max(object.visualRadius, 2) * 1.16, 20, 14), atmosphereMaterial.material);
|
|
39215
|
+
atmosphere.userData.objectId = object.objectId;
|
|
39216
|
+
root.add(atmosphere);
|
|
39217
|
+
materials.push(atmosphereMaterial);
|
|
39218
|
+
}
|
|
39219
|
+
if (object.object.type === "comet") {
|
|
39220
|
+
const tailMaterial = {
|
|
39221
|
+
material: new THREE.MeshBasicMaterial({
|
|
39222
|
+
color: theme.cometTail,
|
|
39223
|
+
transparent: true,
|
|
39224
|
+
opacity: 0.36,
|
|
39225
|
+
depthWrite: false
|
|
39226
|
+
}),
|
|
39227
|
+
baseColor: theme.cometTail,
|
|
39228
|
+
baseOpacity: 0.36,
|
|
39229
|
+
hoveredOpacity: 0.48,
|
|
39230
|
+
selectedOpacity: 0.56
|
|
39231
|
+
};
|
|
39232
|
+
const tail = new THREE.Mesh(new THREE.ConeGeometry(Math.max(object.visualRadius * 0.55, 2), Math.max(object.visualRadius * 2.8, 8), 12, 1, true), tailMaterial.material);
|
|
39233
|
+
tail.position.set(-Math.max(object.visualRadius * 1.4, 4), 0, 0);
|
|
39234
|
+
tail.rotation.z = -Math.PI / 2;
|
|
39235
|
+
tail.userData.objectId = object.objectId;
|
|
39236
|
+
root.add(tail);
|
|
39237
|
+
materials.push(tailMaterial);
|
|
39238
|
+
}
|
|
39239
|
+
const halo = createHalo(THREE, object, theme);
|
|
39240
|
+
if (halo) {
|
|
39241
|
+
halo.visible = false;
|
|
39242
|
+
halo.userData.objectId = object.objectId;
|
|
39243
|
+
root.add(halo);
|
|
39244
|
+
}
|
|
39245
|
+
return { objectId: object.objectId, root, halo, materials };
|
|
39144
39246
|
}
|
|
39145
39247
|
function createOrbitVisual2(THREE, orbit, theme) {
|
|
39146
39248
|
const root = new THREE.Group();
|
|
@@ -39148,60 +39250,174 @@ void main() {
|
|
|
39148
39250
|
root.rotation.y = degreesToRadians3(orbit.rotationDeg);
|
|
39149
39251
|
root.rotation.x = degreesToRadians3(orbit.inclinationDeg);
|
|
39150
39252
|
const baseColor = orbit.object.properties.color ?? theme.orbit;
|
|
39151
|
-
const materials = [];
|
|
39152
39253
|
if (orbit.band) {
|
|
39153
|
-
const
|
|
39154
|
-
|
|
39155
|
-
|
|
39156
|
-
|
|
39157
|
-
|
|
39158
|
-
|
|
39159
|
-
|
|
39160
|
-
|
|
39254
|
+
const material2 = {
|
|
39255
|
+
material: new THREE.MeshBasicMaterial({
|
|
39256
|
+
color: baseColor,
|
|
39257
|
+
transparent: true,
|
|
39258
|
+
opacity: theme.orbitBandOpacity,
|
|
39259
|
+
side: 2,
|
|
39260
|
+
depthWrite: false
|
|
39261
|
+
}),
|
|
39262
|
+
baseColor,
|
|
39263
|
+
baseOpacity: theme.orbitBandOpacity,
|
|
39264
|
+
hoveredOpacity: Math.min(theme.orbitBandOpacity + 0.1, 0.58),
|
|
39265
|
+
selectedOpacity: Math.min(theme.orbitBandOpacity + 0.18, 0.72),
|
|
39266
|
+
hoveredColor: theme.accent,
|
|
39267
|
+
selectedColor: theme.accentStrong
|
|
39268
|
+
};
|
|
39269
|
+
const mesh = new THREE.Mesh(bandGeometryForOrbit(THREE, orbit), material2.material);
|
|
39161
39270
|
mesh.userData.objectId = orbit.objectId;
|
|
39162
39271
|
root.add(mesh);
|
|
39163
|
-
materials
|
|
39164
|
-
}
|
|
39165
|
-
|
|
39272
|
+
return { objectId: orbit.objectId, root, materials: [material2] };
|
|
39273
|
+
}
|
|
39274
|
+
const material = {
|
|
39275
|
+
material: new THREE.LineBasicMaterial({
|
|
39166
39276
|
color: baseColor,
|
|
39167
39277
|
transparent: true,
|
|
39168
|
-
opacity:
|
|
39169
|
-
})
|
|
39170
|
-
|
|
39171
|
-
|
|
39172
|
-
|
|
39173
|
-
|
|
39174
|
-
|
|
39175
|
-
|
|
39176
|
-
}
|
|
39278
|
+
opacity: theme.orbitOpacity
|
|
39279
|
+
}),
|
|
39280
|
+
baseColor,
|
|
39281
|
+
baseOpacity: theme.orbitOpacity,
|
|
39282
|
+
hoveredOpacity: Math.min(theme.orbitOpacity + 0.18, 0.72),
|
|
39283
|
+
selectedOpacity: Math.min(theme.orbitOpacity + 0.3, 0.88),
|
|
39284
|
+
hoveredColor: theme.accent,
|
|
39285
|
+
selectedColor: theme.accentStrong
|
|
39286
|
+
};
|
|
39287
|
+
const geometry = new THREE.BufferGeometry().setFromPoints(sampleOrbitPoints(THREE, orbit, 120));
|
|
39288
|
+
const line = new THREE.LineLoop(geometry, material.material);
|
|
39289
|
+
line.userData.objectId = orbit.objectId;
|
|
39290
|
+
root.add(line);
|
|
39291
|
+
return { objectId: orbit.objectId, root, materials: [material] };
|
|
39292
|
+
}
|
|
39293
|
+
function materialForObject(THREE, object, baseColor, theme) {
|
|
39294
|
+
if (object.object.type === "star") {
|
|
39295
|
+
return {
|
|
39296
|
+
material: new THREE.MeshStandardMaterial({
|
|
39297
|
+
color: baseColor,
|
|
39298
|
+
emissive: new THREE.Color(theme.starGlow),
|
|
39299
|
+
emissiveIntensity: 1.2,
|
|
39300
|
+
roughness: 0.35,
|
|
39301
|
+
metalness: 0.02
|
|
39302
|
+
}),
|
|
39303
|
+
baseColor,
|
|
39304
|
+
baseOpacity: 1,
|
|
39305
|
+
hoveredOpacity: 1,
|
|
39306
|
+
selectedOpacity: 1,
|
|
39307
|
+
hoveredColor: theme.starCore,
|
|
39308
|
+
selectedColor: "#fff2c4",
|
|
39309
|
+
baseEmissive: theme.starGlow,
|
|
39310
|
+
hoveredEmissive: theme.starGlow,
|
|
39311
|
+
selectedEmissive: "#fff6cc",
|
|
39312
|
+
baseEmissiveIntensity: 1.2,
|
|
39313
|
+
hoveredEmissiveIntensity: 1.5,
|
|
39314
|
+
selectedEmissiveIntensity: 1.8
|
|
39315
|
+
};
|
|
39316
|
+
}
|
|
39317
|
+
if (object.object.type === "phenomenon") {
|
|
39318
|
+
return {
|
|
39319
|
+
material: new THREE.MeshPhongMaterial({
|
|
39320
|
+
color: baseColor,
|
|
39321
|
+
transparent: true,
|
|
39322
|
+
opacity: 0.7,
|
|
39323
|
+
emissive: new THREE.Color(baseColor),
|
|
39324
|
+
emissiveIntensity: 0.32,
|
|
39325
|
+
shininess: 90
|
|
39326
|
+
}),
|
|
39327
|
+
baseColor,
|
|
39328
|
+
baseOpacity: 0.7,
|
|
39329
|
+
hoveredOpacity: 0.82,
|
|
39330
|
+
selectedOpacity: 0.9,
|
|
39331
|
+
hoveredColor: theme.accent,
|
|
39332
|
+
selectedColor: theme.selectionHalo,
|
|
39333
|
+
baseEmissive: baseColor,
|
|
39334
|
+
hoveredEmissive: theme.accent,
|
|
39335
|
+
selectedEmissive: theme.selectionHalo,
|
|
39336
|
+
baseEmissiveIntensity: 0.32,
|
|
39337
|
+
hoveredEmissiveIntensity: 0.52,
|
|
39338
|
+
selectedEmissiveIntensity: 0.74
|
|
39339
|
+
};
|
|
39340
|
+
}
|
|
39341
|
+
const shininess = object.object.type === "structure" ? 70 : object.object.type === "ring" ? 42 : object.object.type === "belt" ? 26 : 36;
|
|
39177
39342
|
return {
|
|
39178
|
-
|
|
39179
|
-
|
|
39180
|
-
|
|
39181
|
-
|
|
39343
|
+
material: new THREE.MeshPhongMaterial({
|
|
39344
|
+
color: baseColor,
|
|
39345
|
+
specular: new THREE.Color(theme.objectSpecular),
|
|
39346
|
+
shininess,
|
|
39347
|
+
transparent: false,
|
|
39348
|
+
opacity: 1,
|
|
39349
|
+
emissive: new THREE.Color(0),
|
|
39350
|
+
emissiveIntensity: 0.02
|
|
39351
|
+
}),
|
|
39352
|
+
baseColor,
|
|
39353
|
+
baseOpacity: 1,
|
|
39354
|
+
hoveredOpacity: 1,
|
|
39355
|
+
selectedOpacity: 1,
|
|
39356
|
+
hoveredColor: shiftColorLightness(THREE, baseColor, 0.08),
|
|
39357
|
+
selectedColor: shiftColorLightness(THREE, baseColor, 0.16),
|
|
39358
|
+
hoveredEmissive: "#8fcaff",
|
|
39359
|
+
selectedEmissive: theme.selectionHalo,
|
|
39360
|
+
baseEmissiveIntensity: 0.02,
|
|
39361
|
+
hoveredEmissiveIntensity: 0.12,
|
|
39362
|
+
selectedEmissiveIntensity: 0.22
|
|
39182
39363
|
};
|
|
39183
39364
|
}
|
|
39184
39365
|
function geometryForObject(THREE, object) {
|
|
39185
39366
|
const radius = Math.max(object.visualRadius, 2);
|
|
39186
39367
|
switch (object.object.type) {
|
|
39187
39368
|
case "star":
|
|
39188
|
-
return new THREE.SphereGeometry(radius * 1.
|
|
39369
|
+
return new THREE.SphereGeometry(radius * 1.14, 34, 24);
|
|
39189
39370
|
case "structure":
|
|
39190
|
-
return
|
|
39371
|
+
return geometryForStructure(THREE, object, radius);
|
|
39191
39372
|
case "phenomenon":
|
|
39192
|
-
return new THREE.
|
|
39373
|
+
return new THREE.IcosahedronGeometry(radius * 1.12, 1);
|
|
39193
39374
|
case "belt":
|
|
39375
|
+
return new THREE.TorusGeometry(Math.max(radius * 1.15, 4), Math.max(radius * 0.28, 1), 10, 24);
|
|
39194
39376
|
case "ring":
|
|
39195
|
-
return new THREE.
|
|
39377
|
+
return new THREE.TorusGeometry(Math.max(radius, 4), Math.max(radius * 0.18, 0.8), 10, 30);
|
|
39378
|
+
case "asteroid":
|
|
39379
|
+
return new THREE.DodecahedronGeometry(radius, 0);
|
|
39380
|
+
case "comet":
|
|
39381
|
+
return new THREE.SphereGeometry(radius * 0.94, 18, 14);
|
|
39196
39382
|
default:
|
|
39197
|
-
return new THREE.SphereGeometry(radius,
|
|
39383
|
+
return new THREE.SphereGeometry(radius, 24, 18);
|
|
39384
|
+
}
|
|
39385
|
+
}
|
|
39386
|
+
function geometryForStructure(THREE, object, radius) {
|
|
39387
|
+
const kind = String(object.object.properties.kind ?? "").toLowerCase();
|
|
39388
|
+
if (kind.includes("relay")) {
|
|
39389
|
+
return new THREE.OctahedronGeometry(radius * 1.15, 0);
|
|
39390
|
+
}
|
|
39391
|
+
if (kind.includes("elevator") || kind.includes("skyhook")) {
|
|
39392
|
+
return new THREE.CylinderGeometry(radius * 0.36, radius * 0.52, radius * 2.4, 10);
|
|
39393
|
+
}
|
|
39394
|
+
if (kind.includes("station")) {
|
|
39395
|
+
return new THREE.TorusKnotGeometry(radius * 0.6, Math.max(radius * 0.18, 0.6), 42, 8);
|
|
39396
|
+
}
|
|
39397
|
+
return new THREE.BoxGeometry(radius * 1.45, radius * 1.2, radius * 1.45);
|
|
39398
|
+
}
|
|
39399
|
+
function createHalo(THREE, object, theme) {
|
|
39400
|
+
const radius = Math.max(object.visualRadius, 2);
|
|
39401
|
+
const geometry = object.object.type === "structure" ? new THREE.BoxGeometry(radius * 2.2, radius * 2.2, radius * 2.2) : new THREE.SphereGeometry(radius * 1.38, 18, 14);
|
|
39402
|
+
return new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
|
|
39403
|
+
color: theme.selectionHalo,
|
|
39404
|
+
transparent: true,
|
|
39405
|
+
opacity: 0.18,
|
|
39406
|
+
depthWrite: false,
|
|
39407
|
+
side: 1
|
|
39408
|
+
}));
|
|
39409
|
+
}
|
|
39410
|
+
function shouldRenderAtmosphere(object) {
|
|
39411
|
+
if (object.object.type !== "planet" && object.object.type !== "moon") {
|
|
39412
|
+
return false;
|
|
39198
39413
|
}
|
|
39414
|
+
return object.object.properties.atmosphere !== void 0;
|
|
39199
39415
|
}
|
|
39200
39416
|
function bandGeometryForOrbit(THREE, orbit) {
|
|
39201
39417
|
const thickness = Math.max(orbit.bandThickness ?? 8, 3);
|
|
39202
39418
|
const points = sampleOrbitPoints(THREE, orbit, 72);
|
|
39203
39419
|
const curve = new THREE.CatmullRomCurve3(points, true);
|
|
39204
|
-
return new THREE.TubeGeometry(curve,
|
|
39420
|
+
return new THREE.TubeGeometry(curve, 144, thickness * 0.18, 10, true);
|
|
39205
39421
|
}
|
|
39206
39422
|
function sampleOrbitPoints(THREE, orbit, segments = 96) {
|
|
39207
39423
|
const points = [];
|
|
@@ -39213,6 +39429,94 @@ void main() {
|
|
|
39213
39429
|
}
|
|
39214
39430
|
return points;
|
|
39215
39431
|
}
|
|
39432
|
+
function createStarfield(THREE, count) {
|
|
39433
|
+
const geometry = new THREE.BufferGeometry();
|
|
39434
|
+
const positions = new Float32Array(count * 3);
|
|
39435
|
+
const colors = new Float32Array(count * 3);
|
|
39436
|
+
for (let index = 0; index < count; index += 1) {
|
|
39437
|
+
const offset = index * 3;
|
|
39438
|
+
const radius = 1800 + Math.random() * 2600;
|
|
39439
|
+
const theta = Math.random() * Math.PI * 2;
|
|
39440
|
+
const phi = Math.acos(2 * Math.random() - 1);
|
|
39441
|
+
positions[offset] = radius * Math.sin(phi) * Math.cos(theta);
|
|
39442
|
+
positions[offset + 1] = radius * Math.cos(phi) * 0.45;
|
|
39443
|
+
positions[offset + 2] = radius * Math.sin(phi) * Math.sin(theta);
|
|
39444
|
+
}
|
|
39445
|
+
geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
|
|
39446
|
+
geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
|
|
39447
|
+
return new THREE.Points(geometry, new THREE.PointsMaterial({
|
|
39448
|
+
size: 5,
|
|
39449
|
+
transparent: true,
|
|
39450
|
+
opacity: 0.84,
|
|
39451
|
+
depthWrite: false,
|
|
39452
|
+
vertexColors: true,
|
|
39453
|
+
sizeAttenuation: true
|
|
39454
|
+
}));
|
|
39455
|
+
}
|
|
39456
|
+
function configureRenderer(renderer, THREE, quality) {
|
|
39457
|
+
const pixelRatioCap = quality === "high" ? 2.4 : quality === "low" ? 1.2 : 1.8;
|
|
39458
|
+
renderer.setPixelRatio?.(Math.min(globalThis.window?.devicePixelRatio ?? 1, pixelRatioCap));
|
|
39459
|
+
if ("outputColorSpace" in renderer && "SRGBColorSpace" in THREE) {
|
|
39460
|
+
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
|
39461
|
+
} else if ("outputEncoding" in renderer && "sRGBEncoding" in THREE) {
|
|
39462
|
+
renderer.outputEncoding = THREE.sRGBEncoding;
|
|
39463
|
+
}
|
|
39464
|
+
if ("ACESFilmicToneMapping" in THREE) {
|
|
39465
|
+
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
|
39466
|
+
}
|
|
39467
|
+
}
|
|
39468
|
+
function updateEnvironment(runtime, renderOptions) {
|
|
39469
|
+
const theme = resolveTheme(renderOptions?.theme);
|
|
39470
|
+
const quality = renderOptions?.quality ?? "balanced";
|
|
39471
|
+
const style3d = renderOptions?.style3d ?? "symbolic";
|
|
39472
|
+
const count = quality === "high" ? 520 : quality === "low" ? 180 : 320;
|
|
39473
|
+
const positions = new Float32Array(count * 3);
|
|
39474
|
+
const colors = new Float32Array(count * 3);
|
|
39475
|
+
const bright = new runtime.THREE.Color(theme.starfield);
|
|
39476
|
+
const dim = new runtime.THREE.Color(theme.starfieldDim);
|
|
39477
|
+
for (let index = 0; index < count; index += 1) {
|
|
39478
|
+
const offset = index * 3;
|
|
39479
|
+
const radius = 1800 + Math.random() * 2600;
|
|
39480
|
+
const theta = Math.random() * Math.PI * 2;
|
|
39481
|
+
const phi = Math.acos(2 * Math.random() - 1);
|
|
39482
|
+
positions[offset] = radius * Math.sin(phi) * Math.cos(theta);
|
|
39483
|
+
positions[offset + 1] = radius * Math.cos(phi) * 0.45;
|
|
39484
|
+
positions[offset + 2] = radius * Math.sin(phi) * Math.sin(theta);
|
|
39485
|
+
const color = Math.random() > 0.72 ? bright : dim;
|
|
39486
|
+
colors[offset] = color.r;
|
|
39487
|
+
colors[offset + 1] = color.g;
|
|
39488
|
+
colors[offset + 2] = color.b;
|
|
39489
|
+
}
|
|
39490
|
+
runtime.scene3d.background = new runtime.THREE.Color(theme.backgroundStart);
|
|
39491
|
+
runtime.scene3d.fog = new runtime.THREE.FogExp2(theme.spaceFog, 85e-5);
|
|
39492
|
+
runtime.ambientLight.intensity = style3d === "cinematic" ? 0.18 : 0.26;
|
|
39493
|
+
runtime.fillLight.intensity = style3d === "cinematic" ? 0.32 : 0.4;
|
|
39494
|
+
runtime.rimLight.intensity = style3d === "cinematic" ? 0.28 : 0.22;
|
|
39495
|
+
runtime.renderer.toneMappingExposure = style3d === "cinematic" ? 1.18 : 1.08;
|
|
39496
|
+
runtime.starfield.geometry.setAttribute("position", new runtime.THREE.BufferAttribute(positions, 3));
|
|
39497
|
+
runtime.starfield.geometry.setAttribute("color", new runtime.THREE.BufferAttribute(colors, 3));
|
|
39498
|
+
runtime.starfield.material.opacity = quality === "high" ? 0.96 : quality === "low" ? 0.72 : 0.84;
|
|
39499
|
+
runtime.starfield.material.size = quality === "high" ? 5.5 : quality === "low" ? 4.25 : 5;
|
|
39500
|
+
}
|
|
39501
|
+
function applyVisualState(THREE, materials, selected, hovered) {
|
|
39502
|
+
for (const entry of materials) {
|
|
39503
|
+
const material = entry.material;
|
|
39504
|
+
if (!material) {
|
|
39505
|
+
continue;
|
|
39506
|
+
}
|
|
39507
|
+
const color = selected ? entry.selectedColor ?? entry.baseColor : hovered ? entry.hoveredColor ?? entry.baseColor : entry.baseColor;
|
|
39508
|
+
material.color?.set?.(new THREE.Color(color));
|
|
39509
|
+
if (typeof material.opacity === "number") {
|
|
39510
|
+
material.opacity = selected ? entry.selectedOpacity : hovered ? entry.hoveredOpacity : entry.baseOpacity;
|
|
39511
|
+
material.transparent = material.opacity < 0.999;
|
|
39512
|
+
}
|
|
39513
|
+
const emissive = selected ? entry.selectedEmissive ?? entry.baseEmissive : hovered ? entry.hoveredEmissive ?? entry.baseEmissive : entry.baseEmissive;
|
|
39514
|
+
material.emissive?.set?.(emissive ? new THREE.Color(emissive) : new THREE.Color(0));
|
|
39515
|
+
if ("emissiveIntensity" in material) {
|
|
39516
|
+
material.emissiveIntensity = selected ? entry.selectedEmissiveIntensity ?? entry.baseEmissiveIntensity ?? 0 : hovered ? entry.hoveredEmissiveIntensity ?? entry.baseEmissiveIntensity ?? 0 : entry.baseEmissiveIntensity ?? 0;
|
|
39517
|
+
}
|
|
39518
|
+
}
|
|
39519
|
+
}
|
|
39216
39520
|
function colorForObject(object) {
|
|
39217
39521
|
switch (object.object.type) {
|
|
39218
39522
|
case "star":
|
|
@@ -39235,35 +39539,23 @@ void main() {
|
|
|
39235
39539
|
return "#b8f2ff";
|
|
39236
39540
|
}
|
|
39237
39541
|
}
|
|
39238
|
-
function
|
|
39239
|
-
const color = new THREE.Color(
|
|
39240
|
-
|
|
39241
|
-
|
|
39242
|
-
} else if (hovered) {
|
|
39243
|
-
color.offsetHSL(0, 0, 0.08);
|
|
39244
|
-
}
|
|
39245
|
-
for (const material of materials) {
|
|
39246
|
-
if (!material) {
|
|
39247
|
-
continue;
|
|
39248
|
-
}
|
|
39249
|
-
material.color?.set?.(color);
|
|
39250
|
-
if (typeof material.opacity === "number") {
|
|
39251
|
-
material.opacity = selected ? 0.85 : hovered ? 0.72 : material.transparent ? 0.55 : 1;
|
|
39252
|
-
}
|
|
39253
|
-
material.emissive?.set?.(selected ? new THREE.Color("#ffdda9") : hovered ? new THREE.Color("#cfe9ff") : new THREE.Color(0));
|
|
39254
|
-
material.emissiveIntensity = selected ? 0.28 : hovered ? 0.14 : material.emissiveIntensity ?? 0.08;
|
|
39255
|
-
}
|
|
39542
|
+
function shiftColorLightness(THREE, colorValue, delta) {
|
|
39543
|
+
const color = new THREE.Color(colorValue);
|
|
39544
|
+
color.offsetHSL(0, 0, delta);
|
|
39545
|
+
return `#${color.getHexString()}`;
|
|
39256
39546
|
}
|
|
39257
39547
|
function clearGroup(group) {
|
|
39258
39548
|
while (group.children.length > 0) {
|
|
39259
39549
|
const child = group.children[0];
|
|
39260
39550
|
group.remove(child);
|
|
39261
|
-
child.
|
|
39262
|
-
|
|
39263
|
-
|
|
39264
|
-
|
|
39265
|
-
|
|
39266
|
-
|
|
39551
|
+
child.traverse?.((node) => {
|
|
39552
|
+
node.geometry?.dispose?.();
|
|
39553
|
+
if (Array.isArray(node.material)) {
|
|
39554
|
+
node.material.forEach((entry) => entry?.dispose?.());
|
|
39555
|
+
} else {
|
|
39556
|
+
node.material?.dispose?.();
|
|
39557
|
+
}
|
|
39558
|
+
});
|
|
39267
39559
|
}
|
|
39268
39560
|
}
|
|
39269
39561
|
function ensureWebGLSupport() {
|
|
@@ -39527,6 +39819,8 @@ void main() {
|
|
|
39527
39819
|
preset: options.preset,
|
|
39528
39820
|
projection: options.projection,
|
|
39529
39821
|
viewMode: options.viewMode ?? "2d",
|
|
39822
|
+
quality: options.quality ?? "balanced",
|
|
39823
|
+
style3d: options.style3d ?? "symbolic",
|
|
39530
39824
|
camera: options.camera ? { ...options.camera } : null,
|
|
39531
39825
|
scaleModel: options.scaleModel ? { ...options.scaleModel } : void 0,
|
|
39532
39826
|
theme: options.theme,
|
|
@@ -39546,6 +39840,7 @@ void main() {
|
|
|
39546
39840
|
let cameraRoot = null;
|
|
39547
39841
|
let runtime3d = null;
|
|
39548
39842
|
let minimapRoot = null;
|
|
39843
|
+
let labelRoot = null;
|
|
39549
39844
|
let tooltipRoot = null;
|
|
39550
39845
|
let suppressClick = false;
|
|
39551
39846
|
let activePointerId = null;
|
|
@@ -39570,7 +39865,7 @@ void main() {
|
|
|
39570
39865
|
if (previousTabIndex === null) {
|
|
39571
39866
|
container.tabIndex = 0;
|
|
39572
39867
|
}
|
|
39573
|
-
|
|
39868
|
+
installViewerOverlayStyles();
|
|
39574
39869
|
container.classList.add("wo-viewer-container");
|
|
39575
39870
|
container.style.touchAction = behavior.touch ? "none" : previousTouchAction;
|
|
39576
39871
|
if (!container.style.position) {
|
|
@@ -40120,6 +40415,8 @@ void main() {
|
|
|
40120
40415
|
stopAnimationLoop();
|
|
40121
40416
|
runtime3d?.destroy();
|
|
40122
40417
|
runtime3d = null;
|
|
40418
|
+
labelRoot?.remove();
|
|
40419
|
+
labelRoot = null;
|
|
40123
40420
|
tooltipRoot?.remove();
|
|
40124
40421
|
tooltipRoot = null;
|
|
40125
40422
|
minimapRoot?.remove();
|
|
@@ -40150,6 +40447,7 @@ void main() {
|
|
|
40150
40447
|
svgElement = null;
|
|
40151
40448
|
cameraRoot = null;
|
|
40152
40449
|
minimapRoot = null;
|
|
40450
|
+
labelRoot = null;
|
|
40153
40451
|
tooltipRoot = null;
|
|
40154
40452
|
if (is3DView()) {
|
|
40155
40453
|
spatialScene = spatialScene ?? renderSpatialSceneFromInput(currentInput, renderOptions, providedSpatialScene);
|
|
@@ -40168,6 +40466,10 @@ void main() {
|
|
|
40168
40466
|
minimapRoot.dataset.worldorbitMinimapRoot = "true";
|
|
40169
40467
|
container.append(minimapRoot);
|
|
40170
40468
|
}
|
|
40469
|
+
labelRoot = document.createElement("div");
|
|
40470
|
+
labelRoot.className = "wo-viewer-label-root";
|
|
40471
|
+
labelRoot.dataset.worldorbitLabelRoot = "true";
|
|
40472
|
+
container.append(labelRoot);
|
|
40171
40473
|
if (behavior.tooltipMode !== "disabled") {
|
|
40172
40474
|
tooltipRoot = document.createElement("div");
|
|
40173
40475
|
tooltipRoot.className = "wo-viewer-tooltip-root";
|
|
@@ -40179,6 +40481,7 @@ void main() {
|
|
|
40179
40481
|
if (!is3DView() && (!svgElement || !cameraRoot)) {
|
|
40180
40482
|
throw new Error("Interactive viewer could not locate the rendered SVG camera root.");
|
|
40181
40483
|
}
|
|
40484
|
+
suppressStaticLabelLayers();
|
|
40182
40485
|
state = resetView ? is3DView() ? { ...DEFAULT_VIEWER_STATE } : fitViewerState(scene, { ...DEFAULT_VIEWER_STATE }, constraints) : sanitizeState(state);
|
|
40183
40486
|
applySelection(state.selectedObjectId && getObjectById(state.selectedObjectId) ? state.selectedObjectId : null, false);
|
|
40184
40487
|
applyHover(hoveredObjectId && getObjectById(hoveredObjectId) ? hoveredObjectId : null, false);
|
|
@@ -40213,19 +40516,24 @@ void main() {
|
|
|
40213
40516
|
return;
|
|
40214
40517
|
}
|
|
40215
40518
|
cameraRoot.setAttribute("transform", composeViewerTransform(scene, state));
|
|
40519
|
+
updateScreenLabels();
|
|
40216
40520
|
updateMinimap();
|
|
40217
40521
|
updateTooltip();
|
|
40218
40522
|
}
|
|
40219
40523
|
function applySelection(objectId, emitCallback = true) {
|
|
40220
40524
|
if (!is3DView() && state.selectedObjectId) {
|
|
40221
|
-
container.
|
|
40525
|
+
for (const element of container.querySelectorAll(`[data-object-id="${cssEscape(state.selectedObjectId)}"]`)) {
|
|
40526
|
+
element.classList.remove("wo-object-selected");
|
|
40527
|
+
}
|
|
40222
40528
|
}
|
|
40223
40529
|
state = {
|
|
40224
40530
|
...state,
|
|
40225
40531
|
selectedObjectId: objectId && getObjectById(objectId) ? objectId : null
|
|
40226
40532
|
};
|
|
40227
40533
|
if (!is3DView() && state.selectedObjectId) {
|
|
40228
|
-
container.
|
|
40534
|
+
for (const element of container.querySelectorAll(`[data-object-id="${cssEscape(state.selectedObjectId)}"]`)) {
|
|
40535
|
+
element.classList.add("wo-object-selected");
|
|
40536
|
+
}
|
|
40229
40537
|
}
|
|
40230
40538
|
syncAtlasHighlights();
|
|
40231
40539
|
updateTooltip();
|
|
@@ -40558,14 +40866,17 @@ void main() {
|
|
|
40558
40866
|
};
|
|
40559
40867
|
}
|
|
40560
40868
|
function project2DTooltipPoint(renderObject) {
|
|
40561
|
-
if (!svgElement) {
|
|
40562
|
-
return null;
|
|
40563
|
-
}
|
|
40564
40869
|
const anchor = {
|
|
40565
40870
|
x: renderObject.anchorX ?? renderObject.x,
|
|
40566
40871
|
y: renderObject.anchorY ?? renderObject.y - Math.max(renderObject.visualRadius, renderObject.radius)
|
|
40567
40872
|
};
|
|
40568
|
-
|
|
40873
|
+
return project2DScenePointToContainer(anchor);
|
|
40874
|
+
}
|
|
40875
|
+
function project2DScenePointToContainer(point) {
|
|
40876
|
+
if (!svgElement) {
|
|
40877
|
+
return null;
|
|
40878
|
+
}
|
|
40879
|
+
const viewportPoint = projectWorldPoint(point);
|
|
40569
40880
|
const svgRect = svgElement.getBoundingClientRect();
|
|
40570
40881
|
const containerRect = container.getBoundingClientRect();
|
|
40571
40882
|
return {
|
|
@@ -40664,9 +40975,182 @@ void main() {
|
|
|
40664
40975
|
state,
|
|
40665
40976
|
timeSeconds: animationState.timeSeconds
|
|
40666
40977
|
});
|
|
40978
|
+
updateScreenLabels();
|
|
40667
40979
|
updateMinimap();
|
|
40668
40980
|
updateTooltip();
|
|
40669
40981
|
}
|
|
40982
|
+
function suppressStaticLabelLayers() {
|
|
40983
|
+
if (is3DView()) {
|
|
40984
|
+
return;
|
|
40985
|
+
}
|
|
40986
|
+
container.querySelector('[data-layer-id="labels"]')?.setAttribute("display", "none");
|
|
40987
|
+
for (const element of container.querySelectorAll(".wo-event-label")) {
|
|
40988
|
+
element.setAttribute("display", "none");
|
|
40989
|
+
}
|
|
40990
|
+
}
|
|
40991
|
+
function updateScreenLabels() {
|
|
40992
|
+
if (!labelRoot) {
|
|
40993
|
+
return;
|
|
40994
|
+
}
|
|
40995
|
+
const descriptors = buildScreenLabelDescriptors();
|
|
40996
|
+
labelRoot.replaceChildren(...descriptors.map((descriptor) => createScreenLabelElement(descriptor)));
|
|
40997
|
+
labelRoot.hidden = descriptors.length === 0;
|
|
40998
|
+
}
|
|
40999
|
+
function buildScreenLabelDescriptors() {
|
|
41000
|
+
const descriptors = [];
|
|
41001
|
+
const visibleObjectIds = getVisibleObjectIds();
|
|
41002
|
+
if (layerEnabled("labels")) {
|
|
41003
|
+
for (const label of scene.labels) {
|
|
41004
|
+
if (label.hidden || !visibleObjectIds.has(label.objectId)) {
|
|
41005
|
+
continue;
|
|
41006
|
+
}
|
|
41007
|
+
if (is3DView() && !shouldRender3DLabel(label.objectId, visibleObjectIds)) {
|
|
41008
|
+
continue;
|
|
41009
|
+
}
|
|
41010
|
+
const point = is3DView() ? runtime3d?.projectObjectToContainer(label.objectId) ?? null : project2DScenePointToContainer({ x: label.x, y: label.y });
|
|
41011
|
+
if (!point) {
|
|
41012
|
+
continue;
|
|
41013
|
+
}
|
|
41014
|
+
descriptors.push({
|
|
41015
|
+
key: `object:${label.renderId}`,
|
|
41016
|
+
kind: "object",
|
|
41017
|
+
point: is3DView() ? { x: point.x, y: point.y - 18 } : point,
|
|
41018
|
+
textAnchor: label.textAnchor,
|
|
41019
|
+
objectId: label.objectId,
|
|
41020
|
+
primaryText: label.label,
|
|
41021
|
+
secondaryText: label.secondaryLabel,
|
|
41022
|
+
secondaryOffset: Math.max(label.secondaryY - label.y, 12)
|
|
41023
|
+
});
|
|
41024
|
+
}
|
|
41025
|
+
}
|
|
41026
|
+
if (!is3DView() && layerEnabled("events")) {
|
|
41027
|
+
for (const event of scene.events) {
|
|
41028
|
+
if (event.hidden || !isEventVisible(event, visibleObjectIds)) {
|
|
41029
|
+
continue;
|
|
41030
|
+
}
|
|
41031
|
+
const point = project2DScenePointToContainer({ x: event.x, y: event.y - 10 });
|
|
41032
|
+
if (!point) {
|
|
41033
|
+
continue;
|
|
41034
|
+
}
|
|
41035
|
+
descriptors.push({
|
|
41036
|
+
key: `event:${event.renderId}`,
|
|
41037
|
+
kind: "event",
|
|
41038
|
+
point,
|
|
41039
|
+
textAnchor: "middle",
|
|
41040
|
+
primaryText: event.event.label || event.event.id
|
|
41041
|
+
});
|
|
41042
|
+
}
|
|
41043
|
+
}
|
|
41044
|
+
return descriptors;
|
|
41045
|
+
}
|
|
41046
|
+
function isEventVisible(event, visibleObjectIds) {
|
|
41047
|
+
return event.objectIds.some((objectId) => visibleObjectIds.has(objectId));
|
|
41048
|
+
}
|
|
41049
|
+
function shouldRender3DLabel(objectId, visibleObjectIds) {
|
|
41050
|
+
if (!is3DView()) {
|
|
41051
|
+
return true;
|
|
41052
|
+
}
|
|
41053
|
+
if (objectId === state.selectedObjectId || objectId === hoveredObjectId) {
|
|
41054
|
+
return true;
|
|
41055
|
+
}
|
|
41056
|
+
const object = getObjectById(objectId);
|
|
41057
|
+
if (!object || object.hidden || !visibleObjectIds.has(objectId)) {
|
|
41058
|
+
return false;
|
|
41059
|
+
}
|
|
41060
|
+
if (object.object.type === "star") {
|
|
41061
|
+
return true;
|
|
41062
|
+
}
|
|
41063
|
+
const selected = state.selectedObjectId ? buildObjectDetails(state.selectedObjectId) : null;
|
|
41064
|
+
const hovered = hoveredObjectId ? buildObjectDetails(hoveredObjectId) : null;
|
|
41065
|
+
const selectedFocus = selected ? /* @__PURE__ */ new Set([
|
|
41066
|
+
selected.objectId,
|
|
41067
|
+
...selected.renderObject.ancestorIds,
|
|
41068
|
+
...selected.renderObject.childIds
|
|
41069
|
+
]) : null;
|
|
41070
|
+
const hoveredFocus = hovered ? /* @__PURE__ */ new Set([
|
|
41071
|
+
hovered.objectId,
|
|
41072
|
+
...hovered.renderObject.ancestorIds,
|
|
41073
|
+
...hovered.renderObject.childIds
|
|
41074
|
+
]) : null;
|
|
41075
|
+
if (selectedFocus?.has(objectId) || hoveredFocus?.has(objectId)) {
|
|
41076
|
+
return true;
|
|
41077
|
+
}
|
|
41078
|
+
if (object.semanticGroupIds.length > 0 && object.visualRadius >= 12) {
|
|
41079
|
+
return true;
|
|
41080
|
+
}
|
|
41081
|
+
return object.childIds.length > 0 && object.visualRadius >= 10;
|
|
41082
|
+
}
|
|
41083
|
+
function createScreenLabelElement(descriptor) {
|
|
41084
|
+
const element = document.createElement("div");
|
|
41085
|
+
element.className = `wo-viewer-label wo-viewer-label-${descriptor.kind}`;
|
|
41086
|
+
element.dataset.worldorbitScreenLabel = "true";
|
|
41087
|
+
element.dataset.labelKey = descriptor.key;
|
|
41088
|
+
element.dataset.anchor = descriptor.textAnchor;
|
|
41089
|
+
element.style.left = `${descriptor.point.x}px`;
|
|
41090
|
+
element.style.top = `${descriptor.point.y}px`;
|
|
41091
|
+
if (descriptor.objectId) {
|
|
41092
|
+
element.dataset.objectId = descriptor.objectId;
|
|
41093
|
+
for (const className of resolveScreenLabelClasses(descriptor.objectId)) {
|
|
41094
|
+
element.classList.add(className);
|
|
41095
|
+
}
|
|
41096
|
+
}
|
|
41097
|
+
const primary = document.createElement("span");
|
|
41098
|
+
primary.className = "wo-viewer-label-primary";
|
|
41099
|
+
if (descriptor.kind === "object") {
|
|
41100
|
+
primary.style.fontSize = `${14 * scene.scaleModel.labelMultiplier}px`;
|
|
41101
|
+
}
|
|
41102
|
+
primary.textContent = descriptor.primaryText;
|
|
41103
|
+
element.append(primary);
|
|
41104
|
+
if (descriptor.secondaryText) {
|
|
41105
|
+
const secondary = document.createElement("span");
|
|
41106
|
+
secondary.className = "wo-viewer-label-secondary";
|
|
41107
|
+
secondary.style.fontSize = `${11 * scene.scaleModel.labelMultiplier}px`;
|
|
41108
|
+
secondary.style.marginTop = `${Math.max(descriptor.secondaryOffset ?? 12, 10) - 10}px`;
|
|
41109
|
+
secondary.textContent = descriptor.secondaryText;
|
|
41110
|
+
element.append(secondary);
|
|
41111
|
+
}
|
|
41112
|
+
return element;
|
|
41113
|
+
}
|
|
41114
|
+
function layerEnabled(id) {
|
|
41115
|
+
return renderOptions.layers?.[id] !== false;
|
|
41116
|
+
}
|
|
41117
|
+
function resolveScreenLabelClasses(objectId) {
|
|
41118
|
+
const classes = [];
|
|
41119
|
+
const selectedDetails = buildObjectDetails(state.selectedObjectId);
|
|
41120
|
+
const hoveredDetails = buildObjectDetails(hoveredObjectId);
|
|
41121
|
+
if (state.selectedObjectId === objectId) {
|
|
41122
|
+
classes.push("wo-object-selected");
|
|
41123
|
+
}
|
|
41124
|
+
if (selectedDetails) {
|
|
41125
|
+
const selectedChain = /* @__PURE__ */ new Set([
|
|
41126
|
+
selectedDetails.objectId,
|
|
41127
|
+
...selectedDetails.renderObject.childIds,
|
|
41128
|
+
...selectedDetails.renderObject.ancestorIds
|
|
41129
|
+
]);
|
|
41130
|
+
const selectedAncestors = new Set(selectedDetails.ancestors.map((ancestor) => ancestor.objectId));
|
|
41131
|
+
if (selectedChain.has(objectId)) {
|
|
41132
|
+
classes.push("wo-chain-selected");
|
|
41133
|
+
}
|
|
41134
|
+
if (selectedAncestors.has(objectId)) {
|
|
41135
|
+
classes.push("wo-ancestor-selected");
|
|
41136
|
+
}
|
|
41137
|
+
}
|
|
41138
|
+
if (hoveredDetails) {
|
|
41139
|
+
const hoveredChain = /* @__PURE__ */ new Set([
|
|
41140
|
+
hoveredDetails.objectId,
|
|
41141
|
+
...hoveredDetails.renderObject.childIds,
|
|
41142
|
+
...hoveredDetails.renderObject.ancestorIds
|
|
41143
|
+
]);
|
|
41144
|
+
const hoveredAncestors = new Set(hoveredDetails.ancestors.map((ancestor) => ancestor.objectId));
|
|
41145
|
+
if (hoveredChain.has(objectId)) {
|
|
41146
|
+
classes.push("wo-chain-hover");
|
|
41147
|
+
}
|
|
41148
|
+
if (hoveredAncestors.has(objectId)) {
|
|
41149
|
+
classes.push("wo-ancestor-hover");
|
|
41150
|
+
}
|
|
41151
|
+
}
|
|
41152
|
+
return classes;
|
|
41153
|
+
}
|
|
40670
41154
|
function create3DFocusState(objectId) {
|
|
40671
41155
|
const target = spatialScene?.focusTargets.find((entry) => entry.objectId === objectId);
|
|
40672
41156
|
if (!target) {
|
|
@@ -40732,7 +41216,9 @@ void main() {
|
|
|
40732
41216
|
layers: renderOptions.layers ? { ...renderOptions.layers } : void 0,
|
|
40733
41217
|
theme: renderOptions.theme && typeof renderOptions.theme === "object" ? { ...renderOptions.theme } : renderOptions.theme,
|
|
40734
41218
|
activeEventId: renderOptions.activeEventId ?? null,
|
|
40735
|
-
viewMode: renderOptions.viewMode ?? "2d"
|
|
41219
|
+
viewMode: renderOptions.viewMode ?? "2d",
|
|
41220
|
+
quality: renderOptions.quality ?? "balanced",
|
|
41221
|
+
style3d: renderOptions.style3d ?? "symbolic"
|
|
40736
41222
|
};
|
|
40737
41223
|
}
|
|
40738
41224
|
function mergeRenderOptions(current, next) {
|
|
@@ -40750,7 +41236,9 @@ void main() {
|
|
|
40750
41236
|
...next.layers
|
|
40751
41237
|
} : current.layers ? { ...current.layers } : void 0,
|
|
40752
41238
|
theme: next.theme && typeof next.theme === "object" ? { ...next.theme } : next.theme ?? current.theme,
|
|
40753
|
-
viewMode: next.viewMode ?? current.viewMode ?? "2d"
|
|
41239
|
+
viewMode: next.viewMode ?? current.viewMode ?? "2d",
|
|
41240
|
+
quality: next.quality ?? current.quality ?? "balanced",
|
|
41241
|
+
style3d: next.style3d ?? current.style3d ?? "symbolic"
|
|
40754
41242
|
};
|
|
40755
41243
|
}
|
|
40756
41244
|
function hasSceneAffectingRenderOptions(options) {
|
|
@@ -40918,7 +41406,7 @@ void main() {
|
|
|
40918
41406
|
}
|
|
40919
41407
|
return value.replace(/["\\]/g, "\\$&");
|
|
40920
41408
|
}
|
|
40921
|
-
function
|
|
41409
|
+
function installViewerOverlayStyles() {
|
|
40922
41410
|
if (typeof document === "undefined" || document.getElementById(TOOLTIP_STYLE_ID)) {
|
|
40923
41411
|
return;
|
|
40924
41412
|
}
|
|
@@ -40953,6 +41441,60 @@ void main() {
|
|
|
40953
41441
|
height: 100%;
|
|
40954
41442
|
min-height: 320px;
|
|
40955
41443
|
}
|
|
41444
|
+
.wo-viewer-label-root {
|
|
41445
|
+
position: absolute;
|
|
41446
|
+
inset: 0;
|
|
41447
|
+
z-index: 8;
|
|
41448
|
+
pointer-events: none;
|
|
41449
|
+
overflow: hidden;
|
|
41450
|
+
}
|
|
41451
|
+
.wo-viewer-label {
|
|
41452
|
+
position: absolute;
|
|
41453
|
+
display: grid;
|
|
41454
|
+
gap: 2px;
|
|
41455
|
+
padding: 4px 8px;
|
|
41456
|
+
border-radius: 999px;
|
|
41457
|
+
background: linear-gradient(180deg, rgba(5, 16, 26, 0.72), rgba(5, 16, 26, 0.38));
|
|
41458
|
+
border: 1px solid rgba(164, 194, 228, 0.16);
|
|
41459
|
+
color: #edf6ff;
|
|
41460
|
+
font-family: "Segoe UI Variable", "Segoe UI", sans-serif;
|
|
41461
|
+
line-height: 1.15;
|
|
41462
|
+
text-shadow: 0 1px 2px rgba(7, 16, 25, 0.65), 0 0 18px rgba(7, 16, 25, 0.18);
|
|
41463
|
+
white-space: nowrap;
|
|
41464
|
+
}
|
|
41465
|
+
.wo-viewer-label[data-anchor="middle"] { transform: translate(-50%, 0); }
|
|
41466
|
+
.wo-viewer-label[data-anchor="end"] { transform: translate(-100%, 0); }
|
|
41467
|
+
.wo-viewer-label-primary {
|
|
41468
|
+
font-size: 14px;
|
|
41469
|
+
font-weight: 600;
|
|
41470
|
+
letter-spacing: 0.02em;
|
|
41471
|
+
}
|
|
41472
|
+
.wo-viewer-label-secondary {
|
|
41473
|
+
font-size: 11px;
|
|
41474
|
+
font-weight: 500;
|
|
41475
|
+
color: rgba(237, 246, 255, 0.72);
|
|
41476
|
+
}
|
|
41477
|
+
.wo-viewer-label-event {
|
|
41478
|
+
color: #ffce8a;
|
|
41479
|
+
text-transform: uppercase;
|
|
41480
|
+
letter-spacing: 0.04em;
|
|
41481
|
+
}
|
|
41482
|
+
.wo-viewer-label-event .wo-viewer-label-primary {
|
|
41483
|
+
font-size: 10px;
|
|
41484
|
+
font-weight: 700;
|
|
41485
|
+
}
|
|
41486
|
+
.wo-viewer-label.wo-object-selected .wo-viewer-label-primary,
|
|
41487
|
+
.wo-viewer-label.wo-chain-selected .wo-viewer-label-primary,
|
|
41488
|
+
.wo-viewer-label.wo-chain-hover .wo-viewer-label-primary {
|
|
41489
|
+
color: #ffce8a;
|
|
41490
|
+
}
|
|
41491
|
+
.wo-viewer-label.wo-object-selected .wo-viewer-label-secondary {
|
|
41492
|
+
color: #8fcaff;
|
|
41493
|
+
}
|
|
41494
|
+
.wo-viewer-label.wo-ancestor-selected .wo-viewer-label-primary,
|
|
41495
|
+
.wo-viewer-label.wo-ancestor-hover .wo-viewer-label-primary {
|
|
41496
|
+
opacity: 0.82;
|
|
41497
|
+
}
|
|
40956
41498
|
.wo-viewer-tooltip-root {
|
|
40957
41499
|
position: absolute;
|
|
40958
41500
|
z-index: 12;
|
|
@@ -41087,6 +41629,7 @@ void main() {
|
|
|
41087
41629
|
}
|
|
41088
41630
|
function mountWorldOrbitEmbeds(root = document, options = {}) {
|
|
41089
41631
|
const viewers = /* @__PURE__ */ new Map();
|
|
41632
|
+
const cleanupCallbacks = [];
|
|
41090
41633
|
const elements = [...root.querySelectorAll(EMBED_SELECTOR)];
|
|
41091
41634
|
for (const element of elements) {
|
|
41092
41635
|
const payload = deserializePayloadFromElement(element);
|
|
@@ -41100,14 +41643,16 @@ void main() {
|
|
|
41100
41643
|
const initialSelectionObjectId = options.viewer?.initialSelectionObjectId ?? payload.options?.initialSelectionObjectId;
|
|
41101
41644
|
const minimap = options.viewer?.minimap ?? payload.options?.minimap;
|
|
41102
41645
|
const viewMode = options.viewer?.viewMode ?? payload.options?.viewMode ?? embedModeToViewMode(mode);
|
|
41646
|
+
const measureViewport = () => resolveEmbedViewport(element, payload.scene, options);
|
|
41103
41647
|
if (mode === "interactive-2d" || mode === "interactive-3d") {
|
|
41104
41648
|
try {
|
|
41649
|
+
const viewport = measureViewport();
|
|
41105
41650
|
const viewer = createInteractiveViewer(element, {
|
|
41106
41651
|
...options.viewer,
|
|
41107
41652
|
scene: payload.scene,
|
|
41108
41653
|
spatialScene: payload.spatialScene,
|
|
41109
|
-
width:
|
|
41110
|
-
height:
|
|
41654
|
+
width: viewport.width,
|
|
41655
|
+
height: viewport.height,
|
|
41111
41656
|
padding: options.padding ?? payload.scene.padding,
|
|
41112
41657
|
preset,
|
|
41113
41658
|
theme,
|
|
@@ -41123,6 +41668,13 @@ void main() {
|
|
|
41123
41668
|
viewer.setAtlasState(payload.options.atlasState);
|
|
41124
41669
|
}
|
|
41125
41670
|
viewers.set(element, viewer);
|
|
41671
|
+
cleanupCallbacks.push(bindEmbedResize(element, () => {
|
|
41672
|
+
const nextViewport = measureViewport();
|
|
41673
|
+
viewer.setRenderOptions({
|
|
41674
|
+
width: nextViewport.width,
|
|
41675
|
+
height: nextViewport.height
|
|
41676
|
+
});
|
|
41677
|
+
}));
|
|
41126
41678
|
options.onMount?.(viewer, element);
|
|
41127
41679
|
} catch (error2) {
|
|
41128
41680
|
if (error2 instanceof WorldOrbit3DUnavailableError && mode === "interactive-3d") {
|
|
@@ -41133,17 +41685,22 @@ void main() {
|
|
|
41133
41685
|
}
|
|
41134
41686
|
}
|
|
41135
41687
|
} else {
|
|
41136
|
-
|
|
41137
|
-
|
|
41138
|
-
|
|
41139
|
-
|
|
41140
|
-
|
|
41141
|
-
|
|
41142
|
-
|
|
41143
|
-
|
|
41144
|
-
|
|
41145
|
-
|
|
41146
|
-
|
|
41688
|
+
const renderStaticEmbed = () => {
|
|
41689
|
+
const viewport = measureViewport();
|
|
41690
|
+
element.innerHTML = renderSceneToSvg(payload.scene, {
|
|
41691
|
+
width: viewport.width,
|
|
41692
|
+
height: viewport.height,
|
|
41693
|
+
padding: options.padding ?? payload.scene.padding,
|
|
41694
|
+
preset,
|
|
41695
|
+
theme,
|
|
41696
|
+
layers,
|
|
41697
|
+
filter: initialFilter,
|
|
41698
|
+
selectedObjectId: initialSelectionObjectId ?? null,
|
|
41699
|
+
subtitle
|
|
41700
|
+
});
|
|
41701
|
+
};
|
|
41702
|
+
renderStaticEmbed();
|
|
41703
|
+
cleanupCallbacks.push(bindEmbedResize(element, renderStaticEmbed));
|
|
41147
41704
|
options.onMount?.(null, element);
|
|
41148
41705
|
}
|
|
41149
41706
|
element.dataset.worldorbitMounted = "true";
|
|
@@ -41151,14 +41708,65 @@ void main() {
|
|
|
41151
41708
|
return {
|
|
41152
41709
|
viewers: [...viewers.values()],
|
|
41153
41710
|
destroy() {
|
|
41711
|
+
for (const cleanup of cleanupCallbacks) {
|
|
41712
|
+
cleanup();
|
|
41713
|
+
}
|
|
41154
41714
|
for (const [element, viewer] of viewers.entries()) {
|
|
41155
41715
|
viewer.destroy();
|
|
41156
41716
|
element.removeAttribute("data-worldorbit-mounted");
|
|
41157
41717
|
}
|
|
41718
|
+
for (const element of elements) {
|
|
41719
|
+
element.removeAttribute("data-worldorbit-mounted");
|
|
41720
|
+
}
|
|
41158
41721
|
viewers.clear();
|
|
41159
41722
|
}
|
|
41160
41723
|
};
|
|
41161
41724
|
}
|
|
41725
|
+
function resolveEmbedViewport(element, scene, options) {
|
|
41726
|
+
const rect = element.getBoundingClientRect();
|
|
41727
|
+
const width = sanitizeViewportDimension(options.width) ?? sanitizeViewportDimension(element.clientWidth) ?? sanitizeViewportDimension(rect.width) ?? scene.width;
|
|
41728
|
+
const explicitHeight = sanitizeViewportDimension(options.height) ?? sanitizeViewportDimension(element.clientHeight) ?? sanitizeViewportDimension(rect.height);
|
|
41729
|
+
const fallbackHeight = Math.max(Math.round(width * (scene.height / Math.max(scene.width, 1))), Math.min(scene.height, 240));
|
|
41730
|
+
return {
|
|
41731
|
+
width,
|
|
41732
|
+
height: explicitHeight ?? fallbackHeight
|
|
41733
|
+
};
|
|
41734
|
+
}
|
|
41735
|
+
function sanitizeViewportDimension(value) {
|
|
41736
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.round(value) : null;
|
|
41737
|
+
}
|
|
41738
|
+
function bindEmbedResize(element, callback) {
|
|
41739
|
+
let lastWidth = -1;
|
|
41740
|
+
let lastHeight = -1;
|
|
41741
|
+
const run = () => {
|
|
41742
|
+
const rect = element.getBoundingClientRect();
|
|
41743
|
+
const nextWidth = Math.round(Math.max(element.clientWidth || rect.width, 0));
|
|
41744
|
+
const nextHeight = Math.round(Math.max(element.clientHeight || rect.height, 0));
|
|
41745
|
+
if (nextWidth === lastWidth && nextHeight === lastHeight) {
|
|
41746
|
+
return;
|
|
41747
|
+
}
|
|
41748
|
+
lastWidth = nextWidth;
|
|
41749
|
+
lastHeight = nextHeight;
|
|
41750
|
+
callback();
|
|
41751
|
+
};
|
|
41752
|
+
run();
|
|
41753
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
41754
|
+
const observer = new ResizeObserver(() => {
|
|
41755
|
+
run();
|
|
41756
|
+
});
|
|
41757
|
+
observer.observe(element);
|
|
41758
|
+
return () => {
|
|
41759
|
+
observer.disconnect();
|
|
41760
|
+
};
|
|
41761
|
+
}
|
|
41762
|
+
const handleWindowResize = () => {
|
|
41763
|
+
run();
|
|
41764
|
+
};
|
|
41765
|
+
window.addEventListener("resize", handleWindowResize);
|
|
41766
|
+
return () => {
|
|
41767
|
+
window.removeEventListener("resize", handleWindowResize);
|
|
41768
|
+
};
|
|
41769
|
+
}
|
|
41162
41770
|
function deserializePayloadFromElement(element) {
|
|
41163
41771
|
const serialized = element.dataset.worldorbitPayload;
|
|
41164
41772
|
if (!serialized) {
|