BINANAParams.ts 41.2 KB
Newer Older
jdurrant's avatar
jdurrant committed
1
2
// This file is part of BINANA, released under the Apache 2.0 License. See
// LICENSE.md or go to https://opensource.org/licenses/Apache-2.0 for full
jdurrant's avatar
jdurrant committed
3
// details. Copyright 2021 Jacob D. Durrant.
jdurrant's avatar
jdurrant committed
4
5
6

import * as Utils from "../../Utils";
import * as BINANAInterface from "../../BINANAInterface";
jdurrant's avatar
jdurrant committed
7
import * as Store from "../../Vue/Store";
8
import { viewer } from "../ThreeDMol";
jdurrant's avatar
jdurrant committed
9
import { IFileInfo, IFileLoadError, IResidueInfo } from "../FileLoaderSystem/Common/Interfaces";
jdurrant's avatar
jdurrant committed
10
11

var FileSaver = require('file-saver');
jdurrant's avatar
jdurrant committed
12
13
14
15
16
17
18

declare var Vue;

/** An object containing the vue-component computed functions. */
let computedFunctions = {
    /**
     * Gets text describing the current interaction coloring scheme.
19
20
     * DEPRECIATED, but leave commented out in case you bring it back in the
     * future.
jdurrant's avatar
jdurrant committed
21
22
     * @returns string  The text.
     */
23
24
25
26
27
28
29
30
31
32
    // "colorByInteractionBtnTxt"(): string {
    //     switch (this.$store.state["colorByInteraction"]) {
    //         case Store.InteractionColoring.MOLECULE:
    //             return "By Molecule";
    //         case Store.InteractionColoring.INTERACTION:
    //             return "By Interaction";
    //         case Store.InteractionColoring.NONE:
    //             return "None";
    //     }
    // },
jdurrant's avatar
jdurrant committed
33
34
35
36
37
38
39
40

    /**
     * Gets the text too use on the bond-visible buttton.
     * @returns string  The text to use.
     */
    "bondVisBtnTxt"(): string {
        if (this.$store.state["bondVisible"]) {
            return "Interactions";
jdurrant's avatar
jdurrant committed
41
        } else {
jdurrant's avatar
jdurrant committed
42
            return "<span style='text-decoration: line-through;'>Interactions</span>";
jdurrant's avatar
jdurrant committed
43
        }
jdurrant's avatar
jdurrant committed
44
    },
jdurrant's avatar
jdurrant committed
45

46
47
48
49
50
51
52
53
54
55
    interactionVisibilityStatus: {
        get(): string {
            return this.$store.state["interactionVisibilityStatus"];
        },
        set(val: string): void {
            this.$store.commit("setVar", {
                name: "interactionVisibilityStatus",
                val: val
            })
        }
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    },

    "legendItems"() {
        let legendItems = this.$store.state["legendItems"];
        
        legendItems = legendItems.filter((l) => {
            let interactionName = l["interactionName"];
            return this.$store.state["bondTypesDetected"][interactionName];
        });
        
        legendItems = legendItems.map((l) => {
            delete l["interactionName"];
            return l;
        });
        
        return legendItems;
jdurrant's avatar
jdurrant committed
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
    },

    "missingHydrogensWarning"(): string {
        let receptorHasHydrogens = this.$store.state["receptorHasHydrogens"];
        let ligandHasHydrogens = this.$store.state["ligandHasHydrogens"];
        if (receptorHasHydrogens && ligandHasHydrogens) {
            // Hydrogens added to both, so return "".
            return "";
        }

        let msg = "";
        if (!receptorHasHydrogens && !ligandHasHydrogens) {
            // Neither has hydrogen atoms.
            msg += "Do your receptor and ligand files include hydrogen atoms? ";
        } else if (!receptorHasHydrogens) {
            msg += "Does your receptor file include hydrogen atoms? ";
        } else {
            msg += "Does your ligand file include hydrogen atoms? ";
        }
        
        msg += "You can further improve BINANA accuracy by adding them if appropriate. ";
        
        if (!receptorHasHydrogens) {
            msg += `To add hydrogen atoms to your receptor, consider using
        <a href="http://molprobity.biochem.duke.edu/"
        target="_blank">MolProbity</a> or
        <a href="http://server.poissonboltzmann.org/"
        target="_blank">PDB2PQR</a>. `
        }

        if (!ligandHasHydrogens) {
            msg += `To add hydrogen atoms to your
        ligand, consider <a href="http://durrantlab.com/gypsum-dl/"
        target="_blank">Gypsum-DL</a> or <a
        href="https://avogadro.cc/docs/menus/build-menu/"
        target="_blank">Avogadro</a>.`
        }
109

jdurrant's avatar
jdurrant committed
110
111
        return msg;
    }
jdurrant's avatar
jdurrant committed
112
113
114
115
116
}

