BINANAInterface.ts 19.5 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

import * as ThreeDMol from "./UI/ThreeDMol";
6
import { firstLetterCapital } from "./Utils";
jdurrant's avatar
jdurrant committed
7
import * as Store from "./Vue/Store";
jdurrant's avatar
jdurrant committed
8

jdurrant's avatar
jdurrant committed
9
10
declare var jQuery;

jdurrant's avatar
jdurrant committed
11
12
let viewer;
let receptorMol;
jdurrant's avatar
jdurrant committed
13
let ligandMol;
jdurrant's avatar
jdurrant committed
14
let binanaData;
15
let binanaFiles;
jdurrant's avatar
jdurrant committed
16

jdurrant's avatar
jdurrant committed
17
18
// A single atom may participate in multiple interactions with other atoms.
// Make sure each atom is rendered in the viewer only once.
jdurrant's avatar
jdurrant committed
19
20
let idxOfAtomsSeen;

jdurrant's avatar
jdurrant committed
21
22
export var ligandInteractingResidues = [];

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
interface ILegendItem {
    name: string;
    color: string;
    colorHex: string;
    representation: string;
    link: string
}

// See https://en.wikipedia.org/wiki/Web_colors
let interactionsInfo: {[key: string]: ILegendItem } = {
    "hydrogenBonds": {
        name: "Hydrogen bond",
        color: "BLACK",
        representation: "solid COLOR arrow from donor to acceptor",
        colorHex: "#000000",  // black
        link: "https://en.wikipedia.org/wiki/Hydrogen_bond"
    },
    "halogenBonds": {
        name: "Halogen bond",
        color: "GREEN",
        representation: "solid COLOR arrow from donor to acceptor",
        colorHex: "#00FF00",  // green
        link: "https://en.wikipedia.org/wiki/Halogen_bond"
    },
    "hydrophobicContacts": {
        name: "Hydrophobics",
        color: "GRAY",
        representation: "COLOR spheres",
        colorHex: "#808080",  // gray
        link: "https://en.wikipedia.org/wiki/Entropic_force#Hydrophobic_force"
    },
    "saltBridges": {
        name: "Salt bridge",
        color: "RED",
        representation: "COLOR dashed line",
        colorHex: "#FF0000",  //red
        link: "https://en.wikipedia.org/wiki/Salt_bridge_(protein_and_supramolecular)"
    },
jdurrant's avatar
jdurrant committed
61
62
63
64
65
66
67
    "metalCoordinations": {
        name: "Metal Coordination",
        color: "ORANGE",
        representation: "COLOR dashed line",
        colorHex: "#FFA500",  //red
        link: "https://en.wikipedia.org/wiki/Coordination_complex"
    },
68
69
70
71
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
109
110
111
112
113
114
115
116
117
118
    "closeContacts": {
        name: "Close contact",
        color: "PURPLE",
        representation: "COLOR spheres",
        colorHex: "#800080",  // purple
        link: "https://en.wikipedia.org/wiki/Steric_effects"
    },
    "closestContacts": {
        name: "Closest contact",
        color: "FUSCHA",
        representation: "COLOR spheres",
        colorHex: "#FF00FF",  // fuscha
        link: "https://en.wikipedia.org/wiki/Steric_effects"
    },
    "piPiStackingInteractions": {
        name: "π-π stacking",
        color: "BLUE",
        representation: "COLOR dashed line",
        colorHex: "#0000FF",  // blue
        link: "https://en.wikipedia.org/wiki/Pi-Stacking_(chemistry)"
    },
    "tStackingInteractions": {
        name: "T-stacking",
        color: "AQUA",
        representation: "COLOR dashed line",
        colorHex: "#00FFFF", // aqua
        link: "https://en.wikipedia.org/wiki/Pi-Stacking_(chemistry)"
    },
    "cationPiInteractions": {
        name: "Cation-π",
        color: "NAVY",
        representation: "COLOR dashed line",
        colorHex: "#000080",  // navy
        link: "https://en.wikipedia.org/wiki/Cation%E2%80%93pi_interaction"
    },
}

let sphereOnlyReps = ["hydrophobicContacts", "closeContacts", "closestContacts"];

