@molstudio/core 0.1.0 → 0.1.2
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/MolStudio.d.ts +9 -0
- package/dist/MolStudio.js +60 -8
- package/package.json +1 -1
package/dist/MolStudio.d.ts
CHANGED
|
@@ -51,6 +51,11 @@ export declare class MolStudio {
|
|
|
51
51
|
loadVolume({ data, label, format }: LoadDataOptions<VolumeFormat>): Promise<void>;
|
|
52
52
|
loadVolumeFromUrl(url: string, label: string, format: VolumeFormat, isBinary: boolean): Promise<void>;
|
|
53
53
|
private applyStructurePreset;
|
|
54
|
+
/**
|
|
55
|
+
* Mol*'s default preset colors ligand carbons by chain, the same color as the protein around them;
|
|
56
|
+
* element colors keep a ligand distinct from its binding pocket.
|
|
57
|
+
*/
|
|
58
|
+
private colorLigandCarbonsByElement;
|
|
54
59
|
private applyVolumeVisuals;
|
|
55
60
|
setVisible(id: string, visible: boolean): void;
|
|
56
61
|
/**
|
|
@@ -113,6 +118,10 @@ export declare class MolStudio {
|
|
|
113
118
|
private transparencyLayers;
|
|
114
119
|
private partLoci;
|
|
115
120
|
private residueRef;
|
|
121
|
+
/**
|
|
122
|
+
* Fits the visible structures, or everything when none is shown. A map's box is usually much larger
|
|
123
|
+
* than its density, so fitting it would leave a fitted model small in the middle of the view.
|
|
124
|
+
*/
|
|
116
125
|
resetCamera(): void;
|
|
117
126
|
setSpinning(spinning: boolean): void;
|
|
118
127
|
setBackground(hex: string): void;
|
package/dist/MolStudio.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { PLDDTConfidenceColorThemeProvider } from "molstar/lib/extensions/model-archive/quality-assessment/color/plddt";
|
|
2
|
+
import { QualityAssessment } from "molstar/lib/extensions/model-archive/quality-assessment/prop";
|
|
3
|
+
import { MmcifFormat } from "molstar/lib/mol-model-formats/structure/mmcif";
|
|
2
4
|
import { DownloadDensity } from "molstar/lib/mol-plugin-state/actions/volume";
|
|
3
5
|
import { PluginConfig } from "molstar/lib/mol-plugin/config";
|
|
4
6
|
import { Volume } from "molstar/lib/mol-model/volume";
|
|
5
7
|
import { Loci } from "molstar/lib/mol-model/loci";
|
|
6
|
-
import { Structure, StructureElement } from "molstar/lib/mol-model/structure";
|
|
8
|
+
import { Model, Structure, StructureElement } from "molstar/lib/mol-model/structure";
|
|
7
9
|
import { createStructureColorThemeParams, createStructureRepresentationParams, } from "molstar/lib/mol-plugin-state/helpers/structure-representation-params";
|
|
8
10
|
import { clearStructureTransparency, setStructureTransparency } from "molstar/lib/mol-plugin-state/helpers/structure-transparency";
|
|
9
11
|
import { createVolumeColorThemeParams } from "molstar/lib/mol-plugin-state/helpers/volume-representation-params";
|
|
@@ -70,7 +72,10 @@ export class MolStudio {
|
|
|
70
72
|
}));
|
|
71
73
|
}
|
|
72
74
|
static async create(target) {
|
|
73
|
-
const
|
|
75
|
+
const spec = DefaultPluginSpec();
|
|
76
|
+
// Mol*'s "auto" mode renders at 1x on mobile browsers, which blurs structures on high-DPI phones.
|
|
77
|
+
spec.config = [...(spec.config ?? []), [PluginConfig.General.ResolutionMode, "native"]];
|
|
78
|
+
const plugin = new PluginContext(spec);
|
|
74
79
|
await plugin.init();
|
|
75
80
|
// Only the pLDDT theme is needed; Mol*'s quality-assessment behaviour also pulls in its React UI.
|
|
76
81
|
plugin.representation.structure.themes.colorThemeRegistry.add(PLDDTConfidenceColorThemeProvider);
|
|
@@ -219,7 +224,27 @@ export class MolStudio {
|
|
|
219
224
|
}
|
|
220
225
|
async applyStructurePreset(raw, format) {
|
|
221
226
|
const trajectory = await this.plugin.builders.structure.parseTrajectory(raw, format);
|
|
222
|
-
await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, "default");
|
|
227
|
+
const result = await this.plugin.builders.structure.hierarchy.applyPreset(trajectory, "default");
|
|
228
|
+
// Mol* parses some malformed input (e.g. text that is not SDF) into an empty structure without failing.
|
|
229
|
+
if (!result?.structure.data?.elementCount) {
|
|
230
|
+
throw new Error(`The ${format} data contains no atoms.`);
|
|
231
|
+
}
|
|
232
|
+
await this.colorLigandCarbonsByElement(result.structure.ref);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Mol*'s default preset colors ligand carbons by chain, the same color as the protein around them;
|
|
236
|
+
* element colors keep a ligand distinct from its binding pocket.
|
|
237
|
+
*/
|
|
238
|
+
async colorLigandCarbonsByElement(structureRef) {
|
|
239
|
+
const structure = this.requireStructure(structureRef);
|
|
240
|
+
const reprs = structure.components
|
|
241
|
+
.filter((component) => staticComponentType(component) === "ligand")
|
|
242
|
+
.flatMap((component) => component.representations)
|
|
243
|
+
.filter((repr) => repr.cell.transform.params?.colorTheme.name === "element-symbol");
|
|
244
|
+
await this.updateEach(reprs, (old) => ({
|
|
245
|
+
...old,
|
|
246
|
+
colorTheme: { ...old.colorTheme, params: { ...old.colorTheme.params, carbonColor: { name: "element-symbol", params: {} } } },
|
|
247
|
+
}));
|
|
223
248
|
}
|
|
224
249
|
async applyVolumeVisuals(raw, format) {
|
|
225
250
|
const provider = this.plugin.dataFormats.get(format);
|
|
@@ -373,7 +398,7 @@ export class MolStudio {
|
|
|
373
398
|
? structure.components.flatMap((component) => component.representations)
|
|
374
399
|
: (volume?.representations ?? this.requireComponent(target).representations);
|
|
375
400
|
const renderObjects = reprs.flatMap((repr) => repr.cell.obj?.data.repr.renderObjects ?? []);
|
|
376
|
-
this.plugin.managers.camera.focusRenderObjects(renderObjects);
|
|
401
|
+
this.plugin.managers.camera.focusRenderObjects(renderObjects, FOCUS_OPTIONS);
|
|
377
402
|
}
|
|
378
403
|
async remove(id) {
|
|
379
404
|
await PluginCommands.State.RemoveObject(this.plugin, {
|
|
@@ -401,7 +426,7 @@ export class MolStudio {
|
|
|
401
426
|
const loci = this.partLoci(part);
|
|
402
427
|
if (part.scope === "residue")
|
|
403
428
|
this.plugin.managers.structure.focus.setFromLoci(loci);
|
|
404
|
-
this.plugin.managers.camera.focusLoci(loci);
|
|
429
|
+
this.plugin.managers.camera.focusLoci(loci, FOCUS_OPTIONS);
|
|
405
430
|
}
|
|
406
431
|
/** Leaves Mol*'s focus view, removing its target and surroundings components, and returns to the earlier view. */
|
|
407
432
|
clearFocus() {
|
|
@@ -555,8 +580,21 @@ export class MolStudio {
|
|
|
555
580
|
return owner ? { objectId: owner.cell.transform.ref, residueIndex } : null;
|
|
556
581
|
}
|
|
557
582
|
// ---- viewport ----
|
|
583
|
+
/**
|
|
584
|
+
* Fits the visible structures, or everything when none is shown. A map's box is usually much larger
|
|
585
|
+
* than its density, so fitting it would leave a fitted model small in the middle of the view.
|
|
586
|
+
*/
|
|
558
587
|
resetCamera() {
|
|
559
|
-
|
|
588
|
+
const renderObjects = this.plugin.managers.structure.hierarchy.current.structures
|
|
589
|
+
.flatMap((structure) => structure.components)
|
|
590
|
+
.flatMap((component) => component.representations)
|
|
591
|
+
.flatMap((repr) => repr.cell.obj?.data.repr.renderObjects ?? [])
|
|
592
|
+
.filter((renderObject) => renderObject.state.visible);
|
|
593
|
+
if (renderObjects.length === 0) {
|
|
594
|
+
PluginCommands.Camera.Reset(this.plugin, {});
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
this.plugin.managers.camera.focusRenderObjects(renderObjects, { extraRadius: 0 });
|
|
560
598
|
}
|
|
561
599
|
setSpinning(spinning) {
|
|
562
600
|
const canvas3d = this.requireCanvas();
|
|
@@ -720,8 +758,7 @@ export class MolStudio {
|
|
|
720
758
|
}
|
|
721
759
|
applicableSchemes(ref) {
|
|
722
760
|
const structure = ref.cell.obj?.data;
|
|
723
|
-
const
|
|
724
|
-
const hasPlddt = !!structure && !!plddt?.isApplicable({ structure });
|
|
761
|
+
const hasPlddt = !!structure && structure.models.some(isPredictedModel);
|
|
725
762
|
return hasPlddt ? ["plddt-confidence", ...BASE_SCHEMES] : [...BASE_SCHEMES];
|
|
726
763
|
}
|
|
727
764
|
// ---- lookup helpers ----
|
|
@@ -834,6 +871,21 @@ const AXES = {
|
|
|
834
871
|
};
|
|
835
872
|
/** Matches Mol*'s default camera focus animation. */
|
|
836
873
|
const CAMERA_TRANSITION_MS = 250;
|
|
874
|
+
/** Keeps the surroundings of small targets (a ligand, a residue) in view instead of filling the screen with them. */
|
|
875
|
+
const FOCUS_OPTIONS = { minRadius: 14 };
|
|
876
|
+
/**
|
|
877
|
+
* Whether B-factors hold pLDDT scores. Mol* assumes so for any model not marked experimental, but most
|
|
878
|
+
* PDB entries lack that mark, so an entry with experimental methods recorded does not count.
|
|
879
|
+
*/
|
|
880
|
+
function isPredictedModel(model) {
|
|
881
|
+
if (QualityAssessment.isApplicable(model, "pLDDT"))
|
|
882
|
+
return true;
|
|
883
|
+
if (!MmcifFormat.is(model.sourceData) || !model.atomicConformation.B_iso_or_equiv.isDefined)
|
|
884
|
+
return false;
|
|
885
|
+
if (Model.isExperimental(model))
|
|
886
|
+
return false;
|
|
887
|
+
return model.sourceData.data.db.exptl.method.rowCount === 0;
|
|
888
|
+
}
|
|
837
889
|
const FOCUS_TAGS = {
|
|
838
890
|
[StructureFocusRepresentationTags.TargetSel]: "target",
|
|
839
891
|
[StructureFocusRepresentationTags.SurrSel]: "surroundings",
|