Skip to content

Commit

Permalink
Merge pull request #7 from 0gust1/feat/first_control_component
Browse files Browse the repository at this point in the history
Feat/first control component
  • Loading branch information
0gust1 authored Sep 15, 2023
2 parents b0219b2 + b2d3a60 commit 6060700
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 88 deletions.
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

0 comments on commit 6060700

Please sign in to comment.