// Certain representations must be represented after others. For example,
// closestContacts should be rendered after closeContacts so both with be
// visible. 
let renderOrder = [
    "hydrophobicContacts",
    "closeContacts",
    "closestContacts",

    // For below, order less important.
    "hydrogenBonds",
    "halogenBonds",
    "saltBridges",
jdurrant's avatar
jdurrant committed
119
    "metalCoordinations",
120
121
122
123
124
125
126
127
128
129
130
    "piPiStackingInteractions",
    "tStackingInteractions",
    "cationPiInteractions",
]
interface IHighlightInfo {
    ligAtomInfs: any;
    recAtomInfs: any;
    interactionType: any[];
    interactionName: string;
}

jdurrant's avatar
jdurrant committed
131
132
133
134
135
136
137
138
139
/**
 * Sets up the interface, brining several variables into the module's scope.
 * @param  {*} view   The 3Dmoljs viewer.
 * @param  {*} recep  The 3Dmoljs receptor molecule object.
 * @param  {*} lig    The 3Dmoljs ligand molecule object.
 */
export function setup(view: any, recep: any, lig: any) {
    viewer = view;
    receptorMol = recep;
jdurrant's avatar
jdurrant committed
140
    ligandMol = lig;
jdurrant's avatar
jdurrant committed
141
142
143
144
145
146
147
148
149
}

/**
 * Starts BINANA.
 * @param  {string} pdbtxt  The text of the receptor.
 * @param  {string} ligtxt  The text of the ligand.
 * @returns void
 */
export function start(pdbtxt: string, ligtxt: string): void {
jdurrant's avatar
jdurrant committed
150
151
152
153
    let binanaParams = Store.store.state["binanaParams"];

    jQuery("body").addClass("waiting");

jdurrant's avatar
jdurrant committed
154
155
156
157
158
    Store.store.commit("setVar", {
        name: "filesToSave",
        val: {}
    });

jdurrant's avatar
jdurrant committed
159
160
161
162
163
    setTimeout(() => {
        var myWorker = new Worker('binanaWebWorker.js', { type: "module" });
        myWorker.postMessage([pdbtxt, ligtxt, binanaParams]);

        myWorker.onmessage = function(e) {
164
165
            binanaFiles = e.data;
            binanaData = JSON.parse(binanaFiles["output.json"]);
jdurrant's avatar
jdurrant committed
166

167
168
169
170
171
172
173
174
175
176
177
178
179
            // Summarize which bonds were detected. Good for determining which
            // bond types should be listed in the table legend, for example.
            let bondTypes = Object.keys(binanaData);
            let bondTypesDetectedVals = bondTypes.map(k => binanaData[k].length !== 0);
            let bondTypesDetected = {};
            for (let i = 0; i < bondTypes.length; i++) {
                bondTypesDetected[bondTypes[i]] = bondTypesDetectedVals[i];
            }
            Store.store.commit("setVar", {
                name: "bondTypesDetected",
                val: bondTypesDetected
            });

jdurrant's avatar
jdurrant committed
180
            // Update the store too.
181
182
183
184
185
            // Store.store.commit("setVar", {
            //     name: "jsonOutput",
            //     val: binanaFiles["output.json"]  // JSON.stringify(binanaData, undefined, 1)
            // });
            
jdurrant's avatar
jdurrant committed
186
            Store.store.commit("setVar", {
187
188
                name: "filesToSave",
                val: binanaFiles
jdurrant's avatar
jdurrant committed
189
190
            });

191
192
            highlightAll();
            
jdurrant's avatar
jdurrant committed
193
194
195
            jQuery("body").removeClass("waiting");
        }
    }, 250);
jdurrant's avatar
jdurrant committed
196
197
}

