worldorbit 3.1.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/core/dist/atlas-edit.js +1 -1
- package/dist/browser/core/dist/atlas-validate.js +1 -1
- package/dist/browser/core/dist/draft-parse.js +7 -5
- package/dist/browser/core/dist/draft.js +2 -2
- package/dist/browser/core/dist/format.js +5 -5
- package/dist/browser/core/dist/load.js +7 -3
- package/dist/browser/core/dist/scene.js +99 -17
- package/dist/browser/core/dist/spatial-scene.js +1 -0
- package/dist/browser/core/dist/types.d.ts +4 -1
- package/dist/browser/editor/dist/editor.js +55 -12
- package/dist/browser/viewer/dist/atlas-state.js +3 -0
- package/dist/browser/viewer/dist/types.d.ts +1 -0
- package/dist/browser/viewer/dist/viewer.js +2 -0
- package/dist/unpkg/core/dist/atlas-edit.js +1 -1
- package/dist/unpkg/core/dist/atlas-validate.js +1 -1
- package/dist/unpkg/core/dist/draft-parse.js +7 -5
- package/dist/unpkg/core/dist/draft.js +2 -2
- package/dist/unpkg/core/dist/format.js +5 -5
- package/dist/unpkg/core/dist/load.js +7 -3
- package/dist/unpkg/core/dist/scene.js +99 -17
- package/dist/unpkg/core/dist/spatial-scene.js +1 -0
- package/dist/unpkg/core/dist/types.d.ts +4 -1
- package/dist/unpkg/editor/dist/editor.js +55 -12
- package/dist/unpkg/viewer/dist/atlas-state.js +3 -0
- package/dist/unpkg/viewer/dist/types.d.ts +1 -0
- package/dist/unpkg/viewer/dist/viewer.js +2 -0
- package/dist/unpkg/worldorbit-core.min.js +12 -12
- package/dist/unpkg/worldorbit-editor.min.js +313 -313
- package/dist/unpkg/worldorbit-markdown.min.js +23 -23
- package/dist/unpkg/worldorbit-viewer.min.js +203 -203
- package/dist/unpkg/worldorbit.js +119 -37
- package/dist/unpkg/worldorbit.min.js +206 -206
- package/package.json +1 -1
- package/packages/core/dist/atlas-edit.js +1 -1
- package/packages/core/dist/atlas-validate.js +1 -1
- package/packages/core/dist/draft-parse.js +7 -5
- package/packages/core/dist/draft.js +2 -2
- package/packages/core/dist/format.js +5 -5
- package/packages/core/dist/load.js +7 -3
- package/packages/core/dist/scene.js +99 -17
- package/packages/core/dist/spatial-scene.js +1 -0
- package/packages/core/dist/types.d.ts +4 -1
- package/packages/editor/dist/editor.js +55 -12
- package/packages/viewer/dist/atlas-state.js +3 -0
- package/packages/viewer/dist/types.d.ts +1 -0
- package/packages/viewer/dist/viewer.js +2 -0
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { collectAtlasDiagnostics } from "./atlas-validate.js";
|
|
2
|
-
export function createEmptyAtlasDocument(systemId = "WorldOrbit", version = "2.6
|
|
2
|
+
export function createEmptyAtlasDocument(systemId = "WorldOrbit", version = "2.6") {
|
|
3
3
|
return {
|
|
4
4
|
format: "worldorbit",
|
|
5
5
|
version,
|
|
@@ -67,7 +67,7 @@ function validateRelation(relation, objectMap, diagnostics) {
|
|
|
67
67
|
}
|
|
68
68
|
function validateViewpoint(viewpoint, groupIds, eventIds, sourceSchemaVersion, diagnostics, objectMap) {
|
|
69
69
|
const filter = viewpoint.filter;
|
|
70
|
-
if (sourceSchemaVersion === "2.1" || sourceSchemaVersion === "2.5" || sourceSchemaVersion === "2.6
|
|
70
|
+
if (sourceSchemaVersion === "2.1" || sourceSchemaVersion === "2.5" || sourceSchemaVersion === "2.6") {
|
|
71
71
|
if (filter) {
|
|
72
72
|
for (const groupId of filter.groupIds) {
|
|
73
73
|
if (!groupIds.has(groupId)) {
|
|
@@ -210,12 +210,12 @@ function parseAtlasSource(source, forcedOutputVersion) {
|
|
|
210
210
|
function assertDraftSchemaHeader(tokens, line) {
|
|
211
211
|
if (tokens.length !== 2 ||
|
|
212
212
|
tokens[0].value.toLowerCase() !== "schema" ||
|
|
213
|
-
!["2.0-draft", "2.0", "2.1", "2.5", "2.6
|
|
214
|
-
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", "schema 2.5", "schema 2.6
|
|
213
|
+
!["2.0-draft", "2.0", "2.1", "2.5", "2.6"].includes(tokens[1].value.toLowerCase())) {
|
|
214
|
+
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", "schema 2.5", "schema 2.6", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
215
215
|
}
|
|
216
216
|
const version = tokens[1].value.toLowerCase();
|
|
217
|
-
return version === "2.6
|
|
218
|
-
? "2.6
|
|
217
|
+
return version === "2.6"
|
|
218
|
+
? "2.6"
|
|
219
219
|
: version === "2.5"
|
|
220
220
|
? "2.5"
|
|
221
221
|
: version === "2.1"
|
|
@@ -1566,8 +1566,10 @@ function schemaVersionRank(version) {
|
|
|
1566
1566
|
return 2;
|
|
1567
1567
|
case "2.5":
|
|
1568
1568
|
return 3;
|
|
1569
|
-
case "2.6
|
|
1569
|
+
case "2.6":
|
|
1570
1570
|
return 4;
|
|
1571
|
+
default:
|
|
1572
|
+
return 5;
|
|
1571
1573
|
}
|
|
1572
1574
|
}
|
|
1573
1575
|
function preprocessAtlasSource(source) {
|
|
@@ -18,8 +18,8 @@ export function upgradeDocumentToV2(document, options = {}) {
|
|
|
18
18
|
}
|
|
19
19
|
return {
|
|
20
20
|
format: "worldorbit",
|
|
21
|
-
version: "2.6
|
|
22
|
-
schemaVersion: "2.6
|
|
21
|
+
version: "2.6",
|
|
22
|
+
schemaVersion: "2.6",
|
|
23
23
|
sourceVersion: document.version,
|
|
24
24
|
theme: document.theme ?? null,
|
|
25
25
|
system,
|
|
@@ -39,18 +39,18 @@ export function formatDocument(document, options = {}) {
|
|
|
39
39
|
const useDraft = schema === "2.0" ||
|
|
40
40
|
schema === "2.1" ||
|
|
41
41
|
schema === "2.5" ||
|
|
42
|
-
schema === "2.6
|
|
42
|
+
schema === "2.6" ||
|
|
43
43
|
schema === "2.0-draft" ||
|
|
44
44
|
document.version === "2.0" ||
|
|
45
45
|
document.version === "2.1" ||
|
|
46
46
|
document.version === "2.5" ||
|
|
47
|
-
document.version === "2.6
|
|
47
|
+
document.version === "2.6" ||
|
|
48
48
|
document.version === "2.0-draft";
|
|
49
49
|
if (useDraft) {
|
|
50
50
|
if (schema === "2.0-draft") {
|
|
51
51
|
const legacyDraftDocument = document.version === "2.0-draft"
|
|
52
52
|
? document
|
|
53
|
-
: document.version === "2.0" || document.version === "2.1" || document.version === "2.5" || document.version === "2.6
|
|
53
|
+
: document.version === "2.0" || document.version === "2.1" || document.version === "2.5" || document.version === "2.6"
|
|
54
54
|
? {
|
|
55
55
|
...document,
|
|
56
56
|
version: "2.0-draft",
|
|
@@ -59,7 +59,7 @@ export function formatDocument(document, options = {}) {
|
|
|
59
59
|
: upgradeDocumentToDraftV2(document);
|
|
60
60
|
return formatDraftDocument(legacyDraftDocument);
|
|
61
61
|
}
|
|
62
|
-
const atlasDocument = document.version === "2.0" || document.version === "2.1" || document.version === "2.5" || document.version === "2.6
|
|
62
|
+
const atlasDocument = document.version === "2.0" || document.version === "2.1" || document.version === "2.5" || document.version === "2.6"
|
|
63
63
|
? document
|
|
64
64
|
: document.version === "2.0-draft"
|
|
65
65
|
? {
|
|
@@ -68,7 +68,7 @@ export function formatDocument(document, options = {}) {
|
|
|
68
68
|
schemaVersion: "2.0",
|
|
69
69
|
}
|
|
70
70
|
: upgradeDocumentToV2(document);
|
|
71
|
-
if ((schema === "2.0" || schema === "2.1" || schema === "2.5" || schema === "2.6
|
|
71
|
+
if ((schema === "2.0" || schema === "2.1" || schema === "2.5" || schema === "2.6") && atlasDocument.version !== schema) {
|
|
72
72
|
return formatAtlasDocument({
|
|
73
73
|
...atlasDocument,
|
|
74
74
|
version: schema,
|
|
@@ -5,9 +5,10 @@ import { WorldOrbitError } from "./errors.js";
|
|
|
5
5
|
import { normalizeDocument } from "./normalize.js";
|
|
6
6
|
import { parseWorldOrbit } from "./parse.js";
|
|
7
7
|
import { validateDocument } from "./validate.js";
|
|
8
|
-
const ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1|\.5)?$/i;
|
|
8
|
+
const ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1|\.5|\.6)?$/i;
|
|
9
9
|
const ATLAS_SCHEMA_21_PATTERN = /^schema\s+2\.1$/i;
|
|
10
10
|
const ATLAS_SCHEMA_25_PATTERN = /^schema\s+2\.5$/i;
|
|
11
|
+
const ATLAS_SCHEMA_26_PATTERN = /^schema\s+2\.6$/i;
|
|
11
12
|
const LEGACY_DRAFT_SCHEMA_PATTERN = /^schema\s+2\.0-draft$/i;
|
|
12
13
|
export function detectWorldOrbitSchemaVersion(source) {
|
|
13
14
|
for (const line of stripCommentsForSchemaDetection(source).split(/\r?\n/)) {
|
|
@@ -22,7 +23,10 @@ export function detectWorldOrbitSchemaVersion(source) {
|
|
|
22
23
|
return "2.1";
|
|
23
24
|
}
|
|
24
25
|
if (ATLAS_SCHEMA_25_PATTERN.test(trimmed)) {
|
|
25
|
-
return "2.
|
|
26
|
+
return "2.5";
|
|
27
|
+
}
|
|
28
|
+
if (ATLAS_SCHEMA_26_PATTERN.test(trimmed)) {
|
|
29
|
+
return "2.6";
|
|
26
30
|
}
|
|
27
31
|
if (ATLAS_SCHEMA_PATTERN.test(trimmed)) {
|
|
28
32
|
return "2.0";
|
|
@@ -88,7 +92,7 @@ export function loadWorldOrbitSourceWithDiagnostics(source) {
|
|
|
88
92
|
schemaVersion === "2.0-draft" ||
|
|
89
93
|
schemaVersion === "2.1" ||
|
|
90
94
|
schemaVersion === "2.5" ||
|
|
91
|
-
schemaVersion === "2.6
|
|
95
|
+
schemaVersion === "2.6") {
|
|
92
96
|
return loadAtlasSourceWithDiagnostics(source, schemaVersion);
|
|
93
97
|
}
|
|
94
98
|
let ast;
|
|
@@ -17,11 +17,12 @@ export function renderDocumentToScene(document, options = {}) {
|
|
|
17
17
|
const schemaProjection = resolveProjection(document, options.projection);
|
|
18
18
|
const camera = normalizeViewCamera(options.camera ?? null);
|
|
19
19
|
const renderProjection = resolveRenderProjection(schemaProjection, camera);
|
|
20
|
-
const scaleModel = resolveScaleModel(layoutPreset, options.scaleModel);
|
|
21
20
|
const spacingFactor = layoutPresetSpacing(layoutPreset);
|
|
21
|
+
const scaleModel = resolveScaleModel(layoutPreset, options.scaleModel, options.bodyScaleMode);
|
|
22
22
|
const systemId = document.system?.id ?? null;
|
|
23
23
|
const activeEventId = options.activeEventId ?? null;
|
|
24
24
|
const effectiveObjects = createEffectiveObjects(document.objects, document.events ?? [], activeEventId);
|
|
25
|
+
const sceneMetricScale = resolveSceneMetricScale(effectiveObjects, width, height, padding, spacingFactor, scaleModel);
|
|
25
26
|
const objectMap = new Map(effectiveObjects.map((object) => [object.id, object]));
|
|
26
27
|
const relationships = buildSceneRelationships(effectiveObjects, objectMap);
|
|
27
28
|
const positions = new Map();
|
|
@@ -61,6 +62,7 @@ export function renderDocumentToScene(document, options = {}) {
|
|
|
61
62
|
spacingFactor,
|
|
62
63
|
projection: renderProjection,
|
|
63
64
|
scaleModel,
|
|
65
|
+
sceneMetricScale,
|
|
64
66
|
};
|
|
65
67
|
const primaryRoot = rootObjects.find((object) => object.type === "star") ?? rootObjects[0] ?? null;
|
|
66
68
|
if (primaryRoot) {
|
|
@@ -82,14 +84,14 @@ export function renderDocumentToScene(document, options = {}) {
|
|
|
82
84
|
const x = width -
|
|
83
85
|
padding -
|
|
84
86
|
140 -
|
|
85
|
-
freePlacementOffsetPx(object.placement?.mode === "free" ? object.placement.distance : undefined, scaleModel);
|
|
87
|
+
freePlacementOffsetPx(object.placement?.mode === "free" ? object.placement.distance : undefined, scaleModel, sceneMetricScale);
|
|
86
88
|
const rowStep = Math.max(76, ((height - padding * 2 - 180) / Math.max(1, freeObjects.length)) * spacingFactor) * scaleModel.freePlacementMultiplier;
|
|
87
89
|
const y = padding + 92 + index * rowStep;
|
|
88
90
|
positions.set(object.id, {
|
|
89
91
|
object,
|
|
90
92
|
x,
|
|
91
93
|
y,
|
|
92
|
-
radius: visualRadiusFor(object, 0, scaleModel),
|
|
94
|
+
radius: visualRadiusFor(object, 0, scaleModel, sceneMetricScale),
|
|
93
95
|
sortKey: computeSortKey(x, y, 0),
|
|
94
96
|
});
|
|
95
97
|
leaderDrafts.push({
|
|
@@ -112,7 +114,7 @@ export function renderDocumentToScene(document, options = {}) {
|
|
|
112
114
|
object,
|
|
113
115
|
x: resolved.x,
|
|
114
116
|
y: resolved.y,
|
|
115
|
-
radius: visualRadiusFor(object, 2, scaleModel),
|
|
117
|
+
radius: visualRadiusFor(object, 2, scaleModel, sceneMetricScale),
|
|
116
118
|
sortKey: computeSortKey(resolved.x, resolved.y, 2),
|
|
117
119
|
anchorX: resolved.anchorX,
|
|
118
120
|
anchorY: resolved.anchorY,
|
|
@@ -164,6 +166,7 @@ export function renderDocumentToScene(document, options = {}) {
|
|
|
164
166
|
scale: String(document.system?.properties.scale ?? layoutPreset),
|
|
165
167
|
units: String(document.system?.properties.units ?? "mixed"),
|
|
166
168
|
preset: frame.preset ?? "custom",
|
|
169
|
+
"body.scaleMode": scaleModel.bodyScaleMode,
|
|
167
170
|
...(camera?.azimuth !== null ? { "camera.azimuth": String(camera?.azimuth) } : {}),
|
|
168
171
|
...(camera?.elevation !== null ? { "camera.elevation": String(camera?.elevation) } : {}),
|
|
169
172
|
...(camera?.roll !== null ? { "camera.roll": String(camera?.roll) } : {}),
|
|
@@ -344,10 +347,11 @@ function buildSceneSubtitle(projection, renderProjection, layoutPreset, camera)
|
|
|
344
347
|
}
|
|
345
348
|
return parts.join(" - ");
|
|
346
349
|
}
|
|
347
|
-
function resolveScaleModel(layoutPreset, overrides) {
|
|
350
|
+
function resolveScaleModel(layoutPreset, overrides, bodyScaleMode) {
|
|
348
351
|
const defaults = defaultScaleModel(layoutPreset);
|
|
349
352
|
return {
|
|
350
353
|
...defaults,
|
|
354
|
+
...(bodyScaleMode ? { bodyScaleMode } : {}),
|
|
351
355
|
...overrides,
|
|
352
356
|
};
|
|
353
357
|
}
|
|
@@ -362,6 +366,7 @@ function defaultScaleModel(layoutPreset) {
|
|
|
362
366
|
ringThicknessMultiplier: 0.92,
|
|
363
367
|
minBodyRadius: 4,
|
|
364
368
|
maxBodyRadius: 36,
|
|
369
|
+
bodyScaleMode: "readable",
|
|
365
370
|
};
|
|
366
371
|
case "presentation":
|
|
367
372
|
return {
|
|
@@ -372,6 +377,7 @@ function defaultScaleModel(layoutPreset) {
|
|
|
372
377
|
ringThicknessMultiplier: 1.16,
|
|
373
378
|
minBodyRadius: 5,
|
|
374
379
|
maxBodyRadius: 48,
|
|
380
|
+
bodyScaleMode: "readable",
|
|
375
381
|
};
|
|
376
382
|
default:
|
|
377
383
|
return {
|
|
@@ -382,6 +388,7 @@ function defaultScaleModel(layoutPreset) {
|
|
|
382
388
|
ringThicknessMultiplier: 1,
|
|
383
389
|
minBodyRadius: 4,
|
|
384
390
|
maxBodyRadius: 40,
|
|
391
|
+
bodyScaleMode: "readable",
|
|
385
392
|
};
|
|
386
393
|
}
|
|
387
394
|
}
|
|
@@ -395,6 +402,51 @@ function layoutPresetSpacing(layoutPreset) {
|
|
|
395
402
|
return 1;
|
|
396
403
|
}
|
|
397
404
|
}
|
|
405
|
+
function resolveSceneMetricScale(objects, width, height, padding, spacingFactor, scaleModel) {
|
|
406
|
+
const orbitMetrics = [];
|
|
407
|
+
const bodyMetrics = [];
|
|
408
|
+
for (const object of objects) {
|
|
409
|
+
const radiusMetric = objectRadiusMetric(object);
|
|
410
|
+
if (radiusMetric !== null && radiusMetric > 0) {
|
|
411
|
+
bodyMetrics.push(radiusMetric);
|
|
412
|
+
}
|
|
413
|
+
const placement = object.placement;
|
|
414
|
+
if (!placement) {
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
if (placement.mode === "orbit") {
|
|
418
|
+
const orbitMetricValue = toDistanceMetric(placement.semiMajor ?? placement.distance ?? null);
|
|
419
|
+
if (orbitMetricValue !== null && orbitMetricValue > 0) {
|
|
420
|
+
orbitMetrics.push(orbitMetricValue);
|
|
421
|
+
}
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
if (placement.mode === "free") {
|
|
425
|
+
const freeMetric = toDistanceMetric(placement.distance ?? null);
|
|
426
|
+
if (freeMetric !== null && freeMetric > 0) {
|
|
427
|
+
orbitMetrics.push(freeMetric);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
const maxDistanceMetric = Math.max(...orbitMetrics, 0);
|
|
432
|
+
const maxBodyMetric = Math.max(...bodyMetrics, 0);
|
|
433
|
+
const baseMetric = Math.max(maxDistanceMetric, maxBodyMetric * 6, 0);
|
|
434
|
+
const referenceMetric = baseMetric +
|
|
435
|
+
Math.max(Math.sqrt(baseMetric), maxBodyMetric * 2, maxDistanceMetric > 0 ? 0.25 : 0);
|
|
436
|
+
if (referenceMetric <= 0) {
|
|
437
|
+
return {
|
|
438
|
+
pixelsPerMetric: null,
|
|
439
|
+
hasExplicitScale: false,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
const availableRadius = Math.max(Math.min(width, height) / 2 - padding - 24, 120) *
|
|
443
|
+
spacingFactor *
|
|
444
|
+
scaleModel.orbitDistanceMultiplier;
|
|
445
|
+
return {
|
|
446
|
+
pixelsPerMetric: availableRadius / referenceMetric,
|
|
447
|
+
hasExplicitScale: true,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
398
450
|
function createSceneObject(position, scaleModel, relationships) {
|
|
399
451
|
const { object, x, y, radius, sortKey, anchorX, anchorY } = position;
|
|
400
452
|
const renderPriority = object.renderHints?.renderPriority ?? 0;
|
|
@@ -1064,7 +1116,7 @@ function parseViewpointGroups(value, document, relationships, objectMap) {
|
|
|
1064
1116
|
return splitListValue(value).map((entry) => {
|
|
1065
1117
|
if (document.schemaVersion === "2.1" ||
|
|
1066
1118
|
document.schemaVersion === "2.5" ||
|
|
1067
|
-
document.schemaVersion === "2.6
|
|
1119
|
+
document.schemaVersion === "2.6" ||
|
|
1068
1120
|
document.groups.some((group) => group.id === entry)) {
|
|
1069
1121
|
return entry;
|
|
1070
1122
|
}
|
|
@@ -1198,7 +1250,7 @@ function placeObject(object, x, y, depth, positions, orbitDrafts, leaderDrafts,
|
|
|
1198
1250
|
object,
|
|
1199
1251
|
x,
|
|
1200
1252
|
y,
|
|
1201
|
-
radius: visualRadiusFor(object, depth, context.scaleModel),
|
|
1253
|
+
radius: visualRadiusFor(object, depth, context.scaleModel, context.sceneMetricScale),
|
|
1202
1254
|
sortKey: computeSortKey(x, y, depth),
|
|
1203
1255
|
});
|
|
1204
1256
|
placeOrbitingChildren(object, positions, orbitDrafts, leaderDrafts, context, depth + 1);
|
|
@@ -1209,7 +1261,7 @@ function placeOrbitingChildren(object, positions, orbitDrafts, leaderDrafts, con
|
|
|
1209
1261
|
return;
|
|
1210
1262
|
}
|
|
1211
1263
|
const orbiting = [...(context.orbitChildren.get(object.id) ?? [])].sort(compareOrbiting);
|
|
1212
|
-
const orbitMetricContext = computeOrbitMetricContext(orbiting, parent.radius, context.spacingFactor, context.scaleModel);
|
|
1264
|
+
const orbitMetricContext = computeOrbitMetricContext(orbiting, parent.radius, context.spacingFactor, context.scaleModel, context.sceneMetricScale);
|
|
1213
1265
|
const orbitRadiiPx = resolveOrbitRadiiPx(orbiting, orbitMetricContext);
|
|
1214
1266
|
orbiting.forEach((child, index) => {
|
|
1215
1267
|
const orbitGeometry = resolveOrbitGeometry(child, index, orbiting.length, parent, orbitMetricContext, orbitRadiiPx[index] ?? orbitMetricContext.innerPx, context);
|
|
@@ -1244,7 +1296,7 @@ function placeOrbitingChildren(object, positions, orbitDrafts, leaderDrafts, con
|
|
|
1244
1296
|
object: child,
|
|
1245
1297
|
x,
|
|
1246
1298
|
y,
|
|
1247
|
-
radius: visualRadiusFor(child, depth + 1, context.scaleModel),
|
|
1299
|
+
radius: visualRadiusFor(child, depth + 1, context.scaleModel, context.sceneMetricScale),
|
|
1248
1300
|
sortKey: computeSortKey(x, y, depth + 1),
|
|
1249
1301
|
anchorX,
|
|
1250
1302
|
anchorY,
|
|
@@ -1273,10 +1325,13 @@ function compareOrbiting(left, right) {
|
|
|
1273
1325
|
return 1;
|
|
1274
1326
|
return left.id.localeCompare(right.id);
|
|
1275
1327
|
}
|
|
1276
|
-
function computeOrbitMetricContext(objects, parentRadius, spacingFactor, scaleModel) {
|
|
1328
|
+
function computeOrbitMetricContext(objects, parentRadius, spacingFactor, scaleModel, sceneMetricScale) {
|
|
1277
1329
|
const metrics = objects.map((object) => orbitMetric(object));
|
|
1278
1330
|
const presentMetrics = metrics.filter((value) => value !== null);
|
|
1279
|
-
const
|
|
1331
|
+
const minimumGapPx = scaleModel.bodyScaleMode === "strict"
|
|
1332
|
+
? Math.max(2, 8 * spacingFactor * scaleModel.orbitDistanceMultiplier)
|
|
1333
|
+
: (objects.length > 2 ? 54 : 64) * spacingFactor * scaleModel.orbitDistanceMultiplier * 0.42;
|
|
1334
|
+
const innerPx = parentRadius + Math.max(minimumGapPx * 1.2, 24 * spacingFactor);
|
|
1280
1335
|
const stepPx = (objects.length > 2 ? 54 : 64) * spacingFactor * scaleModel.orbitDistanceMultiplier;
|
|
1281
1336
|
if (presentMetrics.length === 0) {
|
|
1282
1337
|
return {
|
|
@@ -1287,7 +1342,8 @@ function computeOrbitMetricContext(objects, parentRadius, spacingFactor, scaleMo
|
|
|
1287
1342
|
innerPx,
|
|
1288
1343
|
stepPx,
|
|
1289
1344
|
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx),
|
|
1290
|
-
minimumGapPx
|
|
1345
|
+
minimumGapPx,
|
|
1346
|
+
pixelsPerMetric: sceneMetricScale.pixelsPerMetric,
|
|
1291
1347
|
};
|
|
1292
1348
|
}
|
|
1293
1349
|
const minMetric = Math.min(...presentMetrics);
|
|
@@ -1301,7 +1357,8 @@ function computeOrbitMetricContext(objects, parentRadius, spacingFactor, scaleMo
|
|
|
1301
1357
|
innerPx,
|
|
1302
1358
|
stepPx,
|
|
1303
1359
|
pixelSpread: Math.max(stepPx * Math.max(objects.length - 1, 1), stepPx),
|
|
1304
|
-
minimumGapPx
|
|
1360
|
+
minimumGapPx,
|
|
1361
|
+
pixelsPerMetric: sceneMetricScale.pixelsPerMetric,
|
|
1305
1362
|
};
|
|
1306
1363
|
}
|
|
1307
1364
|
function resolveOrbitGeometry(object, index, count, parent, metricContext, orbitRadiusPx, context) {
|
|
@@ -1366,6 +1423,9 @@ function resolveOrbitGeometry(object, index, count, parent, metricContext, orbit
|
|
|
1366
1423
|
};
|
|
1367
1424
|
}
|
|
1368
1425
|
function resolveOrbitRadiusPx(metric, metricContext) {
|
|
1426
|
+
if (metricContext.pixelsPerMetric !== null) {
|
|
1427
|
+
return metric * metricContext.pixelsPerMetric;
|
|
1428
|
+
}
|
|
1369
1429
|
return metricContext.innerPx + metricContext.stepPx * log2(Math.max(metric, 0) + 1);
|
|
1370
1430
|
}
|
|
1371
1431
|
function resolveOrbitRadiiPx(objects, metricContext) {
|
|
@@ -1404,6 +1464,12 @@ function resolveBandThickness(object, orbitRadius, metricContext, scaleModel) {
|
|
|
1404
1464
|
const outerMetric = toDistanceMetric(toUnitValue(object.properties.outer));
|
|
1405
1465
|
if (innerMetric !== null && outerMetric !== null) {
|
|
1406
1466
|
const thicknessMetric = Math.abs(outerMetric - innerMetric);
|
|
1467
|
+
if (metricContext.pixelsPerMetric !== null) {
|
|
1468
|
+
const thicknessPx = thicknessMetric * metricContext.pixelsPerMetric;
|
|
1469
|
+
return scaleModel.bodyScaleMode === "strict"
|
|
1470
|
+
? Math.max(thicknessPx * scaleModel.ringThicknessMultiplier, 1)
|
|
1471
|
+
: clampNumber(Math.max(thicknessPx * scaleModel.ringThicknessMultiplier, 8), 8, 54);
|
|
1472
|
+
}
|
|
1407
1473
|
if (metricContext.metricSpread > 0) {
|
|
1408
1474
|
return clampNumber((thicknessMetric / metricContext.metricSpread) *
|
|
1409
1475
|
metricContext.pixelSpread *
|
|
@@ -1698,8 +1764,8 @@ function deriveParentAnchor(objectId, positions, objectMap) {
|
|
|
1698
1764
|
}
|
|
1699
1765
|
return positions.get(object.placement.target);
|
|
1700
1766
|
}
|
|
1701
|
-
function visualRadiusFor(object, depth, scaleModel) {
|
|
1702
|
-
const explicitRadius = toVisualSizeMetric(object.properties.radius, scaleModel);
|
|
1767
|
+
function visualRadiusFor(object, depth, scaleModel, sceneMetricScale) {
|
|
1768
|
+
const explicitRadius = toVisualSizeMetric(object.properties.radius, scaleModel, sceneMetricScale);
|
|
1703
1769
|
if (explicitRadius !== null) {
|
|
1704
1770
|
return explicitRadius;
|
|
1705
1771
|
}
|
|
@@ -1766,18 +1832,31 @@ function toDistanceMetric(value) {
|
|
|
1766
1832
|
return value.value;
|
|
1767
1833
|
}
|
|
1768
1834
|
}
|
|
1769
|
-
function freePlacementOffsetPx(distance, scaleModel) {
|
|
1835
|
+
function freePlacementOffsetPx(distance, scaleModel, sceneMetricScale) {
|
|
1770
1836
|
const metric = toDistanceMetric(distance ?? null);
|
|
1771
1837
|
if (metric === null || metric <= 0) {
|
|
1772
1838
|
return 0;
|
|
1773
1839
|
}
|
|
1840
|
+
if (sceneMetricScale.pixelsPerMetric !== null) {
|
|
1841
|
+
const scaled = metric * sceneMetricScale.pixelsPerMetric * scaleModel.freePlacementMultiplier;
|
|
1842
|
+
return scaleModel.bodyScaleMode === "strict"
|
|
1843
|
+
? Math.max(scaled, 0)
|
|
1844
|
+
: clampNumber(scaled, 0, 420);
|
|
1845
|
+
}
|
|
1774
1846
|
return clampNumber(metric * 96 * scaleModel.freePlacementMultiplier, 0, 420);
|
|
1775
1847
|
}
|
|
1776
|
-
function toVisualSizeMetric(value, scaleModel) {
|
|
1848
|
+
function toVisualSizeMetric(value, scaleModel, sceneMetricScale) {
|
|
1777
1849
|
const unitValue = toUnitValue(value);
|
|
1778
1850
|
if (!unitValue) {
|
|
1779
1851
|
return null;
|
|
1780
1852
|
}
|
|
1853
|
+
const physicalMetric = toDistanceMetric(unitValue);
|
|
1854
|
+
if (sceneMetricScale.pixelsPerMetric !== null && physicalMetric !== null && physicalMetric > 0) {
|
|
1855
|
+
const scaled = physicalMetric * sceneMetricScale.pixelsPerMetric * scaleModel.bodyRadiusMultiplier;
|
|
1856
|
+
return scaleModel.bodyScaleMode === "strict"
|
|
1857
|
+
? Math.max(scaled, 0.1)
|
|
1858
|
+
: clampNumber(Math.max(scaled, scaleModel.minBodyRadius), scaleModel.minBodyRadius, scaleModel.maxBodyRadius);
|
|
1859
|
+
}
|
|
1781
1860
|
let size;
|
|
1782
1861
|
switch (unitValue.unit) {
|
|
1783
1862
|
case "sol":
|
|
@@ -1795,6 +1874,9 @@ function toVisualSizeMetric(value, scaleModel) {
|
|
|
1795
1874
|
}
|
|
1796
1875
|
return clampNumber(size * scaleModel.bodyRadiusMultiplier, scaleModel.minBodyRadius, scaleModel.maxBodyRadius);
|
|
1797
1876
|
}
|
|
1877
|
+
function objectRadiusMetric(object) {
|
|
1878
|
+
return toDistanceMetric(toUnitValue(object.properties.radius));
|
|
1879
|
+
}
|
|
1798
1880
|
function toUnitValue(value) {
|
|
1799
1881
|
if (!value || typeof value !== "object" || !("value" in value)) {
|
|
1800
1882
|
return null;
|
|
@@ -12,6 +12,7 @@ export function renderDocumentToSpatialScene(document, options = {}) {
|
|
|
12
12
|
projection: options.projection,
|
|
13
13
|
camera: options.camera,
|
|
14
14
|
scaleModel: options.scaleModel,
|
|
15
|
+
bodyScaleMode: options.bodyScaleMode,
|
|
15
16
|
activeEventId: options.activeEventId,
|
|
16
17
|
};
|
|
17
18
|
const scene = renderDocumentToScene(document, renderOptions);
|
|
@@ -2,12 +2,13 @@ export type WorldOrbitObjectType = "system" | "star" | "planet" | "moon" | "belt
|
|
|
2
2
|
export type PlacementMode = "orbit" | "at" | "surface" | "free";
|
|
3
3
|
export type Unit = "au" | "km" | "m" | "ly" | "pc" | "kpc" | "re" | "rj" | "sol" | "me" | "mj" | "s" | "min" | "h" | "d" | "y" | "ky" | "my" | "gy" | "K" | "deg";
|
|
4
4
|
export type WorldOrbitDocumentVersion = "1.0";
|
|
5
|
-
export type WorldOrbitAtlasDocumentVersion = "2.0" | "2.1" | "2.5" | "2.6
|
|
5
|
+
export type WorldOrbitAtlasDocumentVersion = "2.0" | "2.1" | "2.5" | "2.6";
|
|
6
6
|
export type WorldOrbitDraftDocumentVersion = "2.0-draft";
|
|
7
7
|
export type WorldOrbitAnyDocumentVersion = WorldOrbitDocumentVersion | WorldOrbitAtlasDocumentVersion | WorldOrbitDraftDocumentVersion;
|
|
8
8
|
export type ViewProjection = "topdown" | "isometric" | "orthographic" | "perspective";
|
|
9
9
|
export type RenderProjectionFallback = "topdown" | "isometric";
|
|
10
10
|
export type RenderPresetName = "diagram" | "presentation" | "atlas-card" | "markdown";
|
|
11
|
+
export type BodyScaleMode = "readable" | "strict";
|
|
11
12
|
export interface CoordinatePoint {
|
|
12
13
|
x: number;
|
|
13
14
|
y: number;
|
|
@@ -263,6 +264,7 @@ export interface RenderScaleModel {
|
|
|
263
264
|
ringThicknessMultiplier: number;
|
|
264
265
|
minBodyRadius: number;
|
|
265
266
|
maxBodyRadius: number;
|
|
267
|
+
bodyScaleMode: BodyScaleMode;
|
|
266
268
|
}
|
|
267
269
|
export interface SceneRenderOptions {
|
|
268
270
|
width?: number;
|
|
@@ -272,6 +274,7 @@ export interface SceneRenderOptions {
|
|
|
272
274
|
projection?: "document" | ViewProjection;
|
|
273
275
|
camera?: WorldOrbitViewCamera | null;
|
|
274
276
|
scaleModel?: Partial<RenderScaleModel>;
|
|
277
|
+
bodyScaleMode?: BodyScaleMode;
|
|
275
278
|
activeEventId?: string | null;
|
|
276
279
|
}
|
|
277
280
|
export interface SpatialScaleModel {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cloneAtlasDocument, createEmptyAtlasDocument, formatDocument, getAtlasDocumentNode, loadWorldOrbitSourceWithDiagnostics, materializeAtlasDocument, removeAtlasDocumentNode, resolveAtlasDiagnostics, rotatePoint, upgradeDocumentToV2, validateAtlasDocumentWithDiagnostics, } from "@worldorbit/core";
|
|
1
|
+
import { cloneAtlasDocument, createEmptyAtlasDocument, formatDocument, getAtlasDocumentNode, loadWorldOrbitSourceWithDiagnostics, materializeAtlasDocument, removeAtlasDocumentNode, renderDocumentToScene, resolveAtlasDiagnostics, rotatePoint, upgradeDocumentToV2, validateAtlasDocumentWithDiagnostics, } from "@worldorbit/core";
|
|
2
2
|
import { renderWorldOrbitBlock } from "@worldorbit/markdown";
|
|
3
3
|
import { createInteractiveViewer, } from "@worldorbit/viewer";
|
|
4
4
|
import { getViewerVisibleBounds, invertViewerPoint } from "@worldorbit/viewer/viewer-state";
|
|
@@ -1250,7 +1250,7 @@ export function createWorldOrbitEditor(container, options = {}) {
|
|
|
1250
1250
|
break;
|
|
1251
1251
|
case "orbit-radius":
|
|
1252
1252
|
if (details.object.placement?.mode === "orbit" && details.orbit) {
|
|
1253
|
-
nextDocument = updateOrbitRadius(atlasDocument, dragState.path, dragState.objectId, details, pointer, dragState.orbitRadiusContext ?? null);
|
|
1253
|
+
nextDocument = updateOrbitRadius(atlasDocument, dragState.path, dragState.objectId, viewer.getScene(), details, pointer, dragState.orbitRadiusContext ?? null);
|
|
1254
1254
|
}
|
|
1255
1255
|
break;
|
|
1256
1256
|
case "at-reference":
|
|
@@ -2468,7 +2468,7 @@ function updateOrbitPhase(document, path, objectId, details, pointer) {
|
|
|
2468
2468
|
};
|
|
2469
2469
|
return next;
|
|
2470
2470
|
}
|
|
2471
|
-
function updateOrbitRadius(document, path, objectId, details, pointer, dragContext) {
|
|
2471
|
+
function updateOrbitRadius(document, path, objectId, scene, details, pointer, dragContext) {
|
|
2472
2472
|
const orbit = details.orbit;
|
|
2473
2473
|
if (!orbit || details.object.placement?.mode !== "orbit" || !dragContext) {
|
|
2474
2474
|
return document;
|
|
@@ -2476,25 +2476,54 @@ function updateOrbitRadius(document, path, objectId, details, pointer, dragConte
|
|
|
2476
2476
|
const unrotated = rotatePoint(pointer, { x: orbit.cx, y: orbit.cy }, -orbit.rotationDeg);
|
|
2477
2477
|
const nextDisplayedRadius = Math.max(Math.abs(unrotated.x - orbit.cx), 24);
|
|
2478
2478
|
const nextBaseRadius = Math.max(nextDisplayedRadius - dragContext.radiusOffsetPx, dragContext.innerPx);
|
|
2479
|
-
const nextMetric = orbitRadiusPxToMetric(nextBaseRadius, dragContext.innerPx, dragContext.stepPx);
|
|
2479
|
+
const nextMetric = orbitRadiusPxToMetric(nextBaseRadius, dragContext.innerPx, dragContext.stepPx, dragContext.mode, dragContext.pixelsPerMetric);
|
|
2480
2480
|
const next = cloneAtlasDocument(document);
|
|
2481
2481
|
const placementOwner = findEditablePlacementOwner(next, path, objectId);
|
|
2482
2482
|
if (!placementOwner || placementOwner.placement.mode !== "orbit") {
|
|
2483
2483
|
return document;
|
|
2484
2484
|
}
|
|
2485
|
-
const
|
|
2486
|
-
|
|
2485
|
+
const orbitPlacementOwner = placementOwner;
|
|
2486
|
+
const currentValue = orbitPlacementOwner.placement.semiMajor ??
|
|
2487
|
+
orbitPlacementOwner.placement.distance ?? {
|
|
2487
2488
|
value: 1,
|
|
2488
2489
|
unit: "au",
|
|
2489
2490
|
};
|
|
2490
2491
|
const scaled = distanceMetricToUnitValue(Math.max(nextMetric, 0), dragContext.preferredUnit ?? currentValue.unit);
|
|
2492
|
+
applyOrbitDistanceValue(orbitPlacementOwner, scaled);
|
|
2493
|
+
const targetDisplayedRadius = nextDisplayedRadius;
|
|
2494
|
+
let correctedMetric = nextMetric;
|
|
2495
|
+
for (let iteration = 0; iteration < 3; iteration += 1) {
|
|
2496
|
+
const candidateScene = renderDocumentToScene(materializeAtlasDocument(next), {
|
|
2497
|
+
width: scene.width,
|
|
2498
|
+
height: scene.height,
|
|
2499
|
+
padding: scene.padding,
|
|
2500
|
+
preset: scene.renderPreset ?? undefined,
|
|
2501
|
+
projection: scene.projection,
|
|
2502
|
+
camera: scene.camera,
|
|
2503
|
+
scaleModel: { ...scene.scaleModel },
|
|
2504
|
+
bodyScaleMode: scene.scaleModel.bodyScaleMode,
|
|
2505
|
+
activeEventId: scene.activeEventId,
|
|
2506
|
+
});
|
|
2507
|
+
const renderedOrbit = candidateScene.orbitVisuals.find((entry) => entry.objectId === objectId);
|
|
2508
|
+
const renderedRadius = renderedOrbit?.kind === "circle"
|
|
2509
|
+
? renderedOrbit.radius ?? 0
|
|
2510
|
+
: renderedOrbit?.rx ?? 0;
|
|
2511
|
+
if (renderedRadius >= targetDisplayedRadius - 1) {
|
|
2512
|
+
break;
|
|
2513
|
+
}
|
|
2514
|
+
const correctionFactor = targetDisplayedRadius / Math.max(renderedRadius, 1);
|
|
2515
|
+
correctedMetric *= Math.max(correctionFactor, 1.02);
|
|
2516
|
+
applyOrbitDistanceValue(orbitPlacementOwner, distanceMetricToUnitValue(Math.max(correctedMetric, 0), dragContext.preferredUnit ?? currentValue.unit));
|
|
2517
|
+
}
|
|
2518
|
+
return next;
|
|
2519
|
+
}
|
|
2520
|
+
function applyOrbitDistanceValue(placementOwner, value) {
|
|
2491
2521
|
if (placementOwner.placement.semiMajor) {
|
|
2492
|
-
placementOwner.placement.semiMajor =
|
|
2522
|
+
placementOwner.placement.semiMajor = value;
|
|
2493
2523
|
}
|
|
2494
2524
|
else {
|
|
2495
|
-
placementOwner.placement.distance =
|
|
2525
|
+
placementOwner.placement.distance = value;
|
|
2496
2526
|
}
|
|
2497
|
-
return next;
|
|
2498
2527
|
}
|
|
2499
2528
|
function updateAtReference(document, path, objectId, scene, pointer) {
|
|
2500
2529
|
const candidate = findNearestAtCandidate(scene, objectId, pointer);
|
|
@@ -2533,15 +2562,26 @@ function createOrbitRadiusDragContext(document, scene, details) {
|
|
|
2533
2562
|
!entry.hidden).length;
|
|
2534
2563
|
const spacingFactor = layoutPresetSpacingForScene(scene.layoutPreset);
|
|
2535
2564
|
const stepPx = (siblingCount > 2 ? 54 : 64) * spacingFactor * scene.scaleModel.orbitDistanceMultiplier;
|
|
2565
|
+
const minimumGapPx = scene.scaleModel.bodyScaleMode === "strict"
|
|
2566
|
+
? Math.max(2, 8 * spacingFactor * scene.scaleModel.orbitDistanceMultiplier)
|
|
2567
|
+
: stepPx * 0.42;
|
|
2536
2568
|
const innerPx = details.parent.radius +
|
|
2537
|
-
|
|
2569
|
+
Math.max(minimumGapPx * 1.2, 24 * spacingFactor);
|
|
2538
2570
|
const currentValue = details.object.placement.semiMajor ?? details.object.placement.distance ?? null;
|
|
2539
2571
|
const currentMetric = unitValueToDistanceMetric(currentValue);
|
|
2540
2572
|
const displayedRadius = details.orbit.kind === "circle" ? details.orbit.radius ?? 1 : details.orbit.rx ?? 1;
|
|
2541
|
-
const
|
|
2573
|
+
const usesLinearScale = currentMetric !== null && currentMetric > 0;
|
|
2574
|
+
const pixelsPerMetric = usesLinearScale
|
|
2575
|
+
? displayedRadius / Math.max(currentMetric, 0.0001)
|
|
2576
|
+
: null;
|
|
2577
|
+
const baseRadius = usesLinearScale
|
|
2578
|
+
? currentMetric * Math.max(pixelsPerMetric ?? 0, 0)
|
|
2579
|
+
: orbitMetricToRadiusPx(currentMetric ?? 0, innerPx, stepPx);
|
|
2542
2580
|
return {
|
|
2581
|
+
mode: usesLinearScale ? "linear" : "log",
|
|
2543
2582
|
innerPx,
|
|
2544
2583
|
stepPx,
|
|
2584
|
+
pixelsPerMetric,
|
|
2545
2585
|
radiusOffsetPx: displayedRadius - baseRadius,
|
|
2546
2586
|
preferredUnit: currentValue?.unit ?? null,
|
|
2547
2587
|
};
|
|
@@ -3191,7 +3231,10 @@ function distanceMetricToUnitValue(metric, unit) {
|
|
|
3191
3231
|
function orbitMetricToRadiusPx(metric, innerPx, stepPx) {
|
|
3192
3232
|
return innerPx + stepPx * log2(Math.max(metric, 0) + 1);
|
|
3193
3233
|
}
|
|
3194
|
-
function orbitRadiusPxToMetric(radiusPx, innerPx, stepPx) {
|
|
3234
|
+
function orbitRadiusPxToMetric(radiusPx, innerPx, stepPx, mode, pixelsPerMetric) {
|
|
3235
|
+
if (mode === "linear" && pixelsPerMetric !== null && pixelsPerMetric > 0) {
|
|
3236
|
+
return Math.max(radiusPx / pixelsPerMetric, 0);
|
|
3237
|
+
}
|
|
3195
3238
|
if (radiusPx <= innerPx) {
|
|
3196
3239
|
return 0;
|
|
3197
3240
|
}
|
|
@@ -72,6 +72,7 @@ export function createAtlasStateSnapshot(viewerState, renderOptions, filter, vie
|
|
|
72
72
|
camera: renderOptions.camera ? { ...renderOptions.camera } : null,
|
|
73
73
|
layers: renderOptions.layers ? { ...renderOptions.layers } : undefined,
|
|
74
74
|
scaleModel: renderOptions.scaleModel ? { ...renderOptions.scaleModel } : undefined,
|
|
75
|
+
bodyScaleMode: renderOptions.bodyScaleMode,
|
|
75
76
|
activeEventId: renderOptions.activeEventId ?? null,
|
|
76
77
|
viewMode: renderOptions.viewMode ?? "2d",
|
|
77
78
|
},
|
|
@@ -102,6 +103,7 @@ export function deserializeViewerAtlasState(serialized) {
|
|
|
102
103
|
scaleModel: raw.renderOptions?.scaleModel
|
|
103
104
|
? { ...raw.renderOptions.scaleModel }
|
|
104
105
|
: undefined,
|
|
106
|
+
bodyScaleMode: raw.renderOptions?.bodyScaleMode,
|
|
105
107
|
activeEventId: raw.activeEventId ?? raw.renderOptions?.activeEventId ?? null,
|
|
106
108
|
viewMode: raw.renderOptions?.viewMode ?? "2d",
|
|
107
109
|
},
|
|
@@ -126,6 +128,7 @@ export function createViewerBookmark(name, label, atlasState) {
|
|
|
126
128
|
scaleModel: atlasState.renderOptions.scaleModel
|
|
127
129
|
? { ...atlasState.renderOptions.scaleModel }
|
|
128
130
|
: undefined,
|
|
131
|
+
bodyScaleMode: atlasState.renderOptions.bodyScaleMode,
|
|
129
132
|
activeEventId: atlasState.renderOptions.activeEventId ?? null,
|
|
130
133
|
viewMode: atlasState.renderOptions.viewMode ?? "2d",
|
|
131
134
|
},
|
|
@@ -129,6 +129,7 @@ export interface ViewerAtlasState {
|
|
|
129
129
|
camera?: WorldOrbitViewCamera | null;
|
|
130
130
|
layers?: ViewerLayerOptions;
|
|
131
131
|
scaleModel?: Partial<RenderScaleModel>;
|
|
132
|
+
bodyScaleMode?: SceneRenderOptions["bodyScaleMode"];
|
|
132
133
|
activeEventId?: string | null;
|
|
133
134
|
viewMode?: WorldOrbitViewMode;
|
|
134
135
|
quality?: WorldOrbit3DQuality;
|
|
@@ -44,6 +44,7 @@ export function createInteractiveViewer(container, options) {
|
|
|
44
44
|
padding: options.padding,
|
|
45
45
|
preset: options.preset,
|
|
46
46
|
projection: options.projection,
|
|
47
|
+
bodyScaleMode: options.bodyScaleMode,
|
|
47
48
|
viewMode: options.viewMode ?? "2d",
|
|
48
49
|
quality: options.quality ?? "balanced",
|
|
49
50
|
style3d: options.style3d ?? "symbolic",
|
|
@@ -1595,6 +1596,7 @@ function hasSceneAffectingRenderOptions(options) {
|
|
|
1595
1596
|
options.projection !== undefined ||
|
|
1596
1597
|
options.camera !== undefined ||
|
|
1597
1598
|
options.scaleModel !== undefined ||
|
|
1599
|
+
options.bodyScaleMode !== undefined ||
|
|
1598
1600
|
options.activeEventId !== undefined);
|
|
1599
1601
|
}
|
|
1600
1602
|
function resolveSourceRenderOptions(loaded, renderOptions) {
|