@speckle/shared
Version:
Shared code between various Speckle JS packages
160 lines • 6.86 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatSerializedViewerState = exports.isSerializedViewerState = exports.SERIALIZED_VIEWER_STATE_VERSION = void 0;
const _lodash_1 = require("#lodash");
const index_js_1 = require("../errors/index.js");
const index_js_2 = require("../../core/index.js");
/** Redefining these is unfortunate. Especially since they are not part of viewer-core */
var MeasurementType;
(function (MeasurementType) {
MeasurementType[MeasurementType["PERPENDICULAR"] = 0] = "PERPENDICULAR";
MeasurementType[MeasurementType["POINTTOPOINT"] = 1] = "POINTTOPOINT";
MeasurementType[MeasurementType["AREA"] = 2] = "AREA";
MeasurementType[MeasurementType["POINT"] = 3] = "POINT";
})(MeasurementType || (MeasurementType = {}));
/**
* v1 -> v1.1
* - ui.filters.propertyFilter.isApplied field added
* - ui.spotlightUserId swapped for spotlightUserSessionId
* v1.1 -> v1.2
* - ui.diff added
* v1.2 -> v1.3
* - ui.filters.selectedObjectIds removed in favor of ui.filters.selectedObjectApplicationIds
*/
exports.SERIALIZED_VIEWER_STATE_VERSION = 1.3;
/**
* Note: This only does superficial validation. To really ensure that all of the keys are there, even if prefilled with default values, make sure you invoke
* formatSerializedViewerState() on the state afterwards
*/
const isSerializedViewerState = (val) => {
if (!val)
return false;
const keys = [
'projectId',
'sessionId',
'resources',
'ui',
'viewer'
];
if (!(0, _lodash_1.isObjectLike)(val))
return false;
const valKeys = Object.keys(val);
if ((0, _lodash_1.intersection)(valKeys, keys).length !== keys.length)
return false;
return true;
};
exports.isSerializedViewerState = isSerializedViewerState;
const initializeMissingData = (state) => {
const throwInvalidError = (missingPath) => {
throw new index_js_1.UnformattableSerializedViewerStateError('Required data missing from SerializedViewerState: ' + missingPath);
};
const defaultMeasurementOptions = {
visible: false,
type: MeasurementType.POINTTOPOINT,
vertexSnap: false,
units: 'm',
precision: 2
};
const measurementOptions = {
...defaultMeasurementOptions,
...state.ui?.measurement?.options
};
const selectedObjectApplicationIds = {
// Parse legacy object ids array as object
...(state.ui?.filters?.selectedObjectIds?.reduce((ret, id) => {
ret[id] = null;
return ret;
}, {}) ?? {}),
// Sanitize incoming object
...(0, index_js_2.coerceUndefinedValuesToNull)(state.ui?.filters?.selectedObjectApplicationIds || {})
};
return {
projectId: state.projectId || throwInvalidError('projectId'),
sessionId: state.sessionId || `nullSessionId-${Math.random() * 1000}`,
viewer: {
...(state.viewer || {}),
metadata: {
...(state.viewer?.metadata || {}),
filteringState: state.viewer?.metadata?.filteringState || null
}
},
resources: {
...(state.resources || {}),
request: {
...(state.resources?.request || {}),
resourceIdString: state.resources?.request?.resourceIdString ||
throwInvalidError('resources.request.resourceIdString'),
threadFilters: {
...(state.resources?.request?.threadFilters || {}),
includeArchived: state.resources?.request?.threadFilters?.includeArchived || false,
loadedVersionsOnly: state.resources?.request?.threadFilters?.loadedVersionsOnly || false
}
}
},
ui: {
...(state.ui || {}),
threads: {
...(state.ui?.threads || {}),
openThread: {
...(state.ui?.threads?.openThread || {}),
threadId: state.ui?.threads?.openThread?.threadId || null,
isTyping: state.ui?.threads?.openThread?.isTyping || false,
newThreadEditor: state.ui?.threads?.openThread?.newThreadEditor || false
}
},
diff: {
...(state.ui?.diff || {}),
command: state.ui?.diff?.command || null,
time: state.ui?.diff?.time || 0.5,
mode: state.ui?.diff?.mode || 1
},
spotlightUserSessionId: state.ui?.spotlightUserSessionId || null,
filters: {
...(state.ui?.filters || {}),
isolatedObjectIds: state.ui?.filters?.isolatedObjectIds || [],
hiddenObjectIds: state.ui?.filters?.hiddenObjectIds || [],
selectedObjectApplicationIds,
propertyFilter: {
...(state.ui?.filters?.propertyFilter || {}),
key: state.ui?.filters?.propertyFilter?.key || null,
isApplied: state.ui?.filters?.propertyFilter?.isApplied || false
}
},
camera: {
...(state.ui?.camera || {}),
position: state.ui?.camera?.position || throwInvalidError('ui.camera.position'),
target: state.ui?.camera?.target || throwInvalidError('ui.camera.target'),
isOrthoProjection: state.ui?.camera?.isOrthoProjection || false,
zoom: state.ui?.camera?.zoom || 1
},
viewMode: state.ui?.viewMode || 0,
sectionBox: state.ui?.sectionBox?.min?.length && state.ui?.sectionBox.max?.length
? // Complains otherwise
state.ui.sectionBox
: null,
lightConfig: {
...(state.ui?.lightConfig || {}),
intensity: state.ui?.lightConfig?.intensity,
indirectLightIntensity: state.ui?.lightConfig?.indirectLightIntensity,
elevation: state.ui?.lightConfig?.elevation,
azimuth: state.ui?.lightConfig?.azimuth
},
explodeFactor: state.ui?.explodeFactor || 0,
selection: state.ui?.selection || null,
measurement: {
enabled: state.ui?.measurement?.enabled ?? false,
options: measurementOptions
}
}
};
};
/**
* Formats SerializedViewerState by bringing it up to date with the structure of the latest version
* and ensuring missing keys are initialized with default values
*/
const formatSerializedViewerState = (state) => {
const finalState = initializeMissingData(state);
return finalState;
};
exports.formatSerializedViewerState = formatSerializedViewerState;
//# sourceMappingURL=state.js.map