198
199
200
export function highlight(highlightInfos: IHighlightInfo[]) {
    // Render sticks of protein model too. Clears (resets) the protein
    // rendering.
jdurrant's avatar
jdurrant committed
201
    ThreeDMol.showSticksOrRibbonAsAppropriate();
202

jdurrant's avatar
jdurrant committed
203
    ligandInteractingResidues = [];
204
205
206
207
208
209
210
211
212
213
214

    for (let highlightInfo of highlightInfos) {
        // Add spheres
        if (Store.store["state"]["colorByInteraction"] !== Store.InteractionColoring.NONE) {
            drawSpheres(highlightInfo.ligAtomInfs.concat(highlightInfo.recAtomInfs), highlightInfo.interactionName);
        }
    
        if (Store.store["state"]["bondVisible"]) {
            drawCylinders(highlightInfo.interactionType, highlightInfo.interactionName);
        }

jdurrant's avatar
jdurrant committed
215
        ligandInteractingResidues.push(...highlightInfo.recAtomInfs.map(
216
217
218
219
            i => i[0]["index"]
        ));
    }

jdurrant's avatar
jdurrant committed
220
221
222
223
224
225
226
227
    showDetectedLigandInteractingResidues(receptorMol);

    // Show protein ribbon again (otherwise sometimes parts of ribbon
    // disappear).
    // ThreeDMol.showProteinRibbon(true);

    viewer["render"]();
}
228

jdurrant's avatar
jdurrant committed
229
export function showDetectedLigandInteractingResidues(receptorMol: any, clearExisting=false): void {
230
231
232
    // Regardless, make sure residues participating in interactions appear.
    receptorMol["setStyle"](
        {
jdurrant's avatar
jdurrant committed
233
            "index": ligandInteractingResidues,
234
235
236
237
            "byres": true
        },
        {
            "stick": { "radius": 0.1 },  // 0.15
jdurrant's avatar
jdurrant committed
238
            // "cartoon": { "color": 'spectrum' },
239
        },
jdurrant's avatar
jdurrant committed
240
        !clearExisting  // add
241
242
243
    );
}

jdurrant's avatar
jdurrant committed
244
245
246
247
/**
 * Highlights the specified interaction in the viewer. Sets the atoms involved
 * in the interaction to a different color.
 * @param  {string} interactionName  The name of the interaction.
248
249
 * @returns *  Information about this interaction, that will ultimately be used
 *             to highlight the atoms.
jdurrant's avatar
jdurrant committed
250
 */
251
export function getInfoForHighlight(interactionName: string): IHighlightInfo {
jdurrant's avatar
jdurrant committed
252
253
254
255
256
257
258
259
260
    // make an array for the interactions
    let interactionType = binanaData[interactionName];

    // A single atom may participate in multiple interactions with other
    // atoms. Make sure each atom is rendered in the viewer only once.
    idxOfAtomsSeen = new Set([]);
    let ligAtomInfs = [];
    let recAtomInfs = [];

261
262
263
    // DEPRECIATED IN FAVOR OF TABLE DECRIPTION, but leave this commented in
    // case you want to bring it back.
    // let colorMsg = Store.defaultColorMsg;
jdurrant's avatar
jdurrant committed
264
265
266

    // loop through the interactions
    for (let i = 0; i < interactionType.length; i++) {
jdurrant's avatar
jdurrant committed
267

jdurrant's avatar
jdurrant committed
268
269
270
271
272
273
        let ligandAtomInfs = interactionType[i]["ligandAtoms"];
        let receptorAtomInfs = interactionType[i]["receptorAtoms"];

        // Start by assuming color by molecule.
        let ligColor = "yellow";
        let recepColor = "red";
274
        // colorMsg = "Ligand atoms are highlighted in yellow, and receptor atoms are highlighted in red.";
jdurrant's avatar
jdurrant committed
275

jdurrant's avatar
jdurrant committed
276
        if (Store.store["state"]["colorByInteraction"] === Store.InteractionColoring.INTERACTION) {
jdurrant's avatar
jdurrant committed
277
278
279
280
281
282
283
284
285
286
            // Instead color by interaction.
            switch (interactionName) {
                case "hydrogenBonds":
                    if (ligandAtomInfs.length == 2) {
                        ligColor = "yellow";
                        recepColor = "red";
                    } else {
                        ligColor = "red";
                        recepColor = "yellow";
                    }
287
                    // colorMsg = "Hydrogen-bond donors are highlighted in yellow, and hydrogen-bond acceptors are highlighted in red.";
jdurrant's avatar
jdurrant committed
288
289
290
291
292
293
294
295
296
297
298
                    break;
                case "saltBridges":
                    if (["LYS", "ARG", "HIS", "ARN", "HIP"].indexOf(receptorAtomInfs[0]["resName"]) !== -1) {
                        // Protein residue is positive.
                        recepColor = "blue";
                        ligColor = "red";
                    } else {
                        // Protein residue is negative.
                        recepColor = "red";
                        ligColor = "blue";
                    }
299
                    // colorMsg = "Positively charged groups are highlighted in blue, and negatively charged groups are highlighted in red.";
jdurrant's avatar
jdurrant committed
300
301
302
303
                    break;
            }
        }

jdurrant's avatar
jdurrant committed
304
305
306
307
308
309
        ligAtomInfs = ligAtomInfs.concat(
            getAtomObjRadiusColor(ligandMol, ligandAtomInfs, ligColor)
        );
        recAtomInfs = recAtomInfs.concat(
            getAtomObjRadiusColor(receptorMol, receptorAtomInfs, recepColor)
        );
jdurrant's avatar
jdurrant committed
310
311
    }

312
313
314
315
316
    return {
        ligAtomInfs,
        recAtomInfs,
        interactionType,
        interactionName,
jdurrant's avatar
jdurrant committed
317
    }
jdurrant's avatar
jdurrant committed
318
319
320
321
322
}

