Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/first control component #7

Merged
merged 6 commits into from
Sep 15, 2023
Merged
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
24 changes: 24 additions & 0 deletions src/lib/controls/HighlightInfo.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script lang="ts">
import { getContext } from 'svelte';
import { fade } from 'svelte/transition';
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>

{#if $highlightS?.labels.length > 0}
<div class="molstar-svelte-highlight-info ${clazz || ''}" transition:fade={{ duration: 100 }}>
{#each $highlightS.labels as label}
{@html label}
{/each}
</div>
{/if}

<style lang="postcss">
.molstar-svelte-highlight-info {
@apply absolute right-0 bottom-0 p-2 m-2 rounded bg-slate-400 border border-slate-500 text-white text-xs;
}
</style>
82 changes: 14 additions & 68 deletions src/lib/wrappers/SimpleWrapper.svelte
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
<script lang="ts">
import { BROWSER } from 'esm-env';
import type { Writable } from 'svelte/store';
import { onDestroy, onMount, setContext, createEventDispatcher } from 'svelte';
import { DefaultPluginSpec, PluginSpec } from 'molstar/lib/mol-plugin/spec.js';
import { PluginContext } from 'molstar/lib/mol-plugin/context.js';
import { PluginCommands } from 'molstar/lib/mol-plugin/commands.js';
import { PluginConfig } from 'molstar/lib/mol-plugin/config.js';
import { Color } from 'molstar/lib/mol-util/color';
import { onDestroy, onMount, setContext, createEventDispatcher } from 'svelte';
import type { Writable } from 'svelte/store';
import { BROWSER } from 'esm-env';
import { defaultPluginSpec, defaultCanvas3dSettings } from './simplewrapper-utils.js';

let clazz = '';
let randArray = new Uint8Array(1);

export { clazz as class };
export let didDrawStore: Writable<{ value: number; instanceId: string }> | null = null;

export let plugin: PluginContext | null = null; // used for binding
let randArray = new Uint8Array(1);
export let uid = crypto.getRandomValues(randArray)[0];
let renderer = null;
export let pluginSpecs: Partial<PluginSpec> = defaultPluginSpec;

let initcomplete = false;

let molstarContainerEl: HTMLDivElement;
Expand All @@ -27,31 +27,7 @@

const MySpec: PluginSpec = {
...DefaultPluginSpec(),
config: [[PluginConfig.VolumeStreaming.Enabled, false]],
canvas3d: {
postprocessing: {
occlusion: {
name: 'on',
params: {
samples: 32,
radius: 6,
bias: 1.4,
multiScale: { name: 'off', params: {} },
blurKernelSize: 15,
resolutionScale: 1
}
},
outline: { name: 'on', params: { scale: 1, threshold: 0.99, color: Color(0x000000) } }
},
renderer: {
ambientIntensity: 1.0,
light: [
//{ color: Color(0xffffff), azimuth: 1.0, inclination: 180, intensity: 1.0 }
],
backgroundColor: 0x001f42 as Color
}
}
//config:[[PluginConfig.Structure.DefaultRepresentationPreset, ViewerAutoPreset.id],]
...pluginSpecs
};

plugin = new PluginContext(MySpec);
Expand All @@ -68,38 +44,11 @@
return;
}

renderer = plugin.canvas3d!.props.renderer;
//renderer = plugin.canvas3d!.props.renderer;
if (didDrawStore) {
pluginDidDrawObservable = plugin?.behaviors.interaction.drag.asObservable(); //plugin?.canvas3d?.didDraw;
}
await PluginCommands.Canvas3D.SetSettings(plugin, {
settings: {
/* renderer: {
...renderer,
ambientIntensity: 1.0,
light: [],
backgroundColor: 0x001f42 as Color
}, */
cameraResetDurationMs: 100,
trackball: {
noScroll: true
},
postprocessing: {
occlusion: {
name: 'on',
params: {
multiScale: { name: 'off', params: {} },
samples: 32,
radius: 6,
bias: 1.4,
blurKernelSize: 15,
resolutionScale: 1
}
},
outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000) } }
}
}
});
await PluginCommands.Canvas3D.SetSettings(plugin, defaultCanvas3dSettings);