/** An object containing the vue-component methods functions. */
let methodsFunctions = {
    /**
jdurrant's avatar
jdurrant committed
117
     * Runs when user indicates theye want to use example BINANA files,
jdurrant's avatar
jdurrant committed
118
119
120
     * rather than provide their own.
     * @returns void
     */
jdurrant's avatar
jdurrant committed
121
    "useExampleInputFiles"(): void {
jdurrant's avatar
jdurrant committed
122
123
124
125
126
127
128
129
130
131
132
133
134
        this["showFileInputs"] = false;

        setTimeout(() => {  // Vue.nextTick doesn't work...
            // Update some values.
            this.$store.commit("setVar", {
                name: "receptorContents",
                val: this.$store.state["receptorContentsExample"]
            });

            this.$store.commit("setVar", {
                name: "ligandContents",
                val: this.$store.state["ligandContentsExample"]
            });
jdurrant's avatar
jdurrant committed
135

jdurrant's avatar
jdurrant committed
136
137
138
            // Also update file names so example BINANA command line is valid.
            this.$store.commit("updateFileName", { type: "ligand", filename: "ATP.pdbqt" });
            this.$store.commit("updateFileName", { type: "receptor", filename: "1xdn.pdbqt" });
jdurrant's avatar
jdurrant committed
139
140

            // These values should now validate.
jdurrant's avatar
jdurrant committed
141
            let validateVars = ["receptor", "ligand"];
jdurrant's avatar
jdurrant committed
142
143
144
145
146
147
148
149
150
151
152
            const validateVarsLen = validateVars.length;
            for (let i = 0; i < validateVarsLen; i++) {
                const validateVar = validateVars[i];
                this.$store.commit("setValidationParam", {
                    name: validateVar,
                    val: true
                });
            }
        }, 100);
    },

jdurrant's avatar
jdurrant committed
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
    /**
     * Displays a modal with a video tutorial.
     * @returns void
     */
    "videoTutorial"(): void {
        this.$store.commit("openModal", {
            title: "Video Tutorial",
            body: `<iframe style="height: 479px; box-shadow: 0px 0px 5px rgb(150 150 150);" id="tutorial-iframe" width="100%" height="315" src="https://www.youtube.com/embed/BMnSYvH4Qwg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`
        });

        setTimeout(() => {
            let iframe = document.querySelectorAll("#tutorial-iframe")[0] as HTMLIFrameElement;
            let width = iframe.offsetWidth;
            let height = Math.round(width / 1.6);
            iframe.style.height = height.toString() + "px";
        }, 1000);
    },

jdurrant's avatar
jdurrant committed
171
172
173
174
175
176
    /**
     * Highlights interactions in the 3Dmoljs viewer.
     * @param  {string} interactionName  The name of the interaction type to
     *                                   highlight.
     * @returns void
     */
177
    "updateHighlight"(interactionName: string): void {
jdurrant's avatar
jdurrant committed
178
179
180
181
182
183
        if (interactionName === undefined) {
            interactionName = this.lastInteractionNameUsed;
        } else {
            this.lastInteractionNameUsed = interactionName;
        }

184
185
186
187
188
        if (interactionName === undefined) {
            // Apparently, this.lastInteractionNameUsed not set either (For
            // example, happens when click on interactions between any specific
            // kind of interaction).
            return;
jdurrant's avatar
jdurrant committed
189
        }
190
191
192
193
194
195
196
197
198

        // update interactionVisibilityStatus
        let interactionVisibilityStatus = JSON.parse(this.interactionVisibilityStatus);
        interactionVisibilityStatus[interactionName] =
            (interactionVisibilityStatus[interactionName] === undefined)
            ? true : !interactionVisibilityStatus[interactionName];
        this.interactionVisibilityStatus = JSON.stringify(interactionVisibilityStatus);

        BINANAInterface.highlightAll();
jdurrant's avatar
jdurrant committed
199
200
201
202
203
204
205
    },

    /**
     * Clears the interactions currently displayed in the 3Dmoljs viewer.
     * @returns void
     */
    "clearInteraction"(): void {
206
207
        this.interactionVisibilityStatus = Store.defaultInteractionVisibilityStatus;
        BINANAInterface.highlightAll();
jdurrant's avatar
jdurrant committed
208
209
210
211
212
213
214
215
    },

    /**
     * Fires when the user indicates s/he would like to change the color
     * scheme.
     * @returns void
     */
    "onChangeColor"(): void {
jdurrant's avatar
jdurrant committed
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
        let newVal = undefined;
        switch (this.$store.state["colorByInteraction"]) {
            case Store.InteractionColoring.MOLECULE:
                newVal = Store.InteractionColoring.INTERACTION;
                break;
            case Store.InteractionColoring.INTERACTION:
                newVal = Store.InteractionColoring.NONE;

                // If none, make sure bonds are visible.
                this.$store.commit("setVar", {
                    name: "bondVisible",
                    val: true
                });

                break;
            case Store.InteractionColoring.NONE:
                newVal = Store.InteractionColoring.MOLECULE;
                break;
        }

jdurrant's avatar
jdurrant committed
236
237
        this.$store.commit("setVar", {
            name: "colorByInteraction",
jdurrant's avatar
jdurrant committed
238
            val: newVal
jdurrant's avatar
jdurrant committed
239
240
        });

241
        this["updateHighlight"]();
jdurrant's avatar
jdurrant committed
242
243
244
    },

    /**
245
246
     * Runs when the bond-visibility button is pressed. DEPRECIATED, but
     * keep commented out in case you bring it back in the future.
jdurrant's avatar
jdurrant committed
247
248
     * @returns void
     */
249
250
251
252
253
    // "onBondVisChange"(): void {
    //     this.$store.commit("setVar", {
    //         name: "bondVisible",
    //         val: !this.$store.state["bondVisible"]
    //     });
jdurrant's avatar
jdurrant committed
254

255
256
    //     this["updateHighlight"]();
    // },
jdurrant's avatar
jdurrant committed
257
258
259
260
261
262

    /**
     * Runs when the save button is pressed.
     * @returns void
     */
    "onSaveFiles"(): void {
263
264
265
266
267
268
269
270
271
272
273
274
275
        let getJSZip = import(
            /* webpackChunkName: "JSZip" */ 
            /* webpackMode: "lazy" */
            '../../../node_modules/jszip/lib/index'
        ).then((mod) => {
            // @ts-ignore
            return Promise.resolve(mod.default);
        });

        let getBinana = import(
            /* webpackChunkName: "binana" */ 
            /* webpackMode: "lazy" */
            '../../binanajs/binana'
jdurrant's avatar
jdurrant committed
276
        );
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300

        Promise.all([getJSZip, getBinana]).then((mods) => {
            let JSZip;
            let binana;
            [JSZip, binana] = mods;

            var zip = new JSZip();
            let dataURI = viewer.pngURI();
            let pngBlob = Utils.dataURIToBlob(dataURI);
    
            zip["folder"]("binana_output")["file"]
                // TODO: was receptor.txt. Why?
                ("receptor.pdb", this.$store.state["receptorContents"]
            );
    
            zip["folder"]("binana_output")["file"](
                // TODO: was ligand.txt. Why?
                "ligand.pdb", this.$store.state["ligandContents"]
            );
    
            zip["folder"]("binana_output")["file"](
                "binana.json", this.$store.state["filesToSave"]["output.json"]
            );
    
jdurrant's avatar
jdurrant committed
301
302
303
304
            zip["folder"]("binana_output")["file"](
                "binana.csv", this.$store.state["filesToSave"]["output.csv"]
            );
    
305
306
307
308
309
310
311
312
            zip["folder"]("binana_output")["file"](
                "log.txt", this.$store.state["filesToSave"]["log.txt"]
            );
    
            for (let flnm in this.$store.state["filesToSave"]) {
                zip["folder"]("binana_output")["file"](
                    "vmd/" + flnm, this.$store.state["filesToSave"][flnm]
                );
jdurrant's avatar
jdurrant committed
313
            }
314
315
316
317
318
319
320
321
322
323
    
            zip["folder"]("binana_output")["file"](
                "image.png", pngBlob
            );
            zip["generateAsync"]({["type"]:"blob"}).then(
                function (blob) {
                    FileSaver["saveAs"](blob, "binana_output.zip");
                }
            );
        });
jdurrant's avatar
jdurrant committed
324
    },
jdurrant's avatar
jdurrant committed
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364

    /**
     * Determines whether all form values are valid.
     * @param  {boolean=true} modalWarning  Whether to show a modal if
     *                                      they are not valid.
     * @returns boolean  True if they are valid, false otherwise.
     */
    "validate"(modalWarning: boolean=true): boolean {
        let validations = this.$store.state["validation"];

        let pass = true;

        const paramName = Object.keys(validations);
        const paramNameLen = paramName.length;
        let badParams: string[] = [];
        for (let i = 0; i < paramNameLen; i++) {
            const name = paramName[i];

            if (name === "output") {
                // This one isn't part of the validation.
                continue;
            }

            const valid = validations[name];
            if (valid === false) {
                pass = false;
                badParams.push(name);
            }
        }

        if (pass === false) {
            if (modalWarning === true) {
                this.$store.commit("openModal", {
                    title: "Invalid Parameters!",
                    body: "<p>Please correct the following parameter(s) before continuing: <code>" + badParams.join(" ") + "</code></p>"
                });
            }
        }

        this.$store.commit("setVar", {
jdurrant's avatar
jdurrant committed
365
            name: "binanaParamsValidates",
jdurrant's avatar
jdurrant committed
366
367
368
369
370
            val: pass
        })

        return pass;
    },
jdurrant's avatar
jdurrant committed
371

jdurrant's avatar
jdurrant committed
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
    "getInteractionVisibility"(interactionID: string): boolean {
        let interactionVisibilityStatus = JSON.parse(this.interactionVisibilityStatus);
        if (interactionVisibilityStatus[interactionID] === undefined) {
            return false;
        }
        return interactionVisibilityStatus[interactionID];
    },

    "onError"(msg: IFileLoadError) {
        this.$store.commit("openModal", {
            title: msg.title,
            body: `${msg.body}`
        });
    },

    "onReceptorFileReady"(fileInfo: IFileInfo) {
jdurrant's avatar
jdurrant committed
388
389
        this.$store.commit("setVar", {
            name: "receptorContents",
jdurrant's avatar
jdurrant committed
390
            val: fileInfo.fileContents,
jdurrant's avatar
jdurrant committed
391
392
393
        });
        this.$store.commit("updateFileName", {
            type: "receptor",
jdurrant's avatar
jdurrant committed
394
            filename: fileInfo.filename,
jdurrant's avatar
jdurrant committed
395
        });
jdurrant's avatar
jdurrant committed
396
    },
jdurrant's avatar
jdurrant committed
397

jdurrant's avatar
jdurrant committed
398
    "onLigandFileReady"(fileInfo: IFileInfo) {
jdurrant's avatar
jdurrant committed
399
400
        this.$store.commit("setVar", {
            name: "ligandContents",
jdurrant's avatar
jdurrant committed
401
            val: fileInfo.fileContents,
jdurrant's avatar
jdurrant committed
402
403
404
        });
        this.$store.commit("updateFileName", {
            type: "ligand",
jdurrant's avatar
jdurrant committed
405
            filename: fileInfo.filename,
jdurrant's avatar
jdurrant committed
406
        });
jdurrant's avatar
jdurrant committed
407
    },
jdurrant's avatar
jdurrant committed
408

jdurrant's avatar
jdurrant committed
409
410
411
412
    "onExtractReceptorAtomsToLigand"(residueInfo: IResidueInfo): void {
        // Get the existing ligand contents
        let ligContents = residueInfo.residuePdbLines;
        let ligFilename = residueInfo.residueId.filter(r => [undefined, ""].indexOf(r) === -1).join("-") + ".pdb";
jdurrant's avatar
jdurrant committed
413

jdurrant's avatar
jdurrant committed
414
415
416
        this.$refs["ligandMolLoader"]["loadMolFromExternal"](
            ligFilename, ligContents
        );
jdurrant's avatar
jdurrant committed
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
    },

    /**
     * Shows more details about how the interactions are detected.
     * @returns void
     */
    "moreDetails"(): void {
        let getInteractionsMD = fetch("INTERACTIONS.md")
            .then((response) => response.text())
            .then((data) => Promise.resolve(data));

        let getMarkdownIt = import(
            /* webpackChunkName: "MarkdownIt" */ 
            /* webpackMode: "lazy" */
            'markdown-it'
        ).then((mod) => {
            // @ts-ignore
            let MarkdownIt = mod.default;
            return Promise.resolve(MarkdownIt);
        });

        Promise.all([getInteractionsMD, getMarkdownIt]).then((payload) => {
            let interactions: string;
            let MarkdownIt: any;
            [interactions, MarkdownIt] = payload;
            let md = new MarkdownIt();
            var result = md.render(interactions);
            this.$store.commit("openModal", {
                title: "Detecting Intramolecular Interactions",
                body: result
                    .replace(/h1\>/g, "h5>")
                    .replace(/\<a /g, '<a target="_blank" ')
                    .replace(/\<table/g, '<table style="margin-bottom:8px;"')
                    .replace(/\<td/g, '<td style="min-width:45px;font-size:80%;padding:4px;"')
                    .replace(/\<th/g, '<th style="min-width:45px;font-size:80%;padding:4px;"')
            });
        })
454
    }
jdurrant's avatar
jdurrant committed
455
456
457
458
459
460
461
462
463
464
465
}