/**
 * Draws interaction spheres in the 3Dmoljs viewer.
 * @param  {*} atomInfs  Information about the atoms.
323
 * @param  {string} interactionName  The name of the interaction.
jdurrant's avatar
jdurrant committed
324
325
 * @returns void
 */
326
327
328
329
330
331
function drawSpheres(atomInfs: any[], interactionName: string): void {
    // Certain interactionNames aren't associated with spheres.
    if (sphereOnlyReps.indexOf(interactionName) === -1) {
        return;
    }

jdurrant's avatar
jdurrant committed
332
333
334
335
336
337
    const coorsLen = atomInfs.length;
    for (let i = 0; i < coorsLen; i++) {
        const atomInf = atomInfs[i];
        const atom = atomInf[0];
        viewer["addSphere"]({
            "center": {"x": atom["x"], "y": atom["y"], "z": atom["z"]},
338
339
            "radius": 0.6 * atomInf[1],   // scale down vdw radius a bit. Was 0.6.
            "color": interactionsInfo[interactionName].colorHex,  // atomInf[2],
jdurrant's avatar
jdurrant committed
340
            "opacity": 0.65
jdurrant's avatar
jdurrant committed
341
342
343
344
        });
    }
}

jdurrant's avatar
jdurrant committed
345
346
347
348
349
350
351
352
/**
 * Draws the cylinders representing the interactions.
 * @param  {*}      interactionType  The atom informations that match this
 *                                   interaction type.
 * @param  {string} interactionName  The name of the interaction.
 * @returns void
 */
