Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/lib/controls/Scene.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script lang="ts">
import { getContext } from 'svelte';

import type { PluginContext } from 'molstar/lib/mol-plugin/context';
const plugin = getContext<{ getPlugin: () => PluginContext }>('molstar').getPlugin();
const highlightS = plugin.behaviors.labels.highlight;

let clazz = '';
export { clazz as class };
</script>

<!-- <ul>
{#each plugin.log.entries as log}
<li>{log.type} - {log.message}</li>
{/each}
</ul>

<ul>
{#each plugin.hierarchy.current.structures as structure}
<li>{structure.label}</li>
{/each}
</ul> -->

<style lang="postcss">
.molstar-svelte-highlight-info {
}
</style>
104 changes: 104 additions & 0 deletions src/lib/elements/StructureAlphaFold.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<script lang="ts">
/**
* Load a structure from an URL
* @param url URL to load the structure from
* @param type Type of the structure
*/

import { getContext, onMount, onDestroy } from 'svelte';
import { PluginContext } from 'molstar/lib/mol-plugin/context.js';
import { PluginCommands } from 'molstar/lib/mol-plugin/commands.js';
import { DownloadStructure } from 'molstar/lib/mol-plugin-state/actions/structure.js';
import { QualityAssessmentPLDDTPreset } from 'molstar/lib/extensions/model-archive/quality-assessment/behavior.js';
import type { BuiltInTrajectoryFormat } from 'molstar/lib/mol-plugin-state/formats/trajectory.js';
import { StructureRepresentationPresetProvider } from 'molstar/lib/mol-plugin-state/builder/structure/representation-preset.js';
import { PluginConfig } from 'molstar/lib/mol-plugin/config.js';

export let url: string;
export let type: BuiltInTrajectoryFormat;
export let alphaDBId: string;
type Preset =
| 'auto'
| 'empty'
| 'illustrative'
| 'atomic-detail'
| 'polymer-cartoon'
| 'polymer-and-ligand'
| 'protein-and-nucleic'
| 'coarse-surface'
| undefined;

const plugin = getContext<{ getPlugin: () => PluginContext }>('molstar').getPlugin();

let structure: Awaited<ReturnType<typeof plugin.builders.structure.createStructure>>;

// FIXME: move this at molstar wrapper level.
// when unmounting + mounting again, molstar understably complains about the preset already being registred.
plugin.builders.structure.representation.registerPreset(QualityAssessmentPLDDTPreset);

const init = async () => {
let data;

const params = DownloadStructure.createDefaultParams(plugin.state.data.root.obj!, plugin);

data = await plugin.builders.data.download({ url: url }, { state: { isGhost: false } });
const trajectory = await plugin.builders.structure.parseTrajectory(data, type);
const model = await plugin.builders.structure.createModel(trajectory);
const struct = await plugin.builders.structure.createStructure(model);
structure = struct;

console.log('structure', structure);

await plugin.builders.structure.hierarchy.applyPreset(
trajectory,
'preset-structure-representation-ma-quality-assessment-plddt',
params
);
//await plugin.builders.structure.hierarchy.applyPreset(model, 'default', params);

//const model = await plugin.builders.structure.createModel(trajectory);
//const params = StructureRepresentationPresetProvider.CommonParams;
//await QualityAssessmentPLDDTPreset.apply(model.ref, params, plugin);
//const struct = await plugin.builders.structure.createStructure(model);
//structure = struct;

//await plugin.managers.structure.component.updateRepresentationsTheme();

//await plugin.builders.structure.hierarchy.applyPreset(structure, 'default', params);
//await plugin.builders.structure.hierarchy.applyPreset(structure, 'default');
//QualityAssessmentPLDDTPreset.apply(structure, params, plugin);
// await plugin.managers.structure.component.applyPreset(
// structure,
// QualityAssessmentPLDDTPreset,
// params
// );

// const params = DownloadStructure.createDefaultParams(plugin.state.data.root.obj!, plugin);
// await plugin.runTask(
// plugin.state.data.applyAction(DownloadStructure, {
// source: {
// name: 'alphafolddb' as const,
// params: {
// id: alphaDBId,
// options: {
// ...params.source.params.options,
// representation: 'preset-structure-representation-ma-quality-assessment-plddt'
// }
// }
// }
// })
// );

return;
//return;
};
onMount(async () => {
await init();
});
onDestroy(() => {
plugin.commands.dispatch(PluginCommands.State.RemoveObject, {
state: plugin.state.data,
ref: structure.ref
});
});
</script>
2 changes: 1 addition & 1 deletion src/lib/elements/StructureURL.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
const model = await plugin.builders.structure.createModel(trajectory);
const struct = await plugin.builders.structure.createStructure(model);
structure = struct;
await plugin.builders.structure.hierarchy.applyPreset(structure, 'default');
await plugin.builders.structure.hierarchy.applyPreset(trajectory, 'default');
};
onMount(() => {
init();
Expand Down
15 changes: 10 additions & 5 deletions src/lib/wrappers/SimpleWrapper.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
let randArray = new Uint8Array(1);

export { clazz as class };
export let pluginCssClasses = '';
export let didDrawStore: Writable<{ value: number; instanceId: string }> | null = null;
export let plugin: PluginContext | null = null; // used for binding
export let uid = crypto.getRandomValues(randArray)[0];
Expand All @@ -35,10 +36,13 @@
setContext('molstar', { getPlugin: () => plugin });

async function init() {
if (!BROWSER) return;
if (!plugin) return;
await plugin.init();

if (!window?.molstarInstances) {
window.molstarInstances = new Map();
}
window.molstarInstances.set(uid, plugin);

if (!plugin.initViewer(molstarCanvasEl, molstarContainerEl)) {
console.error('Failed to init Mol*');
return;
Expand All @@ -60,7 +64,7 @@
}

onMount(async () => {
if (!BROWSER) return;
if (!BROWSER || !plugin) return;
await init();
initcomplete = true;
});
Expand All @@ -69,6 +73,7 @@
if (initcomplete) {
await plugin?.clear();
plugin?.dispose();
window.molstarInstances.delete(uid);
}
});

Expand All @@ -80,8 +85,8 @@
}
</script>

<div class="molstar-svelte_wrapper">
<div class={`plugin_container ${clazz || ''}`}>
<div class="molstar-svelte_wrapper {clazz || ''}">
<div class="plugin_container {pluginCssClasses || ''}">
<div
bind:this={molstarContainerEl}
style="position: absolute; top: 0; left: 0; right: 0; bottom: 0"
Expand Down
19 changes: 18 additions & 1 deletion src/routes/components/simple-controls/+page.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,31 @@
return m.default;
});

