worldorbit 2.5.16 → 2.5.17
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 +1 -1
- package/dist/browser/core/dist/index.js +750 -73
- package/dist/browser/editor/dist/index.js +1303 -135
- package/dist/browser/markdown/dist/index.js +631 -72
- package/dist/browser/viewer/dist/index.js +658 -77
- package/dist/unpkg/core/dist/index.js +750 -73
- package/dist/unpkg/editor/dist/index.js +1303 -135
- package/dist/unpkg/markdown/dist/index.js +631 -72
- package/dist/unpkg/viewer/dist/index.js +658 -77
- package/dist/unpkg/worldorbit-core.min.js +12 -12
- package/dist/unpkg/worldorbit-editor.min.js +284 -202
- package/dist/unpkg/worldorbit-markdown.min.js +66 -58
- package/dist/unpkg/worldorbit-viewer.min.js +76 -68
- package/dist/unpkg/worldorbit.js +797 -78
- package/dist/unpkg/worldorbit.min.js +80 -72
- package/package.json +1 -1
- package/packages/core/dist/atlas-edit.js +74 -0
- package/packages/core/dist/atlas-validate.js +122 -8
- package/packages/core/dist/draft-parse.js +212 -8
- package/packages/core/dist/draft.d.ts +5 -2
- package/packages/core/dist/draft.js +59 -3
- package/packages/core/dist/format.js +63 -1
- package/packages/core/dist/normalize.js +1 -0
- package/packages/core/dist/scene.js +248 -46
- package/packages/core/dist/types.d.ts +41 -2
- package/packages/editor/dist/editor.js +597 -61
- package/packages/editor/dist/types.d.ts +3 -1
- package/packages/viewer/dist/atlas-state.js +6 -0
- package/packages/viewer/dist/atlas-viewer.js +1 -0
- package/packages/viewer/dist/render.js +31 -2
- package/packages/viewer/dist/theme.js +1 -0
- package/packages/viewer/dist/tooltip.js +9 -0
- package/packages/viewer/dist/types.d.ts +8 -1
- package/packages/viewer/dist/viewer.js +12 -1
|
@@ -541,6 +541,7 @@
|
|
|
541
541
|
system,
|
|
542
542
|
groups: [],
|
|
543
543
|
relations: [],
|
|
544
|
+
events: [],
|
|
544
545
|
objects
|
|
545
546
|
};
|
|
546
547
|
}
|
|
@@ -924,8 +925,10 @@
|
|
|
924
925
|
const scaleModel = resolveScaleModel(layoutPreset, options.scaleModel);
|
|
925
926
|
const spacingFactor = layoutPresetSpacing(layoutPreset);
|
|
926
927
|
const systemId = document2.system?.id ?? null;
|
|
927
|
-
const
|
|
928
|
-
const
|
|
928
|
+
const activeEventId = options.activeEventId ?? null;
|
|
929
|
+
const effectiveObjects = createEffectiveObjects(document2.objects, document2.events ?? [], activeEventId);
|
|
930
|
+
const objectMap = new Map(effectiveObjects.map((object) => [object.id, object]));
|
|
931
|
+
const relationships = buildSceneRelationships(effectiveObjects, objectMap);
|
|
929
932
|
const positions = /* @__PURE__ */ new Map();
|
|
930
933
|
const orbitDrafts = [];
|
|
931
934
|
const leaderDrafts = [];
|
|
@@ -934,7 +937,7 @@
|
|
|
934
937
|
const atObjects = [];
|
|
935
938
|
const surfaceChildren = /* @__PURE__ */ new Map();
|
|
936
939
|
const orbitChildren = /* @__PURE__ */ new Map();
|
|
937
|
-
for (const object of
|
|
940
|
+
for (const object of effectiveObjects) {
|
|
938
941
|
const placement = object.placement;
|
|
939
942
|
if (!placement) {
|
|
940
943
|
rootObjects.push(object);
|
|
@@ -1029,13 +1032,14 @@
|
|
|
1029
1032
|
const objects = [...positions.values()].map((position) => createSceneObject(position, scaleModel, relationships));
|
|
1030
1033
|
const orbitVisuals = orbitDrafts.map((draft) => createOrbitVisual(draft, relationships.groupIds.get(draft.object.id) ?? null));
|
|
1031
1034
|
const leaders = leaderDrafts.map((draft) => createLeaderLine(draft));
|
|
1032
|
-
const labels = createSceneLabels(objects, height, scaleModel.labelMultiplier);
|
|
1035
|
+
const labels = createSceneLabels(objects, width, height, scaleModel.labelMultiplier);
|
|
1033
1036
|
const relations = createSceneRelations(document2, objects);
|
|
1034
|
-
const
|
|
1035
|
-
const
|
|
1037
|
+
const events = createSceneEvents(document2.events ?? [], objects, activeEventId);
|
|
1038
|
+
const layers = createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels);
|
|
1039
|
+
const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, scaleModel.labelMultiplier);
|
|
1036
1040
|
const semanticGroups = createSceneSemanticGroups(document2, objects);
|
|
1037
1041
|
const viewpoints = createSceneViewpoints(document2, projection, frame.preset, relationships, objectMap);
|
|
1038
|
-
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels);
|
|
1042
|
+
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, scaleModel.labelMultiplier);
|
|
1039
1043
|
return {
|
|
1040
1044
|
width,
|
|
1041
1045
|
height,
|
|
@@ -1061,6 +1065,8 @@
|
|
|
1061
1065
|
groups,
|
|
1062
1066
|
semanticGroups,
|
|
1063
1067
|
viewpoints,
|
|
1068
|
+
events,
|
|
1069
|
+
activeEventId,
|
|
1064
1070
|
objects,
|
|
1065
1071
|
orbitVisuals,
|
|
1066
1072
|
relations,
|
|
@@ -1068,6 +1074,35 @@
|
|
|
1068
1074
|
labels
|
|
1069
1075
|
};
|
|
1070
1076
|
}
|
|
1077
|
+
function createEffectiveObjects(objects, events, activeEventId) {
|
|
1078
|
+
const cloned = objects.map((object) => structuredClone(object));
|
|
1079
|
+
if (!activeEventId) {
|
|
1080
|
+
return cloned;
|
|
1081
|
+
}
|
|
1082
|
+
const activeEvent = events.find((event) => event.id === activeEventId);
|
|
1083
|
+
if (!activeEvent) {
|
|
1084
|
+
return cloned;
|
|
1085
|
+
}
|
|
1086
|
+
const objectMap = new Map(cloned.map((object) => [object.id, object]));
|
|
1087
|
+
for (const pose of activeEvent.positions) {
|
|
1088
|
+
const object = objectMap.get(pose.objectId);
|
|
1089
|
+
if (!object) {
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1092
|
+
object.placement = pose.placement ? structuredClone(pose.placement) : null;
|
|
1093
|
+
if (pose.inner) {
|
|
1094
|
+
object.properties.inner = { ...pose.inner };
|
|
1095
|
+
} else {
|
|
1096
|
+
delete object.properties.inner;
|
|
1097
|
+
}
|
|
1098
|
+
if (pose.outer) {
|
|
1099
|
+
object.properties.outer = { ...pose.outer };
|
|
1100
|
+
} else {
|
|
1101
|
+
delete object.properties.outer;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
return cloned;
|
|
1105
|
+
}
|
|
1071
1106
|
function resolveLayoutPreset(document2) {
|
|
1072
1107
|
const rawScale = String(document2.system?.properties.scale ?? "balanced").toLowerCase();
|
|
1073
1108
|
switch (rawScale) {
|
|
@@ -1223,24 +1258,14 @@
|
|
|
1223
1258
|
hidden: draft.object.properties.hidden === true
|
|
1224
1259
|
};
|
|
1225
1260
|
}
|
|
1226
|
-
function createSceneLabels(objects, sceneHeight, labelMultiplier) {
|
|
1261
|
+
function createSceneLabels(objects, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1227
1262
|
const labels = [];
|
|
1228
1263
|
const occupied = [];
|
|
1229
|
-
const
|
|
1264
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1265
|
+
const visibleObjects = [...objects].filter((object) => !object.hidden && object.object.renderHints?.renderLabel !== false).sort(compareLabelPlacementOrder);
|
|
1230
1266
|
for (const object of visibleObjects) {
|
|
1231
|
-
const
|
|
1232
|
-
|
|
1233
|
-
let labelY = object.y + direction * (object.radius + 18 * labelMultiplier);
|
|
1234
|
-
let secondaryY = labelY + direction * (16 * labelMultiplier);
|
|
1235
|
-
let bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1236
|
-
let attempts = 0;
|
|
1237
|
-
while (occupied.some((entry) => rectsOverlap(entry, bounds)) && attempts < 10) {
|
|
1238
|
-
labelY += direction * 14 * labelMultiplier;
|
|
1239
|
-
secondaryY += direction * 14 * labelMultiplier;
|
|
1240
|
-
bounds = createLabelRect(object.x, labelY, secondaryY, labelHalfWidth, direction);
|
|
1241
|
-
attempts += 1;
|
|
1242
|
-
}
|
|
1243
|
-
occupied.push(bounds);
|
|
1267
|
+
const placement = selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) ?? createLabelPlacement(object, defaultVerticalDirection(object, objectMap.get(object.parentId ?? "") ?? null, sceneHeight), 0, labelMultiplier);
|
|
1268
|
+
occupied.push(createLabelRect(object, placement, labelMultiplier));
|
|
1244
1269
|
labels.push({
|
|
1245
1270
|
renderId: `${object.renderId}-label`,
|
|
1246
1271
|
objectId: object.objectId,
|
|
@@ -1249,17 +1274,128 @@
|
|
|
1249
1274
|
semanticGroupIds: [...object.semanticGroupIds],
|
|
1250
1275
|
label: object.label,
|
|
1251
1276
|
secondaryLabel: object.secondaryLabel,
|
|
1252
|
-
x:
|
|
1253
|
-
y: labelY,
|
|
1254
|
-
secondaryY,
|
|
1255
|
-
textAnchor:
|
|
1256
|
-
direction: direction
|
|
1277
|
+
x: placement.x,
|
|
1278
|
+
y: placement.labelY,
|
|
1279
|
+
secondaryY: placement.secondaryY,
|
|
1280
|
+
textAnchor: placement.textAnchor,
|
|
1281
|
+
direction: placement.direction,
|
|
1257
1282
|
hidden: object.hidden
|
|
1258
1283
|
});
|
|
1259
1284
|
}
|
|
1260
1285
|
return labels;
|
|
1261
1286
|
}
|
|
1262
|
-
function
|
|
1287
|
+
function compareLabelPlacementOrder(left, right) {
|
|
1288
|
+
const priorityDiff = labelPlacementPriority(left) - labelPlacementPriority(right);
|
|
1289
|
+
if (priorityDiff !== 0) {
|
|
1290
|
+
return priorityDiff;
|
|
1291
|
+
}
|
|
1292
|
+
const renderPriorityDiff = (right.object.renderHints?.renderPriority ?? 0) - (left.object.renderHints?.renderPriority ?? 0);
|
|
1293
|
+
if (renderPriorityDiff !== 0) {
|
|
1294
|
+
return renderPriorityDiff;
|
|
1295
|
+
}
|
|
1296
|
+
return left.sortKey - right.sortKey;
|
|
1297
|
+
}
|
|
1298
|
+
function labelPlacementPriority(object) {
|
|
1299
|
+
switch (object.object.type) {
|
|
1300
|
+
case "star":
|
|
1301
|
+
return 0;
|
|
1302
|
+
case "planet":
|
|
1303
|
+
return 1;
|
|
1304
|
+
case "moon":
|
|
1305
|
+
return 2;
|
|
1306
|
+
case "belt":
|
|
1307
|
+
case "ring":
|
|
1308
|
+
return 3;
|
|
1309
|
+
case "asteroid":
|
|
1310
|
+
case "comet":
|
|
1311
|
+
return 4;
|
|
1312
|
+
case "structure":
|
|
1313
|
+
case "phenomenon":
|
|
1314
|
+
return 5;
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
function selectLabelPlacement(object, objectMap, occupied, sceneWidth, sceneHeight, labelMultiplier) {
|
|
1318
|
+
for (const direction of preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight)) {
|
|
1319
|
+
const maxAttempts = direction === "left" || direction === "right" ? 4 : 6;
|
|
1320
|
+
for (let attempt = 0; attempt <= maxAttempts; attempt += 1) {
|
|
1321
|
+
const placement = createLabelPlacement(object, direction, attempt, labelMultiplier);
|
|
1322
|
+
const rect = createLabelRect(object, placement, labelMultiplier);
|
|
1323
|
+
if (!occupied.some((entry) => rectsOverlap(entry, rect))) {
|
|
1324
|
+
return placement;
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
return null;
|
|
1329
|
+
}
|
|
1330
|
+
function preferredLabelDirections(object, objectMap, sceneWidth, sceneHeight) {
|
|
1331
|
+
const parent = object.parentId ? objectMap.get(object.parentId) ?? null : null;
|
|
1332
|
+
const vertical = defaultVerticalDirection(object, parent, sceneHeight);
|
|
1333
|
+
const oppositeVertical = vertical === "below" ? "above" : "below";
|
|
1334
|
+
const horizontal = defaultHorizontalDirection(object, parent, sceneWidth);
|
|
1335
|
+
const oppositeHorizontal = horizontal === "right" ? "left" : "right";
|
|
1336
|
+
const preferHorizontal = object.object.type === "structure" || object.object.type === "phenomenon" || object.object.placement?.mode === "at" || object.object.placement?.mode === "surface" || object.object.placement?.mode === "free";
|
|
1337
|
+
return preferHorizontal ? [horizontal, vertical, oppositeHorizontal, oppositeVertical] : [vertical, horizontal, oppositeVertical, oppositeHorizontal];
|
|
1338
|
+
}
|
|
1339
|
+
function defaultVerticalDirection(object, parent, sceneHeight) {
|
|
1340
|
+
if (parent && Math.abs(object.y - parent.y) > 6) {
|
|
1341
|
+
return object.y >= parent.y ? "below" : "above";
|
|
1342
|
+
}
|
|
1343
|
+
return object.y > sceneHeight * 0.62 ? "above" : "below";
|
|
1344
|
+
}
|
|
1345
|
+
function defaultHorizontalDirection(object, parent, sceneWidth) {
|
|
1346
|
+
if (parent && Math.abs(object.x - parent.x) > 6) {
|
|
1347
|
+
return object.x >= parent.x ? "right" : "left";
|
|
1348
|
+
}
|
|
1349
|
+
return object.x >= sceneWidth / 2 ? "right" : "left";
|
|
1350
|
+
}
|
|
1351
|
+
function createLabelPlacement(object, direction, attempt, labelMultiplier) {
|
|
1352
|
+
const step = 14 * labelMultiplier;
|
|
1353
|
+
switch (direction) {
|
|
1354
|
+
case "above": {
|
|
1355
|
+
const labelY = object.y - (object.radius + 18 * labelMultiplier + attempt * step);
|
|
1356
|
+
return {
|
|
1357
|
+
x: object.x,
|
|
1358
|
+
labelY,
|
|
1359
|
+
secondaryY: labelY - 16 * labelMultiplier,
|
|
1360
|
+
textAnchor: "middle",
|
|
1361
|
+
direction
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
case "below": {
|
|
1365
|
+
const labelY = object.y + object.radius + 18 * labelMultiplier + attempt * step;
|
|
1366
|
+
return {
|
|
1367
|
+
x: object.x,
|
|
1368
|
+
labelY,
|
|
1369
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1370
|
+
textAnchor: "middle",
|
|
1371
|
+
direction
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
case "left": {
|
|
1375
|
+
const x = object.x - (object.visualRadius + 16 * labelMultiplier + attempt * step);
|
|
1376
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1377
|
+
return {
|
|
1378
|
+
x,
|
|
1379
|
+
labelY,
|
|
1380
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1381
|
+
textAnchor: "end",
|
|
1382
|
+
direction
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
case "right": {
|
|
1386
|
+
const x = object.x + object.visualRadius + 16 * labelMultiplier + attempt * step;
|
|
1387
|
+
const labelY = object.y - 4 * labelMultiplier;
|
|
1388
|
+
return {
|
|
1389
|
+
x,
|
|
1390
|
+
labelY,
|
|
1391
|
+
secondaryY: labelY + 16 * labelMultiplier,
|
|
1392
|
+
textAnchor: "start",
|
|
1393
|
+
direction
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
function createSceneLayers(orbitVisuals, relations, events, leaders, objects, labels) {
|
|
1263
1399
|
const backOrbitIds = orbitVisuals.filter((visual) => !visual.hidden && Boolean(visual.backArcPath)).map((visual) => visual.renderId);
|
|
1264
1400
|
const frontOrbitIds = orbitVisuals.filter((visual) => !visual.hidden).map((visual) => visual.renderId);
|
|
1265
1401
|
return [
|
|
@@ -1274,6 +1410,10 @@
|
|
|
1274
1410
|
id: "relations",
|
|
1275
1411
|
renderIds: relations.filter((relation) => !relation.hidden).map((relation) => relation.renderId)
|
|
1276
1412
|
},
|
|
1413
|
+
{
|
|
1414
|
+
id: "events",
|
|
1415
|
+
renderIds: events.filter((event) => !event.hidden).map((event) => event.renderId)
|
|
1416
|
+
},
|
|
1277
1417
|
{
|
|
1278
1418
|
id: "objects",
|
|
1279
1419
|
renderIds: objects.filter((object) => !object.hidden).map((object) => object.renderId)
|
|
@@ -1285,7 +1425,7 @@
|
|
|
1285
1425
|
{ id: "metadata", renderIds: ["wo-title", "wo-subtitle", "wo-meta"] }
|
|
1286
1426
|
];
|
|
1287
1427
|
}
|
|
1288
|
-
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships) {
|
|
1428
|
+
function createSceneGroups(objects, orbitVisuals, leaders, labels, relationships, labelMultiplier) {
|
|
1289
1429
|
const groups = /* @__PURE__ */ new Map();
|
|
1290
1430
|
const ensureGroup = (groupId) => {
|
|
1291
1431
|
if (!groupId) {
|
|
@@ -1334,7 +1474,7 @@
|
|
|
1334
1474
|
}
|
|
1335
1475
|
}
|
|
1336
1476
|
for (const group of groups.values()) {
|
|
1337
|
-
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels);
|
|
1477
|
+
group.contentBounds = calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier);
|
|
1338
1478
|
}
|
|
1339
1479
|
return [...groups.values()].sort((left, right) => left.label.localeCompare(right.label));
|
|
1340
1480
|
}
|
|
@@ -1368,6 +1508,29 @@
|
|
|
1368
1508
|
};
|
|
1369
1509
|
}).sort((left, right) => left.relation.id.localeCompare(right.relation.id));
|
|
1370
1510
|
}
|
|
1511
|
+
function createSceneEvents(events, objects, activeEventId) {
|
|
1512
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1513
|
+
return events.map((event) => {
|
|
1514
|
+
const objectIds = [.../* @__PURE__ */ new Set([
|
|
1515
|
+
...event.targetObjectId ? [event.targetObjectId] : [],
|
|
1516
|
+
...event.participantObjectIds
|
|
1517
|
+
])];
|
|
1518
|
+
const positions = objectIds.map((objectId) => objectMap.get(objectId)).filter(Boolean);
|
|
1519
|
+
const centroidX = positions.length > 0 ? positions.reduce((sum, object) => sum + object.x, 0) / positions.length : 0;
|
|
1520
|
+
const centroidY = positions.length > 0 ? positions.reduce((sum, object) => sum + object.y, 0) / positions.length : 0;
|
|
1521
|
+
return {
|
|
1522
|
+
renderId: `${createRenderId(event.id)}-event`,
|
|
1523
|
+
eventId: event.id,
|
|
1524
|
+
event,
|
|
1525
|
+
objectIds,
|
|
1526
|
+
participantIds: [...event.participantObjectIds],
|
|
1527
|
+
targetObjectId: event.targetObjectId,
|
|
1528
|
+
x: centroidX,
|
|
1529
|
+
y: centroidY,
|
|
1530
|
+
hidden: event.hidden || positions.length === 0 || positions.every((object) => object.hidden) || activeEventId !== null && event.id !== activeEventId
|
|
1531
|
+
};
|
|
1532
|
+
}).sort((left, right) => left.event.id.localeCompare(right.event.id));
|
|
1533
|
+
}
|
|
1371
1534
|
function createSceneViewpoints(document2, projection, preset, relationships, objectMap) {
|
|
1372
1535
|
const generatedOverview = createGeneratedOverviewViewpoint(document2, projection, preset);
|
|
1373
1536
|
const drafts = /* @__PURE__ */ new Map();
|
|
@@ -1421,6 +1584,7 @@
|
|
|
1421
1584
|
summary: "Fit the whole system with the current atlas defaults.",
|
|
1422
1585
|
objectId: null,
|
|
1423
1586
|
selectedObjectId: null,
|
|
1587
|
+
eventIds: [],
|
|
1424
1588
|
projection,
|
|
1425
1589
|
preset,
|
|
1426
1590
|
rotationDeg: 0,
|
|
@@ -1457,6 +1621,9 @@
|
|
|
1457
1621
|
draft.select = normalizedValue;
|
|
1458
1622
|
}
|
|
1459
1623
|
return;
|
|
1624
|
+
case "events":
|
|
1625
|
+
draft.eventIds = splitListValue(normalizedValue);
|
|
1626
|
+
return;
|
|
1460
1627
|
case "projection":
|
|
1461
1628
|
case "view":
|
|
1462
1629
|
draft.projection = parseViewProjection(normalizedValue) ?? projection;
|
|
@@ -1513,6 +1680,7 @@
|
|
|
1513
1680
|
summary: draft.summary?.trim() || createViewpointSummary(label, objectId, filter),
|
|
1514
1681
|
objectId,
|
|
1515
1682
|
selectedObjectId,
|
|
1683
|
+
eventIds: [...new Set(draft.eventIds ?? [])],
|
|
1516
1684
|
projection: draft.projection ?? projection,
|
|
1517
1685
|
preset: draft.preset ?? preset,
|
|
1518
1686
|
rotationDeg: draft.rotationDeg ?? 0,
|
|
@@ -1570,7 +1738,7 @@
|
|
|
1570
1738
|
next["orbits-front"] = enabled;
|
|
1571
1739
|
continue;
|
|
1572
1740
|
}
|
|
1573
|
-
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1741
|
+
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "events" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1574
1742
|
next[rawLayer] = enabled;
|
|
1575
1743
|
}
|
|
1576
1744
|
}
|
|
@@ -1618,7 +1786,7 @@
|
|
|
1618
1786
|
}
|
|
1619
1787
|
return parts.join(" - ");
|
|
1620
1788
|
}
|
|
1621
|
-
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels) {
|
|
1789
|
+
function calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
1622
1790
|
let minX = Number.POSITIVE_INFINITY;
|
|
1623
1791
|
let minY = Number.POSITIVE_INFINITY;
|
|
1624
1792
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -1648,7 +1816,7 @@
|
|
|
1648
1816
|
for (const label of labels) {
|
|
1649
1817
|
if (label.hidden)
|
|
1650
1818
|
continue;
|
|
1651
|
-
includeLabelBounds(label, include);
|
|
1819
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
1652
1820
|
}
|
|
1653
1821
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
1654
1822
|
return createBounds(0, 0, width, height);
|
|
@@ -1686,13 +1854,10 @@
|
|
|
1686
1854
|
include(object.x - object.visualRadius - 24, object.y - object.visualRadius - 16);
|
|
1687
1855
|
include(object.x + object.visualRadius + 24, object.y + object.visualRadius + 36);
|
|
1688
1856
|
}
|
|
1689
|
-
function includeLabelBounds(label, include) {
|
|
1690
|
-
const
|
|
1691
|
-
|
|
1692
|
-
include(
|
|
1693
|
-
include(label.x + labelHalfWidth, label.y + 8);
|
|
1694
|
-
include(label.x - labelHalfWidth, label.secondaryY - 14);
|
|
1695
|
-
include(label.x + labelHalfWidth, label.secondaryY + 8);
|
|
1857
|
+
function includeLabelBounds(label, include, labelMultiplier) {
|
|
1858
|
+
const bounds = createLabelRectFromText(label.x, label.y, label.secondaryY, label.textAnchor, label.direction, label.label, label.secondaryLabel, labelMultiplier);
|
|
1859
|
+
include(bounds.left, bounds.top);
|
|
1860
|
+
include(bounds.right, bounds.bottom);
|
|
1696
1861
|
}
|
|
1697
1862
|
function placeObject(object, x, y, depth, positions, orbitDrafts, leaderDrafts, context) {
|
|
1698
1863
|
if (positions.has(object.id)) {
|
|
@@ -2082,7 +2247,7 @@
|
|
|
2082
2247
|
return null;
|
|
2083
2248
|
}
|
|
2084
2249
|
}
|
|
2085
|
-
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels) {
|
|
2250
|
+
function calculateGroupBounds(group, objects, orbitVisuals, leaders, labels, labelMultiplier) {
|
|
2086
2251
|
let minX = Number.POSITIVE_INFINITY;
|
|
2087
2252
|
let minY = Number.POSITIVE_INFINITY;
|
|
2088
2253
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
@@ -2111,7 +2276,7 @@
|
|
|
2111
2276
|
}
|
|
2112
2277
|
for (const label of labels) {
|
|
2113
2278
|
if (!label.hidden && group.labelIds.includes(label.objectId)) {
|
|
2114
|
-
includeLabelBounds(label, include);
|
|
2279
|
+
includeLabelBounds(label, include, labelMultiplier);
|
|
2115
2280
|
}
|
|
2116
2281
|
}
|
|
2117
2282
|
if (!Number.isFinite(minX) || !Number.isFinite(minY)) {
|
|
@@ -2136,12 +2301,28 @@
|
|
|
2136
2301
|
}
|
|
2137
2302
|
return current.id;
|
|
2138
2303
|
}
|
|
2139
|
-
function createLabelRect(
|
|
2304
|
+
function createLabelRect(object, placement, labelMultiplier) {
|
|
2305
|
+
return createLabelRectFromText(placement.x, placement.labelY, placement.secondaryY, placement.textAnchor, placement.direction, object.label, object.secondaryLabel, labelMultiplier);
|
|
2306
|
+
}
|
|
2307
|
+
function createLabelRectFromText(x, labelY, secondaryY, textAnchor, direction, label, secondaryLabel, labelMultiplier) {
|
|
2308
|
+
const labelHalfWidth = estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier);
|
|
2309
|
+
const labelWidth = labelHalfWidth * 2;
|
|
2310
|
+
const topPadding = direction === "above" ? 18 : 12;
|
|
2311
|
+
const bottomPadding = direction === "above" ? 8 : 12;
|
|
2312
|
+
let left = x - labelHalfWidth;
|
|
2313
|
+
let right = x + labelHalfWidth;
|
|
2314
|
+
if (textAnchor === "start") {
|
|
2315
|
+
left = x;
|
|
2316
|
+
right = x + labelWidth;
|
|
2317
|
+
} else if (textAnchor === "end") {
|
|
2318
|
+
left = x - labelWidth;
|
|
2319
|
+
right = x;
|
|
2320
|
+
}
|
|
2140
2321
|
return {
|
|
2141
|
-
left
|
|
2142
|
-
right
|
|
2143
|
-
top: Math.min(labelY, secondaryY) -
|
|
2144
|
-
bottom: Math.max(labelY, secondaryY) +
|
|
2322
|
+
left,
|
|
2323
|
+
right,
|
|
2324
|
+
top: Math.min(labelY, secondaryY) - topPadding,
|
|
2325
|
+
bottom: Math.max(labelY, secondaryY) + bottomPadding
|
|
2145
2326
|
};
|
|
2146
2327
|
}
|
|
2147
2328
|
function rectsOverlap(left, right) {
|
|
@@ -2328,11 +2509,6 @@
|
|
|
2328
2509
|
function customColorFor(value) {
|
|
2329
2510
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
2330
2511
|
}
|
|
2331
|
-
function estimateLabelHalfWidth(object, labelMultiplier) {
|
|
2332
|
-
const primaryWidth = object.label.length * 4.6 * labelMultiplier + 18;
|
|
2333
|
-
const secondaryWidth = object.secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
2334
|
-
return Math.max(primaryWidth, secondaryWidth, object.visualRadius + 18);
|
|
2335
|
-
}
|
|
2336
2512
|
function estimateLabelHalfWidthFromText(label, secondaryLabel, labelMultiplier) {
|
|
2337
2513
|
const primaryWidth = label.length * 4.6 * labelMultiplier + 18;
|
|
2338
2514
|
const secondaryWidth = secondaryLabel.length * 3.9 * labelMultiplier + 18;
|
|
@@ -2349,7 +2525,7 @@
|
|
|
2349
2525
|
}
|
|
2350
2526
|
|
|
2351
2527
|
// packages/core/dist/draft.js
|
|
2352
|
-
function materializeAtlasDocument(document2) {
|
|
2528
|
+
function materializeAtlasDocument(document2, options = {}) {
|
|
2353
2529
|
const system = document2.system ? {
|
|
2354
2530
|
type: "system",
|
|
2355
2531
|
id: document2.system.id,
|
|
@@ -2360,6 +2536,8 @@
|
|
|
2360
2536
|
properties: materializeDraftSystemProperties(document2.system),
|
|
2361
2537
|
info: materializeDraftSystemInfo(document2.system)
|
|
2362
2538
|
} : null;
|
|
2539
|
+
const objects = document2.objects.map(cloneWorldOrbitObject);
|
|
2540
|
+
applyEventPoseOverrides(objects, document2.events ?? [], options.activeEventId ?? null);
|
|
2363
2541
|
return {
|
|
2364
2542
|
format: "worldorbit",
|
|
2365
2543
|
version: "1.0",
|
|
@@ -2367,7 +2545,8 @@
|
|
|
2367
2545
|
system,
|
|
2368
2546
|
groups: structuredClone(document2.groups ?? []),
|
|
2369
2547
|
relations: structuredClone(document2.relations ?? []),
|
|
2370
|
-
|
|
2548
|
+
events: document2.events.map(cloneWorldOrbitEvent),
|
|
2549
|
+
objects
|
|
2371
2550
|
};
|
|
2372
2551
|
}
|
|
2373
2552
|
function cloneWorldOrbitObject(object) {
|
|
@@ -2389,6 +2568,52 @@
|
|
|
2389
2568
|
info: { ...object.info }
|
|
2390
2569
|
};
|
|
2391
2570
|
}
|
|
2571
|
+
function cloneWorldOrbitEvent(event) {
|
|
2572
|
+
return {
|
|
2573
|
+
...event,
|
|
2574
|
+
participantObjectIds: [...event.participantObjectIds],
|
|
2575
|
+
tags: [...event.tags],
|
|
2576
|
+
positions: event.positions.map(cloneWorldOrbitEventPose)
|
|
2577
|
+
};
|
|
2578
|
+
}
|
|
2579
|
+
function cloneWorldOrbitEventPose(pose) {
|
|
2580
|
+
return {
|
|
2581
|
+
objectId: pose.objectId,
|
|
2582
|
+
placement: clonePlacement(pose.placement),
|
|
2583
|
+
inner: pose.inner ? { ...pose.inner } : void 0,
|
|
2584
|
+
outer: pose.outer ? { ...pose.outer } : void 0
|
|
2585
|
+
};
|
|
2586
|
+
}
|
|
2587
|
+
function clonePlacement(placement) {
|
|
2588
|
+
return placement ? structuredClone(placement) : null;
|
|
2589
|
+
}
|
|
2590
|
+
function applyEventPoseOverrides(objects, events, activeEventId) {
|
|
2591
|
+
if (!activeEventId) {
|
|
2592
|
+
return;
|
|
2593
|
+
}
|
|
2594
|
+
const event = events.find((entry) => entry.id === activeEventId);
|
|
2595
|
+
if (!event) {
|
|
2596
|
+
return;
|
|
2597
|
+
}
|
|
2598
|
+
const objectMap = new Map(objects.map((object) => [object.id, object]));
|
|
2599
|
+
for (const pose of event.positions) {
|
|
2600
|
+
const object = objectMap.get(pose.objectId);
|
|
2601
|
+
if (!object) {
|
|
2602
|
+
continue;
|
|
2603
|
+
}
|
|
2604
|
+
object.placement = clonePlacement(pose.placement);
|
|
2605
|
+
if (pose.inner) {
|
|
2606
|
+
object.properties.inner = { ...pose.inner };
|
|
2607
|
+
} else {
|
|
2608
|
+
delete object.properties.inner;
|
|
2609
|
+
}
|
|
2610
|
+
if (pose.outer) {
|
|
2611
|
+
object.properties.outer = { ...pose.outer };
|
|
2612
|
+
} else {
|
|
2613
|
+
delete object.properties.outer;
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
}
|
|
2392
2617
|
function cloneProperties(properties) {
|
|
2393
2618
|
const next = {};
|
|
2394
2619
|
for (const [key, value] of Object.entries(properties)) {
|
|
@@ -2477,6 +2702,9 @@
|
|
|
2477
2702
|
if ((viewpoint.filter?.groupIds.length ?? 0) > 0) {
|
|
2478
2703
|
info2[`${prefix}.groups`] = viewpoint.filter?.groupIds.join(" ") ?? "";
|
|
2479
2704
|
}
|
|
2705
|
+
if (viewpoint.events.length > 0) {
|
|
2706
|
+
info2[`${prefix}.events`] = viewpoint.events.join(" ");
|
|
2707
|
+
}
|
|
2480
2708
|
}
|
|
2481
2709
|
for (const annotation of system.annotations) {
|
|
2482
2710
|
const prefix = `annotation.${annotation.id}`;
|
|
@@ -2501,7 +2729,7 @@
|
|
|
2501
2729
|
if (orbitFront !== void 0 || orbitBack !== void 0) {
|
|
2502
2730
|
tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
|
|
2503
2731
|
}
|
|
2504
|
-
for (const key of ["background", "guides", "relations", "objects", "labels", "metadata"]) {
|
|
2732
|
+
for (const key of ["background", "guides", "relations", "events", "objects", "labels", "metadata"]) {
|
|
2505
2733
|
if (layers[key] !== void 0) {
|
|
2506
2734
|
tokens.push(layers[key] ? key : `-${key}`);
|
|
2507
2735
|
}
|
|
@@ -2675,6 +2903,7 @@
|
|
|
2675
2903
|
const diagnostics = [];
|
|
2676
2904
|
const objectMap = new Map(document2.objects.map((object) => [object.id, object]));
|
|
2677
2905
|
const groupIds = new Set(document2.groups.map((group) => group.id));
|
|
2906
|
+
const eventIds = new Set(document2.events.map((event) => event.id));
|
|
2678
2907
|
if (!document2.system) {
|
|
2679
2908
|
diagnostics.push(error("validate.system.required", "Atlas documents must declare exactly one system."));
|
|
2680
2909
|
}
|
|
@@ -2684,6 +2913,7 @@
|
|
|
2684
2913
|
["viewpoint", document2.system?.viewpoints.map((viewpoint) => viewpoint.id) ?? []],
|
|
2685
2914
|
["annotation", document2.system?.annotations.map((annotation) => annotation.id) ?? []],
|
|
2686
2915
|
["relation", document2.relations.map((relation) => relation.id)],
|
|
2916
|
+
["event", document2.events.map((event) => event.id)],
|
|
2687
2917
|
["object", document2.objects.map((object) => object.id)]
|
|
2688
2918
|
]) {
|
|
2689
2919
|
for (const id of ids) {
|
|
@@ -2699,11 +2929,14 @@
|
|
|
2699
2929
|
validateRelation(relation, objectMap, diagnostics);
|
|
2700
2930
|
}
|
|
2701
2931
|
for (const viewpoint of document2.system?.viewpoints ?? []) {
|
|
2702
|
-
|
|
2932
|
+
validateViewpoint(viewpoint.filter, viewpoint.events ?? [], groupIds, eventIds, sourceSchemaVersion, diagnostics, viewpoint.id);
|
|
2703
2933
|
}
|
|
2704
2934
|
for (const object of document2.objects) {
|
|
2705
2935
|
validateObject(object, document2.system, objectMap, groupIds, diagnostics);
|
|
2706
2936
|
}
|
|
2937
|
+
for (const event of document2.events) {
|
|
2938
|
+
validateEvent(event, objectMap, diagnostics);
|
|
2939
|
+
}
|
|
2707
2940
|
return diagnostics;
|
|
2708
2941
|
}
|
|
2709
2942
|
function validateRelation(relation, objectMap, diagnostics) {
|
|
@@ -2721,13 +2954,19 @@
|
|
|
2721
2954
|
diagnostics.push(error("validate.relation.kind.required", `Relation "${relation.id}" is missing a "kind" value.`));
|
|
2722
2955
|
}
|
|
2723
2956
|
}
|
|
2724
|
-
function
|
|
2725
|
-
if (
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2957
|
+
function validateViewpoint(filter, eventRefs, groupIds, eventIds, sourceSchemaVersion, diagnostics, viewpointId) {
|
|
2958
|
+
if (sourceSchemaVersion === "2.1") {
|
|
2959
|
+
if (filter) {
|
|
2960
|
+
for (const groupId of filter.groupIds) {
|
|
2961
|
+
if (!groupIds.has(groupId)) {
|
|
2962
|
+
diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${viewpointId}".`, void 0, `viewpoint.${viewpointId}.groups`));
|
|
2963
|
+
}
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
for (const eventId of eventRefs) {
|
|
2967
|
+
if (!eventIds.has(eventId)) {
|
|
2968
|
+
diagnostics.push(warn("validate.viewpoint.event.unknown", `Unknown event "${eventId}" in viewpoint "${viewpointId}".`, void 0, `viewpoint.${viewpointId}.events`));
|
|
2969
|
+
}
|
|
2731
2970
|
}
|
|
2732
2971
|
}
|
|
2733
2972
|
}
|
|
@@ -2813,6 +3052,103 @@
|
|
|
2813
3052
|
}
|
|
2814
3053
|
}
|
|
2815
3054
|
}
|
|
3055
|
+
function validateEvent(event, objectMap, diagnostics) {
|
|
3056
|
+
const fieldPrefix = `event.${event.id}`;
|
|
3057
|
+
const referencedIds = /* @__PURE__ */ new Set();
|
|
3058
|
+
if (!event.kind.trim()) {
|
|
3059
|
+
diagnostics.push(error("validate.event.kind.required", `Event "${event.id}" is missing a "kind" value.`, void 0, `${fieldPrefix}.kind`));
|
|
3060
|
+
}
|
|
3061
|
+
if (!event.targetObjectId && event.participantObjectIds.length === 0) {
|
|
3062
|
+
diagnostics.push(error("validate.event.references.required", `Event "${event.id}" must define a "target" or at least one participant.`, void 0, `${fieldPrefix}.participants`));
|
|
3063
|
+
}
|
|
3064
|
+
if (event.targetObjectId) {
|
|
3065
|
+
referencedIds.add(event.targetObjectId);
|
|
3066
|
+
if (!objectMap.has(event.targetObjectId)) {
|
|
3067
|
+
diagnostics.push(error("validate.event.target.unknown", `Unknown event target "${event.targetObjectId}" on "${event.id}".`, void 0, `${fieldPrefix}.target`));
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
const seenParticipants = /* @__PURE__ */ new Set();
|
|
3071
|
+
for (const participantId of event.participantObjectIds) {
|
|
3072
|
+
referencedIds.add(participantId);
|
|
3073
|
+
if (seenParticipants.has(participantId)) {
|
|
3074
|
+
diagnostics.push(warn("validate.event.participants.duplicate", `Event "${event.id}" repeats participant "${participantId}".`, void 0, `${fieldPrefix}.participants`));
|
|
3075
|
+
continue;
|
|
3076
|
+
}
|
|
3077
|
+
seenParticipants.add(participantId);
|
|
3078
|
+
if (!objectMap.has(participantId)) {
|
|
3079
|
+
diagnostics.push(error("validate.event.participants.unknown", `Unknown event participant "${participantId}" on "${event.id}".`, void 0, `${fieldPrefix}.participants`));
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
if (event.targetObjectId && event.participantObjectIds.length > 0 && !event.participantObjectIds.includes(event.targetObjectId)) {
|
|
3083
|
+
diagnostics.push(warn("validate.event.target.notParticipant", `Event "${event.id}" defines a target outside its participants list.`, void 0, `${fieldPrefix}.target`));
|
|
3084
|
+
}
|
|
3085
|
+
if (event.positions.length === 0) {
|
|
3086
|
+
diagnostics.push(warn("validate.event.positions.missing", `Event "${event.id}" has no positions block and cannot drive a scene snapshot.`, void 0, `${fieldPrefix}.positions`));
|
|
3087
|
+
}
|
|
3088
|
+
if (/(?:^|[-_])(solar-eclipse|lunar-eclipse|transit|occultation)(?:$|[-_])/.test(event.kind) && referencedIds.size < 3) {
|
|
3089
|
+
diagnostics.push(warn("validate.event.kind.participants", `Event "${event.id}" looks like an eclipse or transit but references fewer than three bodies.`, void 0, `${fieldPrefix}.participants`));
|
|
3090
|
+
}
|
|
3091
|
+
const poseIds = /* @__PURE__ */ new Set();
|
|
3092
|
+
for (const pose of event.positions) {
|
|
3093
|
+
const poseFieldPrefix = `${fieldPrefix}.pose.${pose.objectId}`;
|
|
3094
|
+
if (poseIds.has(pose.objectId)) {
|
|
3095
|
+
diagnostics.push(error("validate.event.pose.duplicate", `Event "${event.id}" defines "${pose.objectId}" more than once in positions.`, void 0, poseFieldPrefix));
|
|
3096
|
+
continue;
|
|
3097
|
+
}
|
|
3098
|
+
poseIds.add(pose.objectId);
|
|
3099
|
+
const object = objectMap.get(pose.objectId);
|
|
3100
|
+
if (!object) {
|
|
3101
|
+
diagnostics.push(error("validate.event.pose.object.unknown", `Unknown event pose object "${pose.objectId}" on "${event.id}".`, void 0, poseFieldPrefix));
|
|
3102
|
+
continue;
|
|
3103
|
+
}
|
|
3104
|
+
if (!referencedIds.has(pose.objectId)) {
|
|
3105
|
+
diagnostics.push(warn("validate.event.pose.unreferenced", `Event pose "${pose.objectId}" on "${event.id}" is not listed in target/participants.`, void 0, poseFieldPrefix));
|
|
3106
|
+
}
|
|
3107
|
+
validateEventPose(pose, object, objectMap, diagnostics, poseFieldPrefix, event.id);
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
function validateEventPose(pose, object, objectMap, diagnostics, fieldPrefix, eventId) {
|
|
3111
|
+
const placement = pose.placement;
|
|
3112
|
+
if (!placement) {
|
|
3113
|
+
diagnostics.push(error("validate.event.pose.placement.required", `Event "${eventId}" pose "${pose.objectId}" is missing a placement mode.`, void 0, fieldPrefix));
|
|
3114
|
+
return;
|
|
3115
|
+
}
|
|
3116
|
+
if (placement.mode === "orbit") {
|
|
3117
|
+
if (!objectMap.has(placement.target)) {
|
|
3118
|
+
diagnostics.push(error("validate.event.pose.orbit.target.unknown", `Unknown event orbit target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.orbit`));
|
|
3119
|
+
}
|
|
3120
|
+
if (placement.distance && placement.semiMajor) {
|
|
3121
|
+
diagnostics.push(error("validate.event.pose.orbit.distanceConflict", `Event "${eventId}" pose "${pose.objectId}" cannot declare both "distance" and "semiMajor".`, void 0, `${fieldPrefix}.distance`));
|
|
3122
|
+
}
|
|
3123
|
+
return;
|
|
3124
|
+
}
|
|
3125
|
+
if (placement.mode === "surface") {
|
|
3126
|
+
const target = objectMap.get(placement.target);
|
|
3127
|
+
if (!target) {
|
|
3128
|
+
diagnostics.push(error("validate.event.pose.surface.target.unknown", `Unknown event surface target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.surface`));
|
|
3129
|
+
} else if (!SURFACE_TARGET_TYPES2.has(target.type)) {
|
|
3130
|
+
diagnostics.push(error("validate.event.pose.surface.target.invalid", `Event surface target "${placement.target}" on "${eventId}:${pose.objectId}" is not surface-capable.`, void 0, `${fieldPrefix}.surface`));
|
|
3131
|
+
}
|
|
3132
|
+
return;
|
|
3133
|
+
}
|
|
3134
|
+
if (placement.mode === "at") {
|
|
3135
|
+
if (object.type !== "structure" && object.type !== "phenomenon") {
|
|
3136
|
+
diagnostics.push(error("validate.event.pose.at.objectType", `Only structures and phenomena may use "at" placement in events; found "${object.type}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3137
|
+
}
|
|
3138
|
+
const reference = placement.reference;
|
|
3139
|
+
if (reference.kind === "named" && !objectMap.has(reference.name)) {
|
|
3140
|
+
diagnostics.push(error("validate.event.pose.at.target.unknown", `Unknown event at-reference target "${placement.target}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3141
|
+
} else if (reference.kind === "anchor" && !objectMap.has(reference.objectId)) {
|
|
3142
|
+
diagnostics.push(error("validate.event.pose.anchor.target.unknown", `Unknown event anchor target "${reference.objectId}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3143
|
+
} else if (reference.kind === "lagrange") {
|
|
3144
|
+
if (!objectMap.has(reference.primary)) {
|
|
3145
|
+
diagnostics.push(error("validate.event.pose.lagrange.primary.unknown", `Unknown event Lagrange target "${reference.primary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3146
|
+
} else if (reference.secondary && !objectMap.has(reference.secondary)) {
|
|
3147
|
+
diagnostics.push(error("validate.event.pose.lagrange.secondary.unknown", `Unknown event Lagrange target "${reference.secondary}" on "${eventId}:${pose.objectId}".`, void 0, `${fieldPrefix}.at`));
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
2816
3152
|
function validateAtTarget(object, objectMap, diagnostics) {
|
|
2817
3153
|
const reference = object.placement?.mode === "at" ? object.placement.reference : null;
|
|
2818
3154
|
if (!reference) {
|
|
@@ -3013,6 +3349,21 @@
|
|
|
3013
3349
|
});
|
|
3014
3350
|
}
|
|
3015
3351
|
var DRAFT_OBJECT_FIELD_KEYS = new Set(DRAFT_OBJECT_FIELD_SPECS.keys());
|
|
3352
|
+
var EVENT_POSE_FIELD_KEYS = /* @__PURE__ */ new Set([
|
|
3353
|
+
"orbit",
|
|
3354
|
+
"distance",
|
|
3355
|
+
"semiMajor",
|
|
3356
|
+
"eccentricity",
|
|
3357
|
+
"period",
|
|
3358
|
+
"angle",
|
|
3359
|
+
"inclination",
|
|
3360
|
+
"phase",
|
|
3361
|
+
"at",
|
|
3362
|
+
"surface",
|
|
3363
|
+
"free",
|
|
3364
|
+
"inner",
|
|
3365
|
+
"outer"
|
|
3366
|
+
]);
|
|
3016
3367
|
function parseWorldOrbitAtlas(source) {
|
|
3017
3368
|
return parseAtlasSource(source);
|
|
3018
3369
|
}
|
|
@@ -3027,12 +3378,15 @@
|
|
|
3027
3378
|
const objectNodes = [];
|
|
3028
3379
|
const groups = [];
|
|
3029
3380
|
const relations = [];
|
|
3381
|
+
const events = [];
|
|
3382
|
+
const eventPoseNodes = /* @__PURE__ */ new Map();
|
|
3030
3383
|
let sawDefaults = false;
|
|
3031
3384
|
let sawAtlas = false;
|
|
3032
3385
|
const viewpointIds = /* @__PURE__ */ new Set();
|
|
3033
3386
|
const annotationIds = /* @__PURE__ */ new Set();
|
|
3034
3387
|
const groupIds = /* @__PURE__ */ new Set();
|
|
3035
3388
|
const relationIds = /* @__PURE__ */ new Set();
|
|
3389
|
+
const eventIds = /* @__PURE__ */ new Set();
|
|
3036
3390
|
for (let index = 0; index < lines.length; index++) {
|
|
3037
3391
|
const rawLine = lines[index];
|
|
3038
3392
|
const lineNumber = index + 1;
|
|
@@ -3063,7 +3417,7 @@
|
|
|
3063
3417
|
continue;
|
|
3064
3418
|
}
|
|
3065
3419
|
if (indent === 0) {
|
|
3066
|
-
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, { sawDefaults, sawAtlas });
|
|
3420
|
+
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, { sawDefaults, sawAtlas });
|
|
3067
3421
|
if (section.kind === "system") {
|
|
3068
3422
|
system = section.system;
|
|
3069
3423
|
} else if (section.kind === "defaults") {
|
|
@@ -3082,6 +3436,7 @@
|
|
|
3082
3436
|
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
3083
3437
|
}
|
|
3084
3438
|
const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
|
|
3439
|
+
const normalizedEvents = events.map((event) => normalizeDraftEvent(event, eventPoseNodes.get(event.id) ?? []));
|
|
3085
3440
|
const outputVersion = forcedOutputVersion ?? (sourceSchemaVersion === "2.0-draft" ? "2.0" : sourceSchemaVersion);
|
|
3086
3441
|
const baseDocument = {
|
|
3087
3442
|
format: "worldorbit",
|
|
@@ -3089,6 +3444,7 @@
|
|
|
3089
3444
|
system,
|
|
3090
3445
|
groups,
|
|
3091
3446
|
relations,
|
|
3447
|
+
events: normalizedEvents,
|
|
3092
3448
|
objects,
|
|
3093
3449
|
diagnostics
|
|
3094
3450
|
};
|
|
@@ -3124,7 +3480,7 @@
|
|
|
3124
3480
|
const version = tokens[1].value.toLowerCase();
|
|
3125
3481
|
return version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
3126
3482
|
}
|
|
3127
|
-
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, flags) {
|
|
3483
|
+
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, events, eventPoseNodes, viewpointIds, annotationIds, groupIds, relationIds, eventIds, flags) {
|
|
3128
3484
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
3129
3485
|
switch (keyword) {
|
|
3130
3486
|
case "system":
|
|
@@ -3161,7 +3517,7 @@
|
|
|
3161
3517
|
if (!system) {
|
|
3162
3518
|
throw new WorldOrbitError('Atlas section "viewpoint" requires a preceding system declaration', line, tokens[0].column);
|
|
3163
3519
|
}
|
|
3164
|
-
return startViewpointSection(tokens, line, system, viewpointIds);
|
|
3520
|
+
return startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics);
|
|
3165
3521
|
case "annotation":
|
|
3166
3522
|
if (!system) {
|
|
3167
3523
|
throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
|
|
@@ -3173,6 +3529,9 @@
|
|
|
3173
3529
|
case "relation":
|
|
3174
3530
|
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "relation", { line, column: tokens[0].column });
|
|
3175
3531
|
return startRelationSection(tokens, line, relations, relationIds);
|
|
3532
|
+
case "event":
|
|
3533
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "event", { line, column: tokens[0].column });
|
|
3534
|
+
return startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics);
|
|
3176
3535
|
case "object":
|
|
3177
3536
|
return startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes);
|
|
3178
3537
|
default:
|
|
@@ -3209,7 +3568,7 @@
|
|
|
3209
3568
|
seenFields: /* @__PURE__ */ new Set()
|
|
3210
3569
|
};
|
|
3211
3570
|
}
|
|
3212
|
-
function startViewpointSection(tokens, line, system, viewpointIds) {
|
|
3571
|
+
function startViewpointSection(tokens, line, system, viewpointIds, sourceSchemaVersion, diagnostics) {
|
|
3213
3572
|
if (tokens.length !== 2) {
|
|
3214
3573
|
throw new WorldOrbitError("Invalid viewpoint declaration", line, tokens[0]?.column ?? 1);
|
|
3215
3574
|
}
|
|
@@ -3226,6 +3585,7 @@
|
|
|
3226
3585
|
summary: "",
|
|
3227
3586
|
focusObjectId: null,
|
|
3228
3587
|
selectedObjectId: null,
|
|
3588
|
+
events: [],
|
|
3229
3589
|
projection: system.defaults.view,
|
|
3230
3590
|
preset: system.defaults.preset,
|
|
3231
3591
|
zoom: null,
|
|
@@ -3238,6 +3598,8 @@
|
|
|
3238
3598
|
return {
|
|
3239
3599
|
kind: "viewpoint",
|
|
3240
3600
|
viewpoint,
|
|
3601
|
+
sourceSchemaVersion,
|
|
3602
|
+
diagnostics,
|
|
3241
3603
|
seenFields: /* @__PURE__ */ new Set(),
|
|
3242
3604
|
inFilter: false,
|
|
3243
3605
|
filterIndent: null,
|
|
@@ -3328,6 +3690,49 @@
|
|
|
3328
3690
|
seenFields: /* @__PURE__ */ new Set()
|
|
3329
3691
|
};
|
|
3330
3692
|
}
|
|
3693
|
+
function startEventSection(tokens, line, events, eventPoseNodes, eventIds, sourceSchemaVersion, diagnostics) {
|
|
3694
|
+
if (tokens.length !== 2) {
|
|
3695
|
+
throw new WorldOrbitError("Invalid event declaration", line, tokens[0]?.column ?? 1);
|
|
3696
|
+
}
|
|
3697
|
+
const id = normalizeIdentifier(tokens[1].value);
|
|
3698
|
+
if (!id) {
|
|
3699
|
+
throw new WorldOrbitError("Event id must not be empty", line, tokens[1].column);
|
|
3700
|
+
}
|
|
3701
|
+
if (eventIds.has(id)) {
|
|
3702
|
+
throw new WorldOrbitError(`Duplicate event id "${id}"`, line, tokens[1].column);
|
|
3703
|
+
}
|
|
3704
|
+
const event = {
|
|
3705
|
+
id,
|
|
3706
|
+
kind: "",
|
|
3707
|
+
label: humanizeIdentifier2(id),
|
|
3708
|
+
summary: null,
|
|
3709
|
+
targetObjectId: null,
|
|
3710
|
+
participantObjectIds: [],
|
|
3711
|
+
timing: null,
|
|
3712
|
+
visibility: null,
|
|
3713
|
+
tags: [],
|
|
3714
|
+
color: null,
|
|
3715
|
+
hidden: false,
|
|
3716
|
+
positions: []
|
|
3717
|
+
};
|
|
3718
|
+
const rawPoses = [];
|
|
3719
|
+
events.push(event);
|
|
3720
|
+
eventPoseNodes.set(id, rawPoses);
|
|
3721
|
+
eventIds.add(id);
|
|
3722
|
+
return {
|
|
3723
|
+
kind: "event",
|
|
3724
|
+
event,
|
|
3725
|
+
sourceSchemaVersion,
|
|
3726
|
+
diagnostics,
|
|
3727
|
+
seenFields: /* @__PURE__ */ new Set(),
|
|
3728
|
+
rawPoses,
|
|
3729
|
+
inPositions: false,
|
|
3730
|
+
positionsIndent: null,
|
|
3731
|
+
activePose: null,
|
|
3732
|
+
poseIndent: null,
|
|
3733
|
+
activePoseSeenFields: /* @__PURE__ */ new Set()
|
|
3734
|
+
};
|
|
3735
|
+
}
|
|
3331
3736
|
function startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes) {
|
|
3332
3737
|
if (tokens.length < 3) {
|
|
3333
3738
|
throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
|
|
@@ -3384,6 +3789,9 @@
|
|
|
3384
3789
|
case "relation":
|
|
3385
3790
|
applyRelationField(section, tokens, line);
|
|
3386
3791
|
return;
|
|
3792
|
+
case "event":
|
|
3793
|
+
applyEventField(section, indent, tokens, line);
|
|
3794
|
+
return;
|
|
3387
3795
|
case "object":
|
|
3388
3796
|
applyObjectField(section, indent, tokens, line);
|
|
3389
3797
|
return;
|
|
@@ -3510,7 +3918,14 @@
|
|
|
3510
3918
|
section.viewpoint.rotationDeg = parseFiniteNumber2(value, line, tokens[0].column, "rotation");
|
|
3511
3919
|
return;
|
|
3512
3920
|
case "layers":
|
|
3513
|
-
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line);
|
|
3921
|
+
section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line, section.sourceSchemaVersion, section.diagnostics);
|
|
3922
|
+
return;
|
|
3923
|
+
case "events":
|
|
3924
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "viewpoint.events", {
|
|
3925
|
+
line,
|
|
3926
|
+
column: tokens[0].column
|
|
3927
|
+
});
|
|
3928
|
+
section.viewpoint.events = parseTokenList(tokens.slice(1), line, "events");
|
|
3514
3929
|
return;
|
|
3515
3930
|
default:
|
|
3516
3931
|
throw new WorldOrbitError(`Unknown viewpoint field "${tokens[0].value}"`, line, tokens[0].column);
|
|
@@ -3615,6 +4030,106 @@
|
|
|
3615
4030
|
throw new WorldOrbitError(`Unknown relation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3616
4031
|
}
|
|
3617
4032
|
}
|
|
4033
|
+
function applyEventField(section, indent, tokens, line) {
|
|
4034
|
+
if (section.activePose && indent <= (section.poseIndent ?? 0)) {
|
|
4035
|
+
section.activePose = null;
|
|
4036
|
+
section.poseIndent = null;
|
|
4037
|
+
section.activePoseSeenFields.clear();
|
|
4038
|
+
}
|
|
4039
|
+
if (!section.activePose && section.inPositions && indent <= (section.positionsIndent ?? 0)) {
|
|
4040
|
+
section.inPositions = false;
|
|
4041
|
+
section.positionsIndent = null;
|
|
4042
|
+
}
|
|
4043
|
+
if (section.activePose) {
|
|
4044
|
+
section.activePose.fields.push(parseEventPoseField(tokens, line, section.activePoseSeenFields));
|
|
4045
|
+
return;
|
|
4046
|
+
}
|
|
4047
|
+
if (section.inPositions) {
|
|
4048
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "pose") {
|
|
4049
|
+
throw new WorldOrbitError(`Unknown event positions field "${tokens[0].value}"`, line, tokens[0]?.column ?? 1);
|
|
4050
|
+
}
|
|
4051
|
+
const objectId = tokens[1].value;
|
|
4052
|
+
if (!objectId.trim()) {
|
|
4053
|
+
throw new WorldOrbitError("Event pose object id must not be empty", line, tokens[1].column);
|
|
4054
|
+
}
|
|
4055
|
+
const rawPose = {
|
|
4056
|
+
objectId,
|
|
4057
|
+
fields: [],
|
|
4058
|
+
location: { line, column: tokens[0].column }
|
|
4059
|
+
};
|
|
4060
|
+
section.rawPoses.push(rawPose);
|
|
4061
|
+
section.activePose = rawPose;
|
|
4062
|
+
section.poseIndent = indent;
|
|
4063
|
+
section.activePoseSeenFields = /* @__PURE__ */ new Set();
|
|
4064
|
+
return;
|
|
4065
|
+
}
|
|
4066
|
+
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "positions") {
|
|
4067
|
+
if (section.seenFields.has("positions")) {
|
|
4068
|
+
throw new WorldOrbitError('Duplicate event field "positions"', line, tokens[0].column);
|
|
4069
|
+
}
|
|
4070
|
+
section.seenFields.add("positions");
|
|
4071
|
+
section.inPositions = true;
|
|
4072
|
+
section.positionsIndent = indent;
|
|
4073
|
+
return;
|
|
4074
|
+
}
|
|
4075
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
4076
|
+
switch (key) {
|
|
4077
|
+
case "kind":
|
|
4078
|
+
section.event.kind = joinFieldValue(tokens, line);
|
|
4079
|
+
return;
|
|
4080
|
+
case "label":
|
|
4081
|
+
section.event.label = joinFieldValue(tokens, line);
|
|
4082
|
+
return;
|
|
4083
|
+
case "summary":
|
|
4084
|
+
section.event.summary = joinFieldValue(tokens, line);
|
|
4085
|
+
return;
|
|
4086
|
+
case "target":
|
|
4087
|
+
section.event.targetObjectId = joinFieldValue(tokens, line);
|
|
4088
|
+
return;
|
|
4089
|
+
case "participants":
|
|
4090
|
+
section.event.participantObjectIds = parseTokenList(tokens.slice(1), line, "participants");
|
|
4091
|
+
return;
|
|
4092
|
+
case "timing":
|
|
4093
|
+
section.event.timing = joinFieldValue(tokens, line);
|
|
4094
|
+
return;
|
|
4095
|
+
case "visibility":
|
|
4096
|
+
section.event.visibility = joinFieldValue(tokens, line);
|
|
4097
|
+
return;
|
|
4098
|
+
case "tags":
|
|
4099
|
+
section.event.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4100
|
+
return;
|
|
4101
|
+
case "color":
|
|
4102
|
+
section.event.color = joinFieldValue(tokens, line);
|
|
4103
|
+
return;
|
|
4104
|
+
case "hidden":
|
|
4105
|
+
section.event.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4106
|
+
line,
|
|
4107
|
+
column: tokens[0].column
|
|
4108
|
+
});
|
|
4109
|
+
return;
|
|
4110
|
+
default:
|
|
4111
|
+
throw new WorldOrbitError(`Unknown event field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4112
|
+
}
|
|
4113
|
+
}
|
|
4114
|
+
function parseEventPoseField(tokens, line, seenFields) {
|
|
4115
|
+
if (tokens.length < 2) {
|
|
4116
|
+
throw new WorldOrbitError("Invalid event pose field line", line, tokens[0]?.column ?? 1);
|
|
4117
|
+
}
|
|
4118
|
+
const key = tokens[0].value;
|
|
4119
|
+
if (!EVENT_POSE_FIELD_KEYS.has(key)) {
|
|
4120
|
+
throw new WorldOrbitError(`Unknown event pose field "${key}"`, line, tokens[0].column);
|
|
4121
|
+
}
|
|
4122
|
+
if (seenFields.has(key)) {
|
|
4123
|
+
throw new WorldOrbitError(`Duplicate event pose field "${key}"`, line, tokens[0].column);
|
|
4124
|
+
}
|
|
4125
|
+
seenFields.add(key);
|
|
4126
|
+
return {
|
|
4127
|
+
type: "field",
|
|
4128
|
+
key,
|
|
4129
|
+
values: tokens.slice(1).map((token) => token.value),
|
|
4130
|
+
location: { line, column: tokens[0].column }
|
|
4131
|
+
};
|
|
4132
|
+
}
|
|
3618
4133
|
function applyObjectField(section, indent, tokens, line) {
|
|
3619
4134
|
if (section.activeBlock && indent <= (section.blockIndent ?? 0)) {
|
|
3620
4135
|
section.activeBlock = null;
|
|
@@ -3673,7 +4188,7 @@
|
|
|
3673
4188
|
function parseObjectTypeTokens(tokens, line) {
|
|
3674
4189
|
return parseTokenList(tokens, line, "objectTypes").filter((value) => value === "star" || value === "planet" || value === "moon" || value === "belt" || value === "asteroid" || value === "comet" || value === "ring" || value === "structure" || value === "phenomenon");
|
|
3675
4190
|
}
|
|
3676
|
-
function parseLayerTokens(tokens, line) {
|
|
4191
|
+
function parseLayerTokens(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
3677
4192
|
const layers = {};
|
|
3678
4193
|
for (const token of parseTokenList(tokens, line, "layers")) {
|
|
3679
4194
|
const enabled = !token.startsWith("-") && !token.startsWith("!");
|
|
@@ -3683,7 +4198,13 @@
|
|
|
3683
4198
|
layers["orbits-front"] = enabled;
|
|
3684
4199
|
continue;
|
|
3685
4200
|
}
|
|
3686
|
-
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
4201
|
+
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "events" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
4202
|
+
if (raw === "events" && sourceSchemaVersion && diagnostics) {
|
|
4203
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "layers.events", {
|
|
4204
|
+
line,
|
|
4205
|
+
column: tokens[0]?.column ?? 1
|
|
4206
|
+
});
|
|
4207
|
+
}
|
|
3687
4208
|
layers[raw] = enabled;
|
|
3688
4209
|
}
|
|
3689
4210
|
}
|
|
@@ -3822,7 +4343,7 @@
|
|
|
3822
4343
|
}
|
|
3823
4344
|
function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
3824
4345
|
const fieldMap = collectDraftFields(node.fields);
|
|
3825
|
-
const placement =
|
|
4346
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
3826
4347
|
const properties = normalizeDraftProperties(node.objectType, fieldMap);
|
|
3827
4348
|
const groups = parseOptionalTokenList(fieldMap.get("groups")?.[0]);
|
|
3828
4349
|
const epoch = parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]);
|
|
@@ -3874,6 +4395,24 @@
|
|
|
3874
4395
|
}
|
|
3875
4396
|
return object;
|
|
3876
4397
|
}
|
|
4398
|
+
function normalizeDraftEvent(event, rawPoses) {
|
|
4399
|
+
return {
|
|
4400
|
+
...event,
|
|
4401
|
+
participantObjectIds: [...new Set(event.participantObjectIds)],
|
|
4402
|
+
tags: [...new Set(event.tags)],
|
|
4403
|
+
positions: rawPoses.map((pose) => normalizeDraftEventPose(pose))
|
|
4404
|
+
};
|
|
4405
|
+
}
|
|
4406
|
+
function normalizeDraftEventPose(rawPose) {
|
|
4407
|
+
const fieldMap = collectDraftFields(rawPose.fields);
|
|
4408
|
+
const placement = extractPlacementFromFieldMap(fieldMap);
|
|
4409
|
+
return {
|
|
4410
|
+
objectId: rawPose.objectId,
|
|
4411
|
+
placement,
|
|
4412
|
+
inner: parseOptionalUnitField(fieldMap.get("inner")?.[0], "inner"),
|
|
4413
|
+
outer: parseOptionalUnitField(fieldMap.get("outer")?.[0], "outer")
|
|
4414
|
+
};
|
|
4415
|
+
}
|
|
3877
4416
|
function collectDraftFields(fields) {
|
|
3878
4417
|
const grouped = /* @__PURE__ */ new Map();
|
|
3879
4418
|
for (const field of fields) {
|
|
@@ -3890,7 +4429,7 @@
|
|
|
3890
4429
|
}
|
|
3891
4430
|
return grouped;
|
|
3892
4431
|
}
|
|
3893
|
-
function
|
|
4432
|
+
function extractPlacementFromFieldMap(fieldMap) {
|
|
3894
4433
|
const orbitField = fieldMap.get("orbit")?.[0];
|
|
3895
4434
|
const atField = fieldMap.get("at")?.[0];
|
|
3896
4435
|
const surfaceField = fieldMap.get("surface")?.[0];
|
|
@@ -4326,6 +4865,7 @@
|
|
|
4326
4865
|
background: true,
|
|
4327
4866
|
guides: true,
|
|
4328
4867
|
relations: true,
|
|
4868
|
+
events: true,
|
|
4329
4869
|
orbits: true,
|
|
4330
4870
|
objects: true,
|
|
4331
4871
|
labels: true,
|
|
@@ -4529,6 +5069,7 @@
|
|
|
4529
5069
|
const orbitMarkup = layers.orbits ? renderOrbitLayer(scene, visibleObjectIds, layers.structures) : { back: "", front: "" };
|
|
4530
5070
|
const leaderMarkup = layers.guides ? scene.leaders.filter((leader) => !leader.hidden).filter((leader) => visibleObjectIds.has(leader.objectId)).filter((leader) => layers.structures || !isStructureLike(leader.object)).map((leader) => `<line class="wo-leader wo-leader-${leader.mode}" x1="${leader.x1}" y1="${leader.y1}" x2="${leader.x2}" y2="${leader.y2}" data-render-id="${escapeXml(leader.renderId)}" data-group-id="${escapeAttribute(leader.groupId ?? "")}" />`).join("") : "";
|
|
4531
5071
|
const relationMarkup = layers.relations ? scene.relations.filter((relation) => !relation.hidden).filter((relation) => visibleObjectIds.has(relation.fromObjectId) && visibleObjectIds.has(relation.toObjectId)).map((relation) => `<line class="wo-relation" x1="${relation.x1}" y1="${relation.y1}" x2="${relation.x2}" y2="${relation.y2}" data-render-id="${escapeXml(relation.renderId)}" data-relation-id="${escapeAttribute(relation.relationId)}" />`).join("") : "";
|
|
5072
|
+
const eventMarkup = layers.events ? scene.events.filter((event) => !event.hidden).map((event) => renderSceneEventOverlay(scene, event, visibleObjectIds, theme)).join("") : "";
|
|
4532
5073
|
const objectMarkup = layers.objects ? visibleObjects.map((object) => renderSceneObject(object, options.selectedObjectId ?? null, theme)).join("") : "";
|
|
4533
5074
|
const labelMarkup = layers.labels ? visibleLabels.map((label) => renderSceneLabel(scene, label, options.selectedObjectId ?? null)).join("") : "";
|
|
4534
5075
|
const metadataMarkup = layers.metadata ? `<text class="wo-title" x="56" y="64">${escapeXml(scene.title)}</text>
|
|
@@ -4564,6 +5105,9 @@
|
|
|
4564
5105
|
.wo-orbit-front { opacity: 0.9; }
|
|
4565
5106
|
.wo-orbit-band { stroke: ${theme.orbitBand}; stroke-linecap: round; }
|
|
4566
5107
|
.wo-relation { stroke: ${theme.relation}; stroke-width: 2; stroke-dasharray: 10 6; }
|
|
5108
|
+
.wo-event-line { stroke: ${theme.accent}; stroke-width: 1.6; stroke-dasharray: 5 5; opacity: 0.72; }
|
|
5109
|
+
.wo-event-node { fill: ${theme.accent}; stroke: ${theme.selected}; stroke-width: 1.4; opacity: 0.92; }
|
|
5110
|
+
.wo-event-label { fill: ${theme.accent}; font-family: ${theme.fontFamily}; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
|
|
4567
5111
|
.wo-leader { stroke: ${theme.leader}; stroke-width: 1.5; stroke-dasharray: 6 5; }
|
|
4568
5112
|
.wo-label { fill: ${theme.ink}; font-family: ${theme.fontFamily}; font-weight: 600; letter-spacing: 0.02em; }
|
|
4569
5113
|
.wo-label-secondary { fill: ${theme.muted}; font-family: ${theme.fontFamily}; font-weight: 500; }
|
|
@@ -4598,6 +5142,7 @@
|
|
|
4598
5142
|
${layers.orbits ? `<g data-layer-id="orbits-back">${orbitMarkup.back}</g>` : ""}
|
|
4599
5143
|
${layers.guides ? `<g data-layer-id="guides">${leaderMarkup}</g>` : ""}
|
|
4600
5144
|
${layers.relations ? `<g data-layer-id="relations">${relationMarkup}</g>` : ""}
|
|
5145
|
+
${layers.events ? `<g data-layer-id="events">${eventMarkup}</g>` : ""}
|
|
4601
5146
|
${layers.objects ? `<g data-layer-id="objects">${objectMarkup}</g>` : ""}
|
|
4602
5147
|
${layers.orbits ? `<g data-layer-id="orbits-front">${orbitMarkup.front}</g>` : ""}
|
|
4603
5148
|
${layers.labels ? `<g data-layer-id="labels">${labelMarkup}</g>` : ""}
|
|
@@ -4605,6 +5150,20 @@
|
|
|
4605
5150
|
</g>
|
|
4606
5151
|
</g>
|
|
4607
5152
|
</svg>`;
|
|
5153
|
+
}
|
|
5154
|
+
function renderSceneEventOverlay(scene, event, visibleObjectIds, theme) {
|
|
5155
|
+
const participants = event.objectIds.filter((objectId) => visibleObjectIds.has(objectId)).map((objectId) => scene.objects.find((object) => object.objectId === objectId && !object.hidden)).filter(Boolean);
|
|
5156
|
+
if (participants.length === 0) {
|
|
5157
|
+
return "";
|
|
5158
|
+
}
|
|
5159
|
+
const stroke = event.event.color || theme.accent;
|
|
5160
|
+
const label = event.event.label || event.event.id;
|
|
5161
|
+
const lineMarkup = participants.map((object) => `<line class="wo-event-line" x1="${event.x}" y1="${event.y}" x2="${object.x}" y2="${object.y}" stroke="${escapeAttribute(stroke)}" data-event-id="${escapeAttribute(event.eventId)}" data-object-id="${escapeAttribute(object.objectId)}" />`).join("");
|
|
5162
|
+
return `<g class="wo-event" data-render-id="${escapeXml(event.renderId)}" data-event-id="${escapeAttribute(event.eventId)}">
|
|
5163
|
+
${lineMarkup}
|
|
5164
|
+
<circle class="wo-event-node" cx="${event.x}" cy="${event.y}" r="5" fill="${escapeAttribute(stroke)}" />
|
|
5165
|
+
<text class="wo-event-label" x="${event.x}" y="${event.y - 10}" text-anchor="middle" font-size="10">${escapeXml(label)}</text>
|
|
5166
|
+
</g>`;
|
|
4608
5167
|
}
|
|
4609
5168
|
function renderOrbitLayer(scene, visibleObjectIds, includeStructures) {
|
|
4610
5169
|
const backParts = [];
|