function drawCylinders(interactionType: any[], interactionName: string): void {
353
354
355
356
357
    // Certain interactionNames aren't associated with cylinder bonds.
    if (sphereOnlyReps.indexOf(interactionName) !== -1) {
        return;
    }

jdurrant's avatar
jdurrant committed
358
359
360
361
362
363
    // Get atoms.
    let interactionTypeAtoms = interactionType.map(i => [
        i["ligandAtoms"].map(l => atomInfTo3DMolAtom(ligandMol, l)),
        i["receptorAtoms"].map(r => atomInfTo3DMolAtom(receptorMol, r))
    ]);

364
365
    if (["hydrogenBonds", "halogenBonds"].indexOf(interactionName) !== -1) {
        let hBondHeavyAtomPairs = interactionTypeAtoms.map(i => [
366
367
            [2 - i[0].length, i[0].filter(a => a !== undefined && a["elem"] !== "H")[0]],
            [2 - i[1].length, i[1].filter(a => a !== undefined && a["elem"] !== "H")[0]]
368
369
370
371
        ]);
        hBondHeavyAtomPairs = hBondHeavyAtomPairs.map(i => i.sort().map(i2 => i2[1]));
    
        for (let i = 0; i < hBondHeavyAtomPairs.length; i++){
372
373
374
375
376
377
378
379
380
381
382
383
384
385
            if (hBondHeavyAtomPairs[i][0] !== undefined && hBondHeavyAtomPairs[i][1] !== undefined) {
                // viewer["addCylinder"]({
                viewer["addArrow"]({
                    "dashed": true,
                    "start": {"x": hBondHeavyAtomPairs[i][0]["x"], "y": hBondHeavyAtomPairs[i][0]["y"], "z": hBondHeavyAtomPairs[i][0]["z"]},
                    "end": {"x": hBondHeavyAtomPairs[i][1]["x"], "y": hBondHeavyAtomPairs[i][1]["y"], "z": hBondHeavyAtomPairs[i][1]["z"]},
                    "radius": 0.125, // 0.1,
                    "radiusRatio": 3.0,
                    "mid": 0.7,
                    "fromCap": 2,
                    "toCap": 2,
                    "color": interactionsInfo[interactionName].colorHex // 'black'
                });
            }
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
        }
    } else {
        // If not hydrogen bond, just line between geometric centers.
        let centerPoints = interactionTypeAtoms.map(i => [
            [i[0].length, i[0].map(a => [a["x"], a["y"], a["z"]]).reduce(
                (c1, c2) => [(c1[0] + c2[0]), (c1[1] + c2[1]), (c1[2] + c2[2])]
            )],
            [i[1].length, i[1].map(a => [a["x"], a["y"], a["z"]]).reduce(
                (c1, c2) => [(c1[0] + c2[0]), (c1[1] + c2[1]), (c1[2] + c2[2])]
            )],
        ]);
        centerPoints = centerPoints.map(i => [
            i[0][1].map(v => v / i[0][0]),
            i[1][1].map(v => v / i[1][0]),
        ]);
    
        for (let i = 0; i < centerPoints.length; i++) {
            let start = {"x": centerPoints[i][0][0], "y": centerPoints[i][0][1], "z": centerPoints[i][0][2]};
            let end = {"x": centerPoints[i][1][0], "y": centerPoints[i][1][1], "z": centerPoints[i][1][2]};
    
            viewer["addCylinder"]({
            // viewer["addArrow"]({
                "dashed": true,
                "start": start,
                "end": end,
                "radius": 0.125,  // 0.1,
                // "radiusRatio": 3.0,
                // "mid": 0.7,
                "fromCap": 2,
                "toCap": 2,
                "color": interactionsInfo[interactionName].colorHex  // 'black'
            });
        }
jdurrant's avatar
jdurrant committed
419
420
421
    }
}

jdurrant's avatar
jdurrant committed
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
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
// See https://en.wikipedia.org/wiki/Atomic_radii_of_the_elements_(data_page)
let vdwRadii = {
    "H": 1.20,
    "He": 1.40,
    "Li": 1.82,
    "Be": 1.53,
    "B": 1.92,
    "C": 1.70,
    "N": 1.55,
    "O": 1.52,
    "F": 1.47,
    "Ne": 1.54,
    "Na": 2.27,
    "Mg": 1.73,
    "Al": 1.84,
    "Si": 2.10,
    "P": 1.80,
    "S": 1.80,
    "Cl": 1.75,
    "Ar": 1.88,
    "K": 2.75,
    "Ca": 2.31,
    "Sc": 2.11,
    "Ni": 1.63,
    "Cu": 1.40,
    "Zn": 1.39,
    "Ga": 1.87,
    "Ge": 2.11,
    "As": 1.85,
    "Se": 1.90,
    "Br": 1.85,
    "Kr": 8.8,
    "Rb": 3.03,
    "Sr": 2.49,
    "Pd": 1.63,
    "Ag": 1.72,
    "Cd": 1.58,
    "In": 1.93,
    "Sn": 2.17,
    "Sb": 2.06,
    "Te": 2.06,
    "I": 1.98,
    "Xe": 1.08,
    "Cs": 3.43,
    "Ba": 2.68,
    "Pr": 1.0,
    "Nd": 2.0,
    "Pt": 1.75,
    "Au": 1.66,
    "Hg": 1.55,
    "Tl": 1.96,
    "Pb": 2.02,
    "Bi": 2.07,
    "Po": 1.97,
    "At": 1.27,
    "Rn": 1.20
}

jdurrant's avatar
jdurrant committed
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
/**
 * Converts atom information to a 3dmoljs atom.
 * @param  {*} mol      The 3dmol.js molecule.
 * @param  {*} atomInf  Information about the atom.
 * @returns *  The 3dmoljs atom.
 */
function atomInfTo3DMolAtom(mol: any, atomInf: any): any {
    let selecteds = mol["selectedAtoms"]({
        "atom": atomInf["atomName"],
        "serial": atomInf["atomIndex"],
        "resi": atomInf["resID"]
    });
    let selected = selecteds[0];  //  Should be only one such atom.
    return selected;
}