/**
 * The vue-component mounted function.
 * @returns void
 */
function mountedFunction(): void {
    this["webAssemblyAvaialble"] = Utils.webAssemblySupported();
}

/**
jdurrant's avatar
jdurrant committed
466
 * Setup the binana-params Vue commponent.
jdurrant's avatar
jdurrant committed
467
468
469
 * @returns void
 */
export function setup(): void {
jdurrant's avatar
jdurrant committed
470
    Vue.component('binana-params', {
471
        "template": /* html */ `
jdurrant's avatar
jdurrant committed
472
            <div>
jdurrant's avatar
jdurrant committed
473
474
475
476
477
478
479
480
481
482
483
484
485
                <sub-section
                    v-if="$store.state.receptorContents === '' || $store.state.ligandContents === ''"
                >
                    <div role="tablist">
                        <b-card no-body class="mb-1">
                            <b-card-header header-tag="header" class="p-1" role="tab">
                                <b-button block href="#" v-b-toggle.accordion-3 variant="default">Advanced Parameters</b-button>
                            </b-card-header>
                            <b-collapse id="accordion-3" role="tabpanel">
                                <b-card-body>
                                    <b-card class="mb-2 text-center" style="margin-bottom:1.4rem !important;">
                                        <b-card-text>Parameters used to identify close contacts.</b-card-text>
                                        <numeric-input
jdurrant's avatar
jdurrant committed
486
                                            label="Closest Contacts Dist1 Cutoff"
jdurrant's avatar
jdurrant committed
487
488
489
490
491
492
493
494
495
496
                                            id="close_contacts_dist1_cutoff"
                                            description="Ligand/protein atoms that come within this number of
                                            angstroms are &quot;closest contacts.&quot;" placeholder="$store.state.close_contacts_dist1_cutoff"
                                        ></numeric-input>
                                        <numeric-input
                                            label="Close Contacts Dist2 Cutoff"
                                            id="close_contacts_dist2_cutoff"
                                            description="Ligand/protein atoms that come within this number of
                                            angstroms are &quot;close contacts.&quot;" placeholder="$store.state.close_contacts_dist2_cutoff"
                                        ></numeric-input>
jdurrant's avatar
jdurrant committed
497
                                        <div class="learnMoreLink"><b-link href="#" @click="moreDetails">(Learn more about advanced parameters)</b-link></div>
jdurrant's avatar
jdurrant committed
498
499
500
501
502
503
504
505
506
507
508
509
510
                                    </b-card>
                                    <!-- <numeric-input
                                        label="Electrostatic Dist Cutoff"
                                        id="electrostatic_dist_cutoff"
                                        description="<b>???</b>" placeholder="$store.state.electrostatic_dist_cutoff"
                                    ></numeric-input> -->
                                    <!-- <numeric-input
                                        label="Active Site Flexibility Dist Cutoff"
                                        id="active_site_flexibility_dist_cutoff"
                                        description="<b>???</b>" placeholder="$store.state.active_site_flexibility_dist_cutoff"
                                    ></numeric-input> -->

                                    <b-card class="mb-2 text-center" style="margin-bottom:1.4rem !important;">
jdurrant's avatar
jdurrant committed
511
                                        <b-card-text>Parameters used to identify hydrogen and halogen bonds.</b-card-text>
jdurrant's avatar
jdurrant committed
512
513
                                        <numeric-input
                                            label="Hydrogen Bond Dist Cutoff"
jdurrant's avatar
jdurrant committed
514
                                            id="hydrogen_bond_dist_cutoff"
jdurrant's avatar
jdurrant committed
515
516
                                            description="A hydrogen bond is identified if the hydrogen-bond
                                            donor comes within this number of angstroms of the hydrogen-bond
jdurrant's avatar
jdurrant committed
517
                                            acceptor." placeholder="$store.state.hydrogen_bond_dist_cutoff"
jdurrant's avatar
jdurrant committed
518
519
                                        ></numeric-input>
                                        <numeric-input
jdurrant's avatar
jdurrant committed
520
                                            label="Hydrogen and Halogen Bond Angle Cutoff"
521
                                            id="hydrogen_halogen_bond_angle_cutoff"
jdurrant's avatar
jdurrant committed
522
523
                                            description="A hydrogen or halogen bond is identified if the angle formed
                                            between the donor, the hydrogen/halide atom, and the acceptor is no
524
                                            greater than this number of degrees." placeholder="$store.state.hydrogen_halogen_bond_angle_cutoff"
jdurrant's avatar
jdurrant committed
525
                                        ></numeric-input>
jdurrant's avatar
jdurrant committed
526
527
528
529
530
531
532
                                        <numeric-input
                                            label="Halogen Bond Dist Cutoff"
                                            id="halogen_bond_dist_cutoff"
                                            description="A halogen bond is identified if the halogen-bond
                                            donor comes within this number of angstroms of the halogen-bond
                                            acceptor." placeholder="$store.state.halogen_bond_dist_cutoff"
                                        ></numeric-input>
jdurrant's avatar
jdurrant committed
533
                                        <div class="learnMoreLink"><b-link href="#" @click="moreDetails">(Learn more about advanced parameters)</b-link></div>
jdurrant's avatar
jdurrant committed
534
535
536
537
538
539
                                    </b-card>

                                    <b-card class="mb-2 text-center" style="margin-bottom:1.4rem !important;">
                                        <b-card-text>
                                            <div style='text-align:left;'>
                                                Parameters used to identify interactions between
jdurrant's avatar
jdurrant committed
540
                                                aromatic rings. Once an aromatic ring is identified, a plane is
jdurrant's avatar
jdurrant committed
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
                                                defined that passes through three ring atoms. The center of
                                                the ring is the average of all ring-atom coordinates,
                                                and the radius is the maximum distance between the center and
                                                any of those atoms. A ring disk is centered on the ring center
                                                point, oriented along the ring plane.
                                            </div>
                                        </b-card-text>

                                        <numeric-input
                                            label="π Padding Dist"
                                            id="pi_padding_dist"
                                            description="The radius of the ring disk is equal to that of the
                                            ring plus a small buffer (this number of angstroms)." placeholder="$store.state.pi_padding_dist"
                                        ></numeric-input>
                                        <numeric-input
                                            label="π-π Interacting Dist Cutoff"
                                            id="pi_pi_interacting_dist_cutoff"
                                            description="A π-π or T-stacking interaction is identified
                                            if the centers of two aromatic rings are within this number of
                                            angstroms." placeholder="$store.state.pi_pi_interacting_dist_cutoff"
                                        ></numeric-input>
                                        <numeric-input
                                            label="π-Stacking Angle Tolerance"
                                            id="pi_stacking_angle_tolerance"
                                            description="A π-π stacking interaction is identified if the
                                            angle between the normal vectors of two aromatic rings is less
                                            than this number of degrees." placeholder="$store.state.pi_stacking_angle_tolerance"
                                        ></numeric-input>
                                        <numeric-input
                                            label="T-Stacking Angle Tolerance"
                                            id="T_stacking_angle_tolerance"
                                            description="A T-stacking interaction is identified if the
                                            angle between the normal vectors of two aromatic rings is within
                                            this number of degrees of being perpendicular." placeholder="$store.state.T_stacking_angle_tolerance"
                                        ></numeric-input>
                                        <numeric-input
                                            label="T-Stacking Closest Dist Cutoff"
                                            id="T_stacking_closest_dist_cutoff"
                                            description="A T-stacking interaction is identified if two aromatic
                                            rings are within this number of angstroms at their nearest point (see
                                            also -pi_pi_interacting_dist_cutoff parameter above)." placeholder="$store.state.T_stacking_closest_dist_cutoff"
                                        ></numeric-input>
                                        <numeric-input
                                            label="Cation-π Dist Cutoff"
                                            id="cation_pi_dist_cutoff"
                                            description="A Cation-π interaction is identified if a charged functional
                                            group comes within this distance of an aromaic-ring center." placeholder="$store.state.cation_pi_dist_cutoff"
                                        ></numeric-input>
jdurrant's avatar
jdurrant committed
589
                                        <div class="learnMoreLink"><b-link href="#" @click="moreDetails">(Learn more about advanced parameters)</b-link></div>
jdurrant's avatar
jdurrant committed
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
                                    </b-card>

                                    <b-card class="mb-2 text-center" style="margin-bottom:1.4rem !important;">
                                        <b-card-text>Parameters used to identify other notable interactions.</b-card-text>
                                        <numeric-input
                                            label="Salt Bridge Dist Cutoff"
                                            id="salt_bridge_dist_cutoff"
                                            description="Charged functional groups that come within this
                                            number of angstroms participate in &quot;electrostatic
                                            interactions.&quot;" placeholder="$store.state.salt_bridge_dist_cutoff"
                                        ></numeric-input>
                                        <numeric-input
                                            label="Hydrophobic Dist Cutoff"
                                            id="hydrophobic_dist_cutoff"
                                            description="Ligand/receptor carbon atoms that come within this
                                            number of angstroms participate in &quot;hydrophobic
                                            contacts.&quot;" placeholder="$store.state.hydrophobic_dist_cutoff"
                                        ></numeric-input>
jdurrant's avatar
jdurrant committed
608
609
610
611
612
613
614
                                        <numeric-input
                                            label="Metal Coordination Dist Cutoff"
                                            id="metal_coordination_dist_cutoff"
                                            description="Atoms such as nitrogens and oxygens that come within this
                                            number of angstroms of a metal cation participate in &quot;metal coordination
                                            contacts.&quot;" placeholder="$store.state.metal_coordination_dist_cutoff"
                                        ></numeric-input>
jdurrant's avatar
jdurrant committed
615
                                        <div class="learnMoreLink"><b-link href="#" @click="moreDetails">(Learn more about advanced parameters)</b-link></div>
jdurrant's avatar
jdurrant committed
616
617
618
619
620
621
622
623
                                    </b-card>
                                </b-card-body>
                            </b-collapse>
                        </b-card>
                    </div>
                </sub-section>

                <sub-section title="Input Files" v-if="showFileInputs">
jdurrant's avatar
jdurrant committed
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
                    <mol-loader
                        :allowDeleteHeteroAtoms="true"
                        :allowExtractHeteroAtoms="true"
                        :multipleFiles="false"
                        :fileLoaderPlugins="['pdb-id-input', 'file-loader-input']"
                        label="Receptor"
                        description="Formats: PDB, PDBQT. Consider first (1) adding polar hydrogen atoms if necessary and (2) removing any ligands from the file."
                        extraDescription=""
                        accept=".pdb, .pdbqt"
                        convert=""
                        :required="true"
                        @onError="onError"
                        @onFileReady="onReceptorFileReady"
                        @onExtractAtoms="onExtractReceptorAtomsToLigand"
                    ></mol-loader>
                    <!-- , 'url-input']" -->

                    <mol-loader
                        ref="ligandMolLoader"
                        :allowDeleteHeteroAtoms="false"
                        :allowExtractHeteroAtoms="false"
                        :multipleFiles="false"
                        :fileLoaderPlugins="['file-loader-input']"
                        label="Ligand"
                        description="Formats: PDB, PDBQT, SDF. Consider first adding polar hydrogen atoms if necessary."
                        extraDescription=""
                        accept=".pdb, .pdbqt, .sdf"
                        convert=""
                        :required="true"
                        @onError="onError"
                        @onFileReady="onLigandFileReady"
                    ></mol-loader>
                    <!-- , 'url-input']" -->

jdurrant's avatar
jdurrant committed
658
                    <form-button @click.native="useExampleInputFiles" cls="float-right">Use Example Files</form-button>  <!-- variant="default" -->
jdurrant's avatar
jdurrant committed
659
                    <form-button @click.native="videoTutorial" cls="float-right mr-2">Video Tutorial</form-button>  <!-- variant="default" -->
jdurrant's avatar
jdurrant committed
660
661
662
663
664
665
666
667
668
669
670
671
                </sub-section>

                <sub-section title="Molecular Viewer">
                    <form-group
                        label=""
                        id="input-group-receptor-3dmol"
                        description=""
                    >
                        <div class="bv-example-row container-fluid">
                            <b-row>
                                <b-col style="padding-left: 0; padding-right: 0;">
                                    <threedmol type="receptor"></threedmol>
jdurrant's avatar
jdurrant committed
672
673
                                </b-col>
                            </b-row>
jdurrant's avatar
jdurrant committed
674
675
676
677
                        </div>
                    </form-group>

                    <b-container
678
                        v-if="($store.state.receptorContents != '') && ($store.state.ligandContents != '')"
jdurrant's avatar
jdurrant committed
679
                    >
680
681
682
683
                        <div 
                            v-if="JSON.stringify($store.state.filesToSave) == '{}'"
                            style="font-weight:bold;text-align:center;"
                        >
684
                            <br /><br />
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
                            Identifying interactions...
                        </div>
                        <span v-else>
                            <b-row no-gutters>
                                <b-col no-gutters>
                                    <b-dropdown variant="primary" text="Common" block>
                                        <b-dropdown-item @click="updateHighlight('hydrogenBonds');">
                                            <check-mark :value="getInteractionVisibility('hydrogenBonds')">
                                                <div class="centerMenuItem" style="width:115px;">
                                                    Hydrogen Bonds
                                                </div>
                                            </check-mark>
                                        </b-dropdown-item>
                                        <b-dropdown-item @click="updateHighlight('halogenBonds');">
                                            <check-mark :value="getInteractionVisibility('halogenBonds')">
                                                <div class="centerMenuItem" style="width:115px;">
                                                    Halogen Bonds
                                                </div>
                                            </check-mark>
                                        </b-dropdown-item>
                                        <b-dropdown-item @click="updateHighlight('hydrophobicContacts');">
                                            <check-mark :value="getInteractionVisibility('hydrophobicContacts')">
                                                <div class="centerMenuItem" style="width:115px;">
                                                    Hydrophobic
                                                </div>
                                            </check-mark>
                                        </b-dropdown-item>
                                        <b-dropdown-item @click="updateHighlight('saltBridges');">
                                            <check-mark :value="getInteractionVisibility('saltBridges')">
                                                <div class="centerMenuItem" style="width:115px;">
                                                    Salt Bridge
                                                </div>
                                            </check-mark>
                                        </b-dropdown-item>
jdurrant's avatar
jdurrant committed
719
720
721
722
723
724
725
                                        <b-dropdown-item @click="updateHighlight('metalCoordinations');">
                                            <check-mark :value="getInteractionVisibility('metalCoordinations')">
                                                <div class="centerMenuItem" style="width:115px;">
                                                    Metal Coordination
                                                </div>
                                            </check-mark>
                                        </b-dropdown-item>
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
                                    </b-dropdown>
                                </b-col>
                                <b-col no-gutters>
                                    <b-dropdown variant="primary" text="Contacts" block>
                                        <b-dropdown-item @click="updateHighlight('closeContacts');">
                                            <check-mark :value="getInteractionVisibility('closeContacts')">
                                                <div class="centerMenuItem" style="width:55px;">
                                                    Close
                                                </div>
                                            </check-mark>
                                        </b-dropdown-item>
                                        <b-dropdown-item @click="updateHighlight('closestContacts');">
                                            <check-mark :value="getInteractionVisibility('closestContacts')">
                                                <div class="centerMenuItem" style="width:55px;">
                                                    Closest
                                                </div>
                                            </check-mark>
                                        </b-dropdown-item>
                                    </b-dropdown>
                                </b-col>
                                <b-col no-gutters>
                                    <b-dropdown variant="primary" text="Aromatic" block>
                                        <b-dropdown-item @click="updateHighlight('piPiStackingInteractions');">
                                            <check-mark :value="getInteractionVisibility('piPiStackingInteractions')">
                                                <div class="centerMenuItem" style="width:95px;">
                                                    π-π Stacking
                                                </div>
                                            </check-mark>
                                        </b-dropdown-item>
                                        <b-dropdown-item @click="updateHighlight('tStackingInteractions');">
                                            <check-mark :value="getInteractionVisibility('tStackingInteractions')">
                                                <div class="centerMenuItem" style="width:95px;">
                                                    T Shaped
                                                </div>
                                            </check-mark>
                                        </b-dropdown-item>
                                        <b-dropdown-item @click="updateHighlight('cationPiInteractions');">
                                            <check-mark :value="getInteractionVisibility('cationPiInteractions')">
                                                <div class="centerMenuItem" style="width:95px;">
                                                    Cation-π
                                                </div>
                                            </check-mark>
                                        </b-dropdown-item>
                                    </b-dropdown>
                                </b-col>
                                <b-col no-gutters>
                                    <b-button variant="primary" @click="clearInteraction();" block>Reset</b-button>
                                </b-col>
                            </b-row>
                            <b-row no-gutters>
                                <!-- 
                                DEPRECIATED, but leave commented out in case you
                                bring it back in the future.
                                <b-col no-gutters @click="updateHighlight();">
                                    <b-button @click="onChangeColor();" block>
                                        {{colorByInteractionBtnTxt}}
                                    </b-button>
                                </b-col>
                                -->
                                <!--
                                DEPRECIATED, but leave comented out in case you
                                bring it back in the future.
                                <b-col no-gutters>
                                    <b-button @click="onBondVisChange();" block v-html="bondVisBtnTxt">
                                    </b-button>
                                </b-col>
                                -->
                                <b-col no-gutters>
                                    <b-button @click="onSaveFiles();" block>
                                        Save
                                    </b-button>
                                </b-col>
                            </b-row>
                            
                            <b-table striped small :items="legendItems">
                                <template #cell(Representation)="data">
                                    <span v-html="data.value"></span>
                                </template>
                                <template #cell(Name)="data">
                                    <span v-html="data.value"></span>
                                </template>
                            </b-table>
jdurrant's avatar
jdurrant committed
808
809
810
                            <div class="learnMoreLink" style="margin-top: -12px;">
                                (<b-link href="#" @click="moreDetails">More details about interaction detection</b-link>)
                            </div>
811

jdurrant's avatar
jdurrant committed
812
                            <b-alert show style="margin-top:8px;" variant="warning" v-if="missingHydrogensWarning !== ''">
jdurrant's avatar
jdurrant committed
813
                                <span v-html="missingHydrogensWarning"></span>
814
815
816
817
818
819

                                <br /><br />

                                You may also get this warning if one or more of your files is
                                improperly formatted.
                            </b-alert>
820

821
822
823
824
825
826
827
828
829
830
                            <!--
                            DEPRECIATED IN FAVOR OF TABLE DECRIPTION, but leave this 
                            commented in case you want to bring it back.
                            <b-row v-if="this.$store.state.colorMessage !== ''" no-gutters>
                                <b-col no-gutters>
                                    <p style="text-align:center;">({{this.$store.state.colorMessage}})</p>
                                </b-col>
                            </b-row>
                            -->
                        </span>
jdurrant's avatar
jdurrant committed
831
832
833
834
                    </b-container>
                </sub-section>

                <span style="display:none;">{{validate(false)}}</span>  <!-- Hackish. Just to make reactive. -->
835
            </div>
jdurrant's avatar
jdurrant committed
836
837
838
839
840
841
842
843
844
845
846
847
        `,
        "props": {},
        "computed": computedFunctions,

        /**
         * Get the data associated with this component.
         * @returns any  The data.
         */
        "data"() {
            return {
                "showFileInputs": true,
                "webAssemblyAvaialble": true,
jdurrant's avatar
jdurrant committed
848
849
850
                lastInteractionNameUsed: undefined,
                "forceLigandFileName": null,
                "nonProteinResidues": ""
jdurrant's avatar
jdurrant committed
851
852
853
854
855
856
857
858
859
860
861
            }
        },
        "methods": methodsFunctions,

        /**
         * Runs when the vue component is mounted.
         * @returns void
         */
        "mounted": mountedFunction
    })
}