/* await PluginCommands.State.Update(plugin,{
options:{
Expand All @@ -114,15 +63,12 @@
if (!BROWSER) return;
await init();
initcomplete = true;

//console.log('plugin');
//console.dir(plugin);
});

onDestroy(async () => {
if (initcomplete) {
await plugin?.clear();
await plugin?.dispose();
plugin?.dispose();
}
});

Expand All @@ -142,12 +88,12 @@
>
<canvas bind:this={molstarCanvasEl} />
{#if BROWSER && initcomplete}
<slot name="elements" />
<slot name="inside" />
{/if}
</div>
</div>
{#if BROWSER && initcomplete}
<slot name="controls" />
<slot name="outside" />
{/if}
</div>

Expand Down
60 changes: 60 additions & 0 deletions src/lib/wrappers/simplewrapper-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { PluginConfig } from 'molstar/lib/mol-plugin/config.js';
import type { PluginSpec } from 'molstar/lib/mol-plugin/spec.js';
import { Color } from 'molstar/lib/mol-util/color/color.js';

export const defaultPluginSpec: Partial<PluginSpec> = {
config: [[PluginConfig.VolumeStreaming.Enabled, false]],
canvas3d: {
postprocessing: {
occlusion: {
name: 'on',
params: {
samples: 32,
radius: 6,
bias: 1.4,
multiScale: { name: 'off', params: {} },
blurKernelSize: 15,
resolutionScale: 1
}
},
outline: { name: 'on', params: { scale: 1, threshold: 0.99, color: Color(0x000000) } }
},
renderer: {
ambientIntensity: 1.0,
light: [
//{ color: Color(0xffffff), azimuth: 1.0, inclination: 180, intensity: 1.0 }
],
backgroundColor: 0x001f42 as Color
}
}
//config:[[PluginConfig.Structure.DefaultRepresentationPreset, ViewerAutoPreset.id],]
};

export const defaultCanvas3dSettings = {
settings: {
/* renderer: {
...renderer,
ambientIntensity: 1.0,
light: [],
backgroundColor: 0x001f42 as Color
}, */
cameraResetDurationMs: 100,
trackball: {
noScroll: true
},
postprocessing: {
occlusion: {
name: 'on',
params: {
multiScale: { name: 'off', params: {} },
samples: 32,
radius: 6,
bias: 1.4,
blurKernelSize: 15,
resolutionScale: 1
}
},
outline: { name: 'on', params: { scale: 1, threshold: 0.33, color: Color(0x000000) } }
}
}
};
1 change: 1 addition & 0 deletions src/routes/AppHeader.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
class="flex flex-col items-center text-gray-400 hover:text-gray-600"
>
<img src="{base}/github-mark.svg" alt="Mol* logo" class="h-8" />
<!-- svelte-ignore missing-declaration -->
<span class="self-end justify-self-end ml-auto">(v{__PKG_VERSION__})</span>
</a>

Expand Down
1 change: 1 addition & 0 deletions src/routes/Menu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
Components:
<ul role="list" class="sublist">
<li><a href="{base}/components/simple-elements">SimpleWrapper + elements</a></li>
<li><a href="{base}/components/simple-controls">SimpleWrapper + controls</a></li>
</ul>
</li>
</ul>
Expand Down
20 changes: 20 additions & 0 deletions src/routes/components/simple-controls/+page.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script lang="ts">
import { browser} from '$app/environment';


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

</script>

# SimpleWrapper + controls

## Highlight info

