Skip to content
Snippets Groups Projects
context.ts 5.79 KiB
Newer Older
David Sehnal's avatar
David Sehnal committed
/**
 * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
 *
 * @author David Sehnal <david.sehnal@gmail.com>
 */

import { Transformer, Transform, State } from 'mol-state';
import { Canvas3D } from 'mol-canvas3d/canvas3d';
David Sehnal's avatar
David Sehnal committed
import { StateTransforms } from './state/transforms';
import { PluginStateObject as SO } from './state/objects';
David Sehnal's avatar
David Sehnal committed
import { RxEventHelper } from 'mol-util/rx-event-helper';
import { PluginState } from './state';
David Sehnal's avatar
David Sehnal committed
import { PluginCommand, PluginCommands } from './command';
David Sehnal's avatar
David Sehnal committed
import { Task } from 'mol-task';
David Sehnal's avatar
David Sehnal committed
import { merge } from 'rxjs';
David Sehnal's avatar
David Sehnal committed
import { PluginBehaviors, BuiltInPluginBehaviors } from './behavior';
import { Loci, EmptyLoci } from 'mol-model/loci';
import { Representation } from 'mol-repr';
David Sehnal's avatar
David Sehnal committed
import { CreateStructureFromPDBe } from './state/actions/basic';
import { LogEntry } from 'mol-util/log-entry';
import { TaskManager } from './util/task-manager';
David Sehnal's avatar
David Sehnal committed