const loadComponentDemoWithControls2 = async () =>
import('./DemoControls2.svelte').then((m) => {
return m.default;
});

</script>

# SimpleWrapper + controls

## Highlight info
## Highlight info + ButtonBar

{#if browser}
{#await loadComponentDemoWithControls() then MolstarComp}
<div class="not-prose">
<svelte:component this={MolstarComp} />
</div>
{/await}
{/if}

## Highlight info + ButtonBar variant

{#if browser}
{#await loadComponentDemoWithControls2() then MolstarComp}
<div class="not-prose">
<svelte:component this={MolstarComp} />
</div>
{/await}
{/if}
5 changes: 3 additions & 2 deletions src/routes/components/simple-controls/DemoControls.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@
import StructureURL from '$lib/elements/StructureURL.svelte';
import HighlightInfo from '$lib/controls/HighlightInfo.svelte';
import MolstarWrapper from '$lib/wrappers/SimpleWrapper.svelte';

import ButtonBar from '$lib/controls/ButtonBar.svelte';
export let structuresURLs = [
{ url: 'https://files.rcsb.org/view/7YUB.cif', type: 'mmcif' },
{ url: 'https://alphafold.ebi.ac.uk/files/AF-P00533-F1-model_v4.cif', type: 'mmcif' }
];
let selectedStructuresURLs = [...structuresURLs];
</script>

<MolstarWrapper class="h-96 relative">
<MolstarWrapper class="" pluginCssClasses="h-96 w-full">
<svelte:fragment slot="inside">
{#each selectedStructuresURLs as structureURL (`${structureURL.url}-${structureURL.type}`)}
<StructureURL url={structureURL.url} type={structureURL.type} />
{/each}
<HighlightInfo />
</svelte:fragment>
<svelte:fragment slot="outside">
<ButtonBar />
<div>
Displaying:
{#each selectedStructuresURLs as structureURL (`${structureURL.url}-${structureURL.type}`)}
Expand Down
37 changes: 37 additions & 0 deletions src/routes/components/simple-controls/DemoControls2.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<script lang="ts">
import StructureURL from '$lib/elements/StructureURL.svelte';
import StructureAlphaFold from '$lib/elements/StructureAlphaFold.svelte';
import HighlightInfo from '$lib/controls/HighlightInfo.svelte';
import DebugPanel from '$lib/controls/debug/DebugPanel.svelte';
import Scene from '$lib/controls/Scene.svelte';
import MolstarWrapper from '$lib/wrappers/SimpleWrapper.svelte';
import ButtonBar from '$lib/controls/ButtonBar.svelte';
export let structuresURLs = [
{ url: 'https://alphafold.ebi.ac.uk/files/AF-Q8W3K0-F1-model_v4.cif', type: 'mmcif' }
];
let selectedStructuresURLs = [...structuresURLs];
</script>

<div>
<MolstarWrapper pluginCssClasses="h-96 w-full" class="flex">
<svelte:fragment slot="inside">
<StructureAlphaFold
url={selectedStructuresURLs[0].url}
type={selectedStructuresURLs[0].type}
/>

<HighlightInfo />
</svelte:fragment>
<div slot="outside" class="flex flex-col">
<ButtonBar class="flex flex-col bg-red-500" />
<DebugPanel panelOpen={false} />
<Scene />
<div>
Displaying:
{#each selectedStructuresURLs as structureURL (`${structureURL.url}-${structureURL.type}`)}
<p class="text-xs"><span>{structureURL.url}</span> <span>({structureURL.type})</span></p>
{/each}
</div>
</div>
</MolstarWrapper>
</div>
2 changes: 1 addition & 1 deletion src/routes/components/simple-elements/DemoRCSB.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<p class="text-xs">
Selected: <span class="text-violet-500">{selectedPdbIds.join(', ')}</span>
</p>
<MolstarWrapper class="h-96">
<MolstarWrapper class="h-96" pluginCssClasses="h-96 w-full">
<svelte:fragment slot="inside">
{#each selectedPdbIds as pdbId (pdbId)}
<StructureRCSB {pdbId} />
Expand Down
2 changes: 1 addition & 1 deletion src/routes/components/simple-elements/DemoURL.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
>{selectedStructuresURLs.map((e) => e.url).join(', ')}</span
>
</p>
<MolstarWrapper class="h-96">
<MolstarWrapper class="h-96" pluginCssClasses="h-96 w-full">
<svelte:fragment slot="inside">
{#each selectedStructuresURLs as structureURL (`${structureURL.url}-${structureURL.type}`)}
<StructureURL url={structureURL.url} type={structureURL.type} />
Expand Down
2 changes: 1 addition & 1 deletion src/routes/components/simple-elements/DemoURLChain.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
>{selectedStructuresURLs.map((e) => e.url).join(', ')}</span
>
</p>
<MolstarWrapper class="h-96">
<MolstarWrapper class="" pluginCssClasses="h-96 w-full">
<svelte:fragment slot="inside">
{#each selectedStructuresURLs as structureURL (`${structureURL.url}-${structureURL.type}-${structureURL.chainId}`)}
<StructureURLChain
Expand Down
6 changes: 2 additions & 4 deletions src/routes/getting-started/+page.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,18 @@ export let structureType = 'mmcif';

#### Slots

You'll get 2 slots: `elements` and `controls`.
You'll get 2 slots: `inside` and `outside`.

Each component you'll inject in these two slots:
- will be rendered in a different container (depending on the slot).
- will be able to get the Molstar plugin instance through Svelte's getContext(), like: `const plugin = getContext('molstar').getPlugin()`.

The `inside` slot is injected in the same container as the Molstar's plugin canvas, while the `outside` slot is injected outside of it (but still in the container of `SimpleWrapper`).

Typically, if you want to position a UI element on top of the canvas, you'll want to use the `elements` slot, while if you want to position a UI element outside of the canvas, you'll want to use the `controls` slot.
Typically, if you want to position a UI element on top of the canvas, you'll want to use the `inside` slot, while if you want to position a UI element outside of the canvas, you'll want to use the `outside` slot.

In the example above, we're using `<svelte:fragment>` to inject our components without an extra container/wrapping element, but you can use any element you want.



### Loading the component in a page

#### In a Sveltekit application
Expand Down