{#if browser}
{#await loadComponentDemoWithControls() then MolstarComp}
<svelte:component this={MolstarComp} />
{/await}
{/if}
28 changes: 28 additions & 0 deletions src/routes/components/simple-controls/DemoControls.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script lang="ts">
import StructureURL from '$lib/elements/StructureURL.svelte';
import HighlightInfo from '$lib/controls/HighlightInfo.svelte';
import MolstarWrapper from '$lib/wrappers/SimpleWrapper.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">
<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">
<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>
</svelte:fragment>
</MolstarWrapper>
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 @@ -11,7 +11,7 @@
Selected: <span class="text-violet-500">{selectedPdbIds.join(', ')}</span>
</p>
<MolstarWrapper class="h-96">
<svelte:fragment slot="elements">
<svelte:fragment slot="inside">
{#each selectedPdbIds as pdbId (pdbId)}
<StructureRCSB {pdbId} />
{/each}
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 @@ -18,7 +18,7 @@
>
</p>
<MolstarWrapper class="h-96">
<svelte:fragment slot="elements">
<svelte:fragment slot="inside">
{#each selectedStructuresURLs as structureURL (`${structureURL.url}-${structureURL.type}`)}
<StructureURL url={structureURL.url} type={structureURL.type} />
{/each}
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 @@ -22,7 +22,7 @@
>
</p>
<MolstarWrapper class="h-96">
<svelte:fragment slot="elements">
<svelte:fragment slot="inside">
{#each selectedStructuresURLs as structureURL (`${structureURL.url}-${structureURL.type}-${structureURL.chainId}`)}
<StructureURLChain
url={structureURL.url}
Expand Down
51 changes: 34 additions & 17 deletions src/routes/getting-started/+page.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,8 @@ npm install molstar-svelte

## Usage

### In a Sveltekit application

As an in-browser and WEBGL-heavy toolkit, Molstar doesn't play well with SSR (Sever Side Rendering) and some flavors of SSG (Static Site Generation), so you'll need some extra work to run it smoothly in a Sveltekit application.

For now, it's recommended to:
- Create your own component in which you will compose the Molstar components (entry component / composition root).
- Dynamically import this component in your page (using `<svelte:component>`).

**Component example:**
### Component example:
```svelte
<!-- your component -->
<script lang="ts">
Expand All @@ -26,21 +19,45 @@ export let url = 'https://alphafold.ebi.ac.uk/files/AF-P05067-F1-model_v4.cif';
export let structureType = 'mmcif';

</script>

<!-- you will have to give an height to the wrapper, it will be the initial height of the canvas -->
<SimpleWrapper class="h-96">
<svelte:fragment slot="elements">
<!-- here you can inject/compose "html-less" components that will render on the Molstar's plugin canvas -->
<svelte:fragment slot="inside">
<!-- here you can inject/compose components that will render in the same container of the Molstar's plugin canvas -->
<StructureURL url={url} type={structureType} />
</svelte:fragment>
<svelte:fragment slot="controls">
<!-- here you can inject/compose "html" components that will render outside of the Molstar's plugin canvas -->
<!-- Useful for UI elements, buttons, etc. -->
<svelte:fragment slot="outside">
<!-- here you can inject/compose "html" components that will render the container of the Molstar's plugin canvas -->
<p>Currently displaying {url}</p>
</svelte:fragment>
</SimpleWrapper>
```

**Component usage example:**
#### Slots

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

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.

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

As an in-browser and WEBGL-heavy toolkit, Molstar doesn't play well with SSR (Sever Side Rendering) and some flavors of SSG (Static Site Generation), so you'll need some extra work to run it smoothly in a Sveltekit application.

For now, it's recommended to:
- Create your own component in which you will compose the Molstar components (entry component / composition root).
- Dynamically import this component in your page (using `<svelte:component>`).

```svelte
<script lang="ts">
const import3DViz = async () =>
Expand All @@ -54,10 +71,10 @@ export let structureType = 'mmcif';
{:catch error}
<p>ARRH, ERROR: {error}</p>
{/await}

```

### In a Svelte application

#### In a Svelte application

The previous method should work, but you should also be able to use the components directly in your Svelte application (without the need for a dynamic import).

Expand Down