export class PluginContext {
David Sehnal's avatar
David Sehnal committed
    private disposed = false;
    private ev = RxEventHelper.create();
    private tasks = new TaskManager();
David Sehnal's avatar
David Sehnal committed
    readonly state = new PluginState(this);
David Sehnal's avatar
David Sehnal committed
    readonly commands = new PluginCommand.Manager();
    readonly events = {
David Sehnal's avatar
David Sehnal committed
        state: {
            data: this.state.data.events,
            behavior: this.state.behavior.events,
David Sehnal's avatar
David Sehnal committed
            cameraSnapshots: this.state.cameraSnapshots.events,
            snapshots: this.state.snapshots.events,
        log: this.ev<LogEntry>(),
        task: this.tasks.events
David Sehnal's avatar
David Sehnal committed
    };

David Sehnal's avatar
David Sehnal committed
    readonly behaviors = {
David Sehnal's avatar
David Sehnal committed
        state: {
            data: this.state.data.behaviors,
            behavior: this.state.behavior.behaviors
David Sehnal's avatar
David Sehnal committed
        },
        canvas: {
            highlightLoci: this.ev.behavior<{ loci: Loci, repr?: Representation.Any }>({ loci: EmptyLoci }),
            selectLoci: this.ev.behavior<{ loci: Loci, repr?: Representation.Any }>({ loci: EmptyLoci }),
        },
David Sehnal's avatar
David Sehnal committed
        command: this.commands.behaviour
    };

    readonly canvas3d: Canvas3D;
David Sehnal's avatar
David Sehnal committed

David Sehnal's avatar
David Sehnal committed

David Sehnal's avatar
David Sehnal committed
    initViewer(canvas: HTMLCanvasElement, container: HTMLDivElement) {
        try {
            (this.canvas3d as Canvas3D) = Canvas3D.create(canvas, container);
            this.canvas3d.animate();
            console.log('canvas3d created');
David Sehnal's avatar
David Sehnal committed
            return true;
        } catch (e) {
            console.error(e);
            return false;
        }
    }

    log(e: LogEntry) {
        this.events.log.next(e);
    }

David Sehnal's avatar
David Sehnal committed
    /**
     * This should be used in all transform related request so that it could be "spoofed" to allow
     * "static" access to resources.
     */
    async fetch(url: string, type: 'string' | 'binary' = 'string'): Promise<string | Uint8Array> {
David Sehnal's avatar
David Sehnal committed
        const req = await fetch(url, { referrerPolicy: 'origin-when-cross-origin' });
David Sehnal's avatar
David Sehnal committed
        return type === 'string' ? await req.text() : new Uint8Array(await req.arrayBuffer());
    }

    runTask<T>(task: Task<T>) {
        return this.tasks.run(task);
David Sehnal's avatar
David Sehnal committed
    }

David Sehnal's avatar
David Sehnal committed
    dispose() {
        if (this.disposed) return;
David Sehnal's avatar
David Sehnal committed
        this.commands.dispose();
David Sehnal's avatar
David Sehnal committed
        this.canvas3d.dispose();
        this.ev.dispose();
        this.state.dispose();
        this.tasks.dispose();
David Sehnal's avatar
David Sehnal committed
        this.disposed = true;
    }

David Sehnal's avatar
David Sehnal committed
    private initBuiltInBehavior() {
        BuiltInPluginBehaviors.State.registerDefault(this);
        BuiltInPluginBehaviors.Representation.registerDefault(this);
        BuiltInPluginBehaviors.Camera.registerDefault(this);

        merge(this.state.data.events.log, this.state.behavior.events.log).subscribe(e => this.events.log.next(e));
David Sehnal's avatar
David Sehnal committed
    }

    async _test_initBehaviors() {
David Sehnal's avatar
David Sehnal committed
        const tree = this.state.behavior.tree.build()
            .toRoot().apply(PluginBehaviors.Representation.HighlightLoci, { ref: PluginBehaviors.Representation.HighlightLoci.id })
            .toRoot().apply(PluginBehaviors.Representation.SelectLoci, { ref: PluginBehaviors.Representation.SelectLoci.id })
David Sehnal's avatar
David Sehnal committed
            .getTree();

David Sehnal's avatar
David Sehnal committed
        await this.runTask(this.state.behavior.update(tree));
David Sehnal's avatar
David Sehnal committed
    }

David Sehnal's avatar
David Sehnal committed
    _test_initDataActions() {
        this.state.data.actions
            .add(CreateStructureFromPDBe)
David Sehnal's avatar
David Sehnal committed
            .add(StateTransforms.Data.Download)
            .add(StateTransforms.Data.ParseCif)
David Sehnal's avatar
David Sehnal committed
            .add(StateTransforms.Model.CreateStructureAssembly)
            .add(StateTransforms.Model.CreateStructure)
            .add(StateTransforms.Model.CreateModelFromTrajectory)
David Sehnal's avatar
David Sehnal committed
            .add(StateTransforms.Visuals.CreateStructureRepresentation);
David Sehnal's avatar
David Sehnal committed
    applyTransform(state: State, a: Transform.Ref, transformer: Transformer, params: any) {
        const tree = state.tree.build().to(a).apply(transformer, params);
David Sehnal's avatar
David Sehnal committed
        return PluginCommands.State.Update.dispatch(this, { state, tree });
David Sehnal's avatar
David Sehnal committed
    }

David Sehnal's avatar
David Sehnal committed
    updateTransform(state: State, a: Transform.Ref, params: any) {
        const tree = state.build().to(a).update(params);
David Sehnal's avatar
David Sehnal committed
        return PluginCommands.State.Update.dispatch(this, { state, tree });
David Sehnal's avatar
David Sehnal committed
    private initEvents() {
David Sehnal's avatar
David Sehnal committed
        merge(this.events.state.data.object.created, this.events.state.behavior.object.created).subscribe(o => {
            if (!SO.isBehavior(o.obj)) return;
            console.log('registering behavior', o.obj.label);
David Sehnal's avatar
David Sehnal committed
            o.obj.data.register();
        });

        merge(this.events.state.data.object.removed, this.events.state.behavior.object.removed).subscribe(o => {
            if (!SO.isBehavior(o.obj)) return;
David Sehnal's avatar
David Sehnal committed
            o.obj.data.unregister();
David Sehnal's avatar
David Sehnal committed

        merge(this.events.state.data.object.updated, this.events.state.behavior.object.updated).subscribe(o => {
            if (o.action === 'recreate') {
                if (o.oldObj && SO.isBehavior(o.oldObj)) o.oldObj.data.unregister();
                if (o.obj && SO.isBehavior(o.obj)) o.obj.data.register();
            }
David Sehnal's avatar
David Sehnal committed
        });
    }

    constructor() {
        this.initEvents();
David Sehnal's avatar
David Sehnal committed
        this.initBuiltInBehavior();
David Sehnal's avatar
David Sehnal committed

David Sehnal's avatar
David Sehnal committed
        this._test_initBehaviors();
        this._test_initDataActions();
David Sehnal's avatar
David Sehnal committed
    // logger = ;
    // settings = ;
}