jdurrant's avatar
jdurrant committed
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
/**
 * Gets the info about the atoms.
 * @param  {*} mol         The molecule with the atoms.
 * @param  {*} atomInfs    The atom information.
 * @param  {string} color  The highlighting color to use.
 * @returns *  A list of atom data ([atom,radius,color], [atom,radius,color],
 *             ...)
 */
function getAtomObjRadiusColor(mol: any, atomInfs: any, color: string): any[] {
    // Keep track of ligand and receptor coordinates where spheres should be
    // added.
    let atomObjsRadiiColors = [];

    for (let j = 0; j < atomInfs.length; j++) {
        // change the color for the atom
        let atomInf = atomInfs[j];
jdurrant's avatar
jdurrant committed
512

jdurrant's avatar
jdurrant committed
513
514
515
516
        if (idxOfAtomsSeen.has(atomInf["atomIndex"])) {
            continue;
        }
        idxOfAtomsSeen.add(atomInf["atomIndex"]);
jdurrant's avatar
jdurrant committed
517
        let atom = atomInfTo3DMolAtom(mol, atomInf);
518
519
520
521
522
523
524
        if (atom === undefined) {
            // This happens is PDB fed to binana doesn't match one in viewport.
            // For example, you removed water molcules in web interface, but PDB
            // fed to BINANA still includes water molecules.
            continue;
        }

jdurrant's avatar
jdurrant committed
525
        let radius = vdwRadii[atom["elem"]];
526

jdurrant's avatar
jdurrant committed
527
528
529
530
531
532
533
534
535
536
537
538
539
        radius = radius === undefined ? 1.5 : radius;

        atomObjsRadiiColors.push([atom, radius, color])
    }

    return atomObjsRadiiColors;
}

/**
 * Clears the previous interactions displayed in the 3Dmoljs viewer.
 * @returns void
 */
export function clearInteraction(): void {
jdurrant's avatar
jdurrant committed
540
541
542
543
    if (viewer === undefined) {
        return;
    }

jdurrant's avatar
jdurrant committed
544
    ThreeDMol.showSticksOrRibbonAsAppropriate();
jdurrant's avatar
jdurrant committed
545
546
547
548

    viewer["removeAllShapes"]();
    viewer["render"]();
}
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

export function highlightAll(): void {
    let interactionVisibilityStatus = JSON.parse(Store.store.state["interactionVisibilityStatus"]);

    clearInteraction();

    let highlightInfos = [];
    let tableData = [];
    for (let interactionName of renderOrder) {
        if (interactionVisibilityStatus[interactionName]) {
            highlightInfos.push(
                getInfoForHighlight(interactionName)
            );

            let interactionInfo = interactionsInfo[interactionName];
            let linewidth = "50";
            let linkIcon = `<svg version="1.1" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="612px" height="792px" viewBox="0 0 612 792" xml:space="preserve"> <path fill="#FFFFFF" stroke="#000000" stroke-width="${linewidth}" d="M30.6,304.2h367.2v367.2H30.6V304.2z"/> <path fill="#FFFFFF" stroke="#000000" stroke-width="${linewidth}" d="M275.4,181.8v-61.2h306v306h-61.2L459,365.4L275.4,549L153,426.6 L336.6,243L275.4,181.8z"/></svg>`;
            let linkEncoded = "data:image/svg+xml;base64," + btoa(linkIcon);

            tableData.push({
                "Name": `${interactionInfo.name} <a target="_blank" href="${interactionInfo.link}"><img style="width:15px; height:15px; position:relative; top:-2px; margin-left:3px;" src="${linkEncoded}"></a>`,
                "Representation": firstLetterCapital(
                    interactionInfo.representation
                        .replace(/COLOR/g, `<span style="font-weight:bold; color:${interactionInfo.colorHex}; text-shadow: 1px 1px 2px #555555;">${interactionInfo.color}</span>`)
                ) + ".",
574
                "interactionName": interactionName
575
576
577
578
579
580
581
582
583
584
585
586
                // "Link": interactionInfo.link
            });
        }
    }

    Store.store.commit("setVar", {
        name: "legendItems",
        val: tableData
    })

    highlight(highlightInfos);
}